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)).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) role.user_set.update(token_expired=0) role.save() return json_response(error=error)
def get(self, request): form, error = JsonParser( Argument('id', type=int, help='未指定操作对象'), Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数'), Argument('env_id', type=int, help='缺少必要参数'), ).parse(request.GET) if error is None: form.o_id, data = form.pop('id'), [] for item in Config.objects.filter(**form).annotate( update_user=F('updated_by__nickname')): tmp = item.to_dict() tmp['update_user'] = item.update_user data.append(tmp) return json_response(data) return json_response(error=error)
def post(self, request): form, error = JsonParser( Argument('o_id', type=int, help='缺少必要参数'), Argument('env_id', type=int, help='缺少必要参数'), Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数')).parse(request.body) if error is None: data = [] for item in ConfigHistory.objects.filter(**form).annotate( update_user=F('updated_by__nickname')): tmp = item.to_dict() tmp['action_alias'] = item.get_action_display() tmp['update_user'] = item.update_user data.append(tmp) return json_response(data) return json_response(error=error)
def patch(self, request): form, error = JsonParser( Argument('id', type=int, help='请指定操作对象'), Argument('is_active', type=bool, required=False) ).parse(request.body, True) if error is None: Task.objects.filter(pk=form.id).update(**form) if form.get('is_active') is not None: if form.is_active: task = Task.objects.filter(pk=form.id).first() message = {'id': form.id, 'action': 'add'} message.update(task.to_dict(selects=('trigger', 'trigger_args', 'command', 'targets'))) else: message = {'id': form.id, 'action': 'remove'} rds_cli = get_redis_connection() rds_cli.lpush(settings.SCHEDULE_KEY, json.dumps(message)) 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: 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) if request.user.role: request.user.role.add_deploy_perm('apps', app.id) return json_response(error=error)
def get(self, request): form, error = JsonParser(Argument('id', type=int, help='参数错误'), Argument('file', help='请输入文件路径')).parse(request.GET) if error is None: host = Host.objects.filter(pk=1).first() if not host: return json_response(error='未找到指定主机') filename = os.path.basename(form.file) cli = host.get_ssh().get_client() sftp = cli.open_sftp() f = sftp.open(form.file) return FileResponseAfter(cli.close, f, as_attachment=True, filename=filename) return json_response(error=error)
def post(self, request): form, error = JsonParser( Argument('id', type=int, required=False), Argument('name', help='请输入联系人姓名'), Argument('phone', required=False), Argument('email', required=False), Argument('ding', required=False), Argument('wx_token', required=False), Argument('qy_wx', required=False), ).parse(request.body) if error is None: if form.id: Contact.objects.filter(pk=form.id).update(**form) else: form.created_by = request.user Contact.objects.create(**form) return json_response(error=error)
def post_diff(request): form, error = JsonParser( Argument('o_id', type=int, help='缺少必要参数'), Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数'), Argument('envs', type=list, filter=lambda x: len(x), help='缺少必要参数'), ).parse(request.body) if error is None: data, form.env_id__in = {}, form.pop('envs') for item in Config.objects.filter(**form).order_by('key'): if item.key in data: data[item.key][item.env_id] = item.value else: data[item.key] = {'key': item.key, item.env_id: item.value} return json_response(list(data.values())) return json_response(error=error)
def post_request_ext2(request): form, error = JsonParser( Argument('id', type=int, required=False), Argument('deploy_id', type=int, help='缺少必要参数'), Argument('name', help='请输申请标题'), Argument('host_ids', type=list, filter=lambda x: len(x), help='请选择要部署的主机'), Argument('extra', type=dict, required=False), Argument('version', default=''), Argument('type', default='1'), Argument('plan', required=False), Argument('desc', 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='未找到该发布配置') extra = form.pop('extra') if DeployExtend2.objects.filter( deploy=deploy, host_actions__contains='"src_mode": "1"').exists(): if not extra: return json_response( error='该应用的发布配置中使用了数据传输动作且设置为发布时上传,请上传要传输的数据') form.spug_version = extra['path'] form.extra = json.dumps(extra) else: form.spug_version = Repository.make_spug_version(deploy.id) form.name = form.name.replace("'", '') form.status = '0' if deploy.is_audit else '1' form.host_ids = json.dumps(form.host_ids) if form.id: req = DeployRequest.objects.get(pk=form.id) is_required_notify = deploy.is_audit and req.status == '-1' DeployRequest.objects.filter(pk=form.id).update( created_by=request.user, reason=None, **form) else: req = DeployRequest.objects.create(created_by=request.user, **form) is_required_notify = deploy.is_audit if is_required_notify: Thread(target=Helper.send_deploy_notify, args=(req, 'approve_req')).start() 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('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) 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 try: CronTrigger(minute=minute, hour=hour, day=day, month=month, 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 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='标识符必须为字母、数字、-和下划线的组合') service = Service.objects.filter(key=form.key).first() if service and service.id != form.id: return json_response(error=f'唯一标识符 {form.key} 已存在,请更改后重试') if form.id: Service.objects.filter(pk=form.id).update(**form) else: Service.objects.create(created_by=request.user, **form) 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() return json_response(error=error)
def delete(self, request): form, error = JsonParser(Argument('id', type=int, help='请指定操作对象')).parse(request.GET) if error is None: rel_apps = [] for app in App.objects.filter(rel_services__isnull=False): rel_services = json.loads(app.rel_services) if form.id in rel_services: rel_apps.append(app.name) if rel_apps: return json_response( error= f'该服务在配置中心已被 "{", ".join(rel_apps)}" 依赖,请解除依赖关系后再尝试删除。') # auto delete configs Config.objects.filter(type='src', o_id=form.id).delete() ConfigHistory.objects.filter(type='src', o_id=form.id).delete() Service.objects.filter(pk=form.id).delete() return json_response(error=error)
def delete(self, request): form, error = JsonParser( Argument('id', type=int, help='请指定操作对象') ).parse(request.GET) if error is None: if Deploy.objects.filter(app_id=form.id).exists(): return json_response(error='该应用在应用发布中已存在关联的发布配置,请删除相关发布配置后再尝试删除') # auto delete configs Config.objects.filter(type='app', o_id=form.id).delete() ConfigHistory.objects.filter(type='app', o_id=form.id).delete() for app in App.objects.filter(rel_apps__isnull=False): rel_apps = json.loads(app.rel_apps) if form.id in rel_apps: rel_apps.remove(form.id) app.rel_apps = json.dumps(rel_apps) app.save() App.objects.filter(pk=form.id).delete() return json_response(error=error)
def post(self, request): form, error = JsonParser( Argument('id', type=int, required=False), Argument('name', help='请输入引擎名称'), Argument('engine_type', filter=lambda x: x in dict(ExecEngine.ENGINE_TYPES), help='请选择引擎类型'), Argument('start_user', help='请输入启动用户', required=False), Argument('start_command', help='请输入启动命令', required=False), Argument('start_script', help='请输入启动脚本', required=False), Argument('engine_desc', required=False)).parse(request.body) if error is None: if form.id: # 更新 ExecEngine.objects.filter(pk=form.pop('id')).update(**form) else: ExecEngine.objects.create(**form) return json_response(error=error)
def ldap_test(request): form, error = JsonParser( Argument('server'), Argument('port', type=int), Argument('admin_dn'), Argument('password'), ).parse(request.body) if error is None: try: con = ldap.initialize("ldap://{0}:{1}".format( form.server, form.port), bytes_mode=False) con.simple_bind_s(form.admin_dn, form.password) return json_response() except Exception as e: error = eval(str(e)) return json_response(error=error['desc']) 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: 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, os.path.join(form.path, file.name), callback=callback) 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 post(self, request): form, error = JsonParser( Argument('o_id', type=int, help='缺少必要参数'), Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数'), Argument('envs', type=list, filter=lambda x: len(x), help='请选择环境'), Argument('key', help='请输入Key'), Argument('is_public', type=bool, help='缺少必要参数'), Argument('value', type=str, default=''), Argument('desc', required=False) ).parse(request.body) if error is None: form.value = form.value.strip() form.updated_at = human_datetime() form.updated_by = request.user envs = form.pop('envs') for env_id in envs: Config.objects.create(env_id=env_id, **form) ConfigHistory.objects.create(action='1', env_id=env_id, **form) return json_response(error=error)
def delete(self, request): form, error = JsonParser( Argument('id', type=int, help='参数错误') ).parse(request.GET) if error is None: group = Group.objects.filter(pk=form.id).first() if not group: return json_response(error='未找到指定分组') if Group.objects.filter(parent_id=group.id).exists(): return json_response(error='请移除子分组后再尝试删除') if group.hosts.exists(): return json_response(error='请移除分组下的主机后再尝试删除') if not Group.objects.exclude(pk=form.id).exists(): return json_response(error='请至少保留一个分组') role = Role.objects.filter(group_perms__regex=fr'[^0-9]{form.id}[^0-9]').first() if role: return json_response(error=f'账户角色【{role.name}】的主机权限关联该分组,请解除关联后再尝试删除') group.delete() return json_response(error=error)
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 post(self, request): form, error = JsonParser( Argument('id', type=int, required=False), Argument('name', help='请输入任务名称'), Argument('addr', help='请输入监控地址'), Argument('type', filter=lambda x: x in dict(Detection.TYPES), help='请选择监控类型'), Argument('extra', required=False), Argument('desc', required=False), Argument('rate', type=int, default=5), Argument('threshold', type=int, default=3), Argument('quiet', type=int, default=24 * 60), Argument('notify_grp', type=list, required=False), Argument('notify_mode', type=list, required=False), ).parse(request.body) if error is None: add_monitor(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) return json_response(token) 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.key = form.key.replace("'", '') env = Environment.objects.filter(key=form.key).first() if env and env.id != form.id: return json_response(error=f'唯一标识符 {form.key} 已存在,请更改后重试') if form.id: Environment.objects.filter(pk=form.id).update(**form) else: env = Environment.objects.create(created_by=request.user, **form) if request.user.role: request.user.role.add_deploy_perm('envs', env.id) return json_response(error=error)
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(self, request): form, error = JsonParser( Argument('id', type=int, required=False), Argument('name', help='请输入模版名称'), Argument('type', help='请选择模版类型'), Argument('body', help='请输入模版内容'), Argument('interpreter', default='sh'), Argument('host_ids', type=list, handler=json.dumps, default=[]), Argument('desc', required=False) ).parse(request.body) if error is None: if form.id: form.updated_at = human_datetime() form.updated_by = request.user ExecTemplate.objects.filter(pk=form.pop('id')).update(**form) else: form.created_by = request.user ExecTemplate.objects.create(**form) return json_response(error=error)
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('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('id', type=int, required=False), Argument('title', help='请输入导航标题'), Argument('desc', help='请输入导航描述'), Argument('logo', help='请上传导航logo'), Argument('links', type=list, filter=lambda x: len(x), help='请设置导航链接'), ).parse(request.body) if error is None: form.links = json.dumps(form.links) if form.id: Navigation.objects.filter(pk=form.id).update(**form) else: nav = Navigation.objects.create(**form) nav.sort_id = nav.id nav.save() return json_response(error=error)
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)