@@ -21,6 +21,7 @@ import org.apache.linkis.common.conf.Configuration
2121import org .apache .linkis .common .log .LogUtils
2222import org .apache .linkis .common .utils .{Logging , Utils }
2323import org .apache .linkis .common .utils .CodeAndRunTypeUtils .LANGUAGE_TYPE_AI_SQL
24+ import org .apache .linkis .datasourcemanager .common .domain .DataSource
2425import org .apache .linkis .entrance .conf .EntranceConfiguration
2526import org .apache .linkis .entrance .conf .EntranceConfiguration ._
2627import org .apache .linkis .entrance .interceptor .EntranceInterceptor
@@ -52,6 +53,7 @@ class AISQLTransformInterceptor extends EntranceInterceptor with Logging {
5253 val sqlLanguage : String = LANGUAGE_TYPE_AI_SQL
5354 val sparkEngineType : String = AI_SQL_DEFAULT_SPARK_ENGINE_TYPE
5455 val hiveEngineType : String = AI_SQL_DEFAULT_HIVE_ENGINE_TYPE
56+ val starrocksEngineType : String = AISQL_DEFAULT_STARROCKS_ENGINE_TYPE
5557 val labels : util.List [Label [_]] = jobRequest.getLabels
5658 val codeType : String = LabelUtil .getCodeType(labels)
5759 // engineType and creator have been verified in LabelCheckInterceptor.
@@ -105,24 +107,110 @@ class AISQLTransformInterceptor extends EntranceInterceptor with Logging {
105107 )
106108 } else {
107109 logger.info(s " start intelligent selection execution engine for ${jobRequest.getId}" )
108- val engineType : String =
109- EntranceUtils .getDynamicEngineType(jobRequest.getExecutionCode, logAppender)
110+
111+ /**
112+ * Check for StarRocks engine switch if feature is enabled Priority: runtime parameters >
113+ * script comment > template configuration
114+ */
115+ var forceEngineType : String = null
116+ if (AISQL_STARROCKS_SWITCH .getValue) {
117+ // 1. Check runtime parameters
118+ val runtimeEngineType = getRuntimeEngineType(jobRequest.getParams)
119+
120+ // 2. Check script comment
121+ val scriptEngineType = if (runtimeEngineType == null ) {
122+ TemplateConfUtils .getCustomEngineType(
123+ jobRequest.getExecutionCode,
124+ org.apache.linkis.common.utils.CodeAndRunTypeUtils .getLanguageTypeByCodeType(codeType)
125+ )
126+ } else null
127+
128+ // Determine final engine type
129+ val targetEngineType = Option (runtimeEngineType)
130+ .orElse(Option (scriptEngineType))
131+ .orNull
132+
133+ // If StarRocks engine is specified
134+ if (" starrocks" .equalsIgnoreCase(targetEngineType)) {
135+ // Check whitelist
136+ val (user, creator) = LabelUtil .getUserCreator(jobRequest.getLabels)
137+ if (! isUserInStarRocksWhitelist(user)) {
138+ logger.warn(
139+ s " User $user is not in StarRocks whitelist for task ${jobRequest.getId}, using default engine selection "
140+ )
141+ logAppender.append(
142+ LogUtils .generateWarn(
143+ s " User $user is not in StarRocks whitelist, using default engine selection \n "
144+ )
145+ )
146+ } else {
147+ forceEngineType = " starrocks"
148+ }
149+ }
150+ }
151+ val engineType : String = {
152+ EntranceUtils .getDynamicEngineType(
153+ jobRequest.getExecutionCode,
154+ logAppender,
155+ forceEngineType
156+ )
157+ }
110158 if (" hive" .equals(engineType)) {
111159 changeEngineLabel(hiveEngineType, labels)
112- logAppender.append(
113- LogUtils .generateInfo(s " use $hiveEngineType by intelligent selection. \n " )
114- )
115160 currentEngineType = hiveEngineType
161+ } else if (" starrocks" .equals(engineType)) {
162+
163+ Utils .tryCatch {
164+ val dataSource : DataSource = EntranceUtils .getDatasourceByDatasourceTypeAndUser(
165+ " starrocks" ,
166+ jobRequest.getSubmitUser,
167+ jobRequest.getExecuteUser
168+ )
169+ if (dataSource != null ) {
170+ val dsParams : util.Map [String , AnyRef ] = new util.HashMap [String , AnyRef ]()
171+ dsParams.put(" wds.linkis.engine.runtime.datasource" , dataSource.getDataSourceName)
172+ TaskUtils .addRuntimeMap(jobRequest.getParams, dsParams)
173+ changeEngineLabel(starrocksEngineType, labels)
174+ currentEngineType = starrocksEngineType
175+ logAppender.append(
176+ LogUtils .generateInfo(
177+ s " use starrocks engine with datasource name : ${dataSource.getDataSourceName} \n "
178+ )
179+ )
180+ } else {
181+ // use hive for datasource not exists
182+ changeEngineLabel(hiveEngineType, labels)
183+ currentEngineType = hiveEngineType
184+ logger.warn(
185+ s " Failed to select starrocks engine, for user ${jobRequest.getExecuteUser} datasource not exists. "
186+ )
187+ logAppender.append(
188+ LogUtils .generateInfo(
189+ s " Failed to select starrocks engine, ${jobRequest.getExecuteUser} datasource does not exist. now use $currentEngineType \n "
190+ )
191+ )
192+ }
193+ } { t =>
194+ // use hive for exception
195+ changeEngineLabel(hiveEngineType, labels)
196+ currentEngineType = hiveEngineType
197+ logger.warn(" Failed to select starrocks engine: " , t)
198+ logAppender.append(
199+ LogUtils .generateInfo(
200+ s " Failed to select starrocks engine, service exception. now use $currentEngineType \n "
201+ )
202+ )
203+ }
116204 } else {
117205 changeEngineLabel(sparkEngineType, labels)
118- logAppender.append(
119- LogUtils .generateInfo(s " use $sparkEngineType by intelligent selection. \n " )
120- )
121206 currentEngineType = sparkEngineType
122207 }
123208 logger.info(
124209 s " end intelligent selection execution engine, and engineType is ${currentEngineType} for ${jobRequest.getId}. "
125210 )
211+ logAppender.append(
212+ LogUtils .generateInfo(s " use $currentEngineType by intelligent selection. \n " )
213+ )
126214 EntranceUtils .dealsparkDynamicConf(jobRequest, logAppender, jobRequest.getParams)
127215 }
128216
@@ -179,4 +267,64 @@ class AISQLTransformInterceptor extends EntranceInterceptor with Logging {
179267 labels.add(newEngineTypeLabel)
180268 }
181269
270+ /**
271+ * Get engine type from runtime parameters
272+ * @param params
273+ * job request parameters
274+ * @return
275+ * engine type, such as "starrocks", null if not found
276+ */
277+ private def getRuntimeEngineType (params : util.Map [String , AnyRef ]): String = {
278+ if (params == null ) return null
279+
280+ val runtimeParams = TaskUtils .getRuntimeMap(params)
281+ if (runtimeParams == null ) return null
282+
283+ val engineType = runtimeParams.get(TemplateConfUtils .confEngineTypeKey)
284+ if (engineType != null ) engineType.toString else null
285+ }
286+
287+ /**
288+ * Check if user is in StarRocks whitelist
289+ * @param submitUser
290+ * the user who submits the task
291+ * @return
292+ * true if user is in whitelist or whitelist is empty (allow all users), false otherwise
293+ */
294+ private def isUserInStarRocksWhitelist (submitUser : String ): Boolean = {
295+ val whitelistUsers = AISQL_STARROCKS_WHITELIST_USERS .getValue
296+ val whitelistDepartments = AISQL_STARROCKS_WHITELIST_DEPARTMENTS .getValue
297+
298+ // If both whitelists are empty, allow all users
299+ if (StringUtils .isBlank(whitelistUsers) && StringUtils .isBlank(whitelistDepartments)) {
300+ return true
301+ }
302+
303+ // Check user whitelist
304+ if (StringUtils .isNotBlank(whitelistUsers)) {
305+ val users = whitelistUsers.split(" ," ).map(_.trim)
306+ if (users.contains(submitUser)) {
307+ logger.info(s " User $submitUser is in StarRocks whitelist (user) " )
308+ return true
309+ }
310+ }
311+
312+ // Check department whitelist
313+ if (StringUtils .isNotBlank(whitelistDepartments)) {
314+ val userDepartmentId = EntranceUtils .getUserDepartmentId(submitUser)
315+ if (StringUtils .isNotBlank(userDepartmentId)) {
316+ val departments = whitelistDepartments.split(" ," ).map(_.trim)
317+ if (departments.contains(userDepartmentId)) {
318+ logger.info(
319+ s " User $submitUser (department: $userDepartmentId) is in StarRocks whitelist (department) "
320+ )
321+ return true
322+ }
323+ }
324+ }
325+
326+ logger.warn(s " User $submitUser is not in StarRocks whitelist " )
327+ false
328+ }
329+
182330}
0 commit comments