perf: Admin and auditor can view and stop task

pull/14432/head
wangruidong 2024-11-08 17:50:33 +08:00 committed by Bryan
parent 1a41a7450e
commit 5b27acf4ef
11 changed files with 75 additions and 29 deletions

View File

@ -22,6 +22,9 @@ from common.plugins.es import QuerySet as ESQuerySet
from common.sessions.cache import user_session_manager from common.sessions.cache import user_session_manager
from common.storage.ftp_file import FTPFileStorageHandler from common.storage.ftp_file import FTPFileStorageHandler
from common.utils import is_uuid, get_logger, lazyproperty from common.utils import is_uuid, get_logger, lazyproperty
from ops.const import Types
from ops.models import Job
from ops.serializers.job import JobSerializer
from orgs.mixins.api import OrgReadonlyModelViewSet, OrgModelViewSet from orgs.mixins.api import OrgReadonlyModelViewSet, OrgModelViewSet
from orgs.models import Organization from orgs.models import Organization
from orgs.utils import current_org, tmp_to_root_org from orgs.utils import current_org, tmp_to_root_org
@ -39,14 +42,14 @@ from .serializers import (
FTPLogSerializer, UserLoginLogSerializer, JobLogSerializer, FTPLogSerializer, UserLoginLogSerializer, JobLogSerializer,
OperateLogSerializer, OperateLogActionDetailSerializer, OperateLogSerializer, OperateLogActionDetailSerializer,
PasswordChangeLogSerializer, ActivityUnionLogSerializer, PasswordChangeLogSerializer, ActivityUnionLogSerializer,
FileSerializer, UserSessionSerializer FileSerializer, UserSessionSerializer, JobsAuditSerializer
) )
from .utils import construct_userlogin_usernames from .utils import construct_userlogin_usernames
logger = get_logger(__name__) logger = get_logger(__name__)
class JobAuditViewSet(OrgReadonlyModelViewSet): class JobLogAuditViewSet(OrgReadonlyModelViewSet):
model = JobLog model = JobLog
extra_filter_backends = [DatetimeRangeFilterBackend] extra_filter_backends = [DatetimeRangeFilterBackend]
date_range_filter_fields = [ date_range_filter_fields = [
@ -58,6 +61,20 @@ class JobAuditViewSet(OrgReadonlyModelViewSet):
ordering = ['-date_start'] ordering = ['-date_start']
class JobsAuditViewSet(OrgModelViewSet):
model = Job
search_fields = ['creator__name']
filterset_fields = ['creator__name']
serializer_class = JobsAuditSerializer
ordering = ['-is_periodic', '-date_created']
http_method_names = ['get', 'options', 'patch']
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.exclude(type=Types.upload_file).filter(instant=False)
return queryset
class FTPLogViewSet(OrgModelViewSet): class FTPLogViewSet(OrgModelViewSet):
model = FTPLog model = FTPLog
serializer_class = FTPLogSerializer serializer_class = FTPLogSerializer

View File

@ -7,7 +7,7 @@ from audits.backends.db import OperateLogStore
from common.serializers.fields import LabeledChoiceField, ObjectRelatedField from common.serializers.fields import LabeledChoiceField, ObjectRelatedField
from common.utils import reverse, i18n_trans from common.utils import reverse, i18n_trans
from common.utils.timezone import as_current_tz from common.utils.timezone import as_current_tz
from ops.serializers.job import JobExecutionSerializer from ops.serializers.job import JobExecutionSerializer, JobSerializer
from orgs.mixins.serializers import BulkOrgResourceModelSerializer from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from terminal.models import Session from terminal.models import Session
from users.models import User from users.models import User
@ -34,6 +34,21 @@ class JobLogSerializer(JobExecutionSerializer):
} }
class JobsAuditSerializer(JobSerializer):
class Meta(JobSerializer.Meta):
fields = JobSerializer.Meta.fields
def validate(self, attrs):
allowed_fields = {'is_periodic'}
submitted_fields = set(attrs.keys())
invalid_fields = submitted_fields - allowed_fields
if invalid_fields:
raise serializers.ValidationError(
f"Updating {', '.join(invalid_fields)} fields is not allowed"
)
return attrs
class FTPLogSerializer(serializers.ModelSerializer): class FTPLogSerializer(serializers.ModelSerializer):
operate = LabeledChoiceField(choices=OperateChoices.choices, label=_("Operate")) operate = LabeledChoiceField(choices=OperateChoices.choices, label=_("Operate"))

