예제 #1
0
class SubJobResult(db.Model):

    STATUS_OK = 1
    STATUS_DELETE = 2

    id = db.Column(db.BigInteger, primary_key=True)
    sub_job_id = db.Column(db.BigInteger, db.ForeignKey('sub_job.id'))
    result = db.Column(db.Text)
    created_time = db.Column(db.DateTime)
    status = db.Column(db.Integer, nullable=False)

    def __init__(self, sub_job, result, created_time=None, status=None):
        self.sub_job_id = sub_job.id
        self.result = json.dumps(result) if isinstance(result, (
            dict,
            list,
            tuple,
        )) else result
        self.created_time = timezone.now(
        ) if created_time is None else created_time
        self.status = self.STATUS_OK if status is None else status

    @classmethod
    def create(cls, sub_job, result):
        job_result = cls(sub_job=sub_job, result=result)
        db.session.add(job_result)
        db.session.commit()
        return job_result
예제 #2
0
class Role(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), nullable=True, default='')
    type = db.Column(db.Integer, nullable=True, default=0)

    created_time = db.Column(db.DateTime, nullable=False)

    status = db.Column(db.Integer, nullable=False, default=0)

    users = db.relationship('User', backref='role', lazy='dynamic')
예제 #3
0
class AssetSysVul(db.Model, AsDictMixin):
    id = db.Column(db.BigInteger, primary_key=True)
    ip = db.Column(db.String(256), nullable=False)
    plugin_ident = db.Column(db.String(128), nullable=False)
    payloads = db.Column(db.Text)
    created_time = db.Column(db.DateTime, nullable=False)
    last_discover_time = db.Column(db.DateTime, nullable=False)

    @classmethod
    def stats(cls):
        return {
            'total':
            cls.query.count(),
            '24_hour':
            cls.query.filter(cls.created_time >= timezone.now() -
                             timedelta(days=1)).count(),
        }

    @classmethod
    def stats_host_vul(cls, topn=10):
        rs = db.session.execute(
            'select ip, count(*) from asset_sys_vul group by ip  order by count desc limit :topn',
            {'topn': topn})
        return [dict(r) for r in rs]

    @classmethod
    def stats_vul_host(cls, topn=10):
        rs = db.session.execute(
            'select plugin_ident, count(*) from asset_sys_vul group by plugin_ident order by count desc limit :topn',
            {'topn': topn})
        return [dict(r) for r in rs]

    @classmethod
    def create_or_replace(cls, key, plugin_ident, payloads):
        obj = cls.query.filter_by(ip=key, plugin_ident=plugin_ident).first()
        if obj is None:
            obj = cls()
            obj.ip = key
            obj.plugin_ident = plugin_ident
            obj.created_time = timezone.now()

        obj.last_discover_time = timezone.now()
        obj.payloads = json.dumps(payloads) if isinstance(
            payloads, (list, dict)) else payloads
        db.session.add(obj)
        db.session.commit()

    @classmethod
    def delete_not_found(cls, key, now):
        cls.query.filter(cls.ip == key, cls.last_discover_time < now).delete()

    @classmethod
    def all(cls, key=None):
        query = cls.query
        if key:
            query = query.filter_by(ip=key)
        return query.all()
예제 #4
0
class WebAsset(db.Model):
    STATUS_NEW = 0
    STATUS_ACK = 1
    STATUS_OFFLINE = 2
    STATUS_DELETE = 3

    id = db.Column(db.BigInteger, primary_key=True)
    name = db.Column(db.String(32), nullable=False, default='')
    url = db.Column(db.String(256), nullable=False, default='')

    group_id = db.Column(db.BigInteger, db.ForeignKey('web_group.id'))
    sys_asset_id = db.Column(db.BigInteger, db.ForeignKey('sys_asset.id'))

    manager = db.Column(db.String(64), nullable=False, default='')

    created_time = db.Column(db.DateTime, nullable=False, default='')
    last_discove_time = db.Column(db.DateTime, nullable=False, default='')

    status = db.Column(db.Integer, nullable=False)

    @classmethod
    def all(cls):
        return cls.query.filter(cls.status.notin_([cls.STATUS_DELETE])).all()
