diff --git a/bklog/apps/iam/handlers/permission.py b/bklog/apps/iam/handlers/permission.py index 1188601b347..93b0b5e4079 100644 --- a/bklog/apps/iam/handlers/permission.py +++ b/bklog/apps/iam/handlers/permission.py @@ -526,3 +526,19 @@ def grant_creator_action(self, resource: Resource, creator: str = None, raise_ex raise e return grant_result + + def grant_creator_action_batch(self, resource: Resource, creators: list = None, raise_exception=False): + """ + 为多个用户新建实例关联权限授权 + :param resource: 资源实例 + :param creators: 资源创建者列表 + :param raise_exception: 是否抛出异常 + :return: {creator: grant_result} + """ + # 权限中心单次授权仅接受一个 creator,去重后逐个授权 + unique_creators = list(dict.fromkeys(creator for creator in (creators or []) if creator)) + + return { + creator: self.grant_creator_action(resource=resource, creator=creator, raise_exception=raise_exception) + for creator in unique_creators + } diff --git a/bklog/apps/log_databus/handlers/collector/base.py b/bklog/apps/log_databus/handlers/collector/base.py index 198102d5b45..76ec3326c9f 100644 --- a/bklog/apps/log_databus/handlers/collector/base.py +++ b/bklog/apps/log_databus/handlers/collector/base.py @@ -551,6 +551,7 @@ def custom_update( is_platform_index=None, platform_index_visibility=None, platform_index_filter=None, + owners=None, ): collector_config_update = { "collector_config_name": collector_config_name, @@ -654,6 +655,8 @@ def custom_update( etl_handler.update_or_create(**etl_params) self._sync_scene_tags_to_index_set(etl_params["labels"]) + self._authorization_owners(self.data, owners) + custom_config.after_hook(self.data) # add user_operation_record @@ -1129,6 +1132,38 @@ def _authorization_collector(collector_config: CollectorConfig): f"collector_config->({collector_config.collector_config_id}) grant creator action failed, reason: {e}" ) + @staticmethod + def _authorization_owners(collector_config: CollectorConfig, owners: list = None): + """ + 将采集项及其索引集的新建关联权限授予指定用户,仅新增授权,不回收历史权限 + """ + if not owners: + return + + try: + permission = Permission() + permission.grant_creator_action_batch( + resource=ResourceEnum.COLLECTION.create_simple_instance( + collector_config.collector_config_id, attribute={"name": collector_config.collector_config_name} + ), + creators=owners, + ) + + # 按采集项反查索引集,避免内存中的 collector_config.index_set_id 尚未刷新 + index_set = LogIndexSet.objects.filter(collector_config_id=collector_config.collector_config_id).first() + if index_set: + permission.grant_creator_action_batch( + resource=ResourceEnum.INDICES.create_simple_instance( + index_set.index_set_id, attribute={"name": index_set.index_set_name} + ), + creators=owners, + ) + except Exception as e: # pylint: disable=broad-except + logger.warning( + f"collector_config->({collector_config.collector_config_id}) grant creator action to owners " + f"{owners} failed, reason: {e}" + ) + def _itsm_start_judge(self): if self.data.is_custom_scenario: return @@ -1439,6 +1474,7 @@ def custom_create( platform_index_visibility=None, platform_index_filter=None, ignore_exists=False, + owners=None, ): data_link_id = self.get_data_link_id(bk_biz_id=bk_biz_id, data_link_id=int(data_link_id or 0)) collector_config_params = { @@ -1461,6 +1497,8 @@ def custom_create( existing = CollectorConfig.objects.get( collector_config_name_en=collector_config_name_en, bk_biz_id=bkdata_biz_id ) + # 幂等创建同样要保证 owners 拿到权限 + self._authorization_owners(existing, owners) return { "collector_config_id": existing.collector_config_id, "index_set_id": existing.index_set_id, @@ -1574,6 +1612,9 @@ def custom_create( self.data.save(update_fields=["index_set_id"]) self._sync_scene_tags_to_index_set(params["labels"]) + # 索引集ID在清洗创建后才最终确定,因此在此处再对 owners 授权 + self._authorization_owners(self.data, owners) + custom_config.after_hook(self.data) ret = { diff --git a/bklog/apps/log_databus/serializers.py b/bklog/apps/log_databus/serializers.py index 5c7680d4307..484a4a90d31 100644 --- a/bklog/apps/log_databus/serializers.py +++ b/bklog/apps/log_databus/serializers.py @@ -1623,6 +1623,12 @@ class CustomCollectorBaseSerializer(CollectorETLParamsFieldSerializer, ParentInd label=_("备注说明"), max_length=64, required=False, allow_null=True, allow_blank=True ) is_display = serializers.BooleanField(label=_("是否展示"), default=True, required=False) + owners = serializers.ListField( + label=_("授权用户列表"), + required=False, + default=list, + child=serializers.CharField(max_length=64), + ) def validate(self, attrs: dict) -> dict: # 先进行校验 diff --git a/bklog/apps/log_databus/views/collector_views.py b/bklog/apps/log_databus/views/collector_views.py index db24176a1fa..f8b2b8251b1 100644 --- a/bklog/apps/log_databus/views/collector_views.py +++ b/bklog/apps/log_databus/views/collector_views.py @@ -2000,6 +2000,7 @@ def custom_create(self, request): @apiParam {Int} [storage_replies] 副本数量 @apiParam {String} category_id 数据分类 GlobalsConfig.category读取 @apiParam {String} description 备注说明 + @apiParam {List} [owners] 授权用户列表,为其授予采集项与索引集的新建关联权限 @apiParamExample {json} 请求样例: { "bk_biz_id": 2, @@ -2013,7 +2014,8 @@ def custom_create(self, request): "retention": 1, "es_shards": 1, "storage_replies": 1, - "allocation_min_days": 1 + "allocation_min_days": 1, + "owners": ["admin", "user1"] } @apiSuccessExample {json} 成功返回: { @@ -2051,6 +2053,7 @@ def custom_update(self, request, collector_config_id): @apiParam {Int} allocation_min_days 冷热数据时间 @apiParam {Int} es_shards es分片数量 @apiParam {Int} [storage_replies] 副本数量 + @apiParam {List} [owners] 授权用户列表,为其授予采集项与索引集的新建关联权限,仅新增不回收 @apiParamExample {json} 请求样例: { "collector_config_name": "xxxxx", @@ -2060,7 +2063,8 @@ def custom_update(self, request, collector_config_id): "retention": 1, "storage_replies": 1, "es_shards": 1, - "allocation_min_days": 1 + "allocation_min_days": 1, + "owners": ["admin", "user1"] } @apiSuccessExample {json} 成功返回: {