View File

@ -13,7 +13,9 @@ router.register(r'ftp-logs', api.FTPLogViewSet, 'ftp-log')
router.register(r'login-logs', api.UserLoginLogViewSet, 'login-log') router.register(r'login-logs', api.UserLoginLogViewSet, 'login-log')
router.register(r'operate-logs', api.OperateLogViewSet, 'operate-log') router.register(r'operate-logs', api.OperateLogViewSet, 'operate-log')
router.register(r'password-change-logs', api.PasswordChangeLogViewSet, 'password-change-log') router.register(r'password-change-logs', api.PasswordChangeLogViewSet, 'password-change-log')
router.register(r'job-logs', api.JobAuditViewSet, 'job-log') router.register(r'job-logs', api.JobLogAuditViewSet, 'job-log')
router.register(r'jobs', api.JobsAuditViewSet, 'jobs')
router.register(r'my-login-logs', api.MyLoginLogViewSet, 'my-login-log') router.register(r'my-login-logs', api.MyLoginLogViewSet, 'my-login-log')
router.register(r'user-sessions', api.UserSessionViewSet, 'user-session') router.register(r'user-sessions', api.UserSessionViewSet, 'user-session')

View File

@ -200,7 +200,7 @@
"BaseCommandFilterAclList": "Command filter", "BaseCommandFilterAclList": "Command filter",
"BaseConnectMethodACL": "Connect Method ACL", "BaseConnectMethodACL": "Connect Method ACL",
"BaseFlowSetUp": "Flow Set Up", "BaseFlowSetUp": "Flow Set Up",
"BaseJobManagement": "Job Management", "BaseJobManagement": "Job List",
"BaseLoginLog": "Login Log", "BaseLoginLog": "Login Log",
"BaseMyAssets": "My Assets", "BaseMyAssets": "My Assets",
"BaseOperateLog": "Operate Log", "BaseOperateLog": "Operate Log",
@ -651,8 +651,8 @@
"JobCenter": "Job center", "JobCenter": "Job center",
"JobCreate": "Create job", "JobCreate": "Create job",
"JobDetail": "Job details", "JobDetail": "Job details",
"JobExecutionLog": "Job logs", "JobExecutionLog": "Execution record",
"JobManagement": "Jobs", "JobManagement": "Job List",
"JobUpdate": "Update the job", "JobUpdate": "Update the job",
"KingSoftCloud": "KingSoft cloud", "KingSoftCloud": "KingSoft cloud",
"KokoSetting": "KoKo", "KokoSetting": "KoKo",
@ -1410,5 +1410,8 @@
"disallowSelfUpdateFields": "Not allowed to modify the current fields yourself", "disallowSelfUpdateFields": "Not allowed to modify the current fields yourself",
"forceEnableMFAHelpText": "If force enable, user can not disable by themselves", "forceEnableMFAHelpText": "If force enable, user can not disable by themselves",
"removeWarningMsg": "Are you sure you want to remove", "removeWarningMsg": "Are you sure you want to remove",
"setVariable": "Set variable" "setVariable": "Set variable",
"JobsAudit": "Jobs audit",
"JobList": "Job List",
"StopJobMsg": "Stop job successfully"
} }

View File