예제 #5
0
class WebGroup(db.Model):
    STATUS_OK = 0
    STATUS_DELETE = 1

    id = db.Column(db.BigInteger, primary_key=True)
    pid = db.Column(db.BigInteger, nullable=False)
    name = db.Column(db.String(32), nullable=False, default='')
    created_time = db.Column(db.DateTime, nullable=False)

    manager = db.Column(db.String(64), nullable=False, default='')

    status = db.Column(db.Integer, nullable=False)

    assets = db.relationship('WebAsset', backref="group", lazy="dynamic")
예제 #6
0
class SysAsset(db.Model, AsDictMixin):
    WEIGHT_HIGH = 10
    WEIGHT_MEDIUM = 6
    WEIGHT_LOW = 1

    STATUS_NEW = 0
    STATUS_ACK = 1
    STATUS_DELETE = 2

    id = db.Column(db.BigInteger, primary_key=True)
    sn = db.Column(db.String(128), nullable=False, default='')
    name = db.Column(db.String(32), nullable=False, default='')
    ip = db.Column(db.String(256), nullable=False, default='')
    mac = db.Column(db.String(32), nullable=False, default='')
    os = db.Column(db.String(128), nullable=False, default='')
    group_id = db.Column(db.BigInteger, db.ForeignKey('sys_group.id'))

    manager = db.Column(db.String(64), nullable=False, default='')

    weight = db.Column(db.Integer, nullable=False)

    created_time = db.Column(db.DateTime, nullable=False)
    last_discove_time = db.Column(db.DateTime, nullable=False)

    status = db.Column(db.Integer, nullable=False)
    applications = db.relationship('Application', backref='asset', lazy='dynamic')

    @classmethod
    def stats(cls):
        return {
            'total' : cls.query.filter(cls.status.notin_([cls.STATUS_DELETE])).count(),
            '24_hour' : cls.query.filter(cls.created_time>=timezone.now() - timedelta(days=1), cls.status.notin_([cls.STATUS_DELETE])).count(),
        }

    @classmethod
    def all(cls):
        return cls.query.filter(cls.status.notin_([cls.STATUS_DELETE])).all()

    @classmethod
    def get_by_key(cls, value, key='id'):
        return db.session.query(cls).filter_by(**{key : value}).first()

    @classmethod
    def create_or_replace(cls, **kwargs):
        ip = kwargs.get('ip', '')
        obj = cls.get_by_key(ip, key='ip')
        try:

            if obj is None or obj.status == cls.STATUS_DELETE:
                obj = cls()
                obj.ip = ip
                obj.status = cls.STATUS_NEW
                obj.created_time = timezone.now()
                obj.weight = cls.WEIGHT_LOW

            obj.last_discove_time = timezone.now()
            obj.name = kwargs.get('name', obj.name)
            obj.os = kwargs.get('os', obj.os)
            obj.mac = kwargs.get('mac', obj.mac)

            db.session.add(obj)
            db.session.commit()

            for app in kwargs.get('apps', []):
                Application.create_or_replace(app.get('name', ''),
                    app.get('protocol', ''),
                    app.get('port', 0),
                    app.get('state', ''),
                    app.get('product', ''),
                    app.get('version', ''),
                    obj,
                )
        except BaseException as e:
            logger.error(e)
            logger.exception(traceback.format_exc())
            db.session.rollback()

        return obj

    @classmethod
    def delete_by_key(cls, id):
        obj = cls.get_by_key.get(id)
        if obj:
            obj.status = cls.STATUS_DELETE
            db.session.add(obj)
            db.session.commit()

        return obj
