3737import com .tencent .bk .job .common .metrics .CommonMetricNames ;
3838import com .tencent .bk .job .common .model .User ;
3939import com .tencent .bk .job .common .model .dto .AppResourceScope ;
40- import com .tencent .bk .job .common .model .dto .ResourceScope ;
41- import com .tencent .bk .job .common .service .AppScopeMappingService ;
42- import com .tencent .bk .job .common .util .JobContextUtil ;
4340import com .tencent .bk .job .common .model .dto .ApplicationHostDTO ;
41+ import com .tencent .bk .job .common .model .dto .ResourceScope ;
4442import com .tencent .bk .job .common .model .openapi .v3 .EsbCmdbTopoNodeDTO ;
4543import com .tencent .bk .job .common .model .openapi .v3 .EsbDynamicGroupDTO ;
44+ import com .tencent .bk .job .common .service .AppScopeMappingService ;
45+ import com .tencent .bk .job .common .util .JobContextUtil ;
4646import com .tencent .bk .job .common .util .date .DateUtils ;
4747import com .tencent .bk .job .execute .model .esb .v4 .req .OpenApiV4HostDTO ;
4848import com .tencent .bk .job .execute .model .esb .v4 .req .V4ExecuteTargetDTO ;
5959import com .tencent .bk .job .manage .model .esb .v4 .OpenApiV4JobPlanDTO ;
6060import com .tencent .bk .job .manage .model .esb .v4 .req .V4CreateJobPlanRequest ;
6161import com .tencent .bk .job .manage .model .esb .v4 .req .V4JobPlanVariableItem ;
62+ import com .tencent .bk .job .manage .service .host .TenantHostService ;
6263import com .tencent .bk .job .manage .service .plan .TaskPlanService ;
6364import com .tencent .bk .job .manage .service .template .TaskTemplateService ;
6465import org .apache .commons .collections4 .CollectionUtils ;
@@ -83,18 +84,21 @@ public class OpenApiJobPlanV4ResourceImpl implements OpenApiJobPlanV4Resource {
8384 private final TemplateAuthService templateAuthService ;
8485 private final PlanAuthService planAuthService ;
8586 private final AppScopeMappingService appScopeMappingService ;
87+ private final TenantHostService tenantHostService ;
8688
8789 @ Autowired
8890 public OpenApiJobPlanV4ResourceImpl (TaskPlanService planService ,
8991 TaskTemplateService templateService ,
9092 TemplateAuthService templateAuthService ,
9193 PlanAuthService planAuthService ,
92- AppScopeMappingService appScopeMappingService ) {
94+ AppScopeMappingService appScopeMappingService ,
95+ TenantHostService tenantHostService ) {
9396 this .planService = planService ;
9497 this .templateService = templateService ;
9598 this .templateAuthService = templateAuthService ;
9699 this .planAuthService = planAuthService ;
97100 this .appScopeMappingService = appScopeMappingService ;
101+ this .tenantHostService = tenantHostService ;
98102 }
99103
100104 @ Override
@@ -119,7 +123,7 @@ public EsbV4Response<OpenApiV4JobPlanDTO> createJobPlan(String username,
119123 }
120124
121125 List <Long > enableSteps = resolveEnableSteps (request , template );
122- List <TaskVariableDTO > variableList = mapVariables (request .getVariables (), template );
126+ List <TaskVariableDTO > variableList = mapVariables (request .getVariables (), template , user . getTenantId () );
123127
124128 String planName = StringUtils .strip (request .getName ());
125129 if (Boolean .FALSE .equals (
@@ -162,7 +166,9 @@ private List<Long> resolveEnableSteps(V4CreateJobPlanRequest request, TaskTempla
162166 return new ArrayList <>(request .getEnableSteps ());
163167 }
164168
165- private List <TaskVariableDTO > mapVariables (List <V4JobPlanVariableItem > variables , TaskTemplateInfoDTO template ) {
169+ private List <TaskVariableDTO > mapVariables (List <V4JobPlanVariableItem > variables ,
170+ TaskTemplateInfoDTO template ,
171+ String tenantId ) {
166172 if (CollectionUtils .isEmpty (variables )) {
167173 return new ArrayList <>();
168174 }
@@ -220,7 +226,7 @@ private List<TaskVariableDTO> mapVariables(List<V4JobPlanVariableItem> variables
220226 }
221227 );
222228 }
223- TaskTargetDTO taskTargetDTO = buildTaskTargetDTO (item .getExecuteTarget ());
229+ TaskTargetDTO taskTargetDTO = buildTaskTargetDTO (item .getExecuteTarget (), tenantId );
224230 dto .setDefaultValue (taskTargetDTO .toJsonString ());
225231 }
226232 } else if (!item .isFollowTemplate () && item .getValue () != null ) {
@@ -232,7 +238,7 @@ private List<TaskVariableDTO> mapVariables(List<V4JobPlanVariableItem> variables
232238 }
233239
234240 /** 执行目标变量覆盖:仅主机维度,容器 filter 暂不支持。 */
235- private TaskTargetDTO buildTaskTargetDTO (V4ExecuteTargetDTO v4 ) {
241+ private TaskTargetDTO buildTaskTargetDTO (V4ExecuteTargetDTO v4 , String tenantId ) {
236242 if (v4 == null ) {
237243 throw new InvalidParamException (
238244 ErrorCode .ILLEGAL_PARAM_WITH_PARAM_NAME_AND_REASON ,
@@ -265,9 +271,7 @@ private TaskTargetDTO buildTaskTargetDTO(V4ExecuteTargetDTO v4) {
265271 }
266272 TaskHostNodeDTO hostNode = new TaskHostNodeDTO ();
267273 if (CollectionUtils .isNotEmpty (v4 .getHostList ())) {
268- hostNode .setHostList (v4 .getHostList ().stream ()
269- .map (OpenApiJobPlanV4ResourceImpl ::toApplicationHostDTO )
270- .collect (Collectors .toList ()));
274+ hostNode .setHostList (resolveHostList (v4 .getHostList (), tenantId ));
271275 }
272276 if (CollectionUtils .isNotEmpty (v4 .getDynamicGroups ())) {
273277 hostNode .setDynamicGroupId (v4 .getDynamicGroups ().stream ()
@@ -282,15 +286,59 @@ private TaskTargetDTO buildTaskTargetDTO(V4ExecuteTargetDTO v4) {
282286 return new TaskTargetDTO (null , hostNode , null );
283287 }
284288
285- private static ApplicationHostDTO toApplicationHostDTO (OpenApiV4HostDTO host ) {
286- ApplicationHostDTO applicationHost = new ApplicationHostDTO ();
287- if (host .getBkHostId () != null ) {
288- applicationHost .setHostId (host .getBkHostId ());
289- } else {
290- applicationHost .setCloudAreaId (host .getBkCloudId ());
291- applicationHost .setIp (host .getIp ());
289+ /**
290+ * 将 OpenAPI 主机列表解析为 {@link ApplicationHostDTO} 列表,并补全 hostId。
291+ *
292+ * <p>已带 bk_host_id 的直接使用;仅传 bk_cloud_id+ip 的批量从 CMDB(经 TenantHostService 缓存兜底)反查 hostId。
293+ * 未能解析到 hostId 的主机会抛 {@link InvalidParamException},避免创建出页面回显"主机无效"的执行方案。
294+ *
295+ * @param hosts 入参主机列表,已由 {@link com.tencent.bk.job.execute.model.esb.v4.req.validator.V4HostGroupSequenceProvider}
296+ * 保证至少含有 bk_host_id 或 bk_cloud_id+ip
297+ * @param tenantId 当前请求租户 ID
298+ * @return 已补全 hostId 的主机列表
299+ */
300+ private List <ApplicationHostDTO > resolveHostList (List <OpenApiV4HostDTO > hosts , String tenantId ) {
301+ List <ApplicationHostDTO > result = new ArrayList <>(hosts .size ());
302+ Set <String > cloudIpsToResolve = new HashSet <>();
303+ for (OpenApiV4HostDTO host : hosts ) {
304+ ApplicationHostDTO dto = new ApplicationHostDTO ();
305+ if (host .getBkHostId () != null ) {
306+ dto .setHostId (host .getBkHostId ());
307+ } else {
308+ dto .setCloudAreaId (host .getBkCloudId ());
309+ dto .setIp (host .getIp ());
310+ cloudIpsToResolve .add (dto .getCloudIp ());
311+ }
312+ result .add (dto );
292313 }
293- return applicationHost ;
314+ if (cloudIpsToResolve .isEmpty ()) {
315+ return result ;
316+ }
317+
318+ Map <String , ApplicationHostDTO > hostsFromCmdb =
319+ tenantHostService .listHostsByIps (tenantId , cloudIpsToResolve );
320+ List <String > missingCloudIps = new ArrayList <>();
321+ for (ApplicationHostDTO dto : result ) {
322+ if (dto .getHostId () != null ) {
323+ continue ;
324+ }
325+ ApplicationHostDTO cmdbHost = hostsFromCmdb == null ? null : hostsFromCmdb .get (dto .getCloudIp ());
326+ if (cmdbHost == null || cmdbHost .getHostId () == null ) {
327+ missingCloudIps .add (dto .getCloudIp ());
328+ continue ;
329+ }
330+ dto .setHostId (cmdbHost .getHostId ());
331+ }
332+ if (!missingCloudIps .isEmpty ()) {
333+ throw new InvalidParamException (
334+ ErrorCode .ILLEGAL_PARAM_WITH_PARAM_NAME_AND_REASON ,
335+ new Object []{
336+ "variables[].execute_target.host_list" ,
337+ "host not found in cmdb by cloud_id+ip: " + String .join ("," , missingCloudIps )
338+ }
339+ );
340+ }
341+ return result ;
294342 }
295343
296344 private static TaskNodeInfoDTO toTaskNodeInfoDTO (EsbCmdbTopoNodeDTO topoNode ) {
0 commit comments