@ -199,7 +199,7 @@
"BaseCommandFilterAclList": "コマンドフィルタ", "BaseCommandFilterAclList": "コマンドフィルタ",
"BaseConnectMethodACL": "接続方法の承認", "BaseConnectMethodACL": "接続方法の承認",
"BaseFlowSetUp": "フロー設定", "BaseFlowSetUp": "フロー設定",
"BaseJobManagement": "作業管理", "BaseJobManagement": "作業列表",
"BaseLoginLog": "ログインログ", "BaseLoginLog": "ログインログ",
"BaseMyAssets": "私の資産", "BaseMyAssets": "私の資産",
"BaseOperateLog": "Actionログ", "BaseOperateLog": "Actionログ",
@ -509,7 +509,7 @@
"Execute": "実行", "Execute": "実行",
"ExecuteOnce": "一度実行する", "ExecuteOnce": "一度実行する",
"ExecutionDetail": "Action詳細", "ExecutionDetail": "Action詳細",
"ExecutionList": "実行リスト", "ExecutionList": "実行記録",
"ExistError": "この要素は既に存在します", "ExistError": "この要素は既に存在します",
"Existing": "既に存在しています", "Existing": "既に存在しています",
"ExpirationTimeout": "有効期限タイムアウト(秒)", "ExpirationTimeout": "有効期限タイムアウト(秒)",
@ -669,8 +669,8 @@
"JobCenter": "Actionセンター", "JobCenter": "Actionセンター",
"JobCreate": "ジョブ作成", "JobCreate": "ジョブ作成",
"JobDetail": "作業詳細", "JobDetail": "作業詳細",
"JobExecutionLog": "作業ログ", "JobExecutionLog": "実行記録",
"JobManagement": "作業管理", "JobManagement": "作業列表",
"JobUpdate": "アップデート作業", "JobUpdate": "アップデート作業",
"KingSoftCloud": "Kingsoftクラウド", "KingSoftCloud": "Kingsoftクラウド",
"KokoSetting": "KoKo 設定", "KokoSetting": "KoKo 設定",
@ -1268,7 +1268,7 @@
"TemplateAdd": "テンプレート追加", "TemplateAdd": "テンプレート追加",
"TemplateCreate": "テンプレート作成", "TemplateCreate": "テンプレート作成",
"TemplateHelpText": "テンプレートを選択して追加すると、資産の下に存在しないアカウントが自動的に作成され、プッシュされます", "TemplateHelpText": "テンプレートを選択して追加すると、資産の下に存在しないアカウントが自動的に作成され、プッシュされます",
"TemplateManagement": "テンプレート管理", "TemplateManagement": "テンプレート一覧",
"TencentCloud": "テンセントクラウド", "TencentCloud": "テンセントクラウド",
"Terminal": "コンポーネント設定", "Terminal": "コンポーネント設定",
"TerminalDetail": "コンポーネントの詳細", "TerminalDetail": "コンポーネントの詳細",

View File