예제 #7
0
class Application(db.Model):
    STATUS_NEW = 0
    STATUS_ACK = 1
    STATUS_DELETE = 2

    id = db.Column(db.BigInteger, primary_key=True)
    name = db.Column(db.String(128), nullable=False, default='')

    protocol = db.Column(db.String(32), nullable=False, default='')
    port = db.Column(db.Integer, nullable=False, default=0)
    state = db.Column(db.String(32), nullable=False, default='')

    product = db.Column(db.String(128), nullable=False, default='')
    version = db.Column(db.String(64), nullable=False, default='')

    asset_id = db.Column(db.BigInteger, db.ForeignKey('sys_asset.id'))

    created_time = db.Column(db.DateTime, nullable=False, default='')
    last_discove_time = db.Column(db.DateTime, nullable=False, default='')
    status = db.Column(db.Integer, nullable=False)

    @classmethod
    def stats(cls):
        return {
            'total' : cls.query.filter(cls.status.notin_([cls.STATUS_DELETE])).count(),
            '24_hour' : cls.query.filter(cls.created_time>=timezone.now() - timedelta(days=1), cls.status.notin_([cls.STATUS_DELETE])).count(),
        }

    @classmethod
    def stats_port(cls):
        rs = db.session.execute('select port, count(*) from application where status != :status group by port order by count desc', {'status' : cls.STATUS_DELETE})
        return [dict(r) for r in rs]

    @classmethod
    def all(cls):
        return cls.query.filter(cls.status.notin_([cls.STATUS_DELETE])).all()

    @classmethod
    def create_or_replace(cls, name, protocol, port, state, product, version, asset, *args, **kwargs):
        obj = db.session.query(cls).filter_by(asset_id=asset.id, port=port).first()
        if obj is None or obj.status == cls.STATUS_DELETE:
            obj = cls()
            obj.port = port
            obj.created_time = timezone.now()
            obj.status = cls.STATUS_NEW
            obj.asset_id = asset.id

        obj.name = name
        obj.protocol = protocol
        obj.state = state
        obj.product = product
        obj.last_discove_time = timezone.now()

        db.session.add(obj)
        db.session.commit()
예제 #8
0
class SysVulPlugin(db.Model, ValidatorMixin, AsDictMixin):
    STATUS_OK = 1
    STATUS_DELETE = 2

    LEVEL_HEIGHT = 10
    LEVEL_MEDIUM = 6
    LEVEL_LOW = 1

    TYPE_SCRIPT = 'script'
    TYPE_SOCKET = 'socket_request'
    TYPE_HTTP = 'http_request'

    id = db.Column(db.BigInteger, primary_key=True)
    ident = db.Column(db.String(128), nullable=False, default='')
    name = db.Column(db.String(128), nullable=False, default='')
    level = db.Column(db.Integer, nullable=False)
    type = db.Column(db.String(128), nullable=False, default='')
    params = db.Column(db.Text)
    remark = db.Column(db.Text)
    links = db.Column(db.Text)
    created_time = db.Column(db.DateTime, nullable=False)
    status = db.Column(db.Integer, nullable=False)

    def __init__(self,
                 ident=None,
                 name=None,
                 level=None,
                 type=None,
                 params=None,
                 remark=None,
                 links=None,
                 created_time=None,
                 status=None,
                 id=None,
                 from_cache=False):
        self.id = id
        self.ident = ident
        self.name = name
        self.level = level
        self.type = type
        self.params = params
        self.remark = remark
        self.links = links
        self.created_time = timezone.now(
        ) if created_time is None else created_time
        self.status = self.STATUS_OK if status is None else status

    @property
    def params_object(self):
        try:
            return json.loads(self.params)
        except BaseException as e:
            logger.exception(e)
            logger.error(traceback.format_exc())
            return {}

    @classmethod
    def all(cls):
        return db.session.query(cls).filter(
            cls.status != cls.STATUS_DELETE).all()

    @classmethod
    def get_by_key(cls, value, key='id', all=False):
        params = {key: value}
        if not all:
            params['status'] = cls.STATUS_OK
        return cls.query.filter_by(**params).first()

    def to_cache(self, clear=False):
        if clear:
            redis.delete(REDIS_KEYS['PLUGIN_SYS_VUL'].format(ident=self.ident))
        else:
            redis.hmset(REDIS_KEYS['PLUGIN_SYS_VUL'].format(ident=self.ident),
                        self.as_dict_string())
        return True

    @classmethod
    def get_by_cache(cls, ident):
        bplugin = redis.hgetall(
            REDIS_KEYS['PLUGIN_SYS_VUL'].format(ident=ident))
        if bplugin:
            plugin = {'from_cache': True}
            for k, v in bplugin.items():
                plugin[k] = int(v) if k in ('id', 'level', 'status') else v

            return cls(**plugin)
        return None

    def clean(self):

        obj = self.get_by_key(self.name, 'name')
        if self.id:
            if int(self.id) != int(obj.id):
                raise ValidatorException('名称已经存在')
        elif obj:
            raise ValidatorException('名称已经存在')

        obj = self.get_by_key(self.ident, 'ident')
        if self.id:
            if int(self.id) != int(obj.id):
                raise ValidatorException('标识已经存在')
        elif obj:
            raise ValidatorException('标识已经存在')

    @classmethod
    def create_or_replace(cls,
                          ident,
                          name,
                          level,
                          type,
                          params,
                          remark,
                          links,
                          id=None):
        obj = None
        if id:
            obj = cls.get_by_key(id)

        if obj is None:
            obj = cls()

        obj.ident = ident.strip()
        obj.name = name.strip()
        obj.level = level
        obj.type = type
        obj.params = json.dumps(params) if isinstance(params,
                                                      (dict, )) else params
        obj.remark = remark.strip()
        obj.links = links.strip()
        obj.status = cls.STATUS_OK

        has_error, errors = obj.valid()
        if has_error:
            return None, has_error, errors

        db.session.add(obj)
        db.session.commit()
        obj.to_cache()
        return obj, has_error, errors

    @classmethod
    def delete(cls, id):
        obj = cls.get_by_key(id)
        if obj:
            obj.status = cls.STATUS_DELETE
            db.session.add(obj)
            db.session.commit()
            obj.to_cache(True)
        return obj
