From 7d9494640272f23b5358f11e6e8faebb1a57240a Mon Sep 17 00:00:00 2001 From: abhijit_onap Date: Thu, 18 Jun 2020 14:22:52 +0530 Subject: [PATCH] Added Deployment Files Deployment via YAML declarative files. Deployment Objects supported 1. Pod 2. Service Signed-off-by: abhijit_onap Change-Id: I3eee468139779095a9d641bb14c195023a3926c7 --- .../common/eliot-ui/be/src/eliotk8sclient/pom.xml | 42 +++++- .../eliot/eliotbe/eliotk8sclient/AppException.java | 31 ++++ .../eliotk8sclient/common/AppConstants.java | 57 ++++++++ .../controller/AppDeployController.java | 62 ++++++++ .../eliotk8sclient/deploy/GenericDeploy.java | 49 +++++++ .../deploy/GenericDeployFactory.java | 34 +++++ .../deploy/kubernetes/DeployFactory.java | 27 ++++ .../eliotk8sclient/deploy/kubernetes/IDeploy.java | 22 +++ .../deploy/kubernetes/KubernetesDeploy.java | 142 +++++++++++++++++++ .../deploy/kubernetes/PodServiceDeploy.java | 113 +++++++++++++++ .../eliotbe/eliotk8sclient/service/AppService.java | 129 +++++++++++++++++ .../eliotk8sclient/service/AppServiceHandler.java | 157 +++++++++++++++++++++ 12 files changed, 861 insertions(+), 4 deletions(-) create mode 100644 blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/AppException.java create mode 100644 blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/common/AppConstants.java create mode 100755 blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/controller/AppDeployController.java create mode 100644 blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/GenericDeploy.java create mode 100644 blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/GenericDeployFactory.java create mode 100644 blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/DeployFactory.java create mode 100644 blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/IDeploy.java create mode 100644 blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/KubernetesDeploy.java create mode 100644 blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/PodServiceDeploy.java create mode 100644 blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/service/AppService.java create mode 100644 blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/service/AppServiceHandler.java diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/pom.xml b/blueprints/common/eliot-ui/be/src/eliotk8sclient/pom.xml index e33a861..e16d977 100644 --- a/blueprints/common/eliot-ui/be/src/eliotk8sclient/pom.xml +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/pom.xml @@ -15,9 +15,9 @@ eliot backend code for kubernetes client - 1.8 + 11 + true - org.springframework.boot @@ -49,8 +49,42 @@ 5.0.0 compile - - + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + 2.10.3 + + + org.apache.logging.log4j + log4j-core + 2.13.2 + + + org.apache.logging.log4j + log4j-api + 2.13.2 + + + org.bitbucket.b_c + jose4j + 0.4.4 + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.13.2 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + 2.9.9 + + + org.apache.httpcomponents + httpcore + 4.4.13 + + diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/AppException.java b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/AppException.java new file mode 100644 index 0000000..e0a85a4 --- /dev/null +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/AppException.java @@ -0,0 +1,31 @@ +/* + * Copyright 2020 Huawei Technologies Co., Ltd. + * + * Licensed 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 com.eliot.eliotbe.eliotk8sclient; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.CONFLICT) +public class AppException extends RuntimeException { + + private static final long serialVersionUID = 1333309258952411164L; + + public AppException(String msg) { + super(msg); + } +} + diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/common/AppConstants.java b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/common/AppConstants.java new file mode 100644 index 0000000..e5478e9 --- /dev/null +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/common/AppConstants.java @@ -0,0 +1,57 @@ +/* + * Copyright 2020 Huawei Technologies Co., Ltd. + * + * Licensed 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 com.eliot.eliotbe.eliotk8sclient.common; + +public class AppConstants { + + public static final String EMPTY_STRING = ""; + + public static final String POD_NAME = "name"; + + public static final String POD_NAME_SPACE = "namespace"; + + public static final String POD_STATUS = "status"; + + public static final String SERVICE_NAME = "name"; + + public static final String SERVICE_NAME_SPACE = "namespace"; + + public static final String CONTAINERS = "containers"; + + public static final String PODS = "pods"; + + public static final String NAMEANDNAMESPACE = "|!"; + + public static final String K8SPOD = "|~"; + + public static final String POD_TYPE = "|`"; + + public static final String KIND = "kind"; + //public static final String APP_PACKAGE_EXTENSION = ".csar"; + + public static final long MAX_PACKAGE_SIZE = 10485760; + + public static final long MAX_CONFIG_SIZE = 5242880; + + public static final int MAX_PACKAGE_DIR_SIZE = 16; + + public static final int MAX_FILE_PATH_LENGTH = 2048; + + public static final String HTTPS = "https://"; + + public static final String COLON = ":"; +} diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/controller/AppDeployController.java b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/controller/AppDeployController.java new file mode 100755 index 0000000..7e3721b --- /dev/null +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/controller/AppDeployController.java @@ -0,0 +1,62 @@ +/* + * Copyright 2020 Huawei Technologies Co., Ltd. + * + * Licensed 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 com.eliot.eliotbe.eliotk8sclient.controller; + +import com.eliot.eliotbe.eliotk8sclient.service.AppServiceHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.Pattern; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +@Validated +@RestController +public class AppDeployController { + + public static final Logger logger = LoggerFactory.getLogger(AppDeployController.class); + + public static final String HOST_IP_REGEXP + = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"; + public static final String APP_INSTANCE_ID_REGEXP + = "([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}){1}"; + public static final String TENENT_ID_REGEXP = "[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}"; + public static final String WORKLOAD_ID_REGEXP = "^.{1,1024}$"; + public static final String QUERY_REGEXP = "^.{1,512}$"; + @Autowired + private AppServiceHandler appServiceHandler; + + /** + * Upload Deployment YAML file. + * @param file file + * @return + */ + @RequestMapping(path = "/upload", + method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> uploadAppDeployment( + @RequestParam("file") MultipartFile file) throws IOException { + logger.info("Deployment Upload File"); + return appServiceHandler.uploadDeployment(file); + } +} diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/GenericDeploy.java b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/GenericDeploy.java new file mode 100644 index 0000000..8886e3e --- /dev/null +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/GenericDeploy.java @@ -0,0 +1,49 @@ +/* + * Copyright 2020 Huawei Technologies Co., Ltd. + * + * Licensed 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 com.eliot.eliotbe.eliotk8sclient.deploy; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +public abstract class GenericDeploy { + + protected void search(final String pattern, final File folder, List result) { + File[] files = folder.listFiles(); + if (null != files) { + for (final File f : files) { + if (f.isDirectory()) { + search(pattern, f, result); + } + handleFile(f, pattern, result); + } + } + } + + private void handleFile(File f, String pattern, List result) { + if (f.isFile() && f.getName().matches(pattern)) { + try { + result.add(f.getCanonicalPath()); + } catch (IOException e) { + return; + } + } + } + + public abstract String deploy(String packagepath); +} diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/GenericDeployFactory.java b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/GenericDeployFactory.java new file mode 100644 index 0000000..df29165 --- /dev/null +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/GenericDeployFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright 2020 Huawei Technologies Co., Ltd. + * + * Licensed 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 com.eliot.eliotbe.eliotk8sclient.deploy; + + +import com.eliot.eliotbe.eliotk8sclient.deploy.kubernetes.KubernetesDeploy; + +public class GenericDeployFactory { + + /** + * create ubernetesDeploy. + * + * @param deploymentType deploymentType + * @return + */ + public static GenericDeploy create(String deploymentType) { + return new KubernetesDeploy(); + } + +} diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/DeployFactory.java b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/DeployFactory.java new file mode 100644 index 0000000..dc5625a --- /dev/null +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/DeployFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright 2020 Huawei Technologies Co., Ltd. + * + * Licensed 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 com.eliot.eliotbe.eliotk8sclient.deploy.kubernetes; + +import java.nio.file.Path; + +public class DeployFactory { + + public static IDeploy create() { + return new com.eliot.eliotbe.eliotk8sclient.deploy.kubernetes.PodServiceDeploy(); + } + +} diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/IDeploy.java b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/IDeploy.java new file mode 100644 index 0000000..63c246f --- /dev/null +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/IDeploy.java @@ -0,0 +1,22 @@ +/* + * Copyright 2020 Huawei Technologies Co., Ltd. + * + * Licensed 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 com.eliot.eliotbe.eliotk8sclient.deploy.kubernetes; + +public interface IDeploy { + + String deploy(String dstYamlFilePath); +} diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/KubernetesDeploy.java b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/KubernetesDeploy.java new file mode 100644 index 0000000..73df718 --- /dev/null +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/KubernetesDeploy.java @@ -0,0 +1,142 @@ +/* + * Copyright 2020 Huawei Technologies Co., Ltd. + * + * Licensed 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 com.eliot.eliotbe.eliotk8sclient.deploy.kubernetes; + +import com.eliot.eliotbe.eliotk8sclient.deploy.GenericDeploy; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.kubernetes.client.models.*; +import io.kubernetes.client.util.Yaml; +import org.jose4j.json.internal.json_simple.JSONObject; +import org.jose4j.json.internal.json_simple.parser.JSONParser; +import org.jose4j.json.internal.json_simple.parser.ParseException; +import com.eliot.eliotbe.eliotk8sclient.common.AppConstants; +import com.eliot.eliotbe.eliotk8sclient.deploy.GenericDeploy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Path; +import java.util.*; + +public class KubernetesDeploy extends GenericDeploy { + private static final Logger logger = LoggerFactory.getLogger(KubernetesDeploy.class); + + private static final Map> kindClassMap = new HashMap>() { + private static final long serialVersionUID = 3033314593899228898L; + { + put("Pod",V1Pod.class); + put("Deployment",V1Deployment.class); + put("PersistentVolume",V1PersistentVolume.class); + put("PersistentVolumeClaim",V1PersistentVolumeClaim.class); + put("Service",V1Service.class); + } + }; + /** + * deploy. + * @param packagepath packagepath + * @return + */ + public String deploy(String dstYamlFilePath) { + //String dstYamlFilePath = findDeploymentYamlPath(packagepath); + if (StringUtils.isEmpty(dstYamlFilePath)) { + logger.error("not found deploy yaml file."); + return AppConstants.EMPTY_STRING; + } + String yamlContent = readYamlFile(dstYamlFilePath); + String yamlStr = null; + try { + logger.info("before kube config installation "); + yamlStr = deployByYaml(yamlContent,dstYamlFilePath); + } catch (IOException e) { + logger.error("invoke method deployYaml fail : {}",e.getMessage()); + return AppConstants.EMPTY_STRING; + } + return yamlStr; + } + + private String findDeploymentYamlPath(String packagepath) { + List result = new ArrayList<>(); + search(".*\\.yaml", new File(packagepath), result); + String dstYamlFilePath = null; + for (String path : result) { + if (path.contains("Deployment")) { + dstYamlFilePath = path; + } + } + return dstYamlFilePath; + } + + protected String readYamlFile(String pathname) { + File file = new File(pathname); + StringBuilder fileContents = new StringBuilder((int) file.length()); + Scanner scanner; + try { + scanner = new Scanner(file, "UTF-8"); + } catch (FileNotFoundException e) { + logger.error("read yaml file fail : {}",e.getMessage()); + return ""; + } + + String lineSeparator = System.getProperty("line.separator"); + try { + while (scanner.hasNextLine()) { + fileContents.append(scanner.nextLine() + lineSeparator); + } + return fileContents.toString(); + } finally { + scanner.close(); + } + } + + protected void addModelMap(String apiVersion, String kind) { + if (kindClassMap.containsKey(kind)) { + Yaml.addModelMap(apiVersion, kind, kindClassMap.get(kind)); + logger.info("after addModelMap for {}",kindClassMap.get(kind).getName()); + return; + } + logger.error("not found kind : {}",kind); + } + + private String deployByYaml(String yamlContent, String dstYamlFilePath) throws IOException { + logger.info("Inside updateDeploymentYaml to install pod and service"); + ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory()); + for (String ret : yamlContent.split("---")) { + if (StringUtils.isEmpty(ret)) { + continue; + } + Object obj = yamlReader.readValue(ret, Object.class); + String data = new ObjectMapper().writeValueAsString(obj); + try { + JSONObject json = (JSONObject) new JSONParser().parse(data); + if (json.get("kind") == null) { + continue; + } + String kind = json.get("kind").toString(); + String apiVersion = json.get("apiVersion").toString(); + addModelMap(apiVersion,kind); + } catch (ParseException e) { + logger.error("parse data fail : {}",e.getMessage()); + } + } + IDeploy deployment = DeployFactory.create(); + return deployment.deploy(dstYamlFilePath); + } +} diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/PodServiceDeploy.java b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/PodServiceDeploy.java new file mode 100644 index 0000000..fbe9fec --- /dev/null +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/deploy/kubernetes/PodServiceDeploy.java @@ -0,0 +1,113 @@ +/* + * Copyright 2020 Huawei Technologies Co., Ltd. + * + * Licensed 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 com.eliot.eliotbe.eliotk8sclient.deploy.kubernetes; + +import com.google.gson.Gson; +import io.kubernetes.client.ApiException; +import io.kubernetes.client.apis.CoreV1Api; +import io.kubernetes.client.models.V1Pod; +import io.kubernetes.client.models.V1Service; +import io.kubernetes.client.util.Yaml; +import com.eliot.eliotbe.eliotk8sclient.common.AppConstants; +import com.eliot.eliotbe.eliotk8sclient.AppException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +class PodServiceDeploy implements IDeploy { + private static final Logger logger = LoggerFactory.getLogger(com.eliot.eliotbe.eliotk8sclient.deploy.kubernetes.PodServiceDeploy.class); + + private static final Gson gson = new Gson(); + /** + * KubernetesDeployment constructor. + */ + public PodServiceDeploy() { + + } + + /** + * create namespace pod. + * @param dstYamlFilePath dstYamlFilePath + * @return + */ + @Override + public String deploy(String dstYamlFilePath) { + String nameSpace = ""; + logger.info("-------------Kubernetes Deployment via YAML------------"); + List list; + try { + list = Yaml.loadAll(new File(dstYamlFilePath)); + } catch (IOException e) { + logger.error("load yaml file fail : {}",e.getMessage()); + return AppConstants.EMPTY_STRING; + } + + for (Object object : list) { + String type = object.getClass().getSimpleName(); + switch (type) { + case "V1Pod": + nameSpace = handlePodCreateRequest(object); + break; + case "V1Service": + nameSpace = handleServiceCreateRequest(object); + break; + default: + break; + } + } + logger.info("response with both pod and service: {}",nameSpace); + return nameSpace; + } + + private String handleServiceCreateRequest(Object object) { + logger.info("SERVICE create request"); + CoreV1Api v1service = new CoreV1Api(); + V1Service serviceResult; + try { + serviceResult = v1service + .createNamespacedService("default", (V1Service) object, null, null, null); + logger.info("After createNamespacedService call with result: {}", serviceResult); + StringBuilder nameSpace = new StringBuilder("").append(Objects.requireNonNull(serviceResult.getMetadata()) + .getName()).append(AppConstants.NAMEANDNAMESPACE).append(serviceResult.getMetadata() + .getNamespace()).append(AppConstants.POD_TYPE).append("Service").append(AppConstants.K8SPOD); + return nameSpace.toString(); + } catch (ApiException e) { + throw new AppException(e.getMessage()); + } + } + + private String handlePodCreateRequest(Object object) { + logger.info("POD create request"); + CoreV1Api v1pod = new CoreV1Api(); + V1Pod createResult; + try { + createResult = v1pod.createNamespacedPod("default", (V1Pod) object, null, null, null); + logger.info("After createNamespacedPod call with result: {}", createResult); + StringBuilder nameSpace = new StringBuilder("").append(Objects.requireNonNull(createResult.getMetadata()) + .getName()).append(AppConstants.NAMEANDNAMESPACE).append(createResult.getMetadata().getNamespace()) + .append(AppConstants.POD_TYPE).append("Pod").append(AppConstants.K8SPOD); + return nameSpace.toString(); + } catch (ApiException e) { + throw new AppException(e.getMessage()); + } + } +} diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/service/AppService.java b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/service/AppService.java new file mode 100644 index 0000000..c0f6b00 --- /dev/null +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/service/AppService.java @@ -0,0 +1,129 @@ +/* + * Copyright 2020 Huawei Technologies Co., Ltd. + * + * Licensed 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 com.eliot.eliotbe.eliotk8sclient.service; + +import com.eliot.eliotbe.eliotk8sclient.deploy.GenericDeployFactory; +import com.google.gson.Gson; +import io.kubernetes.client.ApiException; +import io.kubernetes.client.apis.CoreV1Api; +import io.kubernetes.client.models.V1PodList; +import org.apache.tomcat.util.http.fileupload.FileUtils; +import org.apache.tomcat.util.http.fileupload.IOUtils; +import com.eliot.eliotbe.eliotk8sclient.AppException; +import com.eliot.eliotbe.eliotk8sclient.common.AppConstants; +import com.eliot.eliotbe.eliotk8sclient.deploy.GenericDeploy; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; +import org.apache.http.ParseException; + +import java.io.File; +//import org.apache.http.ParseException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.security.SecureRandom; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@Component +public class AppService { + private static final Logger logger = LoggerFactory.getLogger(AppService.class); + + private static final Gson gson = new Gson(); + +/* @Value("${DEPLOY_TYPE}") + private String deploymentType;*/ + + //@Value("${PACKAGE_BASE_PATH}") + private String packageBasePath = "/home/root1/eliot/deploy"; + + public String instantiateApplication(String deploymentPathWithFile) { +/* AppLcmUtils.setDefaultApiClient(k8sConfig); + String packageDir = getPackageDirName(AppConstants.MAX_PACKAGE_DIR_SIZE); + String packagePath = extractZipFile(file,packageDir); + if (packagePath.isEmpty()) { + logger.error("extract zip file fail"); + return AppConstants.EMPTY_STRING; + }*/ + try { + logger.info("Deployment Begin..."); + GenericDeploy deploy = GenericDeployFactory.create("kubernetes"); + return deploy.deploy(deploymentPathWithFile); + } catch (AppException | ParseException e) { + throw new AppException(e.getMessage()); + } +/* finally { + if (!packagePath.isEmpty()) { + File appPackage = new File(packagePath); + if (appPackage.exists()) { + try { + FileUtils.cleanDirectory(appPackage); + FileUtils.deleteDirectory(appPackage); + } catch (IOException e) { + logger.error("failed to delete application package : {}",e.getMessage()); + } + } + } + }*/ + } + /** + * Returns storage base path. + * + * @return base path + */ + public String getPackageBasePath() { + File file = new File(packageBasePath); + if (file.exists()) { + logger.info("Inside File Exists"); + return packageBasePath + '/'; + } + boolean isMk = file.mkdir(); + if (!isMk) { + logger.info("Directory Create"); + return AppConstants.EMPTY_STRING; + } + return packageBasePath + '/'; + } + + + /** + * Generate application package directory name. + * + * @param size directory name size + * @return directory name + */ + private String getPackageDirName(int size) { + final String allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + SecureRandom sr = new SecureRandom(); + StringBuilder sb = new StringBuilder(size); + for (int i = 0; i < size; i++) { + sb.append(allowed.charAt(sr.nextInt(allowed.length()))); + } + return sb.toString(); + } + + + +} diff --git a/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/service/AppServiceHandler.java b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/service/AppServiceHandler.java new file mode 100644 index 0000000..406f064 --- /dev/null +++ b/blueprints/common/eliot-ui/be/src/eliotk8sclient/src/main/java/com/eliot/eliotbe/eliotk8sclient/service/AppServiceHandler.java @@ -0,0 +1,157 @@ +/* + * Copyright 2020 Huawei Technologies Co., Ltd. + * + * Licensed 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 com.eliot.eliotbe.eliotk8sclient.service; + + +import org.apache.tomcat.util.http.fileupload.FileUploadException; +import com.eliot.eliotbe.eliotk8sclient.AppException; +import com.eliot.eliotbe.eliotk8sclient.common.AppConstants; +import org.apache.tomcat.util.http.fileupload.FileUtils; +import org.joda.time.LocalDate; +import org.joda.time.LocalDateTime; +import org.joda.time.LocalTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.lang.System; +import java.io.File; +@Component +public class AppServiceHandler { + + public static final Logger logger = LoggerFactory.getLogger(AppServiceHandler.class); + + @Autowired + private AppService appService; + + /** + * Upload deployment file. + * @param file file + * @return + */ + public ResponseEntity> uploadDeployment(MultipartFile file) + throws IOException { + try { + validateFile(file, AppConstants.MAX_CONFIG_SIZE, ""); + } catch (FileUploadException | NullPointerException e) { + Map response = new HashMap<>(); + response.put("error",e.getMessage()); + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } + + String destination = appService.getPackageBasePath() + LocalDate.now().toString() + + LocalTime.now().getMillisOfSecond() +"/"; + File destinationfile = new File(destination); +/* if (file.exists()) { + FileUtils.cleanDirectory(file); + FileUtils.deleteDirectory(file); + }*/ + boolean isMk = destinationfile.mkdir(); + if (!isMk) { + logger.info("package directory creation failed"); + } + + logger.info("destination path is set"); + + String deploymentPathWithFile = null; + + deploymentPathWithFile = storeDeployFile(destination,file); + + appService.instantiateApplication(deploymentPathWithFile); + + Map response = new HashMap<>(); + response.put("Application Deployed","OK"); + return new ResponseEntity<>(response, HttpStatus.OK); + } + + private boolean checkK8sConfigFile(Path k8sConfig) { + if (!k8sConfig.toFile().isFile() || !k8sConfig.toFile().exists()) { + logger.error("Config file does not exist..."); + return false; + } + return true; + } + + private String storeDeployFile(String basePath, MultipartFile file) throws IOException { + // Get the file and save it somewhere + byte[] bytes = file.getBytes(); + + //String packageDir = getPackageDirName(AppConstants.MAX_PACKAGE_DIR_SIZE); + Path path = Paths.get(basePath + file.getOriginalFilename()); + // Path path = Paths.get("~/"); + Files.write(path, bytes); + String deploymentFilePath; + return deploymentFilePath = basePath+ file.getOriginalFilename(); + } + + private Path loadK8sConfigFilePath(String basePath) { + return Paths.get(basePath + ""); + } + +/* private String getPackageDirName(int size) { + final String allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + SecureRandom sr = new SecureRandom(); + StringBuilder sb = new StringBuilder(size); + for (int i = 0; i < size; i++) { + sb.append(allowed.charAt(sr.nextInt(allowed.length()))); + } + return sb.toString(); + }*/ + + /** + * Validate MultipartFile. + * + * @param file file + * @param fileSize file size for validation + * @param extension file extension + * @throws FileUploadException on exception throws + */ + public void validateFile(MultipartFile file, long fileSize, String extension) throws FileUploadException { + if (file == null) { + throw new FileUploadException("file is null"); + } + + if (file.isEmpty()) { + throw new FileUploadException("file is empty"); + } else if (!extension.isEmpty() + && null != file.getOriginalFilename() && !file.getOriginalFilename().endsWith(extension)) { + throw new FileUploadException("package format not supported"); + } else if (file.getSize() > fileSize) { + throw new FileUploadException("file size not in the limit"); + } + } + private ResponseEntity> createErrorResponse(String error) { + Map response = new HashMap<>(); + response.put("error", error); + response.put("status", HttpStatus.INTERNAL_SERVER_ERROR.toString()); + return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); + } +} -- 2.16.6