Exemple #1
0
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)
Exemple #2
0
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)
Exemple #3
0
 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]
     })
Exemple #4
0
 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)
Exemple #5
0
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)
Exemple #6
0
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)
Exemple #7
0
 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)
Exemple #8
0
 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)
Exemple #9
0
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)
Exemple #10
0
 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)
Exemple #11
0
 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)
Exemple #12
0
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)
Exemple #13
0
 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)
Exemple #14
0
 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
     })  #返回区域,主机,权限等信息
Exemple #15
0
 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)
Exemple #16
0
 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)
Exemple #17
0
 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)
Exemple #18
0
 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)
Exemple #19
0
 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)
Exemple #20
0
 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)
Exemple #21
0
    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)
Exemple #22
0
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)
Exemple #23
0
 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)
Exemple #24
0
 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)
Exemple #25
0
    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)
Exemple #26
0
 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)
Exemple #27
0
 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)
Exemple #28
0
    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)
Exemple #29
0
 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)
Exemple #30
0
 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)