예제 #9
0
class PluginConfig(db.Model, ValidatorMixin, AsDictMixin):
    STATUS_OK = 1
    STATUS_DELETE = 2

    id = db.Column(db.BigInteger, primary_key=True)
    key = db.Column(db.String(64), nullable=False, default='')
    value = db.Column(db.Text, nullable=False, default='')
    status = db.Column(db.Integer, nullable=False)
    created_time = db.Column(db.DateTime, nullable=False)

    def __init__(self,
                 key,
                 value=None,
                 status=None,
                 created_time=None,
                 from_cache=False,
                 id=None):
        self.id = id
        self.key = key
        self.value = value
        self.status = self.STATUS_OK if status is None else status
        self.created_time = timezone.now(
        ) if created_time is None else created_time
        self.from_cache = from_cache

    def clean(self):
        obj = self.get_by_key(self.key, 'key')
        if self.id:
            if int(self.id) != int(obj.id):
                raise ValidatorException('键已经存在')
        elif obj:
            raise ValidatorException('键已经存在')

    @property
    def value_object(self):
        try:
            return json.loads(self.value)
        except BaseException as e:
            return self.value

    @classmethod
    def all(cls):
        return cls.query.filter(cls.status != cls.STATUS_DELETE).all()

    @classmethod
    def get_by_key(cls, value, key='id', all=False):
        params = {key: value}
        if not all:
            params['status'] = cls.STATUS_OK
        return cls.query.filter_by(**params).first()

    @classmethod
    def create_or_replace(cls, key, value, id=None):
        obj = None
        if id:
            obj = cls.get_by_key(id)

        if obj is None:
            obj = cls(key=key)

        obj.value = value.strip()
        obj.status = cls.STATUS_OK

        has_error, errors = obj.valid()

        if has_error:
            return None, has_error, errors

        db.session.add(obj)
        db.session.commit()
        obj.to_cache()
        return obj, has_error, errors

    def to_cache(self, clear=False):
        if clear:
            redis.delete(REDIS_KEYS['PLUGIN_CONFIG'].format(ident=self.key))
        else:
            redis.hmset(REDIS_KEYS['PLUGIN_CONFIG'].format(ident=self.key),
                        self.as_dict_string())
        return True

    @classmethod
    def get_by_cache(cls, key):
        bconfig = redis.hgetall(REDIS_KEYS['PLUGIN_CONFIG'].format(ident=key))
        if bconfig:
            plugin = {'from_cache': True}
            for k, v in bconfig.items():
                plugin[k] = int(v) if k in ('id', 'status') else v
            return cls(**plugin)

        return None

    @classmethod
    def delete(cls, id):
        obj = cls.get_by_key(id)
        if obj:
            obj.status = cls.STATUS_DELETE
            db.session.add(obj)
            db.session.commit()
            obj.to_cache(True)
        return obj