@ -200,7 +200,7 @@
"BaseCommandFilterAclList": "命令过滤", "BaseCommandFilterAclList": "命令过滤",
"BaseConnectMethodACL": "连接方式授权", "BaseConnectMethodACL": "连接方式授权",
"BaseFlowSetUp": "流程设置", "BaseFlowSetUp": "流程设置",
"BaseJobManagement": "作业管理", "BaseJobManagement": "作业列表",
"BaseLoginLog": "登录日志", "BaseLoginLog": "登录日志",
"BaseMyAssets": "我的资产", "BaseMyAssets": "我的资产",
"BaseOperateLog": "操作日志", "BaseOperateLog": "操作日志",
@ -497,7 +497,7 @@
"ExecuteAfterSaving": "保存后执行", "ExecuteAfterSaving": "保存后执行",
"ExecuteOnce": "执行一次", "ExecuteOnce": "执行一次",
"ExecutionDetail": "执行详情", "ExecutionDetail": "执行详情",
"ExecutionList": "执行列表", "ExecutionList": "执行记录",
"ExistError": "这个元素已经存在", "ExistError": "这个元素已经存在",
"Existing": "已存在", "Existing": "已存在",
"ExpirationTimeout": "过期超时时间(秒)", "ExpirationTimeout": "过期超时时间(秒)",
@ -655,8 +655,8 @@
"JobCenter": "作业中心", "JobCenter": "作业中心",
"JobCreate": "创建作业", "JobCreate": "创建作业",
"JobDetail": "作业详情", "JobDetail": "作业详情",
"JobExecutionLog": "作业日志", "JobExecutionLog": "执行记录",
"JobManagement": "作业管理", "JobManagement": "作业列表",
"JobUpdate": "更新作业", "JobUpdate": "更新作业",
"KingSoftCloud": "金山云", "KingSoftCloud": "金山云",
"KokoSetting": "KoKo 配置", "KokoSetting": "KoKo 配置",
@ -1236,7 +1236,7 @@
"TemplateAdd": "模版添加", "TemplateAdd": "模版添加",
"TemplateCreate": "创建模版", "TemplateCreate": "创建模版",
"TemplateHelpText": "选择模版添加时,会自动创建资产下不存在的账号并推送", "TemplateHelpText": "选择模版添加时,会自动创建资产下不存在的账号并推送",
"TemplateManagement": "模版管理", "TemplateManagement": "模版列表",
"Templates": "模板", "Templates": "模板",
"TencentCloud": "腾讯云", "TencentCloud": "腾讯云",
"Terminal": "组件设置", "Terminal": "组件设置",
@ -1415,5 +1415,8 @@
"disallowSelfUpdateFields": "不允许自己修改当前字段", "disallowSelfUpdateFields": "不允许自己修改当前字段",
"forceEnableMFAHelpText": "如果强制启用,用户无法自行禁用", "forceEnableMFAHelpText": "如果强制启用,用户无法自行禁用",
"removeWarningMsg": "你确定要移除", "removeWarningMsg": "你确定要移除",
"setVariable": "设置参数" "setVariable": "设置参数",
"JobsAudit": "作业审计",
"JobList": "作业列表",
"StopJobMsg": "停止成功"
} }

View File

@ -260,7 +260,7 @@
"BaseCommandFilterAclList": "命令過濾", "BaseCommandFilterAclList": "命令過濾",
"BaseConnectMethodACL": "連接方式授權", "BaseConnectMethodACL": "連接方式授權",
"BaseFlowSetUp": "流程設定", "BaseFlowSetUp": "流程設定",
"BaseJobManagement": "作業", "BaseJobManagement": "作業列表",
"BaseLoginLog": "登入日誌", "BaseLoginLog": "登入日誌",
"BaseMyAssets": "我的資產", "BaseMyAssets": "我的資產",
"BaseOperateLog": "操作日誌", "BaseOperateLog": "操作日誌",
@ -654,7 +654,7 @@
"ExecuteOnce": "執行一次", "ExecuteOnce": "執行一次",
"Execution": "執行歷史", "Execution": "執行歷史",
"ExecutionDetail": "執行詳情", "ExecutionDetail": "執行詳情",
"ExecutionList": "執行列表", "ExecutionList": "執行記錄",
"ExecutionTimes": "執行次數", "ExecutionTimes": "執行次數",
"ExistError": "這個元素已經存在", "ExistError": "這個元素已經存在",
"Existing": "已存在", "Existing": "已存在",
@ -846,9 +846,9 @@
"JobCenter": "作業中心", "JobCenter": "作業中心",
"JobCreate": "創建作業", "JobCreate": "創建作業",
"JobDetail": "作業詳情", "JobDetail": "作業詳情",
"JobExecutionLog": "作業日誌", "JobExecutionLog": "執行記錄",
"JobList": "作業管理", "JobList": "作業管理",
"JobManagement": "作業", "JobManagement": "作業列表",
"JobName": "作業名稱", "JobName": "作業名稱",
"JobType": "作業類型", "JobType": "作業類型",
"JobUpdate": "更新作業", "JobUpdate": "更新作業",
@ -1610,14 +1610,14 @@
"TempPassword": "臨時密碼有效期為 300 秒,使用後立刻失效", "TempPassword": "臨時密碼有效期為 300 秒,使用後立刻失效",
"TempPasswordTip": "臨時密碼有效時間為 300 秒,使用後立即失效", "TempPasswordTip": "臨時密碼有效時間為 300 秒,使用後立即失效",
"TempToken": "臨時密碼", "TempToken": "臨時密碼",
"Template": "模板管理", "Template": "模板列表",
"TemplateAdd": "模板添加", "TemplateAdd": "模板添加",
"TemplateCreate": "創建模板", "TemplateCreate": "創建模板",
"TemplateDetail": "模板詳情", "TemplateDetail": "模板詳情",
"TemplateHelpText": "選擇模板添加時,會自動創建資產下不存在的帳號並推送", "TemplateHelpText": "選擇模板添加時,會自動創建資產下不存在的帳號並推送",
"TemplateManagement": "模板管理", "TemplateManagement": "模版列表",
"TemplateUpdate": "更新模板", "TemplateUpdate": "更新模板",
"Templates": "模板管理", "Templates": "模板列表",
"TencentCloud": "騰訊雲", "TencentCloud": "騰訊雲",
"Terminal": "組件設置", "Terminal": "組件設置",
"TerminalDetail": "組件詳情", "TerminalDetail": "組件詳情",

