Merge branch 'master' into fix_deploy_1700028675

This commit is contained in:
fxiang21 2023-11-22 18:24:28 +08:00
commit 628c15fe4f
14 changed files with 155 additions and 14212 deletions

1
.gitignore vendored
View File

@ -70,6 +70,7 @@ settings.py
# UI
cmdb-ui/node_modules
cmdb-ui/dist
cmdb-ui/yarn.lock
# Log files
cmdb-ui/npm-debug.log*

View File

@ -1,6 +1,8 @@
import click
from flask.cli import with_appcontext
from api.lib.perm.acl.user import UserCRUD
@click.command()
@with_appcontext
@ -23,50 +25,18 @@ def init_acl():
role_rebuild.apply_async(args=(role.id, app.id), queue=ACL_QUEUE)
# @click.command()
# @with_appcontext
# def acl_clean():
# from api.models.acl import Resource
# from api.models.acl import Permission
# from api.models.acl import RolePermission
#
# perms = RolePermission.get_by(to_dict=False)
#
# for r in perms:
# perm = Permission.get_by_id(r.perm_id)
# if perm and perm.app_id != r.app_id:
# resource_id = r.resource_id
# resource = Resource.get_by_id(resource_id)
# perm_name = perm.name
# existed = Permission.get_by(resource_type_id=resource.resource_type_id, name=perm_name, first=True,
# to_dict=False)
# if existed is not None:
# other = RolePermission.get_by(rid=r.rid, perm_id=existed.id, resource_id=resource_id)
# if not other:
# r.update(perm_id=existed.id)
# else:
# r.soft_delete()
# else:
# r.soft_delete()
#
#
# @click.command()
# @with_appcontext
# def acl_has_resource_role():
# from api.models.acl import Role
# from api.models.acl import App
# from api.lib.perm.acl.cache import HasResourceRoleCache
# from api.lib.perm.acl.role import RoleCRUD
#
# roles = Role.get_by(to_dict=False)
# apps = App.get_by(to_dict=False)
# for role in roles:
# if role.app_id:
# res = RoleCRUD.recursive_resources(role.id, role.app_id)
# if res.get('resources') or res.get('groups'):
# HasResourceRoleCache.add(role.id, role.app_id)
# else:
# for app in apps:
# res = RoleCRUD.recursive_resources(role.id, app.id)
# if res.get('resources') or res.get('groups'):
# HasResourceRoleCache.add(role.id, app.id)
@click.command()
@with_appcontext
def add_user():
"""
create a user
is_admin: default is False
"""
username = click.prompt('Enter username', confirmation_prompt=False)
password = click.prompt('Enter password', hide_input=True, confirmation_prompt=True)
email = click.prompt('Enter email ', confirmation_prompt=False)
UserCRUD.add(username=username, password=password, email=email)

View File