예제 #10
0
class Executor(db.Model, AsDictMixin):

    STATUS_OK = 1
    STATUS_DELETE = 2

    id = db.Column(db.Integer, primary_key=True)
    ident = db.Column(db.String(128), nullable=False, default='')
    hostname = db.Column(db.String(128), nullable=False, default='')
    pid = db.Column(db.Integer, nullable=False, default=0)

    type = db.Column(db.Integer, nullable=False, default=0)

    total = db.Column(db.Integer, nullable=False, default=0)
    busy = db.Column(db.Integer, nullable=False, default=0)
    idle = db.Column(db.Integer, nullable=False, default=0)

    created_time = db.Column(db.DateTime)
    heartbeat_time = db.Column(db.DateTime)
    status = db.Column(db.Integer, nullable=False)

    def __init__(self,
                 ident,
                 hostname,
                 pid,
                 type,
                 total=0,
                 busy=0,
                 idle=0,
                 running=0,
                 created_time=None,
                 heartbeat_time=None,
                 status=None):
        self.ident = ident
        self.hostname = hostname
        self.pid = pid
        self.type = type
        self.total = total
        self.busy = busy
        self.idle = idle
        self.created_time = timezone.now(
        ) if created_time is None else created_time
        self.heartbeat_time = heartbeat_time
        self.status = self.STATUS_OK if status is None else status

    @classmethod
    def stats(cls):
        return {
            'total':
            db.session.query(cls).filter(cls.status == cls.STATUS_OK).count(),
            'online':
            db.session.query(cls).filter(
                cls.status == cls.STATUS_OK, cls.heartbeat_time >=
                timezone.now() - timedelta(minutes=3)).count()
        }

    @property
    def inuse(self):
        return max(self.busy, self.running)

    @property
    def type_text(self):
        texts = {
            2: '资产发现',
            3: '漏洞扫描',
        }
        return texts.get(self.type)

    @property
    def running(self):
        key = '{ident}:{type}'.format(ident=self.ident, type=self.type)
        value = redis.hget(REDIS_KEYS['JOB_EXECUTOR_RUNNING'], key)
        return 0 if value is None else int(value)

    def running_incr(self):
        key = '{ident}:{type}'.format(ident=self.ident, type=self.type)
        return redis.hincrby(REDIS_KEYS['JOB_EXECUTOR_RUNNING'], key, 1)

    def running_decr(self):
        key = '{ident}:{type}'.format(ident=self.ident, type=self.type)
        return redis.hincrby(REDIS_KEYS['JOB_EXECUTOR_RUNNING'], key, -1)

    @classmethod
    def running_decr_by_ident(cls, ident, type):
        obj = cls.query.filter_by(ident=ident, type=type).first()
        if obj:
            obj.running_decr()
        return True

    @classmethod
    def all(cls, online=True):
        query = db.session.query(cls).filter(cls.status == cls.STATUS_OK)
        if online:
            query = query.filter(
                cls.heartbeat_time >= timezone.now() - timedelta(minutes=3))
        return query.all()

    @classmethod
    def create(cls, ident, hostname, pid, type, total, busy, idle):
        executor = cls.query.filter_by(ident=ident, type=type).first()
        if executor is None:
            executor = cls(ident=ident,
                           hostname=hostname,
                           pid=pid,
                           type=type,
                           total=total,
                           busy=busy,
                           idle=idle)

        executor.total = total
        executor.busy = busy
        executor.pid = pid
        executor.heartbeat_time = timezone.now()
        db.session.add(executor)
        db.session.commit()
        return executor

    @classmethod
    def get_by_key(cls, value, key='id'):
        return db.session.query(cls).filter_by(**{key: value}).first()

    def execute(self, sub_job):
        self.running_incr()
        key = REDIS_KEYS['JOB_EXECUTOR'].format(type=sub_job.type,
                                                ident=self.ident)
        redis.lpush(key, json.dumps(sub_job.as_dict()))
        sub_job.start(self.ident)
        return True

    def as_dict(self):
        rt = super(Executor, self).as_dict()
        rt['running'] = self.running
        return rt

    @classmethod
    def delete_by_key(cls, id):
        executor = cls.get_by_key(id)
        if executor:
            executor.status = cls.STATUS_DELETE
            db.session.add(executor)
            db.session.commit()

        return True