View File

@ -225,7 +225,11 @@ class JobExecutionViewSet(OrgBulkModelViewSet):
return Response({'error': serializer.errors}, status=400) return Response({'error': serializer.errors}, status=400)
task_id = serializer.validated_data['task_id'] task_id = serializer.validated_data['task_id']
try: try:
instance = get_object_or_404(JobExecution, pk=task_id, creator=request.user) user = request.user
if user.has_perm("audits.view_joblog"):
instance = get_object_or_404(JobExecution, pk=task_id)
else:
instance = get_object_or_404(JobExecution, pk=task_id, creator=request.user)
except Http404: except Http404:
return Response( return Response(
{'error': _('The task is being created and cannot be interrupted. Please try again later.')}, {'error': _('The task is being created and cannot be interrupted. Please try again later.')},

View File

@ -42,7 +42,7 @@ class JobSerializer(BulkOrgResourceModelSerializer, PeriodTaskSerializerMixin, W
model = Job model = Job
read_only_fields = [ read_only_fields = [
"id", "date_last_run", "date_created", "id", "date_last_run", "date_created",
"date_updated", "average_time_cost" "date_updated", "average_time_cost", "created_by", "material"
] ]
fields_m2m = ['variable'] fields_m2m = ['variable']
fields = read_only_fields + [ fields = read_only_fields + [

View File

@ -101,6 +101,8 @@ class VariableFormDataSerializer(serializers.Serializer):
if not request: if not request:
return return
params = request.query_params params = request.query_params
if params.get('format') == 'openapi':
return
job = params.get('job') job = params.get('job')
adhoc = params.get('adhoc') adhoc = params.get('adhoc')
playbook = params.get('playbook') playbook = params.get('playbook')

View File

@ -45,6 +45,6 @@ def merge_nodes_and_assets(nodes, assets, user):
elif node_id == PermNode.UNGROUPED_NODE_KEY: elif node_id == PermNode.UNGROUPED_NODE_KEY:
node_assets = perm_util.get_ungroup_assets() node_assets = perm_util.get_ungroup_assets()
else: else:
_, node_assets = perm_util.get_node_all_assets(node_id) node, node_assets = perm_util.get_node_all_assets(node_id)
assets.extend(node_assets.exclude(id__in=[asset.id for asset in assets])) assets.extend(node_assets.exclude(id__in=[asset.id for asset in assets]))
return assets return assets