@ -29,7 +29,6 @@ from api.lib.perm.acl.cache import AppCache
from api.lib.perm.acl.resource import ResourceCRUD
from api.lib.perm.acl.resource import ResourceTypeCRUD
from api.lib.perm.acl.role import RoleCRUD
from api.lib.perm.acl.user import UserCRUD
from api.lib.secrets.inner import KeyManage
from api.lib.secrets.inner import global_key_threshold
from api.lib.secrets.secrets import InnerKVManger
@ -128,10 +127,10 @@ def cmdb_init_acl():
# 3. add resource and grant
ci_types = CIType.get_by(to_dict=False)
type_id = ResourceType.get_by(name=ResourceTypeEnum.CI, first=True, to_dict=False).id
resource_type_id = ResourceType.get_by(name=ResourceTypeEnum.CI, first=True, to_dict=False).id
for ci_type in ci_types:
try:
ResourceCRUD.add(ci_type.name, type_id, app_id)
ResourceCRUD.add(ci_type.name, resource_type_id, app_id)
except AbortException:
pass
@ -141,10 +140,10 @@ def cmdb_init_acl():
[PermEnum.READ])
relation_views = PreferenceRelationView.get_by(to_dict=False)
type_id = ResourceType.get_by(name=ResourceTypeEnum.RELATION_VIEW, first=True, to_dict=False).id
resource_type_id = ResourceType.get_by(name=ResourceTypeEnum.RELATION_VIEW, first=True, to_dict=False).id
for view in relation_views:
try:
ResourceCRUD.add(view.name, type_id, app_id)
ResourceCRUD.add(view.name, resource_type_id, app_id)
except AbortException:
pass
@ -154,57 +153,6 @@ def cmdb_init_acl():
[PermEnum.READ])
@click.command()
@click.option(
'-u',
'--user',
help='username'
)
@click.option(
'-p',
'--password',
help='password'
)
@click.option(
'-m',
'--mail',
help='mail'
)
@with_appcontext
def add_user(user, password, mail):
"""
create a user
is_admin: default is False
Example: flask add-user -u <username> -p <password> -m <mail>
"""
assert user is not None
assert password is not None
assert mail is not None
UserCRUD.add(username=user, password=password, email=mail)
@click.command()
@click.option(
'-u',
'--user',
help='username'
)
@with_appcontext
def del_user(user):
"""
delete a user
Example: flask del-user -u <username>
"""
assert user is not None
from api.models.acl import User
u = User.get_by(username=user, first=True, to_dict=False)
u and UserCRUD.delete(u.uid)
@click.command()
@with_appcontext
def cmdb_counter():
@ -474,3 +422,39 @@ def cmdb_password_data_migrate():
if not failed and attr.is_index:
attr.update(is_index=False)
@click.command()
@with_appcontext
def cmdb_agent_init():
"""
Initialize the agent's permissions and obtain the key and secret
"""
from api.models.acl import User
user = User.get_by(username="cmdb_agent", first=True, to_dict=False)
if user is None:
click.echo(
click.style('user cmdb_agent does not exist, please use flask add-user to create it first', fg='red'))
return
# grant
_app = AppCache.get('cmdb') or App.create(name='cmdb')
app_id = _app.id
ci_types = CIType.get_by(to_dict=False)
resource_type_id = ResourceType.get_by(name=ResourceTypeEnum.CI, first=True, to_dict=False).id
for ci_type in ci_types:
try:
ResourceCRUD.add(ci_type.name, resource_type_id, app_id)
except AbortException:
pass
ACLManager().grant_resource_to_role(ci_type.name,
"cmdb_agent",
ResourceTypeEnum.CI,
[PermEnum.READ, PermEnum.UPDATE, PermEnum.ADD, PermEnum.DELETE])
click.echo("Key : {}".format(click.style(user.key, bg='red')))
click.echo("Secret: {}".format(click.style(user.secret, bg='red')))

View File

@ -84,66 +84,6 @@ def clean():
os.remove(full_pathname)
@click.command()
@click.option("--url", default=None, help="Url to test (ex. /static/image.png)")
@click.option(
"--order", default="rule", help="Property on Rule to order by (default: rule)"
)
@with_appcontext
def urls(url, order):
"""Display all of the url matching routes for the project.
Borrowed from Flask-Script, converted to use Click.
"""
rows = []
column_headers = ("Rule", "Endpoint", "Arguments")
if url:
try:
rule, arguments = current_app.url_map.bind("localhost").match(
url, return_rule=True
)
rows.append((rule.rule, rule.endpoint, arguments))
column_length = 3
except (NotFound, MethodNotAllowed) as e:
rows.append(("<{}>".format(e), None, None))
column_length = 1
else:
rules = sorted(
current_app.url_map.iter_rules(), key=lambda rule: getattr(rule, order)
)
for rule in rules:
rows.append((rule.rule, rule.endpoint, None))
column_length = 2
str_template = ""
table_width = 0
if column_length >= 1:
max_rule_length = max(len(r[0]) for r in rows)
max_rule_length = max_rule_length if max_rule_length > 4 else 4
str_template += "{:" + str(max_rule_length) + "}"
table_width += max_rule_length
if column_length >= 2:
max_endpoint_length = max(len(str(r[1])) for r in rows)
max_endpoint_length = max_endpoint_length if max_endpoint_length > 8 else 8
str_template += " {:" + str(max_endpoint_length) + "}"
table_width += 2 + max_endpoint_length
if column_length >= 3:
max_arguments_length = max(len(str(r[2])) for r in rows)
max_arguments_length = max_arguments_length if max_arguments_length > 9 else 9
str_template += " {:" + str(max_arguments_length) + "}"
table_width += 2 + max_arguments_length
click.echo(str_template.format(*column_headers[:column_length]))
click.echo("-" * table_width)
for row in rows:
click.echo(str_template.format(*row[:column_length]))
@click.command()
@with_appcontext
def db_setup():

View File