예제 #11
0
class Job(db.Model, AsDictMixin):

    STATUS_WATING = 1
    STATUS_PREPROCESS = 2
    STATUS_DOING = 3
    STATUS_CANCEL = 4
    STATUS_SUCCESS = 5
    STATUS_FAILURE = 6
    STATUS_DELETE = 7

    PROGRESS_PREPROCESS = 0
    PROGRESS_DOING = 5
    PROGRESS_COMPLATE = 100

    id = db.Column(db.BigInteger, primary_key=True)
    name = db.Column(db.String(64), nullable=False, default='')
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    type = db.Column(db.Integer, nullable=False)
    job_params = db.Column(db.Text)
    progress = db.Column(db.Integer, nullable=False, default=0)
    status = db.Column(db.Integer, nullable=False)
    explain = db.Column(db.String(512), nullable=False, default='')

    created_time = db.Column(db.DateTime, nullable=False)
    start_time = db.Column(db.DateTime)
    finish_time = db.Column(db.DateTime)

    sub_jobs = db.relationship('SubJob', backref="job", lazy='dynamic')

    def __init__(self,
                 user=None,
                 type=None,
                 name='',
                 job_params=None,
                 status=None,
                 explain='',
                 created_time=None,
                 start_time=None,
                 finish_time=None,
                 progress=0,
                 id=None,
                 user_id=None,
                 from_cache=False,
                 *args,
                 **kwargs):
        self.id = id
        self.name = name
        self.user_id = user.id if user else user_id
        self.type = type
        job_params = {} if job_params is None else job_params
        self.job_params = json.dumps(job_params) if isinstance(
            job_params, (dict, )) else job_params
        self.progress = progress
        self.status = self.STATUS_WATING if status is None else status
        self.explain = explain
        self.created_time = timezone.now(
        ) if created_time is None else created_time
        self.start_time = start_time
        self.finish_time = finish_time
        self.from_cache = from_cache

    @property
    def job_params_object(self):
        try:
            return json.loads(self.job_params)
        except BaseException as e:
            return {}

    @classmethod
    def create(cls, user, type, name, job_params):
        job = cls(user=user, type=type, name=name, job_params=job_params)
        db.session.add(job)
        db.session.commit()
        redis.hmset(REDIS_KEYS['JOB_CONTENT'].format(id=job.id),
                    job.as_dict_string())
        redis.lpush(REDIS_KEYS['JOB_PREPROCESS'], job.id)
        return job

    def preprocess(self):
        job = self
        if getattr(self, 'from_cache', False):
            job = self.get_by_key(self.id)
        job.status = self.STATUS_PREPROCESS
        job.progress = self.PROGRESS_PREPROCESS
        db.session.add(job)
        db.session.commit()
        redis.hmset(REDIS_KEYS['JOB_CONTENT'].format(id=self.id), {
            'status': self.STATUS_PREPROCESS,
            'progress': self.PROGRESS_PREPROCESS
        })
        redis.lpush(REDIS_KEYS['JOB_DOING'], self.id)

    def start(self):
        job = self
        if getattr(self, 'from_cache', False):
            job = self.get_by_key(self.id)
        if job.start_time is None:
            job.start_time = timezone.now()
        job.status = self.STATUS_DOING
        redis_content = {'status': self.STATUS_DOING}
        if job.progress < self.PROGRESS_DOING:
            job.progress = self.PROGRESS_DOING
            redis_content['progress'] = self.PROGRESS_DOING
        db.session.add(job)
        db.session.commit()
        redis.hmset(REDIS_KEYS['JOB_CONTENT'].format(id=self.id), {
            'status': self.STATUS_DOING,
            'progress': self.PROGRESS_DOING
        })

    @classmethod
    def get_by_key(cls, value, key='id'):
        return db.session.query(cls).filter_by(**{key: value}).first()

    @classmethod
    def get_by_cache(cls, id):
        bjob = redis.hgetall(REDIS_KEYS['JOB_CONTENT'].format(id=id))
        if bjob:
            job = {'from_cache': True}
            for k, v in bjob.items():
                job[k] = int(v) if k in ('id', 'user_id', 'type', 'progress',
                                         'status') else v
            return cls(**job)
        return None

    def finish(self, status=None, explain=''):
        job = self
        if getattr(self, 'from_cache', False):
            job = self.get_by_key(self.id)

        job.finish_time = timezone.now()
        job.status = self.STATUS_SUCCESS if status is None else self.STATUS_FAILURE
        job.progress = self.PROGRESS_COMPLATE
        job.explain = explain
        db.session.add(job)
        db.session.commit()
        redis.delete(REDIS_KEYS['JOB_CONTENT'].format(id=self.id))
        redis.lrem(REDIS_KEYS['JOB_DOING'], 0, self.id)
        for _, key in JobType.KEYS.items():
            redis.delete(REDIS_KEYS['JOB_QUEUE'].format(type=key, id=self.id))

        return True

    def cancel(self):
        job = self
        if getattr(self, 'from_cache', False):
            job = self.get_by_key(self.id)
        job.status = self.STATUS_CANCEL
        job.progress = self.PROGRESS_COMPLATE
        SubJob.cancel(job)
        db.session.add(job)
        db.session.commit()
        redis.delete(REDIS_KEYS['JOB_CONTENT'].format(id=self.id))
        redis.lrem(REDIS_KEYS['JOB_DOING'], 0, self.id)
        for _, key in JobType.KEYS.items():
            redis.delete(REDIS_KEYS['JOB_QUEUE'].format(type=key, id=self.id))

        return True

    def delete(self):
        job = self
        if getattr(self, 'from_cache', False):
            job = self.get_by_key(self.id)
        job.status = self.STATUS_DELETE
        job.progress = self.PROGRESS_COMPLATE
        SubJob.delete(job)
        db.session.add(job)
        db.session.commit()
        redis.delete(REDIS_KEYS['JOB_CONTENT'].format(id=self.id))
        redis.lrem(REDIS_KEYS['JOB_DOING'], 0, self.id)
        for _, key in JobType.KEYS.items():
            redis.delete(REDIS_KEYS['JOB_QUEUE'].format(type=key, id=self.id))

        return True

    def doing(self, progress=None):
        job = self
        if getattr(self, 'from_cache', False):
            job = self.get_by_key(self.id)

        job.status = self.STATUS_DOING
        if progress is not None:
            job.progress = progress
        db.session.add(job)
        db.session.commit()
