def email_test(request): form, error = JsonParser( Argument('server', help='请输入邮件服务地址'), Argument('port', type=int, help='请输入邮件服务端口号'), Argument('username', help='请输入邮箱账号'), Argument('password', help='请输入密码/授权码'), ).parse(request.body) if error is None: try: if form.port == 465: server = smtplib.SMTP_SSL(form.server, form.port) else: server = smtplib.SMTP(form.server, form.port) server.login(form.username, form.password) return json_response() except Exception as e: error = e.smtp_error.decode('utf-8') return json_response(error=error) return json_response(error=error)
def parse_text(request): form, error = JsonParser( Argument('o_id', type=int, help='缺少必要参数'), Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数'), Argument('env_id', type=int, help='缺少必要参数'), Argument('data', handler=str.strip, help='缺少必要参数')).parse(request.body) if error is None: data = {} for line in form.pop('data').split('\n'): line = line.strip() if line: fields = line.split('=', 1) if len(fields) != 2 or fields[0].strip() == '': return json_response( error=f'解析配置{line!r}失败,确认其遵循 key = value 格式') data[fields[0].strip()] = fields[1].strip() _parse(request, form, data) return json_response(error=error)
def get(self, request): hosts = Host.objects.filter(deleted_by_id__isnull=True) zones = [ x['zone'] for x in hosts.order_by('zone').values('zone').distinct() ] return json_response({ 'zones': zones, 'hosts': [x.to_dict() for x in hosts] })
def patch(self, request): form, error = JsonParser( Argument('id', type=int, help='请指定操作对象'), Argument('username', required=False), Argument('password', required=False), Argument('nickname', required=False), Argument('role_id', required=False), Argument('is_active', type=bool, required=False), ).parse(request.body, True) if error is None: if form.get('password'): form.token_expired = 0 form.password_hash = User.make_password(form.pop('password')) if User.objects.filter( username=form.username, deleted_by_id__isnull=True).exclude(id=form.id).exists(): return json_response(error=f'已存在登录名为【{form.username}】的用户') User.objects.filter(pk=form.pop('id')).update(**form) return json_response(error=error)
def post_import(request): password = request.POST.get('password') file = request.FILES['file'] ws = load_workbook(file, read_only=True)['Sheet1'] summary = { 'invalid': [], 'skip': [], 'fail': [], 'network': [], 'repeat': [], 'success': [], 'error': [] } for i, row in enumerate(ws.rows): if i == 0: # 第1行是表头 略过 continue if not all([row[x].value for x in range(5)]): summary['invalid'].append(i) continue data = AttrDict(zone=row[0].value, name=row[1].value, hostname=row[2].value, port=row[3].value, username=row[4].value, password=row[5].value, desc=row[6].value) if Host.objects.filter(hostname=data.hostname, port=data.port, username=data.username, deleted_by_id__isnull=True).exists(): summary['skip'].append(i) continue try: if valid_ssh(data.hostname, data.port, data.username, data.pop('password') or password, False) is False: summary['fail'].append(i) continue except AuthenticationException: summary['fail'].append(i) continue except socket.error: summary['network'].append(i) continue except Exception: summary['error'].append(i) continue if Host.objects.filter(name=data.name, deleted_by_id__isnull=True).exists(): summary['repeat'].append(i) continue host = Host.objects.create(created_by=request.user, **data) if request.user.role: request.user.role.add_host_perm(host.id) summary['success'].append(i) return json_response(summary)
def login(request): form, error = JsonParser(Argument('username', help='请输入用户名'), Argument('password', help='请输入密码')).parse(request.body) if error is None: user = User.objects.filter(username=form.username).first() if user: if not user.is_active: return json_response(error="账户已被禁用") if user.verify_password(form.password): cache.delete(form.username) x_real_ip = request.headers.get('x-real-ip', '') token_isvalid = user.access_token and len( user.access_token ) == 32 and user.token_expired >= time.time() user.access_token = user.access_token if token_isvalid else uuid.uuid4( ).hex user.token_expired = time.time() + 8 * 60 * 60 user.last_login = human_datetime() user.last_ip = x_real_ip user.save() return json_response({ 'access_token': user.access_token, 'nickname': user.nickname, 'is_supper': user.is_supper, 'has_real_ip': True if x_real_ip else False, 'permissions': [] if user.is_supper else user.page_perms }) value = cache.get_or_set(form.username, 0, 86400) if value >= 3: if user and user.is_active: user.is_active = False user.save() return json_response(error='账户已被禁用') cache.set(form.username, value + 1, 86400) return json_response(error="用户名或密码错误,连续多次错误账户将会被禁用") return json_response(error=error)
def post(self, request): form, error = JsonParser( Argument('id', type=int, help='参数错误'), Argument('token', help='参数错误'), Argument('path', help='参数错误'), ).parse(request.POST) if error is None: if not request.user.has_host_perm(form.id): return json_response(error='无权访问主机,请联系管理员') file = request.FILES.get('file') if not file: return json_response(error='请选择要上传的文件') host = Host.objects.get(pk=form.id) if not host: return json_response(error='未找到指定主机') cli = host.get_ssh() rds_cli = get_redis_connection() callback = partial(self._compute_progress, rds_cli, form.token, file.size) cli.put_file_by_fl(file, f'{form.path}/{file.name}', callback=callback) return json_response(error=error)
def patch(self, request, r_id): form, error = JsonParser(Argument('reason', required=False), Argument('is_pass', type=bool, help='参数错误')).parse(request.body) if error is None: req = DeployRequest.objects.filter(pk=r_id).first() if not req: return json_response(error='未找到指定申请') if not form.is_pass and not form.reason: return json_response(error='请输入驳回原因') if req.status != '0': return json_response(error='该申请当前状态不允许审核') req.approve_at = human_datetime() req.approve_by = request.user req.status = '1' if form.is_pass else '-1' req.reason = form.reason req.save() Thread(target=Helper.send_deploy_notify, args=(req, 'approve_rst')).start() return json_response(error=error)
def parse_json(request): form, error = JsonParser( Argument('o_id', type=int, help='缺少必要参数'), Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数'), Argument('env_id', type=int, help='缺少必要参数'), Argument('data', type=dict, help='缺少必要参数')).parse(request.body) if error is None: data = form.pop('data') _parse(request, form, data) return json_response(error=error)
def post(self, request): form, error = JsonParser(Argument('id', type=int, required=False), Argument('name', help='请输入服务名称'), Argument('key', help='请输入唯一标识符'), Argument('desc', required=False)).parse(request.body) if error is None: form.name = form.name.replace("'", '') app = App.objects.filter(key=form.key).first() if app and app.id != form.id: return json_response(error=f'唯一标识符 {form.key} 已存在,请更改后重试') if form.id: App.objects.filter(pk=form.id).update(**form) else: app = App.objects.create(created_by=request.user, **form) app.sort_id = app.id app.save() if request.user.role: request.user.role.add_deploy_perm('apps', app.id) return json_response(error=error)
def post(self, request): form, error = JsonParser(Argument('id', type=int, required=False), Argument('name', help='请输入角色名称'), Argument('desc', required=False)).parse(request.body) if error is None: if form.id: Role.objects.filter(pk=form.id).update(**form) else: Role.objects.create(created_by=request.user, **form) return json_response(error=error)
def do_task(request): form, error = JsonParser( Argument('host_ids', type=list, filter=lambda x: len(x), help='请选择执行主机'), Argument('command', help='请输入执行命令内容') ).parse(request.body) if error is None: if not request.user.has_host_perm(form.host_ids): return json_response(error='无权访问主机,请联系管理员') token = Channel.get_token() for host in Host.objects.filter(id__in=form.host_ids): Channel.send_ssh_executor( token=token, hostname=host.hostname, port=host.port, username=host.username, command=form.command, pkey=host.private_key, ) return json_response(token) return json_response(error=error)
def delete(self, request): form, error = JsonParser(Argument('id', type=int, help='请指定操作对象')).parse(request.GET) if error is None: user = User.objects.filter(pk=form.id).first() if user: user.role_id = None user.deleted_at = human_datetime() user.deleted_by = request.user user.save() return json_response(error=error)
def get(self, request): #定义get返回函数 host_id = request.GET.get('id') #判断前端是否带有host_id参数请求 if host_id: #如果带host_id参数 if not request.user.has_host_perm(host_id): #判断用户使用有权限 return json_response(error='无权访问该主机,请联系管理员') #返回无权限提示信息 return json_response(Host.objects.get(pk=host_id)) #有权限则返回host_id hosts = Host.objects.filter( deleted_by_id__isnull=True) #从数据库获取hosts信息(id不为空) zones = [ x['zone'] for x in hosts.order_by('zone').values('zone').distinct() ] #从hosts中获取zones信息 perms = [ x.id for x in hosts ] if request.user.is_supper else request.user.host_perms #分离权限信息 return json_response({ 'zones': zones, 'hosts': [x.to_dict() for x in hosts], 'perms': perms }) #返回区域,主机,权限等信息
def delete(self, request): form, error = JsonParser( Argument('host_list', type=list, help='请输入主机列表'), ).parse(request.GET) if error is None and len(form.host_list) > 0: for host in form.host_list: Host.objects.filter(pk=host.get('id')).update( deleted_at=human_datetime(), deleted_by=request.user, ) return json_response(error=error)
def patch(self, request): form, error = JsonParser( Argument('id', type=int, help='参数错误'), Argument('page_perms', type=dict, required=False), Argument('deploy_perms', type=dict, required=False), Argument('host_perms', type=list, required=False)).parse(request.body) if error is None: role = Role.objects.filter(pk=form.pop('id')).first() if not role: return json_response(error='未找到指定角色') if form.page_perms is not None: role.page_perms = json.dumps(form.page_perms) if form.deploy_perms is not None: role.deploy_perms = json.dumps(form.deploy_perms) if form.host_perms is not None: role.host_perms = json.dumps(form.host_perms) role.user_set.update(token_expired=0) role.save() return json_response(error=error)
def get(self, request): form, error = JsonParser(Argument('app_id', type=int, required=False)).parse( request.GET, True) if not request.user.is_supper: perms = request.user.deploy_perms form.app_id__in = perms['apps'] form.env_id__in = perms['envs'] deploys = Deploy.objects.filter(**form).annotate( app_name=F('app__name')) return json_response(deploys)
def post(self, request): form, error = JsonParser( Argument('enable', type=bool, help='参数错误'), Argument('code', required=False) ).parse(request.body) if error is None: if form.enable: if not form.code: return json_response(error='请输入验证码') key = f'{request.user.username}:code' code = cache.get(key) if not code: return json_response(error='验证码已失效,请重新获取') if code != form.code: ttl = cache.ttl(key) cache.expire(key, ttl - 100) return json_response(error='验证码错误') cache.delete(key) AppSetting.set('MFA', {'enable': form.enable}) return json_response(error=error)
def post(self, request): form, error = JsonParser( Argument('username', help='请输入登录名'), Argument('password', help='请输入密码'), Argument('nickname', help='请输入姓名'), Argument('role_id', type=int, help='请选择角色'), ).parse(request.body) if error is None: form.password_hash = User.make_password(form.pop('password')) form.created_by = request.user User.objects.create(**form) return json_response(error=error)
def post(self, request): form, error = JsonParser( Argument('deploy_id', type=int, help='参数错误'), Argument('version', help='请输入构建版本'), Argument('extra', type=list, help='参数错误'), Argument('remarks', required=False) ).parse(request.body) if error is None: deploy = Deploy.objects.filter(pk=form.deploy_id).first() if not deploy: return json_response(error='未找到指定发布配置') form.extra = json.dumps(form.extra) form.spug_version = Repository.make_spug_version(deploy.id) rep = Repository.objects.create( app_id=deploy.app_id, env_id=deploy.env_id, created_by=request.user, **form) Thread(target=dispatch, args=(rep,)).start() return json_response(rep.to_view()) return json_response(error=error)
def post(self, request): form, error = JsonParser( Argument('id', type=int, required=False), Argument('zone', help='请输入主机类型'), Argument('name', help='请输主机名称'), Argument('username', help='请输入登录用户名'), Argument('hostname', help='请输入主机名或IP'), Argument('port', type=int, help='请输入SSH端口'), Argument('desc', required=False), Argument('password', required=False), ).parse(request.body) if error is None: if valid_ssh(form.hostname, form.port, form.username, form.pop('password')) is False: return json_response('auth fail') if form.id: Host.objects.filter(pk=form.pop('id')).update(**form) else: form.created_by = request.user Host.objects.create(**form) return json_response(error=error)
def get_requests(request): form, error = JsonParser( Argument('repository_id', type=int, help='参数错误') ).parse(request.GET) if error is None: requests = [] for item in DeployRequest.objects.filter(repository_id=form.repository_id): data = item.to_dict(selects=('id', 'name', 'created_at')) data['host_ids'] = json.loads(item.host_ids) data['status_alias'] = item.get_status_display() requests.append(data) return json_response(requests)
def get(self, request): # v2.3.14 临时数据初始化 app = App.objects.first() if app and hasattr(app, 'sort_id') and app.sort_id == 0: for app in App.objects.all(): app.sort_id = app.id app.save() query = {} if not request.user.is_supper: query['id__in'] = request.user.deploy_perms['apps'] apps = App.objects.filter(**query) return json_response(apps)
def patch(self, request): form, error = JsonParser( Argument('old_password', required=False), Argument('new_password', required=False), Argument('nickname', required=False), ).parse(request.body, True) if error is None: if form.get('old_password') and form.get('new_password'): if len(form.new_password) < 6: return json_response(error='请设置至少6位的新密码') if request.user.verify_password(form.old_password): request.user.password_hash = User.make_password( form.new_password) request.user.token_expired = 0 request.user.save() else: return json_response(error='原密码错误,请重新输入') if form.get('nickname'): request.user.nickname = form.nickname request.user.save() return json_response(error=error)
def post(self, request): form, error = JsonParser( Argument('id', type=int, required=False), Argument('name', help='请输入服务名称'), Argument('key', help='请输入唯一标识符'), Argument('desc', required=False) ).parse(request.body) if error is None: if not re.fullmatch(r'[-\w]+', form.key, re.ASCII): return json_response(error='标识符必须为字母、数字、-和下划线的组合') app = App.objects.filter(key=form.key).first() if app and app.id != form.id: return json_response(error=f'唯一标识符 {form.key} 已存在,请更改后重试') if form.id: App.objects.filter(pk=form.id).update(**form) else: app = App.objects.create(created_by=request.user, **form) app.sort_id = app.id app.save() return json_response(error=error)
def post(self, request): form, error = JsonParser( Argument('id', type=int, required=False), Argument('type', help='请输入任务类型'), Argument('name', help='请输入任务名称'), Argument('command', help='请输入任务内容'), Argument('rst_notify', type=dict, help='请选择执行失败通知方式'), Argument('targets', type=list, filter=lambda x: len(x), help='请选择执行对象'), Argument('trigger', filter=lambda x: x in dict(Task.TRIGGERS), help='请选择触发器类型'), Argument('trigger_args', help='请输入触发器参数'), Argument('desc', required=False), ).parse(request.body) if error is None: form.targets = json.dumps(form.targets) form.rst_notify = json.dumps(form.rst_notify) if form.trigger == 'cron': args = json.loads(form.trigger_args)['rule'].split() if len(args) != 5: return json_response(error='无效的执行规则,请更正后再试') minute, hour, day, month, week = args week = '0' if week == '7' else week try: CronTrigger(minute=minute, hour=hour, day=day, month=month, day_of_week=week) except ValueError: return json_response(error='无效的执行规则,请更正后再试') if form.id: Task.objects.filter(pk=form.id).update( updated_at=human_datetime(), updated_by=request.user, **form ) task = Task.objects.filter(pk=form.id).first() if task and task.is_active: form.action = 'modify' form.targets = json.loads(form.targets) rds_cli = get_redis_connection() rds_cli.lpush(settings.SCHEDULE_KEY, json.dumps(form)) else: Task.objects.create(created_by=request.user, **form) return json_response(error=error)
def delete(self, request): form, error = JsonParser( Argument('id', type=int, required=False), Argument('expire', required=False), Argument('count', type=int, required=False, help='请输入数字')).parse(request.GET) if error is None: if form.id: DeployRequest.objects.filter(pk=form.id, status__in=('0', '1', '-1')).delete() return json_response() elif form.count: if form.count < 1: return json_response(error='请输入正确的保留数量') counter, ids = defaultdict(int), [] for item in DeployRequest.objects.all(): if counter[item.deploy_id] == form.count: ids.append(item.id) else: counter[item.deploy_id] += 1 count, _ = DeployRequest.objects.filter(id__in=ids).delete() return json_response(count) elif form.expire: count, _ = DeployRequest.objects.filter( created_at__lt=form.expire).delete() return json_response(count) else: return json_response(error='请至少使用一个删除条件') return json_response(error=error)
def delete(self, request): form, error = JsonParser( Argument('id', type=int, required=False), Argument('mode', filter=lambda x: x in ('count', 'expire', 'deploy'), required=False, help='参数错误'), Argument('value', required=False), ).parse(request.GET) if error is None: if form.id: deploy = DeployRequest.objects.filter(pk=form.id).first() if not deploy or deploy.status not in ('0', '1', '-1'): return json_response(error='未找到指定发布申请或当前状态不允许删除') deploy.delete() return json_response() count = 0 if form.mode == 'count': if not str(form.value).isdigit() or int(form.value) < 1: return json_response(error='请输入正确的保留数量') counter, form.value = defaultdict(int), int(form.value) for item in DeployRequest.objects.all(): counter[item.deploy_id] += 1 if counter[item.deploy_id] > form.value: count += 1 item.delete() elif form.mode == 'expire': for item in DeployRequest.objects.filter( created_at__lt=form.value): count += 1 item.delete() elif form.mode == 'deploy': app_id, env_id = str(form.value).split(',') for item in DeployRequest.objects.filter( deploy__app_id=app_id, deploy__env_id=env_id): count += 1 item.delete() return json_response(count) return json_response(error=error)
def patch(self, request): form, error = JsonParser( Argument('id', type=int, help='参数错误'), Argument('sort', filter=lambda x: x in ('up', 'down'), required=False)).parse(request.body) if error is None: env = Environment.objects.filter(pk=form.id).first() if not env: return json_response(error='未找到指定环境') if form.sort: if form.sort == 'up': tmp = Environment.objects.filter( sort_id__gt=env.sort_id).last() else: tmp = Environment.objects.filter( sort_id__lt=env.sort_id).first() if tmp: tmp.sort_id, env.sort_id = env.sort_id, tmp.sort_id tmp.save() env.save() return json_response(error=error)
def delete(self, request): form, error = JsonParser( Argument('id', type=int, help='请指定操作对象') ).parse(request.GET) if error is None: deploy = Deploy.objects.filter(host_ids__regex=fr'\D{form.id}\D').annotate( app_name=F('app__name'), env_name=F('env__name') ).first() if deploy: return json_response(error=f'应用【{deploy.app_name}】在【{deploy.env_name}】的发布配置关联了该主机,请解除关联后再尝试删除该主机') task = Task.objects.filter(targets__regex=fr'\D{form.id}\D').first() if task: return json_response(error=f'任务计划中的任务【{task.name}】关联了该主机,请解除关联后再尝试删除该主机') detection = Detection.objects.filter(type__in=('3', '4'), addr=form.id).first() if detection: return json_response(error=f'监控中心的任务【{detection.name}】关联了该主机,请解除关联后再尝试删除该主机') Host.objects.filter(pk=form.id).update( deleted_at=human_datetime(), deleted_by=request.user, ) return json_response(error=error)