@ -10,14 +10,18 @@ from api.lib.exception import CommitException
class FormatMixin(object):
def to_dict(self):
res = dict([(k, getattr(self, k) if not isinstance(
getattr(self, k), (datetime.datetime, datetime.date, datetime.time)) else str(
getattr(self, k))) for k in getattr(self, "__mapper__").c.keys()])
# FIXME: getattr(cls, "__table__").columns k.name
res = dict()
for k in getattr(self, "__mapper__").c.keys():
if k in {'password', '_password', 'secret', '_secret'}:
continue
res.pop('password', None)
res.pop('_password', None)
res.pop('secret', None)
if k.startswith('_'):
k = k[1:]
if not isinstance(getattr(self, k), (datetime.datetime, datetime.date, datetime.time)):
res[k] = getattr(self, k)
else:
res[k] = str(getattr(self, k))
return res

View File

@ -276,7 +276,6 @@ class ResourceCRUD(object):
from api.tasks.acl import apply_trigger
triggers = TriggerCRUD.match_triggers(app_id, r.name, r.resource_type_id, uid)
current_app.logger.info(triggers)
for trigger in triggers:
# auto trigger should be no uid
apply_trigger.apply_async(args=(trigger.id,),

View File

@ -12,6 +12,9 @@ from Crypto.Cipher import AES
from elasticsearch import Elasticsearch
from flask import current_app
from api.lib.secrets.inner import InnerCrypt
from api.lib.secrets.inner import KeyManage
class BaseEnum(object):
_ALL_ = set() # type: Set[str]
@ -286,3 +289,33 @@ class AESCrypto(object):
text_decrypted = cipher.decrypt(encode_bytes)
return cls.unpad(text_decrypted).decode('utf8')
class Crypto(AESCrypto):
@classmethod
def encrypt(cls, data):
from api.lib.secrets.secrets import InnerKVManger
if not KeyManage(backend=InnerKVManger()).is_seal():
res, status = InnerCrypt().encrypt(data)
if status:
return res
return AESCrypto().encrypt(data)
@classmethod
def decrypt(cls, data):
from api.lib.secrets.secrets import InnerKVManger
if not KeyManage(backend=InnerKVManger()).is_seal():
try:
res, status = InnerCrypt().decrypt(data)
if status:
return res
except:
pass
try:
return AESCrypto().decrypt(data)
except:
return data

View File

@ -12,7 +12,9 @@ from api.lib.cmdb.const import CITypeOperateType
from api.lib.cmdb.const import ConstraintEnum
from api.lib.cmdb.const import OperateType
from api.lib.cmdb.const import ValueTypeEnum
from api.lib.database import Model, Model2
from api.lib.database import Model
from api.lib.database import Model2
from api.lib.utils import Crypto
# template
@ -89,13 +91,37 @@ class Attribute(Model):
compute_expr = db.Column(db.Text)
compute_script = db.Column(db.Text)
choice_web_hook = db.Column(db.JSON)
_choice_web_hook = db.Column('choice_web_hook', db.JSON)
choice_other = db.Column(db.JSON)
uid = db.Column(db.Integer, index=True)
option = db.Column(db.JSON)
def _get_webhook(self):
if self._choice_web_hook:
if self._choice_web_hook.get('headers') and "Cookie" in self._choice_web_hook['headers']:
self._choice_web_hook['headers']['Cookie'] = Crypto.decrypt(self._choice_web_hook['headers']['Cookie'])
if self._choice_web_hook.get('authorization'):
for k, v in self._choice_web_hook['authorization'].items():
self._choice_web_hook['authorization'][k] = Crypto.decrypt(v)
return self._choice_web_hook
def _set_webhook(self, data):
if data:
if data.get('headers') and "Cookie" in data['headers']:
data['headers']['Cookie'] = Crypto.encrypt(data['headers']['Cookie'])
if data.get('authorization'):
for k, v in data['authorization'].items():
data['authorization'][k] = Crypto.encrypt(v)
self._choice_web_hook = data
choice_web_hook = db.synonym("_choice_web_hook", descriptor=property(_get_webhook, _set_webhook))
class CITypeAttribute(Model):
__tablename__ = "c_ci_type_attributes"
@ -130,7 +156,25 @@ class CITypeTrigger(Model):
type_id = db.Column(db.Integer, db.ForeignKey('c_ci_types.id'), nullable=False)
attr_id = db.Column(db.Integer, db.ForeignKey("c_attributes.id"))
option = db.Column('notify', db.JSON)
_option = db.Column('notify', db.JSON)
def _get_option(self):
if self._option and self._option.get('webhooks'):
if self._option['webhooks'].get('authorization'):
for k, v in self._option['webhooks']['authorization'].items():
self._option['webhooks']['authorization'][k] = Crypto.decrypt(v)
return self._option
def _set_option(self, data):
if data and data.get('webhooks'):
if data['webhooks'].get('authorization'):
for k, v in data['webhooks']['authorization'].items():
data['webhooks']['authorization'][k] = Crypto.encrypt(v)
self._option = data
option = db.synonym("_option", descriptor=property(_get_option, _set_option))
class CITriggerHistory(Model):

View File

@ -63,14 +63,15 @@
},
"devDependencies": {
"@ant-design/colors": "^3.2.2",
"@babel/core": "^7.23.2",
"@babel/polyfill": "^7.2.5",
"@babel/preset-env": "^7.23.2",
"@vue/cli-plugin-babel": "4.5.17",
"@vue/cli-plugin-eslint": "^4.0.5",
"@vue/cli-plugin-unit-jest": "^4.0.5",
"@vue/cli-service": "^4.0.5",
"@vue/eslint-config-standard": "^4.0.0",
"@vue/test-utils": "^1.0.0-beta.30",
"babel-core": "7.0.0-bridge.0",
"babel-jest": "^23.6.0",
"babel-plugin-import": "^1.11.0",
"babel-plugin-transform-remove-console": "^6.9.4",

View File

@ -68,6 +68,7 @@
ref="xTable"
row-id="id"
show-overflow
resizable
>
<!-- 1 -->
<vxe-table-column type="checkbox" fixed="left" :width="45"></vxe-table-column>

File diff suppressed because it is too large Load Diff

View File

@ -239,11 +239,6 @@ CREATE TABLE `acl_operation_records` (
-- Dumping data for table `acl_operation_records`
--
LOCK TABLES `acl_operation_records` WRITE;
/*!40000 ALTER TABLE `acl_operation_records` DISABLE KEYS */;
INSERT INTO `acl_operation_records` VALUES (NULL,0,'2023-07-11 16:48:37',NULL,11,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 16:49:09',NULL,12,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 16:49:21',NULL,13,NULL,'admin','0','[\"ACL\"]'),(NULL,0,'2023-07-11 16:49:22',NULL,14,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 16:50:38',NULL,15,NULL,'admin','0','[\"ACL\"]'),(NULL,0,'2023-07-11 16:50:38',NULL,16,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 16:57:53',NULL,17,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:08:22',NULL,18,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:12:20',NULL,19,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:12:24',NULL,20,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:13:11',NULL,21,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:15:17',NULL,22,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:22:31',NULL,23,NULL,'admin','0','[\"ACL\"]'),(NULL,0,'2023-07-11 17:22:31',NULL,24,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:27:19',NULL,25,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:28:49',NULL,26,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:36:06',NULL,27,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:36:10',NULL,28,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:37:06',NULL,29,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:39:05',NULL,30,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:39:10',NULL,31,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:46:52',NULL,32,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 17:54:00',NULL,33,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 18:03:56',NULL,34,NULL,'admin','0','[\"ACL\"]'),(NULL,0,'2023-07-11 18:03:56',NULL,35,'backend','cmdb_agent','1','[\"resources\"]'),(NULL,0,'2023-07-11 18:03:57',NULL,36,'backend','cmdb_agent','1','[\"resources\"]');
/*!40000 ALTER TABLE `acl_operation_records` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `acl_permissions`
@ -659,12 +654,6 @@ CREATE TABLE `c_ad_ci_types` (
-- Dumping data for table `c_ad_ci_types`
--
LOCK TABLES `c_ad_ci_types` WRITE;
/*!40000 ALTER TABLE `c_ad_ci_types` DISABLE KEYS */;
INSERT INTO `c_ad_ci_types` VALUES (NULL,0,'2023-07-11 17:11:52',NULL,2,4,9,NULL,NULL,0,NULL,NULL,300,NULL,NULL,1),(NULL,0,'2023-07-11 17:19:23','2023-07-11 17:19:25',3,5,10,'{}',NULL,0,'','',300,NULL,NULL,1);
/*!40000 ALTER TABLE `c_ad_ci_types` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `c_ad_rules`
--
@ -2248,7 +2237,7 @@ CREATE TABLE `users` (
LOCK TABLES `users` WRITE;
/*!40000 ALTER TABLE `users` DISABLE KEYS */;
INSERT INTO `users` VALUES (NULL,0,1,'admin','admin',NULL,NULL,'admin@one-ops.com',NULL,'e10adc3949ba59abbe56e057f20f883e','','',NULL,'2023-07-11 18:03:55',0,1,NULL,'0000',NULL,NULL),(NULL,0,2,'cmdb_agent','cmdb_agent',NULL,NULL,'cmdb_agent@one-ops.com',NULL,NULL,'ef086550acb543828d9930d15b21a037','U~83O&PT2Qxsd1$H9df2v#*FcsiG1l?n',NULL,NULL,0,NULL,NULL,NULL,NULL,NULL),(NULL,0,3,'worker','worker',NULL,NULL,'worker@one-ops.com',NULL,'b34cd51b4a6e2f96547e4aeb81566a83','0577dfa24e4547ad91bfb23b62951845','~0g7tkFG$@wdHKe*r2rYu2RC2v1?d8I5',NULL,NULL,0,NULL,NULL,NULL,NULL,NULL),(NULL,0,46,'demo','demo',NULL,NULL,'demo@veops.cn',NULL,'e10adc3949ba59abbe56e057f20f883e','0ec692fb318b47e4b739c241d56c12e7','JDcAc563I4L47ji2R?fah1dZ6KPb!Ty0','2023-07-10 08:19:01','2023-07-11 16:30:42',0,1,NULL,'0036',NULL,NULL);
INSERT INTO `users` VALUES (NULL,0,1,'admin','admin',NULL,NULL,'admin@one-ops.com',NULL,'e10adc3949ba59abbe56e057f20f883e','','',NULL,'2023-07-11 18:03:55',0,1,NULL,'0001',NULL,NULL),(NULL,0,2,'cmdb_agent','cmdb_agent',NULL,NULL,'cmdb_agent@one-ops.com',NULL,NULL,'ef086550acb543828d9930d15b21a037','U~83O&PT2Qxsd1$H9df2v#*FcsiG1l?n',NULL,NULL,0,NULL,NULL,'0002',NULL,NULL),(NULL,0,3,'worker','worker',NULL,NULL,'worker@one-ops.com',NULL,'b34cd51b4a6e2f96547e4aeb81566a83','0577dfa24e4547ad91bfb23b62951845','~0g7tkFG$@wdHKe*r2rYu2RC2v1?d8I5',NULL,NULL,0,NULL,NULL,'0003',NULL,NULL),(NULL,0,46,'demo','demo',NULL,NULL,'demo@veops.cn',NULL,'e10adc3949ba59abbe56e057f20f883e','0ec692fb318b47e4b739c241d56c12e7','JDcAc563I4L47ji2R?fah1dZ6KPb!Ty0','2023-07-10 08:19:01','2023-07-11 16:30:42',0,1,NULL,'0004',NULL,NULL);
/*!40000 ALTER TABLE `users` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

View File

@ -22,7 +22,7 @@ cp cmdb-api/settings.example.py cmdb-api/settings.py
- 后端: `cd cmdb-api && pipenv run pipenv install && cd ..`
- 前端: `cd cmdb-ui && yarn install && cd ..`
- 可以将 docs/cmdb.sql 导入到数据库里,登录用户和密码分别是:demo/123456
- 创建数据库表: 进入**cmdb-api**目录执行 `pipenv run flask db-setup && pipenv run flask cmdb-init-cache`
- 创建数据库表: 进入**cmdb-api**目录执行 `pipenv run flask db-setup && pipenv run flask common-check-new-columns && pipenv run flask cmdb-init-cache`
- 启动服务
- 后端: 进入**cmdb-api**目录执行 `pipenv run flask run -h 0.0.0.0`

View File

@ -17,7 +17,7 @@
- frontend: `cd cmdb-ui && yarn install && cd ..`
- Suggest step: (default: user:demo,password:123456)
- Create tables of cmdb database:
in **cmdb-api** directory: `pipenv run flask db-setup && pipenv run flask cmdb-init-cache`
in **cmdb-api** directory: `pipenv run flask db-setup && pipenv run flask common-check-new-columns && pipenv run flask cmdb-init-cache`
` source docs/cmdb.sql`