예제 #12
0
class SubJob(db.Model, AsDictMixin):

    STATUS_WATING = 1
    STATUS_DOING = 2
    STATUS_CANCEL = 3
    STATUS_SUCCESS = 4
    STATUS_FAILURE = 5
    STATUS_DELETE = 6

    id = db.Column(db.BigInteger, primary_key=True)
    job_id = db.Column(db.BigInteger, db.ForeignKey('job.id'))
    type = db.Column(db.Integer, nullable=False)
    job_params = db.Column(db.Text)
    created_time = db.Column(db.DateTime, nullable=False)
    start_time = db.Column(db.DateTime)
    finish_time = db.Column(db.DateTime)
    status = db.Column(db.Integer, nullable=False)

    executor = db.Column(db.String(128), nullable=False, default='')

    explain = db.Column(db.String(512), nullable=False, default='')

    def __init__(self,
                 job,
                 type,
                 job_params=None,
                 created_time=None,
                 start_time=None,
                 finish_time=None,
                 status=None,
                 executor='',
                 explain='',
                 *args,
                 **kwargs):
        self.job_id = job.id
        self.type = type
        job_params = {} if job_params is None else job_params
        self.job_params = json.dumps(job_params) if isinstance(
            job_params, (dict, )) else job_params
        self.created_time = timezone.now(
        ) if created_time is None else created_time
        self.start_time = start_time
        self.finish_time = finish_time
        self.status = self.STATUS_WATING if status is None else status
        self.executor = executor
        self.explain = explain

    @property
    def job_params_object(self):
        try:
            return json.loads(self.job_params)
        except BaseException as e:
            return {}

    @classmethod
    def create(cls, job, type, job_params):
        sub_job = cls(job=job, type=type, job_params=job_params)
        db.session.add(sub_job)
        db.session.commit()
        redis.zadd(
            REDIS_KEYS['JOB_QUEUE'].format(type=JobType.KEYS.get(type),
                                           id=job.id), 0, sub_job.id)
        return sub_job

    @classmethod
    def get_by_key(cls, value, key='id'):
        return db.session.query(cls).filter_by(**{key: value}).first()

    @classmethod
    def cancel(cls, job):
        for obj in cls.query.filter(
                cls.job_id == job.id,
                cls.status.notin_([
                    cls.STATUS_SUCCESS, cls.STATUS_CANCEL, cls.STATUS_FAILURE,
                    cls.STATUS_DELETE
                ])).all():
            obj.status = cls.STATUS_CANCEL
            Executor.running_decr_by_ident(obj.executor, obj.type)
            db.session.add(obj)
            db.session.commit()
        return True

    @classmethod
    def delete(cls, job):
        for obj in cls.query.filter(
                cls.job_id == job.id,
                cls.status.notin_([
                    cls.STATUS_SUCCESS, cls.STATUS_CANCEL, cls.STATUS_FAILURE,
                    cls.STATUS_DELETE
                ])).all():
            obj.status = cls.STATUS_DELETE
            Executor.running_decr_by_ident(obj.executor, obj.type)
            db.session.add(obj)
            db.session.commit()
        return True

    def start(self, executor=None):
        self.status = self.STATUS_DOING
        self.executor = executor if executor else self.executor
        self.start_time = timezone.now()
        redis.zadd(
            REDIS_KEYS['JOB_QUEUE'].format(type=JobType.KEYS.get(self.type),
                                           id=self.job.id), -1, self.id)
        self.job.start()
        db.session.add(self)
        db.session.commit()

    def finish(self, status=None, explain=''):
        if self.status not in [
                self.STATUS_SUCCESS, self.STATUS_CANCEL, self.STATUS_FAILURE,
                self.STATUS_DELETE
        ]:
            Executor.running_decr_by_ident(self.executor, self.type)

        self.status = self.STATUS_SUCCESS if status is None else status
        self.finish_time = timezone.now()
        self.explain = explain
        db.session.add(self)
        db.session.commit()
        redis.zadd(
            REDIS_KEYS['JOB_QUEUE'].format(type=JobType.KEYS.get(self.type),
                                           id=self.job.id), 1, self.id)
