Skip to content

Commit

Permalink
[1.1.17]ECM Support file download (#318)
Browse files Browse the repository at this point in the history
* push sup ecm down log

* push code

* push code

* Code optimization

* add annotation
  • Loading branch information
v-kkhuang authored Nov 1, 2023
1 parent 7bf15b7 commit 8a36b86
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ public enum EngineconnServerErrorCodeSummary implements LinkisErrorCode {
11110,
"the parameters of engineConnInstance and ticketId are both not exists.(engineConnInstance 和ticketId 的参数都不存在.)"),
LOG_IS_NOT_EXISTS(11110, "Log directory {0} does not exists.(日志目录 {0} 不存在.)"),
FAILED_TO_DOWNLOAD(911115, "failed to downLoad(下载失败)");
FAILED_TO_DOWNLOAD(911115, "failed to downLoad(下载失败)"),
FILE_IS_OVERSIZE(911116, "Download file has exceeded 100MB(下载文件已超过100M)"),
PARAMETER_NOT_NULL(911117, "Parameter {0} cannot be empty (参数 {0} 不能为空)");

/** (errorCode)错误码 */
private final int errorCode;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.linkis.ecm.restful;

import org.apache.linkis.ecm.server.exception.ECMErrorException;
import org.apache.linkis.server.Message;
import org.apache.linkis.server.utils.ModuleUserUtils;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;

import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.MessageFormat;

import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.apache.linkis.ecm.errorcode.EngineconnServerErrorCodeSummary.*;

@Api(tags = "ECM")
@RequestMapping(path = "/engineconnManager")
@RestController
public class ECMRestfulApi {

private final Logger logger = LoggerFactory.getLogger(ECMRestfulApi.class);

@ApiOperation(
value = "downloadEngineLog",
notes = "download engine log",
response = Message.class)
@ApiImplicitParams({
@ApiImplicitParam(name = "emInstance", required = true, dataType = "String"),
@ApiImplicitParam(name = "instance", required = true, dataType = "String"),
@ApiImplicitParam(name = "logDirSuffix", required = true, dataType = "String"),
@ApiImplicitParam(name = "logType", required = true, dataType = "String")
})
@ApiOperationSupport(ignoreParameters = {"json"})
@RequestMapping(path = "/downloadEngineLog", method = RequestMethod.GET)
public void downloadEngineLog(
HttpServletRequest req,
HttpServletResponse response,
@RequestParam(value = "emInstance") String emInstance,
@RequestParam(value = "instance") String instance,
@RequestParam(value = "logDirSuffix") String logDirSuffix,
@RequestParam(value = "logType") String logType)
throws IOException, ECMErrorException {
ModuleUserUtils.getOperationUser(req, "downloadEngineLog");
if (StringUtils.isBlank(instance)) {
throw new ECMErrorException(
PARAMETER_NOT_NULL.getErrorCode(),
MessageFormat.format(PARAMETER_NOT_NULL.getErrorDesc(), "instance"));
}
if (StringUtils.isBlank(logDirSuffix)) {
throw new ECMErrorException(
PARAMETER_NOT_NULL.getErrorCode(),
MessageFormat.format(PARAMETER_NOT_NULL.getErrorDesc(), "logDirSuffix"));
}
if (StringUtils.isBlank(logType)) {
throw new ECMErrorException(
PARAMETER_NOT_NULL.getErrorCode(),
MessageFormat.format(PARAMETER_NOT_NULL.getErrorDesc(), "logType"));
}
File inputFile = new File(logDirSuffix, logType);
if (!inputFile.exists()) {
throw new ECMErrorException(
LOG_IS_NOT_EXISTS.getErrorCode(),
MessageFormat.format(LOG_IS_NOT_EXISTS.getErrorDesc(), logDirSuffix));
} else {
long fileSizeInBytes = inputFile.length();
long fileSizeInMegabytes = fileSizeInBytes / (1024 * 1024);
if (fileSizeInMegabytes > 100) {
throw new ECMErrorException(
FILE_IS_OVERSIZE.getErrorCode(),
MessageFormat.format(FILE_IS_OVERSIZE.getErrorDesc(), logDirSuffix));
}
ServletOutputStream outputStream = null;
FileInputStream inputStream = null;
BufferedInputStream fis = null;
PrintWriter writer = null;
try {
inputStream = new FileInputStream(inputFile);
fis = new BufferedInputStream(inputStream);
byte[] buffer = new byte[1024];
int bytesRead = 0;
response.setCharacterEncoding(Consts.UTF_8.toString());
java.nio.file.Path source = Paths.get(inputFile.getPath());
response.addHeader("Content-Type", Files.probeContentType(source));
// filename eg:bdpdws110002_11529_stdout.txt
response.addHeader(
"Content-Disposition",
"attachment;filename=" + instance.replace(":", "_") + "_" + logType + ".txt");
response.addHeader("Content-Length", fileSizeInBytes + "");
outputStream = response.getOutputStream();
while ((bytesRead = fis.read(buffer, 0, 1024)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
logger.error("download failed:", e);
response.reset();
response.setCharacterEncoding(Consts.UTF_8.toString());
response.setContentType("text/plain; charset=utf-8");
writer = response.getWriter();
writer.append("error(错误):" + e.getMessage());
writer.flush();
} finally {
if (outputStream != null) {
outputStream.flush();
}
IOUtils.closeQuietly(outputStream);
IOUtils.closeQuietly(fis);
IOUtils.closeQuietly(inputStream);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,7 @@ object GatewayConfiguration {

val LINKIS_CLUSTER_NAME = CommonVars("linkis.cluster.name", "")

val ENGINECONN_MANAGER_SPRING_NAME =
CommonVars("wds.linkis.engineconnmanager.name", "linkis-cg-engineconnmanager")

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.linkis.gateway.ujes.parser

import org.apache.linkis.common.ServiceInstance
import org.apache.linkis.gateway.config.GatewayConfiguration
import org.apache.linkis.gateway.http.GatewayContext
import org.apache.linkis.gateway.parser.AbstractGatewayParser
import org.apache.linkis.gateway.springcloud.SpringCloudGatewayConfiguration.{
normalPath,
API_URL_PREFIX
}
import org.apache.linkis.protocol.utils.ZuulEntranceUtils

import org.springframework.stereotype.Component

@Component
class ECMRequestGatewayParser extends AbstractGatewayParser {
override def shouldContainRequestBody(gatewayContext: GatewayContext): Boolean = false

override def parse(gatewayContext: GatewayContext): Unit = {
logger.info("start begin ECMRequestGatewayParser {}", gatewayContext)
gatewayContext.getRequest.getRequestURI match {
case ECMRequestGatewayParser.ECM_EXECUTION_REGEX(version, execId) =>
if (sendResponseWhenNotMatchVersion(gatewayContext, version)) return
val serviceInstance =
if (
gatewayContext.getRequest.getQueryParams.containsKey(ECMRequestGatewayParser.INSTANCE)
) {
val instances =
gatewayContext.getRequest.getQueryParams.get(ECMRequestGatewayParser.INSTANCE)
if (null != instances && instances.length == 1) {
ServiceInstance(
GatewayConfiguration.ENGINECONN_MANAGER_SPRING_NAME.getValue,
instances(0)
)
} else {
ServiceInstance(GatewayConfiguration.ENGINECONN_MANAGER_SPRING_NAME.getValue, null)
}
} else {
ServiceInstance(GatewayConfiguration.ENGINECONN_MANAGER_SPRING_NAME.getValue, null)
}
gatewayContext.getGatewayRoute.setServiceInstance(serviceInstance)
case _ =>
}
}

}

object ECMRequestGatewayParser {

val ECM_HEADER =
normalPath(API_URL_PREFIX) + "rest_[a-zA-Z][a-zA-Z_0-9]*/(v\\d+)/engineconnManager/"

val ECM_EXECUTION_REGEX =
(ECM_HEADER + "(downloadEngineLog)").r

val INSTANCE = "emInstance"

}

0 comments on commit 8a36b86

Please sign in to comment.