예제 #13
0
class User(db.Model, ValidatorMixin):
    STATUS_REGISTED = 0
    STATUS_LOCKED = 1
    STATUS_OK = 2
    STATUS_DELETE = 3

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), nullable=False, default='')
    password = db.Column(db.String(512), nullable=False, default='')
    email = db.Column(db.String(64), nullable=False, default='')

    role_id = db.Column(db.Integer, db.ForeignKey('role.id'))

    created_time = db.Column(db.DateTime, nullable=False)
    last_login_time = db.Column(db.DateTime)

    is_super = db.Column(db.Boolean, nullable=False, default=False)
    status = db.Column(db.Integer, nullable=False)


    def __init__(self, name, email, is_super=False, created_time=None, last_login_time=None, status=None, id=None, password=None, role_id=None):
        self.id = id
        self.name = name
        self.password = password
        self.email = email
        self.role_id = role_id
        self.created_time = created_time if created_time else timezone.now()
        self.last_login_time = last_login_time
        self.is_super = is_super
        self.status =  self.STATUS_REGISTED if status is None else status

    @classmethod
    def authenticate(cls, name, password):
        user = cls.query.filter_by(name=name).first()
        if not user:
            user = cls.query.filter_by(email=name).first()

        if user and check_password_hash(user.password, password):
            user.last_login_time = timezone.now()
            db.session.add(user)
            db.session.commit()
            return user

        return None


    def set_password(self, password):
        self.password = generate_password_hash(password)


    def clean_name(self):
        name = self.name.strip()
        if not ValidatorUtils.is_length(name, 3, 32):
            raise ValidatorException('用户名必须为3到32个字符')

        user = User.query.filter_by(name=self.name).first()

        if user and (self.id is None or user.id != self.id):
            raise ValidatorException('用户名已存在')

        return name

    def clean_email(self):
        email = self.email.strip()
        if not ValidatorUtils.is_email(email):
            raise ValidatorException('邮箱格式不正确')

        user = User.query.filter_by(email=self.email).first()
        if user and (self.id is None or user.id != self.id):
            raise ValidatorException('邮箱已存在')

        return email


    @classmethod
    def create(cls, name, password, email, is_super):
        user = cls(name=name, email=email, is_super=is_super, status=cls.STATUS_OK)
        user.set_password(password)

        has_error, errors = user.valid()

        if has_error:
            return None, has_error, errors

        db.session.add(user)
        db.session.commit()
        return user, has_error, errors



    @classmethod
    def get_by_key(cls, value, key='id'):
        return cls.query.filter_by(**{key:value}).first()


    @classmethod
    def all(cls):
        return cls.query.filter(cls.status!=cls.STATUS_DELETE).all()