From 7d9494640272f23b5358f11e6e8faebb1a57240a Mon Sep 17 00:00:00 2001 From: abhijit_onap Date: Thu, 18 Jun 2020 14:22:52 +0530 Subject: [PATCH 01/16] 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 From ed40a3697084f04c50ec4350f14775b4e1131cd9 Mon Sep 17 00:00:00 2001 From: abhijit_onap Date: Tue, 18 Aug 2020 22:39:37 +0530 Subject: [PATCH 02/16] Sphinx documentation configuration files Initial Documentation Files for ELIOT For integration with Read the Docs Modifying build issues in conf.py file Signed-off-by: abhijit_onap Change-Id: Id29469577dcf99f0eda1fc5ea52735e568b925fd --- docs/Makefile | 19 + docs/build/doctrees/environment.pickle | Bin 0 -> 11136 bytes docs/build/doctrees/index.doctree | Bin 0 -> 4827 bytes docs/build/html/.buildinfo | 4 + docs/build/html/_sources/index.rst.txt | 15 + docs/build/html/_static/ajax-loader.gif | Bin 0 -> 673 bytes docs/build/html/_static/alabaster.css | 701 ++ docs/build/html/_static/basic.css | 676 ++ docs/build/html/_static/comment-bright.png | Bin 0 -> 756 bytes docs/build/html/_static/comment-close.png | Bin 0 -> 829 bytes docs/build/html/_static/comment.png | Bin 0 -> 641 bytes docs/build/html/_static/custom.css | 1 + docs/build/html/_static/doctools.js | 315 + docs/build/html/_static/documentation_options.js | 10 + docs/build/html/_static/down-pressed.png | Bin 0 -> 222 bytes docs/build/html/_static/down.png | Bin 0 -> 202 bytes docs/build/html/_static/file.png | Bin 0 -> 286 bytes docs/build/html/_static/jquery-3.2.1.js | 10253 +++++++++++++++++++++ docs/build/html/_static/jquery.js | 4 + docs/build/html/_static/language_data.js | 297 + docs/build/html/_static/minus.png | Bin 0 -> 90 bytes docs/build/html/_static/plus.png | Bin 0 -> 90 bytes docs/build/html/_static/pygments.css | 77 + docs/build/html/_static/searchtools.js | 481 + docs/build/html/_static/underscore-1.3.1.js | 999 ++ docs/build/html/_static/underscore.js | 31 + docs/build/html/_static/up-pressed.png | Bin 0 -> 214 bytes docs/build/html/_static/up.png | Bin 0 -> 203 bytes docs/build/html/_static/websupport.js | 808 ++ docs/build/html/genindex.html | 105 + docs/build/html/index.html | 114 + docs/build/html/objects.inv | Bin 0 -> 266 bytes docs/build/html/search.html | 117 + docs/build/html/searchindex.js | 1 + docs/make.bat | 35 + docs/source/conf.py | 177 + docs/source/index.rst | 15 + 37 files changed, 15255 insertions(+) create mode 100644 docs/Makefile create mode 100644 docs/build/doctrees/environment.pickle create mode 100644 docs/build/doctrees/index.doctree create mode 100644 docs/build/html/.buildinfo create mode 100644 docs/build/html/_sources/index.rst.txt create mode 100644 docs/build/html/_static/ajax-loader.gif create mode 100644 docs/build/html/_static/alabaster.css create mode 100644 docs/build/html/_static/basic.css create mode 100644 docs/build/html/_static/comment-bright.png create mode 100644 docs/build/html/_static/comment-close.png create mode 100644 docs/build/html/_static/comment.png create mode 100644 docs/build/html/_static/custom.css create mode 100644 docs/build/html/_static/doctools.js create mode 100644 docs/build/html/_static/documentation_options.js create mode 100644 docs/build/html/_static/down-pressed.png create mode 100644 docs/build/html/_static/down.png create mode 100644 docs/build/html/_static/file.png create mode 100644 docs/build/html/_static/jquery-3.2.1.js create mode 100644 docs/build/html/_static/jquery.js create mode 100644 docs/build/html/_static/language_data.js create mode 100644 docs/build/html/_static/minus.png create mode 100644 docs/build/html/_static/plus.png create mode 100644 docs/build/html/_static/pygments.css create mode 100644 docs/build/html/_static/searchtools.js create mode 100644 docs/build/html/_static/underscore-1.3.1.js create mode 100644 docs/build/html/_static/underscore.js create mode 100644 docs/build/html/_static/up-pressed.png create mode 100644 docs/build/html/_static/up.png create mode 100644 docs/build/html/_static/websupport.js create mode 100644 docs/build/html/genindex.html create mode 100644 docs/build/html/index.html create mode 100644 docs/build/html/objects.inv create mode 100644 docs/build/html/search.html create mode 100644 docs/build/html/searchindex.js create mode 100644 docs/make.bat create mode 100644 docs/source/conf.py create mode 100644 docs/source/index.rst diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..69fe55e --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/build/doctrees/environment.pickle b/docs/build/doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..40fda3832ebc59bfe5c197ceca6fe83091e9e97e GIT binary patch literal 11136 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 BTtEN- literal 0 HcmV?d00001 diff --git a/docs/build/doctrees/index.doctree b/docs/build/doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..94a1b229a61ec63a7fda0f00bc4b54ab17a7037f GIT binary patch literal 4827 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 literal 0 HcmV?d00001 diff --git a/docs/build/html/.buildinfo b/docs/build/html/.buildinfo new file mode 100644 index 0000000..b4ed781 --- /dev/null +++ b/docs/build/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 70f87642038055f1afc9641247ad84b8 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/build/html/_sources/index.rst.txt b/docs/build/html/_sources/index.rst.txt new file mode 100644 index 0000000..1323f4e --- /dev/null +++ b/docs/build/html/_sources/index.rst.txt @@ -0,0 +1,15 @@ +Welcome to ELIOT-Edge Lightweight IoT Docs +====================================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/build/html/_static/ajax-loader.gif b/docs/build/html/_static/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..61faf8cab23993bd3e1560bff0668bd628642330 GIT binary patch literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nno%(3)e{?)x>&1u}A`t?OF7Z|1gRivOgXi&7IyQd1Pl zGfOfQ60;I3a`F>X^fL3(@);C=vM_KlFfb_o=k{|A33hf2a5d61U}gjg=>Rd%XaNQW zW@Cw{|b%Y*pl8F?4B9 zlo4Fz*0kZGJabY|>}Okf0}CCg{u4`zEPY^pV?j2@h+|igy0+Kz6p;@SpM4s6)XEMg z#3Y4GX>Hjlml5ftdH$4x0JGdn8~MX(U~_^d!Hi)=HU{V%g+mi8#UGbE-*ao8f#h+S z2a0-5+vc7MU$e-NhmBjLIC1v|)9+Im8x1yacJ7{^tLX(ZhYi^rpmXm0`@ku9b53aN zEXH@Y3JaztblgpxbJt{AtE1ad1Ca>{v$rwwvK(>{m~Gf_=-Ro7Fk{#;i~+{{>QtvI yb2P8Zac~?~=sRA>$6{!(^3;ZP0TPFR(G_-UDU(8Jl0?(IXu$~#4A!880|o%~Al1tN literal 0 HcmV?d00001 diff --git a/docs/build/html/_static/alabaster.css b/docs/build/html/_static/alabaster.css new file mode 100644 index 0000000..0eddaeb --- /dev/null +++ b/docs/build/html/_static/alabaster.css @@ -0,0 +1,701 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Georgia, serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Georgia, serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: Georgia, serif; + font-size: 1em; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Georgia, serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: Georgia, serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide fugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} \ No newline at end of file diff --git a/docs/build/html/_static/basic.css b/docs/build/html/_static/basic.css new file mode 100644 index 0000000..0807176 --- /dev/null +++ b/docs/build/html/_static/basic.css @@ -0,0 +1,676 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist td { + vertical-align: top; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/build/html/_static/comment-bright.png b/docs/build/html/_static/comment-bright.png new file mode 100644 index 0000000000000000000000000000000000000000..15e27edb12ac25701ac0ac21b97b52bb4e45415e GIT binary patch literal 756 zcmVgfIX78 z$8Pzv({A~p%??+>KickCb#0FM1rYN=mBmQ&Nwp<#JXUhU;{|)}%&s>suq6lXw*~s{ zvHx}3C%<;wE5CH!BR{p5@ml9ws}y)=QN-kL2?#`S5d*6j zk`h<}j1>tD$b?4D^N9w}-k)bxXxFg>+#kme^xx#qg6FI-%iv2U{0h(Y)cs%5a|m%Pn_K3X_bDJ>EH#(Fb73Z zfUt2Q3B>N+ot3qb*DqbTZpFIn4a!#_R-}{?-~Hs=xSS6p&$sZ-k1zDdtqU`Y@`#qL z&zv-~)Q#JCU(dI)Hf;$CEnK=6CK50}q7~wdbI->?E07bJ0R;!GSQTs5Am`#;*WHjvHRvY?&$Lm-vq1a_BzocI^ULXV!lbMd%|^B#fY;XX)n<&R^L z=84u1e_3ziq;Hz-*k5~zwY3*oDKt0;bM@M@@89;@m*4RFgvvM_4;5LB!@OB@^WbVT zjl{t;a8_>od-~P4 m{5|DvB&z#xT;*OnJqG}gk~_7HcNkCr0000W zanA~u9RIXo;n7c96&U)YLgs-FGlx~*_c{Jgvesu1E5(8YEf&5wF=YFPcRe@1=MJmi zag(L*xc2r0(slpcN!vC5CUju;vHJkHc*&70_n2OZsK%O~A=!+YIw z7zLLl7~Z+~RgWOQ=MI6$#0pvpu$Q43 zP@36QAmu6!_9NPM?o<1_!+stoVRRZbW9#SPe!n;#A_6m8f}|xN1;H{`0RoXQ2LM47 zt(g;iZ6|pCb@h2xk&(}S3=EVBUO0e90m2Lp5CB<(SPIaB;n4))3JB87Or#XPOPcum z?<^(g+m9}VNn4Y&B`g8h{t_$+RB1%HKRY6fjtd-<7&EsU;vs0GM(Lmbhi%Gwcfs0FTF}T zL{_M6Go&E0Eg8FuB*(Yn+Z*RVTBE@10eIOb3El^MhO`GabDll(V0&FlJi2k^;q8af zkENdk2}x2)_KVp`5OAwXZM;dG0?M-S)xE1IKDi6BY@5%Or?#aZ9$gcX)dPZ&wA1a< z$rFXHPn|TBf`e?>Are8sKtKrKcjF$i^lp!zkL?C|y^vlHr1HXeVJd;1I~g&Ob-q)& z(fn7s-KI}G{wnKzg_U5G(V%bX6uk zIa+<@>rdmZYd!9Y=C0cuchrbIjuRB_Wq{-RXlic?flu1*_ux}x%(HDH&nT`k^xCeC ziHi1!ChH*sQ6|UqJpTTzX$aw8e(UfcS^f;6yBWd+(1-70zU(rtxtqR%j z-lsH|CKQJXqD{+F7V0OTv8@{~(wp(`oIP^ZykMWgR>&|RsklFMCnOo&Bd{le} zV5F6424Qzl;o2G%oVvmHgRDP9!=rK8fy^!yV8y*4p=??uIRrrr0?>O!(z*g5AvL2!4z0{sq%vhG*Po}`a<6%kTK5TNhtC8}rXNu&h^QH4A&Sk~Autm*s~45(H7+0bi^MraaRVzr05hQ3iK?j` zR#U@^i0WhkIHTg29u~|ypU?sXCQEQgXfObPW;+0YAF;|5XyaMAEM0sQ@4-xCZe=0e z7r$ofiAxn@O5#RodD8rh5D@nKQ;?lcf@tg4o+Wp44aMl~c47azN_(im0N)7OqdPBC zGw;353_o$DqGRDhuhU$Eaj!@m000000NkvXXu0mjfjZ7Z_ literal 0 HcmV?d00001 diff --git a/docs/build/html/_static/custom.css b/docs/build/html/_static/custom.css new file mode 100644 index 0000000..2a924f1 --- /dev/null +++ b/docs/build/html/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/docs/build/html/_static/doctools.js b/docs/build/html/_static/doctools.js new file mode 100644 index 0000000..344db17 --- /dev/null +++ b/docs/build/html/_static/doctools.js @@ -0,0 +1,315 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/docs/build/html/_static/documentation_options.js b/docs/build/html/_static/documentation_options.js new file mode 100644 index 0000000..366169e --- /dev/null +++ b/docs/build/html/_static/documentation_options.js @@ -0,0 +1,10 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '0.0.3', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, +}; \ No newline at end of file diff --git a/docs/build/html/_static/down-pressed.png b/docs/build/html/_static/down-pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..5756c8cad8854722893dc70b9eb4bb0400343a39 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`OFdm2Ln;`PZ^+1>KjR?B@S0W7 z%OS_REiHONoJ6{+Ks@6k3590|7k9F+ddB6!zw3#&!aw#S`x}3V3&=A(a#84O-&F7T z^k3tZB;&iR9siw0|F|E|DAL<8r-F4!1H-;1{e*~yAKZN5f0|Ei6yUmR#Is)EM(Po_ zi`qJR6|P<~+)N+kSDgL7AjdIC_!O7Q?eGb+L+qOjm{~LLinM4NHn7U%HcK%uoMYO5 VJ~8zD2B3o(JYD@<);T3K0RV0%P>BEl literal 0 HcmV?d00001 diff --git a/docs/build/html/_static/down.png b/docs/build/html/_static/down.png new file mode 100644 index 0000000000000000000000000000000000000000..1b3bdad2ceffae91cee61b32f3295f9bbe646e48 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6CVIL!hEy=F?b*7pIY7kW{q%Rg zx!yQ<9v8bmJwa`TQk7YSw}WVQ()mRdQ;TC;* literal 0 HcmV?d00001 diff --git a/docs/build/html/_static/file.png b/docs/build/html/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/docs/build/html/_static/jquery-3.2.1.js b/docs/build/html/_static/jquery-3.2.1.js new file mode 100644 index 0000000..d2d8ca4 --- /dev/null +++ b/docs/build/html/_static/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Index

+ +
+ +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/build/html/index.html b/docs/build/html/index.html new file mode 100644 index 0000000..0cbf959 --- /dev/null +++ b/docs/build/html/index.html @@ -0,0 +1,114 @@ + + + + + + + + Welcome to ELIOT-Edge Lightweight IoT Docs — ELIOT-Edge Lightweight IoT 0.0.3 documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Welcome to ELIOT-Edge Lightweight IoT Docs¶

+
+
+
+
+

Indices and tables¶

+ +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/build/html/objects.inv b/docs/build/html/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..c530e02960ecc17a1cbcf82da8a27e2b30822c04 GIT binary patch literal 266 zcmY#Z2rkIT%&Sny%qvUHE6FdaR47X=D$dN$Q!wIERtPA{&q_@$u~KmL@$?VTbxlc6 zRq)A7&nPKR1(6D#`5{16VGtcw3P5&9Myf(lYHng?UP@|_LVlV;Nk(R|LRw}{ssfNs z&d)6o*Pej`golUykHvQ(cbkc zb;^@x8Wl}5VmMMYf1Xru_0T#LTs-M>aj>Y@C()Q%o4?K_vB8&uMQe;M8+)A!c3jew zUf0p&T~}lno>#{u#?7r&nkXb7T>ClLt2k(3nD}xvG1c@1uNpcWMcAF6FbiD{-pL@T H@9`1<*BxY# literal 0 HcmV?d00001 diff --git a/docs/build/html/search.html b/docs/build/html/search.html new file mode 100644 index 0000000..98c5102 --- /dev/null +++ b/docs/build/html/search.html @@ -0,0 +1,117 @@ + + + + + + + + Search — ELIOT-Edge Lightweight IoT 0.0.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Search

+
+ +

+ Please activate JavaScript to enable the search + functionality. +

+
+

+ From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

+
+ + + +
+ +
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/build/html/searchindex.js b/docs/build/html/searchindex.js new file mode 100644 index 0000000..2011831 --- /dev/null +++ b/docs/build/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["index"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:54},filenames:["index.rst"],objects:{},objnames:{},objtypes:{},terms:{index:0,modul:0,page:0,search:0},titles:["Welcome to ELIOT-Edge Lightweight IoT Docs"],titleterms:{doc:0,document:[],edg:0,eliot:0,indic:0,iot:0,lightweight:0,tabl:0,welcom:0}}) \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..543c6b1 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..c1713e1 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = u'ELIOT-Edge Lightweight IoT' +copyright = u'2020, ELIOT Authors' +author = u'ELIOT Authors' + +# The short X.Y version +version = u'' +# The full version, including alpha/beta/rc tags +release = u'0.0.3' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'ELIOT-EdgeLightweightIoTdoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'ELIOT-EdgeLightweightIoT.tex', u'ELIOT-Edge Lightweight IoT', + u'ELIOT Authors', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'eliot-edgelightweightiot', u'ELIOT-Edge Lightweight IoT', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'ELIOT-EdgeLightweightIoT', u'ELIOT-Edge Lightweight IoT', + author, 'ELIOT-EdgeLightweightIoT', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + + +# -- Extension configuration ------------------------------------------------- diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..1323f4e --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,15 @@ +Welcome to ELIOT-Edge Lightweight IoT Docs +====================================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` -- 2.16.6 From 4ddf018a0a09afca2b22593f2153ddf6cc2d32c7 Mon Sep 17 00:00:00 2001 From: abhijit_onap Date: Wed, 19 Aug 2020 15:14:58 +0530 Subject: [PATCH 03/16] Modified contents of index.rst file Signed-off-by: abhijit_onap Change-Id: I86672e4c2e0c96d44d4e7ee01d92ee85d4284e11 --- docs/source/index.rst | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 1323f4e..1aa2e39 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,15 +1,24 @@ -Welcome to ELIOT-Edge Lightweight IoT Docs -====================================================== +Welcome to ELIOT Documentation! +=============================== .. toctree:: :maxdepth: 2 :caption: Contents: +ELIOT is "Enterprise Edge Lightweight and IOT" project under Akraino +approved blueprint family and part of Akraino Edge Stack, which intends +to develop a fully integrated edge network infrastructure and running +edge computing applications on lightweight Edge Nodes. +ELIOT targets on making the edge node a lightweight software stack which +can be deployed on edge nodes which have limited hardware capacity by +leveraging lightweight OS, a container running environment and container +orchestration applications. -Indices and tables -================== -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +.. toctree:: + ELIOT Home + +.. toctree:: + ELIOT IOT Gateway Blueprint + ELIOT SD-WAN/WAN Edge/ uCPE Blueprint -- 2.16.6 From 9a9ff3d3bfc8cf2f886cad61841f436bd7039ec4 Mon Sep 17 00:00:00 2001 From: abhijit_onap Date: Thu, 20 Aug 2020 14:58:54 +0530 Subject: [PATCH 04/16] Modified conf.py with html theme. Signed-off-by: abhijit_onap Change-Id: I28c4e03de9fe94c17d463af4403689554891eb97 --- docs/source/conf.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index c1713e1..ffbf954 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -64,10 +64,10 @@ language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] +exclude_patterns = [u'_build', 'proposals', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = None +pygments_style = 'sphinx' # -- Options for HTML output ------------------------------------------------- @@ -75,13 +75,15 @@ pygments_style = None # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # -# html_theme_options = {} +html_theme_options = { + 'prev_next_buttons_location': 'both' +} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, -- 2.16.6 From a66889c1b0f2d52101b5960e65be9e888f499b22 Mon Sep 17 00:00:00 2001 From: Srinivasan Selvam Date: Mon, 5 Oct 2020 17:49:42 +0530 Subject: [PATCH 05/16] Hawkbit installation through docker mode Signed-off-by: Srinivasan Selvam Change-Id: Ia33d12674d84995768accbfc79915c52a693ef8d --- blueprints/iotgateway/scripts/hawkbit.sh | 15 +++++++++++++++ blueprints/iotgateway/scripts/setup.sh | 5 +++++ 2 files changed, 20 insertions(+) create mode 100644 blueprints/iotgateway/scripts/hawkbit.sh diff --git a/blueprints/iotgateway/scripts/hawkbit.sh b/blueprints/iotgateway/scripts/hawkbit.sh new file mode 100644 index 0000000..6679e38 --- /dev/null +++ b/blueprints/iotgateway/scripts/hawkbit.sh @@ -0,0 +1,15 @@ +#!/bin/bash -ex +############################################################################## +# Copyright (c) 2019 Huawei Tech and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +# Install hawkbit through docker container + +sudo docker run -p 8080:8080 hawkbit/hawkbit-update-server:latest + +echo "Hawkbit installation successfull on IOTGateway..................." diff --git a/blueprints/iotgateway/scripts/setup.sh b/blueprints/iotgateway/scripts/setup.sh index 4e06b3a..41f845a 100755 --- a/blueprints/iotgateway/scripts/setup.sh +++ b/blueprints/iotgateway/scripts/setup.sh @@ -206,6 +206,11 @@ install_edgex sleep 20 verify_edgex + +# Installing hawkbit through docker container +chmod +x hawkbit.sh +nohup ./hawkbit.sh + # Installing OPC-UA on IOT Gateway Node cd ${setupPath} -- 2.16.6 From f037da317ccc4857aeef7800c84616d2f6f43067 Mon Sep 17 00:00:00 2001 From: Srinivasan Date: Tue, 3 Nov 2020 12:01:11 +0530 Subject: [PATCH 06/16] K8s version update 1.17.2 Signed-off-by: Srinivasan Change-Id: Ib97dc06de5e3768f1d17a5ac87ae6f47a2037e1d --- blueprints/iotgateway/scripts/k8smaster.sh | 2 +- blueprints/iotgateway/scripts/k8smaster_centos.sh | 2 +- blueprints/iotgateway/scripts/k8sworker.sh | 2 +- blueprints/uCPE/scripts/common_centos.sh | 2 +- blueprints/uCPE/scripts/k8smaster.sh | 2 +- blueprints/uCPE/scripts/k8smaster_centos.sh | 2 +- blueprints/uCPE/scripts/k8sworker.sh | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/blueprints/iotgateway/scripts/k8smaster.sh b/blueprints/iotgateway/scripts/k8smaster.sh index d4ca7b5..00baadf 100644 --- a/blueprints/iotgateway/scripts/k8smaster.sh +++ b/blueprints/iotgateway/scripts/k8smaster.sh @@ -8,7 +8,7 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -KUBE_VERSION=1.16.0-00 +KUBE_VERSION=1.17.2-00 POD_NETWORK_CIDR=192.168.0.0/16 K8S_CNI_VERSION=0.7.5-00 diff --git a/blueprints/iotgateway/scripts/k8smaster_centos.sh b/blueprints/iotgateway/scripts/k8smaster_centos.sh index 69c3ef9..ece9982 100755 --- a/blueprints/iotgateway/scripts/k8smaster_centos.sh +++ b/blueprints/iotgateway/scripts/k8smaster_centos.sh @@ -11,7 +11,7 @@ # constants POD_NETWORK_CIDR=192.168.0.0/16 -KUBE_VERSION=1.16.0-0 +KUBE_VERSION=1.17.2-0 KUBERNETES_CNI=0.7.5-0 # start diff --git a/blueprints/iotgateway/scripts/k8sworker.sh b/blueprints/iotgateway/scripts/k8sworker.sh index e587f7f..f3af840 100644 --- a/blueprints/iotgateway/scripts/k8sworker.sh +++ b/blueprints/iotgateway/scripts/k8sworker.sh @@ -8,7 +8,7 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -KUBE_VERSION=1.16.0-00 +KUBE_VERSION=1.17.2-00 K8S_CNI_VERSION=0.7.5-00 # Install Kubernetes with Kubeadm diff --git a/blueprints/uCPE/scripts/common_centos.sh b/blueprints/uCPE/scripts/common_centos.sh index 100525f..7fff044 100755 --- a/blueprints/uCPE/scripts/common_centos.sh +++ b/blueprints/uCPE/scripts/common_centos.sh @@ -12,7 +12,7 @@ # constants DOCKER_VERSION=18.09.6 -KUBE_VERSION=1.16.0-0 +KUBE_VERSION=1.17.2-0 MACHINE=$(uname -m) # start diff --git a/blueprints/uCPE/scripts/k8smaster.sh b/blueprints/uCPE/scripts/k8smaster.sh index d4ca7b5..00baadf 100644 --- a/blueprints/uCPE/scripts/k8smaster.sh +++ b/blueprints/uCPE/scripts/k8smaster.sh @@ -8,7 +8,7 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -KUBE_VERSION=1.16.0-00 +KUBE_VERSION=1.17.2-00 POD_NETWORK_CIDR=192.168.0.0/16 K8S_CNI_VERSION=0.7.5-00 diff --git a/blueprints/uCPE/scripts/k8smaster_centos.sh b/blueprints/uCPE/scripts/k8smaster_centos.sh index 69c3ef9..ece9982 100755 --- a/blueprints/uCPE/scripts/k8smaster_centos.sh +++ b/blueprints/uCPE/scripts/k8smaster_centos.sh @@ -11,7 +11,7 @@ # constants POD_NETWORK_CIDR=192.168.0.0/16 -KUBE_VERSION=1.16.0-0 +KUBE_VERSION=1.17.2-0 KUBERNETES_CNI=0.7.5-0 # start diff --git a/blueprints/uCPE/scripts/k8sworker.sh b/blueprints/uCPE/scripts/k8sworker.sh index e587f7f..f3af840 100644 --- a/blueprints/uCPE/scripts/k8sworker.sh +++ b/blueprints/uCPE/scripts/k8sworker.sh @@ -8,7 +8,7 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -KUBE_VERSION=1.16.0-00 +KUBE_VERSION=1.17.2-00 K8S_CNI_VERSION=0.7.5-00 # Install Kubernetes with Kubeadm -- 2.16.6 From 98019264e44c1fb840c87ba81bc14f2df104f902 Mon Sep 17 00:00:00 2001 From: arvindpatel Date: Fri, 27 Nov 2020 19:49:12 +0530 Subject: [PATCH 07/16] Ansible playbook added Signed-off-by: arvindpatel Change-Id: I339f8b8b17b9fae0ba898bc0b43764f61cb0e368 --- blueprints/iotgateway/playbooks/config.yml | 94 + .../iotgateway/playbooks/eliot-all-uninstall.yml | 125 + .../iotgateway/playbooks/eliot-inventory.ini | 57 + blueprints/iotgateway/playbooks/eloit-all.yml | 131 + .../playbooks/roles/cadvisor/files/dep.yaml | 91 + .../playbooks/roles/cadvisor/tasks/install.yml | 24 + .../playbooks/roles/cadvisor/tasks/main.yml | 23 + .../playbooks/roles/cadvisor/tasks/uninstall.yml | 26 + .../playbooks/roles/certmanager/tasks/install.yml | 20 + .../playbooks/roles/certmanager/tasks/main.yml | 25 + .../roles/certmanager/tasks/uninstall.yml | 32 + .../playbooks/roles/docker/tasks/install.yml | 100 + .../playbooks/roles/docker/tasks/main.yml | 23 + .../playbooks/roles/docker/tasks/uninstall.yml | 67 + .../playbooks/roles/eg_appstore/tasks/install.yml | 26 + .../playbooks/roles/eg_appstore/tasks/main.yml | 26 + .../roles/eg_appstore/tasks/uninstall.yml | 22 + .../playbooks/roles/eg_certs/tasks/install.yml | 37 + .../playbooks/roles/eg_certs/tasks/main.yml | 25 + .../playbooks/roles/eg_certs/tasks/uninstall.yml | 24 + .../playbooks/roles/eg_developer/tasks/install.yml | 26 + .../playbooks/roles/eg_developer/tasks/main.yml | 25 + .../roles/eg_developer/tasks/uninstall.yml | 22 + .../helm/helm-charts/edgegallery/appstore-0.9.tgz | Bin 0 -> 7213 bytes .../helm/helm-charts/edgegallery/developer-0.9.tgz | Bin 0 -> 9643 bytes .../helm/helm-charts/edgegallery/mecm-fe-0.9.tgz | Bin 0 -> 5905 bytes .../helm/helm-charts/edgegallery/mecm-meo-0.9.tgz | Bin 0 -> 8468 bytes .../helm/helm-charts/edgegallery/mecm-mepm-0.9.tgz | Bin 0 -> 8135 bytes .../helm/helm-charts/edgegallery/mep-0.9.tgz | Bin 0 -> 10948 bytes .../helm-charts/edgegallery/servicecenter-0.9.tgz | Bin 0 -> 5615 bytes .../helm/helm-charts/edgegallery/usermgmt-0.9.tgz | Bin 0 -> 7743 bytes .../helm/helm-charts/stable/grafana-5.5.5.tgz | Bin 0 -> 21051 bytes .../stable/nfs-client-provisioner-1.2.8.tgz | Bin 0 -> 5049 bytes .../helm-charts/stable/nginx-ingress-1.41.2.tgz | Bin 0 -> 24348 bytes .../helm/helm-charts/stable/prometheus-9.3.1.tgz | Bin 0 -> 24108 bytes .../playbooks/roles/eg_helm-repo/tasks/install.yml | 60 + .../playbooks/roles/eg_helm-repo/tasks/main.yml | 25 + .../roles/eg_helm-repo/tasks/uninstall.yml | 31 + .../playbooks/roles/eg_mecm-fe/tasks/install.yml | 26 + .../playbooks/roles/eg_mecm-fe/tasks/main.yml | 25 + .../playbooks/roles/eg_mecm-fe/tasks/uninstall.yml | 22 + .../files/deploy/conf/keys/postgres_init.sql | 29 + .../playbooks/roles/eg_mecm-meo/tasks/install.yml | 73 + .../playbooks/roles/eg_mecm-meo/tasks/main.yml | 26 + .../roles/eg_mecm-meo/tasks/uninstall.yml | 27 + .../files/deploy/conf/keys/postgres_init.sql | 20 + .../conf/manifest/mepm/mepm-service-account.yaml | 30 + .../playbooks/roles/eg_mecm-mepm/tasks/install.yml | 73 + .../playbooks/roles/eg_mecm-mepm/tasks/main.yml | 26 + .../roles/eg_mecm-mepm/tasks/uninstall.yml | 35 + .../files/deploy/conf/edge/metallb/config-map.yaml | 27 + .../files/deploy/conf/edge/metallb/metallb.yaml | 406 +++ .../files/deploy/conf/edge/metallb/namespace.yaml | 21 + .../edge/network-isolation/eg-sp-controller.yaml | 28 + .../conf/edge/network-isolation/eg-sp-rbac.yaml | 49 + .../deploy/conf/edge/network-isolation/multus.yaml | 358 +++ .../playbooks/roles/eg_mep/tasks/install.yml | 273 ++ .../playbooks/roles/eg_mep/tasks/main.yml | 26 + .../playbooks/roles/eg_mep/tasks/uninstall.yml | 107 + .../eg_prerequisite/files/deploy/eg_daemon.sh | 25 + .../roles/eg_prerequisite/tasks/install.yml | 55 + .../playbooks/roles/eg_prerequisite/tasks/main.yml | 22 + .../roles/eg_registry/files/deploy/load-images.sh | 39 + .../playbooks/roles/eg_registry/tasks/install.yml | 106 + .../playbooks/roles/eg_registry/tasks/main.yml | 25 + .../roles/eg_registry/tasks/uninstall.yml | 32 + .../playbooks/roles/eg_secret/tasks/install.yml | 28 + .../playbooks/roles/eg_secret/tasks/main.yml | 26 + .../playbooks/roles/eg_secret/tasks/uninstall.yml | 22 + .../roles/eg_set-helm-repo/tasks/install.yml | 30 + .../roles/eg_set-helm-repo/tasks/main.yml | 22 + .../playbooks/roles/eg_user-mgmt/tasks/install.yml | 42 + .../playbooks/roles/eg_user-mgmt/tasks/main.yml | 26 + .../roles/eg_user-mgmt/tasks/uninstall.yml | 27 + .../playbooks/roles/grafana/files/values.yaml | 2757 ++++++++++++++++++++ .../playbooks/roles/grafana/tasks/install.yml | 47 + .../playbooks/roles/grafana/tasks/main.yml | 21 + .../playbooks/roles/grafana/tasks/uninstall.yml | 34 + .../playbooks/roles/helm/tasks/install.yml | 68 + .../iotgateway/playbooks/roles/helm/tasks/main.yml | 23 + .../playbooks/roles/helm/tasks/uninstall.yml | 54 + .../playbooks/roles/k3s/tasks/install.yml | 74 + .../iotgateway/playbooks/roles/k3s/tasks/main.yml | 22 + .../playbooks/roles/k3s/tasks/uninstall.yml | 39 + .../playbooks/roles/k8s/tasks/install.yml | 38 + .../iotgateway/playbooks/roles/k8s/tasks/main.yml | 23 + .../playbooks/roles/k8s/tasks/uninstall.yml | 31 + .../playbooks/roles/kubeconfig/tasks/install.yml | 25 + .../playbooks/roles/kubeconfig/tasks/main.yml | 21 + .../roles/mepkubeconfig/tasks/install.yml | 25 + .../playbooks/roles/mepkubeconfig/tasks/main.yml | 18 + .../playbooks/roles/prometheus/files/values.yaml | 26 + .../playbooks/roles/prometheus/tasks/install.yml | 48 + .../playbooks/roles/prometheus/tasks/main.yml | 22 + .../playbooks/roles/prometheus/tasks/uninstall.yml | 34 + .../roles/rabbitmq/files/common/configmap.yaml | 20 + .../roles/rabbitmq/files/common/namespace_yaml | 5 + .../roles/rabbitmq/files/common/rbac.yaml | 29 + .../roles/rabbitmq/files/common/services.yaml | 24 + .../roles/rabbitmq/files/statefulset_arm.yaml | 78 + .../roles/rabbitmq/files/statefulset_x86.yaml | 78 + .../playbooks/roles/rabbitmq/tasks/install.yml | 64 + .../playbooks/roles/rabbitmq/tasks/main.yml | 22 + .../playbooks/roles/rabbitmq/tasks/uninstall.yml | 44 + .../roles/service_center/tasks/install.yml | 27 + .../playbooks/roles/service_center/tasks/main.yml | 26 + .../roles/service_center/tasks/uninstall.yml | 22 + .../playbooks/roles/vault/tasks/install.yml | 31 + .../playbooks/roles/vault/tasks/main.yml | 22 + 109 files changed, 7363 insertions(+) create mode 100644 blueprints/iotgateway/playbooks/config.yml create mode 100644 blueprints/iotgateway/playbooks/eliot-all-uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/eliot-inventory.ini create mode 100644 blueprints/iotgateway/playbooks/eloit-all.yml create mode 100644 blueprints/iotgateway/playbooks/roles/cadvisor/files/dep.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/cadvisor/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/cadvisor/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/cadvisor/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/certmanager/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/certmanager/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/certmanager/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/docker/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/docker/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/docker/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_certs/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_certs/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_certs/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_developer/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_developer/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_developer/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/appstore-0.9.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/developer-0.9.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/mecm-fe-0.9.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/mecm-meo-0.9.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/mecm-mepm-0.9.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/mep-0.9.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/servicecenter-0.9.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/usermgmt-0.9.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/stable/grafana-5.5.5.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/stable/nfs-client-provisioner-1.2.8.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/stable/nginx-ingress-1.41.2.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/stable/prometheus-9.3.1.tgz create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-meo/files/deploy/conf/keys/postgres_init.sql create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/files/deploy/conf/keys/postgres_init.sql create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/files/deploy/conf/manifest/mepm/mepm-service-account.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/config-map.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/metallb.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/namespace.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/eg-sp-controller.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/eg-sp-rbac.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/multus.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mep/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mep/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_mep/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_prerequisite/files/deploy/eg_daemon.sh create mode 100644 blueprints/iotgateway/playbooks/roles/eg_prerequisite/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_prerequisite/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_registry/files/deploy/load-images.sh create mode 100644 blueprints/iotgateway/playbooks/roles/eg_registry/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_registry/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_registry/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_secret/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_secret/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_secret/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_set-helm-repo/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_set-helm-repo/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/grafana/files/values.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/grafana/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/grafana/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/grafana/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/helm/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/helm/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/helm/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/k3s/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/k3s/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/k3s/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/k8s/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/k8s/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/k8s/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/kubeconfig/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/kubeconfig/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/mepkubeconfig/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/mepkubeconfig/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/prometheus/files/values.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/prometheus/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/prometheus/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/configmap.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/namespace_yaml create mode 100644 blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/rbac.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/services.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/rabbitmq/files/statefulset_arm.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/rabbitmq/files/statefulset_x86.yaml create mode 100644 blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/service_center/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/service_center/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/service_center/tasks/uninstall.yml create mode 100644 blueprints/iotgateway/playbooks/roles/vault/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/vault/tasks/main.yml diff --git a/blueprints/iotgateway/playbooks/config.yml b/blueprints/iotgateway/playbooks/config.yml new file mode 100644 index 0000000..da7eaf2 --- /dev/null +++ b/blueprints/iotgateway/playbooks/config.yml @@ -0,0 +1,94 @@ +# 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. +--- + +######### Common parameters ######### +######### Mandatory ######### +private_repo_ip: + name: + +######### Optional ######### +eg_image_tag: + name: 0.9 +# User can either give common pwd or can opt to provide individual pwds +common_pwd: + name: + +########## Edge config ############# +######### Mandatory ######### +mep_kong_pg_pwd: + name: +######### Optional ######### +edge_management_interface: + name: eth0 +edge_dataplane_interface: + name: eth1 +eg-management-address: + name: 100.1.1.2/24 +eg-dataplane-address: + name: 200.1.1.2/24 + +# All Edge related password which needs to be specified if user doesn't +# need common password for security purpose +mep_pg_admin_pwd: + name: +mep_cert_pwd: + name: +generate_cert_pass: + name: +mecm_mepm_postgresPassword: + name: +mecm_mepm_postgresLcmCntlrPassword: + name: +mecm_mepm_postgresk8sPluginPassword: + name: + +########### Master config ########### +######### Mandatory ######### +mecm_meo_edgeRepoUserName: + name: +mecm_meo_edgeRepoPassword: + name: + +######### Optional ######### +usermgmt_port: + name: 30067 +appstore_port: + name: 30091 +developer_port: + name: 30092 +mecm_port: + name: 30093 +docker_registry_port: + name: 5000 + +# All Master related password which needs to be specified if user +# doesn't need common password for security purpose +user_mgmt_encryptPassword: + name: +mecm_meo_keystorePassword: + name: +mecm_meo_truststorePassword: + name: +mecm_meo_postgresPassword: + name: +mecm_meo_postgresApmPassword: + name: +mecm_meo_postgresAppoPassword: + name: +mecm_meo_postgresInventoryPassword: + name: +# Only if env structure, ocd in arm and master and edge in x86_64 +master_edge_processor: + name: "x86_64" diff --git a/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml b/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml new file mode 100644 index 0000000..b58890e --- /dev/null +++ b/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml @@ -0,0 +1,125 @@ +# +# 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. + +--- + +############ OCD ############ + +- hosts: ocdconsolidated + become: yes + tags: + - ocdhost + - ocdconsolidated + + roles: + - eg_helm-repo + - eg_registry + - eg_certs + - helm + - k8s + +############ Master ############ + +### EdgeGallery related ### + +- hosts: egmaster + become: yes + tags: + - egmaster + - master + + roles: + - eg_mecm-meo + - eg_mecm-fe + - eg_appstore + - eg_developer + - eg_user-mgmt + - service_center + - eg_secret + +### Other 3rd party related ### + +- hosts: thirdpartymaster + become: yes + tags: + - thirdpartymaster + - master + + roles: + - grafana + +### Pre-Requisites ### + +- hosts: prerequisitemaster + become: yes + tags: + - prerequisitemaster + - master + + roles: + - kubeconfig + - helm + +############ Edge ############ + +### EdgeGallery related ### + +- hosts: egedge + become: yes + tags: + - egedge + - edge + + roles: + - eg_secret + - eg_mep + - eg_mecm-mepm + +### Other 3rd party related ### + +- hosts: thirdpartyedge + become: yes + tags: + - thirdpartyedge + - edge + + roles: + - rabbitmq + - prometheus + - kubeconfig + - mepkubeconfig + - cadvisor + +### Pre-Requisites ### + +- hosts: prerequisiteedge + become: yes + tags: + - prerequisiteedge + - edge + + roles: + - helm + +### Infrastructure ### +- hosts: edge-infra + become: yes + tags: + - edge-infra + - edge + + roles: + - k3s + - docker diff --git a/blueprints/iotgateway/playbooks/eliot-inventory.ini b/blueprints/iotgateway/playbooks/eliot-inventory.ini new file mode 100644 index 0000000..bb5c1e6 --- /dev/null +++ b/blueprints/iotgateway/playbooks/eliot-inventory.ini @@ -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. +# + +[master] +controller1 ansible_host="" ansible_user="" ansible_password="" + +[edge] +edge1 ansible_host="" ansible_user="" ansible_password="" + +[ocdhost] +ocdhost ansible_host="" ansible_user="" ansible_password="" + +### OCD childrens ### + +[ocdconsolidated:children] +ocdhost + +### Master node childrens ### + +[master-infra:children] +master + +[prerequisitemaster:children] +master + +[thirdpartymaster:children] +master + +[egmaster:children] +master + +### Edge node childrens ### + +[edge-infra:children] +edge + +[prerequisiteedge:children] +edge + +[thirdpartyedge:children] +edge + +[egedge:children] +edge diff --git a/blueprints/iotgateway/playbooks/eloit-all.yml b/blueprints/iotgateway/playbooks/eloit-all.yml new file mode 100644 index 0000000..2ea2dec --- /dev/null +++ b/blueprints/iotgateway/playbooks/eloit-all.yml @@ -0,0 +1,131 @@ +# +# 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. +# + +--- + +############ OCD ############ + +- hosts: ocdconsolidated + become: yes + tags: + - ocdhost + - ocdconsolidated + + roles: + - k8s + - helm + - eg_certs + - eg_registry + - eg_helm-repo + +############ Master ############ + +### Pre-Requisites ### + +- hosts: prerequisitemaster + become: yes + tags: + - prerequisitemaster + - master + + roles: + - eg_prerequisite + - helm + - eg_set-helm-repo + - kubeconfig + +### Other 3rd party related ### + +- hosts: thirdpartymaster + become: yes + tags: + - thirdpartymaster + - master + + roles: + - grafana + +### EdgeGallery related ### + +- hosts: egmaster + become: yes + tags: + - egmaster + - master + + roles: + - eg_secret + - service_center + - eg_user-mgmt + - eg_mecm-meo + - eg_mecm-fe + - eg_appstore + - eg_developer + + +############ Edge ############ + +### Infrastructure ### +- hosts: edge-infra + become: yes + tags: + - edge-infra + - edge + + roles: + - docker + - eg_prerequisite + - k3s + +### Pre-Requisites ### + +- hosts: prerequisiteedge + become: yes + tags: + - prerequisiteedge + - edge + + roles: + - helm + +### Other 3rd party related ### + +- hosts: thirdpartyedge + become: yes + tags: + - thirdpartyedge + - edge + + roles: + - rabbitmq + - prometheus + - kubeconfig + - mepkubeconfig + - cadvisor + +### EdgeGallery related ### + +- hosts: egedge + become: yes + tags: + - egedge + - edge + + roles: + - eg_secret + - eg_set-helm-repo + - eg_mep + - eg_mecm-mepm diff --git a/blueprints/iotgateway/playbooks/roles/cadvisor/files/dep.yaml b/blueprints/iotgateway/playbooks/roles/cadvisor/files/dep.yaml new file mode 100644 index 0000000..aaf38b4 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/cadvisor/files/dep.yaml @@ -0,0 +1,91 @@ +# 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. + + +# cadvisor pod +--- +apiVersion: v1 +kind: Pod +metadata: + name: cadvisor + namespace: default + labels: + app: cadvisor + annotations: + seccomp.security.alpha.kubernetes.io/pod: 'docker/default' +spec: + containers: + - image: unibaktr/cadvisor:v0.36.0 + imagePullPolicy: Always + name: cadvisor-pod + ports: + - containerPort: 8080 + hostPort: 8081 + protocol: TCP + resources: + requests: + memory: 200Mi + cpu: 150m + limits: + memory: 2000Mi + cpu: 300m + volumeMounts: + - mountPath: /rootfs + name: rootfs + readOnly: true + # yamllint disable-line rule:key-duplicates + volumeMounts: + - mountPath: /var/run + name: varrun + readOnly: true + # yamllint disable-line rule:key-duplicates + volumeMounts: + - mountPath: /sys + name: sys + readOnly: true + # yamllint disable-line rule:key-duplicates + volumeMounts: + - mountPath: /var/lib/docker + name: varlibdocker + readOnly: true + # yamllint disable-line rule:key-duplicates + volumeMounts: + - mountPath: /dev/disk + name: devdisk + readOnly: true + terminationGracePeriodSeconds: 30 + volumes: + - name: rootfs + hostPath: + path: / + # yamllint disable-line rule:key-duplicates + volumes: + - name: varrun + hostPath: + path: /var/run + # yamllint disable-line rule:key-duplicates + volumes: + - name: sys + hostPath: + path: /sys + # yamllint disable-line rule:key-duplicates + volumes: + - name: varlibdocker + hostPath: + path: /var/lib/docker + # yamllint disable-line rule:key-duplicates + volumes: + - name: devdisk + hostPath: + path: /dev/disk diff --git a/blueprints/iotgateway/playbooks/roles/cadvisor/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/cadvisor/tasks/install.yml new file mode 100644 index 0000000..e6ead6c --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/cadvisor/tasks/install.yml @@ -0,0 +1,24 @@ +# 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. + +--- +- name: copy deploy folder to mep node to install mepserver + copy: + src: dep.yaml + dest: /tmp/cadvisor/ + +- name: Installation of cadvisor + shell: + cmd: kubectl apply -f /tmp/cadvisor/dep.yaml + ignore_errors: 'True' diff --git a/blueprints/iotgateway/playbooks/roles/cadvisor/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/cadvisor/tasks/main.yml new file mode 100644 index 0000000..ce13bd1 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/cadvisor/tasks/main.yml @@ -0,0 +1,23 @@ +# 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. + +--- + +# tasks file for cAdvisor + +- include: "install.yml" + when: operation == 'install' + +- include: "uninstall.yml" + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/cadvisor/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/cadvisor/tasks/uninstall.yml new file mode 100644 index 0000000..93e6b7d --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/cadvisor/tasks/uninstall.yml @@ -0,0 +1,26 @@ +# 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. + +--- +- name: check if cadvisor is installed before removing + shell: + cmd: kubectl get pods | grep cadvisor + register: result + ignore_errors: 'True' + +- name: Uninstallation of cadvisor + shell: + cmd: kubectl delete -f /tmp/cadvisor/dep.yaml + when: result is succeeded + ignore_errors: 'True' diff --git a/blueprints/iotgateway/playbooks/roles/certmanager/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/certmanager/tasks/install.yml new file mode 100644 index 0000000..c70ed66 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/certmanager/tasks/install.yml @@ -0,0 +1,20 @@ +# 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. + +--- +- name: Installation of cert-manager + shell: +# yamllint disable rule:line-length + cmd: kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.15.0/cert-manager.yaml + ignore_errors: 'True' diff --git a/blueprints/iotgateway/playbooks/roles/certmanager/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/certmanager/tasks/main.yml new file mode 100644 index 0000000..7c34071 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/certmanager/tasks/main.yml @@ -0,0 +1,25 @@ +# 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. + +--- + +# tasks file for cert-manager + +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/certmanager/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/certmanager/tasks/uninstall.yml new file mode 100644 index 0000000..260e16f --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/certmanager/tasks/uninstall.yml @@ -0,0 +1,32 @@ +# 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. + +--- +- name: check whether cert-manager applied or not + shell: + cmd: kubectl get pods -n cert-manager + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: Removing cert-manager pods... + when: result.stdout != "" + +- name: Uninstallation of cert-manager + shell: +# yamllint disable rule:line-length + cmd: kubectl delete -f https://github.com/jetstack/cert-manager/releases/download/v0.15.0/cert-manager.yaml + ignore_errors: 'True' + when: result.stdout != "" diff --git a/blueprints/iotgateway/playbooks/roles/docker/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/docker/tasks/install.yml new file mode 100644 index 0000000..c72fe26 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/docker/tasks/install.yml @@ -0,0 +1,100 @@ +# 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. + +--- +- name: Check whether docker is already installed + command: which docker + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: Docker is already present + when: result.stdout != "" + +- debug: +# yamllint disable rule:line-length + msg: Ignore Uninstall Log , Docker not installed continue with Installation +# yamllint disable rule:line-length + when: result.stdout == "" + +- name: "INSTALL: Installing docker update" + command: apt-get update -y + ignore_errors: yes + failed_when: false + no_log: True + +- name: "INSTALL: Installing docker upgrade" +# yamllint disable rule:line-length + command: apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common +# yamllint disable rule:line-length + ignore_errors: yes + when: result is failed and ansible_architecture == 'aarch64' + +- name: "INSTALL: Add repository" + shell: curl -sL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - + when: result is failed and ansible_architecture == 'aarch64' + +- name: "INSTALL: CA-Certificates" +# yamllint disable rule:line-length + shell: sudo add-apt-repository "deb [arch=arm64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" +# yamllint disable rule:line-length + ignore_errors: yes + failed_when: false + no_log: True + when: result is failed and ansible_architecture == 'aarch64' + +- name: "INSTALL: Update....." + command: apt-get update -y + ignore_errors: yes + failed_when: false + no_log: True + when: result is failed and ansible_architecture == 'aarch64' + +- name: "INSTALL: Installed docker" + command: apt-get install -y docker-ce docker-ce-cli containerd.io + ignore_errors: yes + when: result is failed and ansible_architecture == 'aarch64' + +- debug: + msg: "CentOS commands start" + +- name: "INSTALL:Installing docker " + command: yum install -y yum-utils + when: ansible_facts['distribution'] == "CentOS" and result is failed + ignore_errors: yes + no_log: true + +- name: "INSTALL: Add repo" + command: yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo + when: ansible_facts['distribution'] == "CentOS" and result is failed + #ignore_error: yes + no_log: true + +- name: "INSTALL: install containerd.io" + command: yum -y install docker-ce-19.03.8 docker-ce-cli-19.03.8 containerd.io + when: ansible_facts['distribution'] == "CentOS" and result is failed + ignore_errors: yes + no_log: true + +- name: "Start Docker:" + command: systemctl start docker + when: ansible_facts['distribution'] == "CentOS" and result is failed + ignore_errors: yes + #no_log: true + +- name: "Start Docker: enable" + command: systemctl enable docker + when: ansible_facts['distribution'] == "CentOS" and result is failed + ignore_errors: yes diff --git a/blueprints/iotgateway/playbooks/roles/docker/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/docker/tasks/main.yml new file mode 100644 index 0000000..b8f4286 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/docker/tasks/main.yml @@ -0,0 +1,23 @@ +# 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. + +--- +# tasks file for docker +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/docker/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/docker/tasks/uninstall.yml new file mode 100644 index 0000000..f756489 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/docker/tasks/uninstall.yml @@ -0,0 +1,67 @@ +# 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. + +--- +- name: Check whether docker is installed before deleting + command: which docker + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: Uninstalling docker... + when: result.stdout != "" + +- debug: +# yamllint disable rule:line-length + msg: Ignore Uninstall Log , Docker not installed +# yamllint disable rule:line-length + when: result.stdout == "" + +- name: "UNINSTALL: Uninstall docker engine" + command: apt-get purge -y docker-engine + ignore_errors: yes + when: result is succeeded and ansible_architecture == 'aarch64' + +- name: "UNINSTALL: Uninstall docker" + command: apt-get purge -y docker + ignore_errors: yes + when: result is succeeded and ansible_architecture == 'aarch64' + #when: result is succeeded and ansible_architecture == 'x86_64' + +- name: "UNINSTALL: Uninstall docker.io" + command: apt-get purge -y docker.io + ignore_errors: yes + when: result is succeeded and ansible_architecture == 'aarch64' + +- name: "UNINSTALL: Uninstall docker-ce" + command: apt-get purge -y docker-ce + ignore_errors: yes + when: result is succeeded and ansible_architecture == 'aarch64' + #when: result is succeeded and ansible_architecture == 'aarch64' + +- name: "UNINSTALL: Uninstall docker" + command: apt-get purge -y docker-ce-cli + ignore_errors: yes + when: result is succeeded and ansible_architecture == 'aarch64' + #when: result is succeeded + +- debug: + msg: "CentOS commands start" + +- name: "UNINSTALL:Uninstalled docker " + shell: + cmd: yes | yum remove docker-ce docker-ce-cli containerd.io + ignore_errors: yes + no_log: true diff --git a/blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/install.yml new file mode 100644 index 0000000..2b9ad8e --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/install.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +- name: Import vars + include_vars: + file: ../../../config.yml + name: vardata + +- name: Helm install appstore + # yamllint disable rule:line-length + command: helm install appstore-edgegallery edgegallery/appstore --set global.oauth2.authServerAddress=https://{{ ansible_host }}:{{ vardata.usermgmt_port.name}} --set images.appstoreFe.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/appstore-fe --set images.appstoreBe.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/appstore-be --set images.postgres.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/postgres --set images.initservicecenter.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/curl --set images.appstoreFe.tag={{vardata.eg_image_tag.name}} --set images.appstoreBe.tag={{vardata.eg_image_tag.name}} --set images.appstoreFe.pullPolicy=IfNotPresent --set images.appstoreBe.pullPolicy=IfNotPresent --set images.postgres.pullPolicy=IfNotPresent --set images.initservicecenter.pullPolicy=IfNotPresent --set global.ssl.enabled=true --set global.ssl.secretName=edgegallery-ssl-secret diff --git a/blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/main.yml new file mode 100644 index 0000000..e8bea5a --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/main.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +# tasks file for eg_appstore +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/uninstall.yml new file mode 100644 index 0000000..f38b51d --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_appstore/tasks/uninstall.yml @@ -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. +# + +--- + +- name: Uninstall appstore + command: helm uninstall appstore-edgegallery + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/install.yml new file mode 100644 index 0000000..4aa99bf --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/install.yml @@ -0,0 +1,37 @@ +# +# 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. +# + +--- + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Remove old ssl key dir + command: rm -rf /tmp/ssl-eg-keys-certs + args: + chdir: /tmp/ + +- name: Make new ssl key dir + command: mkdir -p /tmp/ssl-eg-keys-certs + args: + chdir: /tmp/ + +- name: generate cert + # yamllint disable rule:line-length + command: docker run -e CERT_VALIDITY_IN_DAYS=365 -v /tmp/ssl-eg-keys-certs:/certs swr.ap-southeast-1.myhuaweicloud.com/edgegallery/deploy-tool:latest + # yamllint disable rule:line-length diff --git a/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/main.yml new file mode 100644 index 0000000..0ddc8f4 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/main.yml @@ -0,0 +1,25 @@ +# +# 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. +# + +--- +# tasks file for eg_certs +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/uninstall.yml new file mode 100644 index 0000000..ca56d0d --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/uninstall.yml @@ -0,0 +1,24 @@ +# +# 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. +# + +--- + +- name: Remove generated certificates + command: rm -rf /tmp/ssl-eg-keys-certs + args: + chdir: /tmp/ + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/eg_developer/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_developer/tasks/install.yml new file mode 100644 index 0000000..107d452 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_developer/tasks/install.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Developer chart installing + # yamllint disable rule:line-length + command: helm install developer-edgegallery edgegallery/developer --set global.oauth2.authServerAddress=https://{{ ansible_host }}:{{ vardata.usermgmt_port.name}} --set images.developerFe.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/developer-fe --set images.developerBe.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/developer-be --set images.postgres.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/postgres --set images.initservicecenter.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/curl --set images.developerFe.tag={{vardata.eg_image_tag.name}} --set images.developerBe.tag={{vardata.eg_image_tag.name}} --set images.developerFe.pullPolicy=IfNotPresent --set images.developerBe.pullPolicy=IfNotPresent --set images.postgres.pullPolicy=IfNotPresent --set images.initservicecenter.pullPolicy=IfNotPresent --set global.ssl.enabled=true --set global.ssl.secretName=edgegallery-ssl-secret diff --git a/blueprints/iotgateway/playbooks/roles/eg_developer/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_developer/tasks/main.yml new file mode 100644 index 0000000..bab0558 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_developer/tasks/main.yml @@ -0,0 +1,25 @@ +# +# 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. +# + +--- +# tasks file for eg_developer +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_developer/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_developer/tasks/uninstall.yml new file mode 100644 index 0000000..787052a --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_developer/tasks/uninstall.yml @@ -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. +# + +--- + +- name: Uninstall developer + command: helm uninstall developer-edgegallery + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/appstore-0.9.tgz b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/appstore-0.9.tgz new file mode 100644 index 0000000000000000000000000000000000000000..53de058bbdfa34df48eb0d87fd59198eac8adcca GIT binary patch literal 7213 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 C`O2;U literal 0 HcmV?d00001 diff --git a/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/mecm-mepm-0.9.tgz b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/mecm-mepm-0.9.tgz new file mode 100644 index 0000000000000000000000000000000000000000..4f5c572f2d250002b82e96ec2787078fa85b3b85 GIT binary patch literal 8135 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 literal 0 HcmV?d00001 diff --git a/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/mep-0.9.tgz b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/mep-0.9.tgz new file mode 100644 index 0000000000000000000000000000000000000000..490d9efaf138e4ab1991b1881529cabe6aeae149 GIT binary patch literal 10948 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 literal 0 HcmV?d00001 diff --git a/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/servicecenter-0.9.tgz b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/edgegallery/servicecenter-0.9.tgz new file mode 100644 index 0000000000000000000000000000000000000000..72aed5a97f229500c45340db64935e5baebc9145 GIT binary patch literal 5615 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 F000KLM9csH literal 0 HcmV?d00001 diff --git a/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/stable/grafana-5.5.5.tgz b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/stable/grafana-5.5.5.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2c67c809fd9de065bc2d0fc2ad19f3f877058259 GIT binary patch literal 21051 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 G*Z}~EZ+Dc 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 P00960P(_ht0D=Gj*EaE4 literal 0 HcmV?d00001 diff --git a/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/stable/nginx-ingress-1.41.2.tgz b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/stable/nginx-ingress-1.41.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..00bd24a18749c8f6c5c6522563251debedfbfe5c GIT binary patch literal 24348 zcmYIvWl$bXv^4I{gS)%CyAzy1kl^m_PVnIFZoxIULvVL@5AL#G-h1oTx4)*QcB*z} zcFvsc(@hc$2Lk)=0qDROjAYeVO=Q1tD|+#98FPGPHC5-b(oyH*R{r{x`-_&XwUNE4 zmxii?kgS=l9oWUkn>ztd11-u`&kKlGW2!zy^{zB)0B^b#Yc%rVXSL-wXLg^LiH2VL zc*zCZd(N3;-pJ`j0K4XAHxFIZ?T-~3iz;drTCgADngx|;ijIy~JBAo!@*QRBxb;&I zQ}2L|$?1c4*ZzRSO;6W%mbaddt=@NC|Ent!qI&?b3Nw5TLmj3FIC~&Qpb_}ZQrwFM zM3G0yu|nPXBZe8>TGTcM%$&9gN^Zi1EBXq;2a@7BGRwjIrZhyq@dJT#|3Df9sXEFB zv*mXFATxwgktT;)0ac{dJhR1;hObzWePSW^h1ShDd>KVT?n|zZN9ovvH=p-ha2l=h zA&64}k%n1nss5tqZLS-?nPb|Up_w_~*wq!3APytK_|pDf8xJhHjoL~>teMSwa-X&9 zKh^p475LtdhPs~k&Iw&S^!w0!)MLUVEivhAB>X8FNQDH!Fv*})3?*>fJziX~yyf`U z&bxR|>u^Ls!Z-zz&$0&kdX}lj4ATg=hX;ihrb5mj83(}CP;k=jrj$EK9fwd^l10zE7@;?X^1gz?-g;@LrNNq2$n&qW%+h8l;=$VFNh0tjC@Orp`=n$;hVC>kiaRuY$n9_p^jq~=_NMNkIc)>0Fvg?%= zsLE(&5~5{}j-H$s1zR`0cY?Jd!o)qe9W4GQA7HS|g7_pvh5HmwjvIF{CLV&`Y~rvZ zA{Qj$O#zOcG2dgPnemamA*^xVKB;c%J8*;VZlI0Q&Dhv0*)ghCmxe+ps3SEZAV`_!Qmv zwJge_qPVzZgopT=)t+=JQ9rk%$IPiIH6>8oI7mV@woY-oV`dfa!@lur7;pW zDkn)pNYF8VZ%D3WuVVn7cIbG7I$=VxJP2H}K#Rt7C)S3zZL|n9kq6Zs@ThdKKfIqY z5$KUM5Uv(a{aM4HoWyUk5TH69!gsWo0_8=dcXk=oP$4KieVIKl`&n@fM|C?O2)lhq z1%g*I3t|*Jl+u_pA%Re#@|MkvHa`%GiS#ido|;*1kh1=ci64r^`v{dE3KsUQA#3}Y zTx=TBUJ);&#DkAiyc|=V42rmMGf8MmRe&T3sbmBsHAOj0e1@NlIb%IPZMc%69d~02 z_xVg&?~Qn6!FwGTrw>vYr1`nOlh6^U;ILyMxn&pzvxCIW8w^sNRW#wb9WCZaVuez` zzkd~ReG9P%q|)}}0!LPUfV*taAyG&0$MDX$p_lNc^RixNYroqBM@;*m3rIW__I4+v ze?T&Y_Qj?)DbN73RIu;Dn;Aqa};p%cc{kHc~X|7AiDM94o+l>L-XMW1eG6qj}R z8uz;?`tL5|J^H0Q<#oViOJ;Lk7d(mK&UU0LSwCtGRV@~(7 zY>#*_)hR4d!r)nP&cH2O59PozUdIG5SV&Ywcr)KL2xZ4Sylz;;LH->LVrgOoiUaX5 zK~c}fGpUy4EElCUq6>gj`vs*JG@-&N_8l=oi3M%Hih0t1aQH`e4_GEj{2m4IH3WSd zqJ_y(oax%duyHu9zvtOV_MCq|x>=7Aw;xjnEH4;yvF!B;T{guv;}2YmqG`&G4<~Rz z&anFF$KFlQ8(c&eH4FsAs-bfBQ+9s@38FBit8}bz?PE-EWArZ+-ZYDTqSARnb&ww$ zggrU}RX*RjzgX|ADih~KX5Mc{*LjPh*tJnfD z{io)Mu=o)r4=4)C9S@HqTz=aqLX=rmG-wQ+!&0P%^k4zmzCYo8Ot@q?x3l$hdo-lb z;NV)cnI<^kuG2#}PA6oJH+L^XBGDQigkb4>gvRsqU7qjJIwm{3MuN9&Is6)KJdeAf z(@i5{YA}$f(!`E_7}5JYD0J6wh2qkIMkjaki3-~29i+tksJKxOCwbxAZC8O$8b)N( zqc}qKR4;U}fw1UWrwRNhCQ;9YQFm-XWUUy0tXcC!TZRB1(_e9jfIcb^*9i%g`jxEF z5G0ExOX2K#y7MaR`N5-083X39owo@LOS|te>ih=Z zr;ZlZMhal@=IY`ref+r>O5tr9dAkj>5&lAN`^ei4XQKJaLPJK#GDV^roCUM)mn08TaG20Mamsk|8nmB~%64q45of2!k!5UO;j%_o!D;mP%Shdx&le@1 zobSM-92$OfO^KV5kg<|GkshUT)HX&lZ2j68$wV0{RRIZeLfIFI77LEU=D%u@x;}}6 z^%s(CHqHK3nFkYvTV0Ty93A!yu}F_ZsZbD?8294G5=o04%c^!YF~>%9 zyN*n@Fh2^>Nx_Qb7#9S#_%#Sw%z!ajT!9@;i#c@a3$!-RPT3qkEiH$@XmaW%Wa=Lj zI0#14+|o~s!8Egy*}MV*z1P0sYTNahC}IMQ6dQ1CZDecNT?C@o6tXap!F;i@q}msR z(&ILjGgJmGy=#6;K;CKyIzK>m;bXG;%5 zjZN#ak8L?VpPphgMWejM-b%MPQaoIC#=fZf024}Q!G}Jw032M1v<(rNzdWgnlJ>;L zc#vYZwn}2iaprs_?^kd$bW=<6WHqv4%V&6D2pb_NiT=Wu6zd#9IYKHz#jWVP$vd5PwWHE!!UTiY_U=Mf9$Q>luE3|uTtv^(H6$gJN;U9aMu-%4UN*;a-P*#zl zJLJ!fgW(2$S3ragMVuJqQL9GdQsIUR0E!-ruC-CFP)GA;<7*)3M)U zfskUm2`X@JNoprR629^|GibJAw;$drsIt{AHtO(~VR7gP<{dU> zWRAPvn4WzZRpA^6T9FfxnUPAP?H5lz>YQRtt(2E=Txi5ARFk^ZfruAaBxG(T*lO`c zN9EJ7u?^e5nKs8tH2Fl%EeeeOn?3Jn9y?@UBq=RBd6dW)&Tu0fM0|O>9}JA#+~Bq$ zF3W5Z6`ArCB62u%_wOeLq@44Ft;A8d3jIXO!Pq7U_PfbZrw;qXyESs2yIf|mO(#VRO4X)fmmFJbxkv9)t8x`MKh?Q5RC7{wsvUAFLvP?Cf>t?mJ{;~KT0 zi$5KTt035sG;xU(eQg>{&ZG!N_XSRf)9zd~_0|?>kl4&KQ;JkMF~P}As&HLbD7OUfhZ1!yyL%tB4UVK9)1?EU=u1SeCkOeZ5s9yD?a_^vH7sHxlZUS z6#bSs(xy|h;iBL8rdU#%rLI5m%*$SV#vJ1{mT?(iWbi~@r&wN=b}mR%!SH@(8GB@= zoHparN$OJY*{CS68X=c=6#b+|L8-9wo!OpdDS@ItjuyR=IT`5X+W+IyJ(lagCaFBHmIT3HHQ$m~cfyL$gs1zV6@2LLkdjYf6Iu zl$grl#q6y*4Xsa4fRo6hzN7MSa$MPD16+qG7stS66bSkHLaEHEuFqMAYZ5dY9_jlJFu6j7)JMUU+HWgz|Z8d3*5VP{$ zbIQFJputd}++A;}G2QwuRa7htbEd2ypOkZf>doR^;gB4VEbaL+yOLCV|5*4`IP$CW zq${4fmD3Vg`;r`T{(Z8~YK!tx;*2-BB|{XS->{c2oIA|WErgVtYUUm`Hx6wmx800g zHyX;a)#M^`>D%PXI1&sojtP!980b3;UHl$W9vNCV(KSO%ooe(DQ$^<$n&g~nfB1z) zT-T1u7>AWzHy_n-q)NpA9!J_|+b}H#Mr~57qpnA?aArd9li>*z<~aV>M#oi$@d9X4%W~~>{Vf1Q~C4rm-#KdR%S(28Tunm z`O0l)eQ;*PQS2i497p3Zd; zoWOA?w#PGe?ord?zl0wp7E^$x=Kex0#m$wm{Y5ArjI%glO2bJSa*Wy6`t8U|5!x-` zP>*3Em2rcO;h83V_m@ywpCnGLaUwjDk}NpLlL2(K*n*Rb|+)|Od) z>_vLUXtV{Nwm!kaZ-1~Yc;#=B@4y<#yAyra)z#8jDTjl&nVba;ao6<1m-CUNk?68H z<=-h?%@NO~=~qXK(wU_XzWZsEzLGs($0+4p23f?80|c;0Z>0IcWUWqcNaa1wUZ6I0 zh`*%R&dA4eOVbN7v`~=WSwsW;sG--Y5SemG`F8%lf@;own*GF(oTPIPTLBG;r;I}H!%f+l2v&!>s zy+6vfS8EB=g~afm|4sYL%lNSWdKyG!DKqGfNa`N9NW$A*$7S9A2o zJBgd#)PAjT8=(b~2DV@VIf$|{_}6zQ5|c9nOnuDPZr6MIYXqFNFEs{tm^AlNQBrd0 z{WMl6A7m?68CVeN81b^GT&i1`&H*@YmN^{QL;luehaY_pAXTsVCjqV8W{>i!E?99k zJ1}on5Hn`K`EODuD2Px&>mX;ad-SqM8}Y4vL#LJVRS_2*q#tRXsJ^JVkoeQN3aXz) z4Qm04l1XuE=1<}GU%g*|weXytCXpch87w9ng1^D~*B*}P;)WBE#UcuR>M&IcJW4Gt zAb8}BpR5DS_v%=-{;5_O2yPwJp$tKYj?dEpbGA4)wlFW>9=^&;vVw&Jx;}!U+dSq9 zJ4UFI5ksoIyBBg()ipK;YNEp``Jm8-LtgDGXF}i6ai_Y{L*8=T*wo+8DjpQCw#>rM zQoTqwALy4dx|M3yp6Thy00yc+*PY5f6_ zPb$m|ohum>hnbW*O{qmTR3o<$U4cy==%=_m`}kmYd0l#qbx|g-;}H=NE#hJ*$yJWT zXtQ;p8U#D}R&e9FENm$u5%FIIm9Lgj@9AypE7G}DAg{zbDm9Du$n&UiLa!b)vfWhE zDRD7+1wP`)z7lwiZI=?FL>=jhv#t}oWnI5nx}4SpqVmqfCbE!F>#UW=AM2$pqoli* zM#uRFXFlBY_=&l@KLzPWiqR4VsBTvH(V5OAlW*5w);5wwv}CTU z)MdgVZI>F0`nmGKYVmE`vs|pn3k}I>jHZ-zkP(CH8fx z0R@`ssr8n6xN|TAFFKXmrL{mn?wUMM6-w&8M@5U-WV;8$|41VbwV#5&-$mFvNwoK8 z{7AFF$-G`{NC}m6%@%K=kBr;FNo;#HqfYQ=QZ)K0h$W)78L~#1Wzzm=B$e_MZ7-r$ zK12~oT(GwYG-|asYGKMc_-7;jJo~lKPiA|y73(UgM02tw4hGms-W?G2`%n`(sYsa3hNegxLxfg>b9{kJi@6I1*l>>iQ@n6eF0XI%w z{;`7qz6}xnm7{=F$u@2}8b@JzPXsz#GSJDj*MXZ(waBL<7_kkrLfa?BruSO@-LDA} z)7A1OR3wqzzB1+NJoI^-KYD|hTV+?m{3Wf!M3{l%mk z_A^JArjBtRtVcBrw(Hl|*W3Le7K>Wp@1M7SUk^zFIKu~b9Tnr1Rk0?na$R5!*hzR} z*$yDL)IYKJ=V@5Q7;kJ`;hu96NkeU48$M*h!~R^tq1K~z1>m^~H}i3JX^IIn`#$mx z*Iyx`dd-06317-zKq{k}F4C1iyLdP670-=*>+-(0x~%okL4Jg|x*ON5OC3%?8cQ$8 zAce5%zrsZhiWB{~spw*0^!=M0_*k26OigsrzIg@WAGn%pqEEIlI#4Zjuu-341KG@2 z;q(^sDEO3oF&qtHz~cK&R$+2ZSyW!u&ZWw z(*cUad9Fws|N5C&yOdaSfEBlGw1A*kLLZUmhPCLVWAVxk~!= z5EOB7HuXj^Xt)ivm7Ar)*d^{|64@T2@as!hrkQ)ho?AVKtZYk#L(xL|1dbb`Fm>qp zZ!+h_uH@fHT5!DNts`g~o11P;9F-H9bkXTncWDz0qL-+IgR|qXlNOp0C7R_-(BXi+<#SL5mNsZ8v2S zxelbtAsGJBw8+mxo9x;ROBz2`UG0pR+1S5lv=jOMeNPADHF?D&i7zpmhLTq7n3naA zk&Y~b9OTh_>^RPW1BLADEVyWpg5Uu>BVb<%XXDf|#-wwNKPQ+%?aC%2A45;-l=Jm` zzHDi#JvtZ;?D_IwbLeGgTEa2u>XjOOJLy0JU{Givg`7=xNo|Tl%QG;_Y7rPa!0k9a zAggg%z<%?wu0B1dGkXO_=x!xIvnYrp*$6EN&OY7!38NlL~n=pB#}> z(rg0!v6K@1q@>rE{ex>7Lsi1xJC+9TnA0_TH@Mp&ElFVef#rFW$%$gmr9|fWz6l!OUtLw!OmFD#d!Pb8`!WL|jS$=Vt>)O)H8H3X-mVN{(J(MoR2>Ce84Sr8}@@UoK!%xSjhl3$f7`SRv@?g4Fi~ zT&`Gs&+Wq1m8Y7@k{kILqrs}dcH7I+H^nkNTbBxIbJ7Xg%9^(5#u#zVeh%-8O5KYw zcI4p^#0ml1=14nAYt{aM#c&>bq}cL!5qodivHBzE*tAv89vYn#1gm&RSWV#l$_x}< zG%0JH)8;|RWcYtR4^&;NsV4GA}T>}`y4UdUQS4VsI4+OAb$Ycc5x6))fn>4tR>7jr-SXe1z$a|Fqa zLZN-wsOkSDG&$Iao*@q=bBxU>pvfazeyYa!#)8LfgGT`oUZEO^UKM#X+}SCSM4lh~ zA||D8$~Pb*#I0ZQw zi`lB6HZVM2-wU3xE2)gOe-3k_duXx11)+4VfZ^uPHcnPVd(_v{Xg`^*HRB#va+-t? zQUKDzf3p7_-f^cOFer#=jnPF+tsBs+M9K*aau1-PkSUftp@)5pcrJ%mE?)&gzKh&_ zuJ7!W2mIdrcigRkfnEmcX2pKc-I-L;Sg?*_5)w|N^vq>%`WLxk2rm9smcd2qegn#! zE(&3JC)~E_)D=sZ=C47B56a>6vVMrIy&njxn!HJ&5JNk?PHkRMI#W~W%zMiRYv(uj`VwnG0 znjdU)iS?QS8+}@KlU1tC}F$zvr(LJUFxq-oKL=-F(+8!Buhje2RN)yaiN& z6HA{@heBVvV<0YZs>Qf>nGpt!qyj1Fm9m-?bD!2yA#(iO5dO=I=e>Y)28Lu4W}%&A z3n7{oMSF6QaR$kablhRevj~vZNgc10$t7=y42U$@i6sIg#1{?^JwKDn_5lhp`LJaG z7%dNMtF4;^nF$9DIpDoO;dk^(c7}nPxX46BvitpYAG;uxp7RW2 zNTVr=iTAtw#Kd~$Nt(b6C$#V^m4^4Km%!%fZcU}LG-R;ByPn%_R0{6s2HMMR&dvWqdEG%1u|s2QJH z=()nsJ5_C+XtauQtumU+l{RmN#SfB0xS-=1%~=0;8^|^E_`McGN(&I@l8%L{qd#AX ze5wQlyh2@!OR^p$_3uEPkQ{t55(sgyZYq6JV6fY8PGZRPNNjSk+Tq9aRm*UxbzX3)Qn6wXnL#agNc~v^A}DefOg>s7npu@;&gL@*Q~2Bv*#r z)PJQ$7TN1qv{ZSMtg#Z_lLzldjT%NEI-mkvMB{T?WNZ`&f75*lz&vC~2Bd0#4g%Fw z7QetO8TKG$?S6sVas|@NfN|!{oBaY)OvCtSyrUU1{@9W=Y5T4HT@kE?G!tOpr^G9*j8N4|6Km_b8HE1o(xf5c|t0?O2%fx8_IXeoATbz*#mEv?{OBYtC0D= zz!yt;T-t>G1KQMqeZR>$F{{t#B`m_f*E|d|$5t@Pj}wH7+OuC~h?oviv_OZqYu5CJ z&hGS@Z&02fCp}BX@*3XWA?Yh)IIGyqVR=ZF1pp0#0Q} zhe(Vh{biUj2M@~$Rrd0T+YtX69^~ldIzR_GWgl}rH+0ISC*>SODT2mxJQ zGqAmM12Bke{~`hwqcNcWe%$s}y6v|La<&|6JAKOlc%0t9mc#-i$giug!AxMlp#%M2Isht+5Ak%OUj0+ zmF(?u4>Je-dIh>GaNX4g5OfMzW z2-~5F@N3%;mIhDK;8pAhquj}qy>{QU4*uow!PC1CP4?nyyJ_l*DyTO83?$O|(<>kY zB!tAM>@PsvTll|!kzyzj$jc&})4NM;nb&`j)H}nuS*V(z?=1BdCcp|8VR-CnfZm`y zEIPtO=!`F4zQ;14CYJwHn~n(KM{JL?G8XUQAf7tZDI|@cpH%q@H}~#53ZAvZsW~7Y zPO+9ID4Z^lukY>=?_8maEyJ<>BMn2r!1>S9{+T_W+Ia~(PDxsA@%e_;-$3`jv<@Le zmu>;qY3v&F;dbhJ3<(T*IGi$KY=@=6FBq`fUy!>Q43HW7C*)~MFw2Fxj?+r|UU~+< zC_7cm12AoGd0Txqj~{veq8~pHUE|hm#5R?2N8uq9r`nA#$HHJIZDd*4m zb>x{8soPu|lefXNBP+(+Jf6f}YJfjoa)63>QhD?%iqr)g3~5jrYJo39BtKSLmuB-^ z=ax;6s7)^*6k$%8-)yxdufX+h1D;}C{%t@UjP7SoWTI{R@yWInXf%V>G7ldAw|G^T zuKtZof9a+Em&)xSP#1Nwequz>?s%a&yxXeVWRjWs!;d9yWovV;q=ipruUwgH8Lyr6 zdjIM%cv|>M?vd>BPt+z_PtiK$0aic11+K}po%ynYhtib+lwY@caL^it*o#V)hQCjO zu;eAbI5OqI-7M{7X`F?YVA2R$5{*qorx(sIIIoEH5a@I&`Z|Rkr8}f9r?X=)ZSCNh zS3JKLA~aNR2I$wrv2%V~U^H)UXpX{I`ri^2{fo@Eut3FT>I~5_ts>QySg44I9fBEy$6EH^#tB|N^|bHX7-M-m+iXUf@D#)pEPo*3e4$Uh1}MLGTqg=F$lJ?J zQmTkF=T^8SY?OBzu;iCX8z-Ypl<|MJ%v>^!xq;BhF&)s5O-lPwKe|MA2c`?k{wRSv z)jQ7w!D5X!X|$(e&@)2JO)2YA)$5hqv1m}5ms6B77E7O!RL%`?-sM$no+7dnx{HkvJmtl4-k1o>+u4lHr;aqzu@3 z0`oK`Z^6!pJ%!=-x*O~maZBZND3nKeY~^KM5g&0*WRZOfFZjaBSl+*RXqqlv4H&vr zb9pXVzw7)O9h;dG7jN3fFJ71N-ut-&Gf*wU$W&1bcYjJRi1iJgm3=V!?-WG&aCwBmujK-meJ)qCn@>{`nlP{&cL3e)gZ&* zmJim%d9|zDkMK_SN;B0^6un{5jF3 zv~p2NTMBiEpv9J&L^(4VQq6dc9@3iHxQ4aKnw>=h0@9>ai*i!4)m=y*XAbbLX#X8| zXxZW|jo>!*9y7RwZ+`HxIzKHNnjg;Nx>EY)Jvh%jKieL=&iIKc;=qBn?6PAXSaUu& z8OX%%+-$GDw?qH_QjoCBGhS4a)G2+eB%6BD^eanHkBZd+0a^E1-{HXpS}*a}j*0vD z!_Z$l*#;NVYf_azO3Xm|eIavC$WamcB5^9$_hLhEN|QN`9Pibybjo2zF7CvJseieQ z(#n>Q-GrF&WX+ysuT#b9VvMvkMXM2)5>Yu9!2WD+TfnHq!clZ9#m4U#`BjMx*nfgC z?s!h%% zw&q1f1&1VM3WLUSAY*cIGzv546ZxU5aaO7U)6r{QMJ1Ji{9{r);OB_eyV(n%V+of^j9OcbPwUt~m|%4L7LN^U0RW`xI|lVRAn z%^>$;^!(4|`3(NH&A?78qC{_gF$;toMYWgX$HcTeO z`L7qM2^pf2rm`eBu=_V|jvd@2cc?jmcq4K_ef?J0jID%a3mNA+TIL990bOarm~`HH zLIZM#YLyv*`yF!FCT9eY9(HY{47S_}aIRckT5JPC8zL*i0k(yL#_uvi-OP_z%0l#c z8mCjRj|8{1a-qNgG(M2%NmGd*)lw@FS&9nR%6fzDD_m>DDK?=!rWJL#i|leExFZ%< zY!ml>77vltU3FF|)M-%Zr>5VW#w|<-mCWa~hL)Z_)@mtTIOG%N_mH|z6{QDa9bcUX zw?!``^DJ9P{;JaVKJ5E!=m3Ax0L&g>2w0{3As1{W#yl_qPzhqng^zMCY5QnxnV$qKm4YgfRhwV+N6$ z+WxZ=dW+V&B7KCCT-YD~8Se@_! zZhoa`irN{5?vMYi(|@66{HRVwu@P$~iJeP9Gud*Imc0A3+QZEEvm{63!vB1%`+2zi ztbsW?@OAtCqbqszz|RzdpNPAQ6880d{~##Qh#(QKHk+!ZOn6+24*8%b-jldgmGHL6 z737m-W)NJR0KCeCRK2%uuO9&`iuD&FRN$&o!2LE(CJrlp6sG$sBWf^f<9^C?oX@42x7WF^-5}{Ip&99(#*p`lK2LNw;8eUC=_#O zI4wDM0rU(qZYj2(#w4@N=fKDQhuBwuu5Y67TM=B2?FM!==6vWA=`|yr`p%+y--0S#Jfy$1Y`V6Nc;=2(WV2wK zwMbT-H)ZwLJ>Qb#<+LlMb_o<;q%2|75BqGzJpqmp!U+}9{1JptC^7uw@bsaq>i~S= zvyUrqi^tWs?foJqU|VwZLXyEPYGSMa&r4Id$G0f4$vtZy?Mz&6|!yLPk)e956lWJe4{37U#v(fiQpiS_YB+Y~Uy@*~jQ@@p#07jAnLuHV^ z4To_;fm8GA2ZRPO21#SmHH+Hceb315qC2Nia6MdgSuzFom(>X@nv z8wjLIv7fdZ(Z&u}h&{MHmtBIXi}{o-7U~l@s&hGi6R#&p)FeWTKCH{RY=JQ%i3>)@DewO zBpF&4dWTR$H`GMt`N&;*K@{#S7VHrUhb_C$dOwQWwqYs@**1{a1GF(R3THnU7s z6q0gqMB6Tl$AHU$incIlm-~pOM?L@|o*8)kwEv-K6X1lD0U)_@_z>Y%V-L@gZQ7HL zh^|(WKEmng`;U0bZu&>Og)%LyIBX@vEFS$zm`T%8ES1MW~lrr9fX5HSciag(Br3=BqGUQaF{UPmYRB| zVE%5k#MN#=yF;0cR7WHmNeqiAHDFf<`A;rBb9ImUsTNkLb4um3$?2@00b2nl!(oR? zL8>o787^~(Dfm3FZ9}#+&tNGf}jk!;% z|K+-BYlQ+|w)^SA0I!n^H07ir;S?Q>uIYA28%RfzI|MS@kyV4-kuZUIXVH!21l(K1 z%_=#Q0cqZyv0iIq!_5x^fb<-gB_Tv^x!tB7dp+zSp{lSQ5~YH{AgN%*pQL3dZ788I z52ft#b>Jlah}A1Sm`V<5iMqxrs)g3Y!^&<$W*U>~I&3wNwdw`1n9?s&6i6W4UI8cJ zPZP(wMSw@G@OtWAz^>95_;+x02oXd;D z14BOk%hmHWD+BO=g7T{S;(%E~7p<%OepNL1A*|VX^|jQ;Iip5Z?<(r1Gf$cD3V+XI z8PwVl=D8U@d@5}1`}fSLEkL6yaq)^!po{xt#Xlz}V34Btx7D%5#DYjP3En94wj0!l z$;B9A`X(n^vHvgqu>P;(wJ=isPZyLaJFIv0*lB|COL0_EreKRZ@xU{7tjWlji3- zMTJb6w9U!_sIUjdrVWzPdfeF(@88U#6GU~b+0-21s_Jk%KQgf?P%B@IZ7(?t)coU* z9!Y4gg0)y77gqwjM`YgG-W@)wKP)JyNOV%VUs+sWMl%DNJo;MC9#nT(6B4%B?{w`D z#%+FKO*Ym~K)Z)!3rOF6)QUeX_W-aXZ!aGKbv^%4|TBFV?D+p==GmW0cqfV3U)`zgBN;C|g;zg6F$`u3oKS&EknD$@R{3J!l|(0aQ4-9%ihMu`a5+Wmyr*#$3F=C_yg5Pp3)lPUoJU!L;kpQ)S9K zJ;1ZX$H!?BVWsjAkpQkUBVIPxM@VOrorUALP>=&$-Jh#gxECc$`VdZE+%IZZqAZgF zLpH-Sv!SJ`iW>!Lk>W{1uGyij-4j%xFUZ@t!1&s6mZ?S6wMlHQ9jjdbAA~JBnq`g2 zr*C9-cV7R%F2`M1uvds*3Mcn^g@`4q@&5;91p>+`GKBKu_d6kwdX&2zJlz-I3&Riv8B@W81n5~ z_cCQau&cM+L%9`M8CF=<2%ff)g~JfSu$5D`5xrzXaoFg=RP&%A%$J~Q?^Pt|kj^m? zLj7&G5*_PmtINhvj?srotv~QdVL&#M7I&^*(Ho>ual;MrGV%6)`4k%H9vk!cPk=iy z_dw(}^sJO~SlxshA3@>FzRAjMU*Nn7ySp3 zIZxfa=j&zKWpl6r93KJHai2ORY(PLSMZDWPu=C8C2H4b10__QEXn^LYxaiL`6>jN! z4o}LtwIYL`9ja&bfBMUaA2@VRTYIXsy0h0EDwIfLM;J) zc8m|v^yAlnCJA`uKJfOz_|Jgnv;O`sMCQ=}+rs1;zDTyWY-IE2?Zj9*!(xVS!!zdc z>YqS7}DzTX^_;_{IWn4E5>w5b(Y9UFJOT zxzb-ar1u?JKjo0(UZM1E{paYm={L1cT{?K%pYO{8{1b-({A=5<0rth96M%}{aMFMB zAbPVjT0ffp{iL(j76?agGf+goSCJ&Tv;W-h1iH4z{{o*o*Pb2!;NR^_UUev6FkB6q z57TLWc@%lV+=st)jjjk!>(w-;zRobr@o;iN2F2HY)uhczg_<<|)^^j1)mLc^;_^~) zBYI`bs>mHLxw96e_f4J9QmP2s&FE$Qv1bvNf$#=D^|QmCiMP0a0O;~9E{hJ2x{x?@ zwc%FA@Nfbd`51=rzV8kR($xMp1EU(1;uYIck1a5=g?R;Beq2e*n*+aiB3j-6^v8gU z#S37?=j>xUgFGON20U^G|E+u-2>*xyJb-);&!+#bTY()6_OQZ02-XAClxM1IoIt2TDjE1tS_okjm9j;?j#tki*-#yUo#Y8~O0b^X z@8GC1O^X?ZOISe4Nh^O5AgO<2@L|M%dJCM0oC=;$2TIR${ghxG7A~y561Zo!_1nhl zTVHx2;zrcn26~oIp0T9U2SM3+U4_-L&LDfYx^P3SrRYCb28HyATR_jd`_0+rV*7t{ z{_uZ%Cn2=E6v?7vMWSHG`L;;t$UkK1yI16c>q%?P7uZJ^v(toCz$fkD)|~6jxZdC^ zcLn^bKuv9RpG|Z&KdN^9t6iWregYpKVgUp|b3y~88feDaPxj-Z_LzM2y>30nko%|1 zUR%wLsq- zpO0Yof~x1#eyg?%P$X*n$*lH_2IN~q!Gj5Xe>}T9bgFZR96yd~Ev`P-tT#6{epBWT z%2Z#0;RJ!B(1vuQ(uPowxXrt`y0}ne=H2aj)sJ^rH-}nMg0NZ1LshZ+R1{?@*<{&W zz%anzgx?2{LiVHiGP&S?NV~5aFb4$KdcebZ{8Z@J>+q(K~6oTaL;zP$}m| zs47zNoo#ZtQ=L7luUB1Nh68gf%`57H?DVDo7U#11pJ%g|EI`)pZTT)|VY?%cy#9CZ zKdTKmV<>tySr|FJ)!GkmTrx-kuij`1;c)A^%tQdC8~DTz-wqIga$q$JoDRVk(nR#3 zppNvQ8a?+598aZO5^)ncprCGz7Xq*|u$X^Xr#AhWb`Lc-jisGYa8R!MIzShgjDaIj z`tOrv529WQgQOS|sg*CiQa@rNuaX4VzM>Q7OtgIieXi<&u`6kZlZ6+%a7*#B{}M^# zcmL&90UjvQhgWDHD&-7*lUBawObGi9KM|nIgZI{t{H(6lDc-y1Vs74>*K6&b6kMPd zS_ogtsN-l!2S=}*qj-wo%7wyOniEOj#!44fmNc~_zJSFyv5vD4gg#($!hRNtelw@o zr7MI0L&LSn#=HA*&;J&pR0|iX7^({?^>r_B?UI~Sj(Z(nw6k!GtFIs@js>nG22Bc_ zAzPDZajY*YwC30X`kYvL@Q?-_t(36)O=SmfixT2{(8w}+oUxc4n-uXe`ieqA!VjzP zqUEcHdF{iwX_roa3EMH$Z{#Rrp)fz}P*li!d%6YDH_l=uTLa0v<8W_r3>C?JD4o|! zJ288oa6${nuKziGZ;-LC%??M1i0|&O6n6=4l2BgJgSQ|gozSj-+UB^$LrkEeY{PbOQlhD9{pWE{N6}tPA~1B$+t~-MEl}9ov$Bj z;i{UNfyY6Tst3$V!umsmLI;~v0!L(hnezQY#XtEumiZR5D0p<8<1~_NpctJ{1Juw;{5rMVZa{}*>2h~crVkOxTMFZjN^DRJX^DLcFoBbZAgKlmHybq4)T zuV5>90ZsVo`Pj%R$=bYRQH*Z(3}YbRM)`67gd@s+!)*Fm*1qY0D}=y@ka*81@B*qB zaYAot`Cd?yO9B^#jCR#XsiW2s2a~QBP$wkDJ+ZqZ{&3`H4tiJ2w}%+S;*o$9YPpe~ znk^yyEKho-(05Dz(6wQz9gK+og+;D)b#`U*rDjFFP$D1$5(f*Y4AwN^%Cco}caD{08! z{1Pb0x&`lp%^UZBT7dJiC4J30`94K`hY{f z!X9#=#r~;2_|^Q`VhQmS(Z1mv^3B=F<#2fMvsI;#)%(1%@4?UsCf3NyzVC9ThwkAl z^ik;`eicbL-jXJExw7lGwlyA0NOfLVIhlfU-B-4wf1 z03#&MnGqUmBL)mZds%o5%3#Emqd&pThks=ROi5beZH}x;VYC@v>_7q{5(_miBJpG@ z&ns&ze}Wrn{77{$gZDEWcyF+a0*d~D1PgyFKLTHV6%r65BE^YMpa*_N~> za~drt(A|Q5%&&UgWK1d}KtkZ`ME4|-1p}XB(F;X?idmBj>p9iPEv`8 zR)AeWYGEzpMKRg~(vO^4S%kqQ@j#MCxKMN|$vUVYTfYL;=bqe4V~l)Ho>Ma%;8{G= zZ(;#gB|W?uln=nlK)X~|@V>aKe!sl0>O8eVYY;WS>E(M6Cv`xWM}6aIjx2cpD^ib83{o3?3!;a>RrHr7TcfN2Xk}aYUx6J+1^BX-Ib>X5>ZrjHHpF zo51GaU_XP7l~7+WJ>nt2xsW=t<*x`lSE<6NZ7=-$%YNr*x9AMi>G3tlExc! zZgFDP4bVN?(`MsD^2~HUr8TfJZZBnH?UZTaB^tw{dr#M0$2;$iYMO<`A!w@Ue&k?0bEy`i&V=RFIP3F-oG)_MS znRW|$F&AhVD=QzE{!L^HM3hnRf20&vOi09P=WPuFoF7yD@_J{}`?;rhAOgiE;U zHy|E+E<&OpZ9sNkWXz+gMHMhVOLomcgz?D7bb6%?Pl;TFwOo{;C~@dX6BYs}@IrzE z1|sB=D6v1|yrLbUG3OK6u31y7Hdd)-+Q=c*oFWOnaL^v6 z(ry(HgPyjmNfFUgMg~j)q9JlI^!)`_>c_F4x9J)ALChJk#RzHBt2VNByx-ulAp{DN14kJd_JUBt!SrYYf>bh&p)w*wpW2P zXSqJ+C-V6v;7U5zZ$wq|R8mJ|WaSHTb1JHGy5rMxK>|K)V?Hq*P{kPJt8hZvNM`t9 z%aPmiHH&Z2p= z#p0TRQPqH?HcYOSt`0OwDw61|S6a7Aev~(fGZ-3^sIr|uGXpEQo-FHxuGouI!1Gs< zx}PvV3_S_rIyF>!Y8jqk0fsgJY9N%NAo<6iB40^H0@sijQ6dNjl;SIe5CgTnN^J@` z)`hUR*RSPZHJZKdxY^p5?Y}hoMOKKX#$QoY{Q#Jo-X5j{zT3FC6|iW*MPwAAz(pPy zEdWKBFX^ z$}4V~BmOKm7^%73gGNVJ$;P)vLuu_L{~-V2C`4 z%zo9HDXGtR#wh!SagfQ-gOFjQe+(dj7;0~Dc#tt_)IIH+qdL>15!qEe@Vg4#RX*)o zLwNlvNKa0AH4gx9nDnyiR!4hTs%S!d>aD_z+2cleVJNlmG9oj?rYNTRZNn11TtjPU z*eZZqVV%kXPnkHhIipPM*Kk+2ab&xHpsk}|zzrreWALb$z(T`Ek*1ODqR@W0!ty+x zN>`i}V+l8c&D*=3! zYL?x)Bt#LEZ+bT%VcmBkpC$JsmcN0%GO>ajgn^BcEH>Iq;9=^Lx!|*-g^gc5t!kX6 zBp^|Oj`b&Sr-V=yN+4T5qZ&yP0GIearh>7_I0ShmEh}`Eo0$^tjyqvjRCQ-+@aEDZ z(cG0;TBz$&1Sp(Y&K>}&_!VuGUk)St2Jl1fYoRljOCm%>LN~P@j;0ssxjXN5_76I} z?iq1~FNt*0g(2?Dyq&}iMs=|(s8UC}fICheNhNv7AHh)U1$j3i{}eaO$e-oiUxdeM zqgjxkgsb8l`o^w4hn)P_9YTRkb)q&u;Qs_S`@NERPG;p@?4!o}G2JY8mNwjwna)?= zkXdvdvLiD{RqlmszmK#TGAN0+aKr`>|4N8Hsb_4b$)~Q!Ys0!}Uv%iBh~Z%JQGn|1 zDv>d125xz~Fruugl}1gy!U8<0tt+N5_c4Z?S@T^UN{JkswLRp}tdf(;dwHNlS&2oXC0R+bF7I}AS-Tvyi~yWp-lgT=^1dEV zf^F7kR+fFUep$90k&IMZKGCJ7>~h#zy1iD?Z8-@w5pD}MKVz{*TmfkuqWD-(J2fZxeTY=_?wW5}I~n?FZYbof{&C|Cv;6^RM1 z;bfWa=lxDE8<$z#Q4+5S&SX^P65Z8rM7yhWROfjvfU`-DkwSI_42q%W+I)l~5ji(t%S&aY-4|q-iS(_$-01f+iC1w`gH^kpv`GL5H5FQs3r) z4drt*A;b~20e?`at4z3s4gyNaOA=wIfXt@xm)#xcc{-`^uJZj<25ySP18jVmLK0A9 zoEfE`N1;PsD#`C>Hd2{DnIcv@UO|m|xGKt$7L0eAjPvZ(<-1p>C)cme_P~3JK;^XX zlMX>)ZO*}z-oICjAAA!*c~HhN>ySM%2JeV)9eytzg{i7rxM}QNVwAXRlQO|fkEM~7 zdFL@VtboVdFmXLu25jtAfsMUoz!nF*-pIIpc9O)VW{q)>1Yws}fA+(TqIA zBB>z{u_j%E$^oID=+G~8z?pY+P}Zdq4(j?+xf=SN!!kh0;a>+Uld+)?TKasigIJxq zp?IpFFnz<13o{~-`6wVG;t9{xNNoP2!^8c81uM?*F#TFmJfu4=OY_k5F`}E*Qaxl@ zMM=zEIYH(F?}|V^ARst1OSLxWZE1OJJfqaTWMX5^)oE3%#jmxSV|b;E=c`ZwoJfu~#wZ5{0GYwyX?L^<7z`=Xf7{JGSI| zy6g1qs(1m`_Q5Kfz0y0XCNEWH94-|gnCnEpd@5flP~oLYITq@!jQFQ|S1LONBO*zV zWlQXo8=Nu-YWtJ0*jYBH64cZ+jEM8nv6V8uO%2qYLV$u#H^CzJG<>2(eV+Bl#&|xR#MPjPRVVi^+!SM#w_}mpEy%`=b$bE0^{Ehsi3Xp5bZ^VpGkF9qBq`yoN;bs@X`TrI1&SrJ0Lf z8c!n?_$)S%V>VDKKN%JM%JfFIBM6_D2>FYYD~NT7NQ+yE$8lUs$@+X?uml%tW9hSNz@q}Yn)X|If^G{D~FcuB|>xI;rJR;MxwJusCuWSl?WLgF~!yczI0;#*Q>m%VA}P^RnCOM_YFwnpa4mLD($i2qAW4Wt03 zCqu{pDq!jTSt-ON0ouOjpI5q2d>5W3r@t+VGa98dJBrI2xF|AXD!#YOhR)#LN%q}ZpuMql8}r1+8yu{ ziL~3>-m(ew3&!k>b%O2%ocU^4`n=)ezLgopM)3q-N@JvaH#9`)r-=i;c~qV?pG@AM zIr3YOa)rc=@CbR}!xTm6f%$D&MBh>l{o%? zNG#S!XOh$M&ouupLlS2|9#lr!c7Jz5hFF zAo`^@x+Vaw-B~DQEDJ@!Eh-so!$_eH$gmV8@oB=d`u;_^I`4@JV#;L5QYJ{iTm#i& zl8ud!tCyZj@z?+TsHC9~PEeQsTaFh+t=1(!EJ;jthGX?ufO(-~3c2W-62o}=&i6Oz zXClDJC+@9I`6)t_?*JL`MP~?jvGI#YUN2AyExFtml#tf2^*#UjL$A|6>hxFVMyH}H zk!aJ~>GhBLyXqKZ6g;2fh{ezsdEEe$c`TItxC=Z;ry~L*58Oejo_g>MR)hUcZ(Udo z_InB|YqbDm@}{c)qW7Yw=M{oD!1sU>_ZBg5hemQWCGSa$K9B*QxX|YV>$E_ME#A0s z>vq{X!zMS7?C4 z5HV>?_>g<6LeA7WCtFH=j@pJI?t-zHceA~t92ssxPcE=)fyZf ziYK(I4H=FX(A~^SJmMNXC3H=Q`kwTPvPq+ zU+J{))Xw@YnRU!lJ}19jfj7tC)teusTyb^v23#k}1Y0d7#OEjhQb4EVF3|V3nHBbr zr3>8yBo1NL?ZP|S^^bK17{@=B2Yj=+v(k3xxf5hB{%d`p)|Z0$)U2y+#z|0d?$zSQF>Mgv;*miWo90bAi+c|S9O81PTh8Vj3cb!eUjr!9x9Q;ldR-LuVt~3gM)pEtsL4=;Pn8u zq~NTDGZkB?OG4}d1MB0ATP@-u|e=NFQCe7 z)9kpjpCkvs3;61&p4(*o-z8hp!NfXdmk%3ql2Seab5|VmN@X`%xM9FpW`?8_xJZ@u0F{MpOa(2m_sVFWQH*`{s4&H|8TMh6vCTsY zM#v|3@-C*OT65*rD8qVWALWmKZSfz8lzKtR)T@+Y%Hom!LISDzN(1jlpG*KC8@pV=>Ke>*H3)8cUn98d1DDCYZ$jU@P^6Da2Y#hOjYXol<6#rQM>ij!`PM;OYQ#G?*}}91Jv#R{r+Kg z{~sRow)=k*rEdSH4faC)*V){~CzI%08yJ`yCbotjdcEEd?Du*mmNk@${U6dz$^X4UUjE;n{~IYa z@_#OC9Iv%y17A<6*#G)1G8lLd;{~<*|1fL+>mO|Q|7J?P|4-(LuOdlc%O<|q(qR8T zzW-k@>;K#9_qP5&8!2nq|4%)LZCSY#?0@}?fMY#B^QiGZy~CXUe}C)$x0#aO|JI6c z_xU$bs`mf70sw3G|50xL?;mdW|3*rA*0OE1-?vce_y5D)fa~`EAZP#YA0HfS_x~nJ zRo2jLwBOfXs`mf78~|$1|AUo9BOeChi3PsDOgb33@Y{{{6_=|0 zzpen_y8YiT*#Ae{{lAft(f_y6zTa4>+W+ec0Irq)2RZ$}ceKCV|C=a}kzsTj?fd1F zs{Ow%2f$kSKX?BxLISt@e*-1G|F_k^i&jfB*R4;BdSDH&M0;KECZz zwg1-@09bqe4|4B+9Bt+Q&6Mo@|2Eq1+bT`=|D)gk9p&ZU*#A$B^0sWt YwrtC`tfBmW0RRC1|FY^Ob^z=G07?Pq)&Kwi literal 0 HcmV?d00001 diff --git a/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/stable/prometheus-9.3.1.tgz b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/files/deploy/helm/helm-charts/stable/prometheus-9.3.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..3b1090b56333c0d9bfc3fe96a75026729802c25b GIT binary patch literal 24108 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 literal 0 HcmV?d00001 diff --git a/blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/install.yml new file mode 100644 index 0000000..5624146 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/install.yml @@ -0,0 +1,60 @@ +# +# 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. +# + +--- + +- name: Doing deployment setup for edge gallery + copy: + src: deploy + dest: /tmp/eg_helm-repo/ + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Helm repo index edgegallery + command: helm repo index edgegallery/ + args: + chdir: /tmp/eg_helm-repo/deploy/helm/helm-charts/ + +- name: Helm repo index stable + command: helm repo index stable/ + args: + chdir: /tmp/eg_helm-repo/deploy/helm/helm-charts/ + +- name: Changing permisiion + command: chmod -R 755 /tmp/eg_helm-repo + +- name: Creating helm repo + # yamllint disable rule:line-length + command: docker run --name helm-repo -v /tmp/eg_helm-repo/deploy/helm/helm-charts/:/usr/share/nginx/html:ro -d -p 8080:80 nginx:stable + args: + chdir: /tmp/eg_helm-repo/deploy/helm/helm-charts/ + +- name: Helm repo add edgegallery + # yamllint disable rule:line-length + command: helm repo add edgegallery http://{{ vardata.private_repo_ip.name}}:8080/edgegallery + args: + chdir: /tmp/eg_helm-repo/deploy/helm/helm-charts/ + +- name: Helm repo add stable + command: helm repo add stable http://{{ vardata.private_repo_ip.name}}:8080/stable + args: + chdir: /tmp/eg_helm-repo/deploy/helm/helm-charts/ + +- debug: + msg: "Helm repo created" diff --git a/blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/main.yml new file mode 100644 index 0000000..858c198 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/main.yml @@ -0,0 +1,25 @@ +# 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. +# + +--- + +# tasks file for eg_helm_repo_add +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/uninstall.yml new file mode 100644 index 0000000..65ea65e --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_helm-repo/tasks/uninstall.yml @@ -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. +# + +--- + +- name: Docker stop helm repo + command: docker stop helm-repo + ignore_errors: yes + no_log: True + +- name: Docker rm helm repo + command: docker rm helm-repo + ignore_errors: yes + no_log: True + +- name: Remove tmp folder + command: rm -rf /tmp/eg_helm-repo + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/install.yml new file mode 100644 index 0000000..0e728b9 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/install.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Install mecm-fe + # yamllint disable rule:line-length + command: helm install mecm-fe-edgegallery edgegallery/mecm-fe --set global.oauth2.authServerAddress=https://{{ ansible_host }}:{{vardata.usermgmt_port.name}} --set images.mecmFe.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/mecm-fe --set images.initservicecenter.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/curl --set images.mecmFe.tag={{vardata.eg_image_tag.name}} --set images.mecmFe.pullPolicy=IfNotPresent --set images.initservicecenter.pullPolicy=IfNotPresent --set global.ssl.enabled=true --set global.ssl.secretName=edgegallery-ssl-secret diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/main.yml new file mode 100644 index 0000000..b168173 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/main.yml @@ -0,0 +1,25 @@ +# +# 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. +# + +--- +# tasks file for eg_mecm-fe +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/uninstall.yml new file mode 100644 index 0000000..6c67b36 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-fe/tasks/uninstall.yml @@ -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. +# + +--- + +- name: Uninstall mecm fe + command: helm uninstall mecm-fe-edgegallery + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/files/deploy/conf/keys/postgres_init.sql b/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/files/deploy/conf/keys/postgres_init.sql new file mode 100644 index 0000000..76e94d6 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/files/deploy/conf/keys/postgres_init.sql @@ -0,0 +1,29 @@ +CREATE USER inventory WITH PASSWORD 'PASSWORD_VALUE' CREATEDB; +CREATE DATABASE inventorydb + WITH + OWNER = inventory + ENCODING = 'UTF8' + LC_COLLATE = 'en_US.utf8' + LC_CTYPE = 'en_US.utf8' + TABLESPACE = pg_default + CONNECTION LIMIT = -1; + +CREATE USER appo WITH PASSWORD 'PASSWORD_VALUE' CREATEDB; +CREATE DATABASE appodb + WITH + OWNER = appo + ENCODING = 'UTF8' + LC_COLLATE = 'en_US.utf8' + LC_CTYPE = 'en_US.utf8' + TABLESPACE = pg_default + CONNECTION LIMIT = -1; + +CREATE USER apm WITH PASSWORD 'PASSWORD_VALUE' CREATEDB; +CREATE DATABASE apmdb + WITH + OWNER = apm + ENCODING = 'UTF8' + LC_COLLATE = 'en_US.utf8' + LC_CTYPE = 'en_US.utf8' + TABLESPACE = pg_default + CONNECTION LIMIT = -1; diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/install.yml new file mode 100644 index 0000000..e6c2fc7 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/install.yml @@ -0,0 +1,73 @@ +# +# 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. +# + +--- + +- name: Doing deployment eg_mecm-meo setup for edge gallery eg_mecm-meo + copy: + src: deploy + dest: /tmp/eg_mecm-meo/ + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Replacing pwd sql + replace: + path: /tmp/eg_mecm-meo/deploy/conf/keys/postgres_init.sql + regexp: 'PASSWORD_VALUE' + replace: "{{ vardata.common_pwd.name }}" + +- name: Set a variable + ansible.builtin.set_fact: + comm_pwd: "{{ vardata.common_pwd.name }}" + +- name: Create mecm-ssl-secret with common pwd + # yamllint disable rule:line-length + command: kubectl create secret generic mecm-ssl-secret --from-file=keystore.p12=/tmp/ssl-eg-keys-certs/keystore.p12 --from-file=keystore.jks=/tmp/ssl-eg-keys-certs/keystore.jks --from-literal=keystorePassword={{ vardata.common_pwd.name}} --from-literal=keystoreType=PKCS12 --from-literal=keyAlias=edgegallery --from-literal=truststorePassword={{ vardata.common_pwd.name}} + # yamllint disable rule:line-length + when: comm_pwd != "" + +- name: Generates certificate mecm-ssl-secret + # yamllint disable rule:line-length + command: kubectl create secret generic mecm-ssl-secret --from-file=keystore.p12=/tmp/ssl-eg-keys-certs/keystore.p12 --from-file=keystore.jks=/tmp/ssl-eg-keys-certs/keystore.jks --from-literal=keystorePassword={{ vardata.mecm_meo_keystorePassword.name}} --from-literal=keystoreType=PKCS12 --from-literal=keyAlias=edgegallery --from-literal=truststorePassword={{ vardata.mecm_meo_truststorePassword.name}} + # yamllint disable rule:line-length + when: comm_pwd == "" + +- name: Create certificate edgegallery-mecm-secret with common pwd + # yamllint disable rule:line-length + command: kubectl create secret generic edgegallery-mecm-secret --from-file=postgres_init.sql=/tmp/eg_mecm-meo/deploy/conf/keys/postgres_init.sql --from-literal=postgresPassword={{ vardata.common_pwd.name}} --from-literal=postgresApmPassword={{ vardata.common_pwd.name}} --from-literal=postgresAppoPassword={{ vardata.common_pwd.name}} --from-literal=postgresInventoryPassword={{ vardata.common_pwd.name}} --from-literal=edgeRepoUserName={{ vardata.mecm_meo_edgeRepoUserName.name}} --from-literal=edgeRepoPassword={{ vardata.mecm_meo_edgeRepoPassword.name}} + # yamllint disable rule:line-length + args: + chdir: /tmp/eg_mecm-meo/deploy/ + when: comm_pwd != "" + +- name: Generates certificate edgegallery-mecm-secret + # yamllint disable rule:line-length + command: kubectl create secret generic edgegallery-mecm-secret --from-file=postgres_init.sql=/tmp/eg_mecm-meo/deploy/conf/keys/postgres_init.sql --from-literal=postgresPassword={{ vardata.mecm_meo_postgresPassword.name}} --from-literal=postgresApmPassword={{ vardata.mecm_meo_postgresApmPassword.name}} --from-literal=postgresAppoPassword={{ vardata.mecm_meo_postgresAppoPassword.name}} --from-literal=postgresInventoryPassword={{ vardata.mecm_meo_postgresInventoryPassword.name}} --from-literal=edgeRepoUserName={{ vardata.mecm_meo_edgeRepoUserName.name}} --from-literal=edgeRepoPassword={{ vardata.mecm_meo_edgeRepoPassword.name}} + # yamllint disable rule:line-length + args: + chdir: /tmp/eg_mecm-meo/deploy/ + when: comm_pwd == "" + +- name: Fs group value + shell: 'getent group docker | cut -d: -f3' + register: result + +- name: Helm install + # yamllint disable rule:line-length + command: helm install mecm-meo-edgegallery edgegallery/mecm-meo --set ssl.secretName=mecm-ssl-secret --set mecm.secretName=edgegallery-mecm-secret --set images.inventory.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/mecm-inventory --set images.appo.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/mecm-appo --set images.apm.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/mecm-apm --set images.postgres.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/postgres --set images.inventory.tag={{ vardata.eg_image_tag.name}} --set images.appo.tag={{ vardata.eg_image_tag.name}} --set images.apm.tag={{ vardata.eg_image_tag.name}} --set images.postgres.tag=12.3 --set images.inventory.pullPolicy=IfNotPresent --set images.appo.pullPolicy=IfNotPresent --set images.apm.pullPolicy=IfNotPresent --set images.postgres.pullPolicy=IfNotPresent --set mecm.docker.fsgroup="{{result.stdout}}" diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/main.yml new file mode 100644 index 0000000..06e1be4 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/main.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +# tasks file for eg_mecm-meo +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/uninstall.yml new file mode 100644 index 0000000..3bd6754 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/uninstall.yml @@ -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. +# + +--- + +- name: Uninstall mecm meo + command: helm uninstall mecm-meo-edgegallery + ignore_errors: yes + no_log: True + +- name: Delete mecm-ssl-secret and edgegallery-mecm-secret + command: kubectl delete secret mecm-ssl-secret edgegallery-mecm-secret + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/files/deploy/conf/keys/postgres_init.sql b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/files/deploy/conf/keys/postgres_init.sql new file mode 100644 index 0000000..0fcc8fc --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/files/deploy/conf/keys/postgres_init.sql @@ -0,0 +1,20 @@ +CREATE USER lcmcontroller WITH PASSWORD 'PASSWORD_VALUE' CREATEDB; +CREATE DATABASE lcmcontrollerdb + WITH + OWNER = lcmcontroller + ENCODING = 'UTF8' + LC_COLLATE = 'en_US.utf8' + LC_CTYPE = 'en_US.utf8' + TABLESPACE = pg_default + CONNECTION LIMIT = -1; + +CREATE USER k8splugin WITH PASSWORD 'PASSWORD_VALUE' CREATEDB; +CREATE DATABASE k8splugindb + WITH + OWNER = k8splugin + ENCODING = 'UTF8' + LC_COLLATE = 'en_US.utf8' + LC_CTYPE = 'en_US.utf8' + TABLESPACE = pg_default + CONNECTION LIMIT = -1; + diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/files/deploy/conf/manifest/mepm/mepm-service-account.yaml b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/files/deploy/conf/manifest/mepm/mepm-service-account.yaml new file mode 100644 index 0000000..9bf8e91 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/files/deploy/conf/manifest/mepm/mepm-service-account.yaml @@ -0,0 +1,30 @@ +# +# 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. +# +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: fabric8-rbac +subjects: + - kind: ServiceAccount + # Reference to upper's `metadata.name` + name: default + # Reference to upper's `metadata.namespace` + namespace: default +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/install.yml new file mode 100644 index 0000000..12a388c --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/install.yml @@ -0,0 +1,73 @@ +# +# 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. +# + +--- + +- name: Doing deployment eg_mecm-mepm setup for edge gallery eg_mecm-mepm + copy: + src: deploy + dest: /tmp/eg_mecm-mepm/ + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Set a variable + ansible.builtin.set_fact: + comm_pwd: "{{ vardata.common_pwd.name }}" + +- name: Replacing password + replace: + path: /tmp/eg_mecm-mepm/deploy/conf/keys/postgres_init.sql + regexp: 'PASSWORD_VALUE' + replace: "{{ vardata.common_pwd.name }}" + +- name: Create mecm-mepm-ssl-secret secret + # yamllint disable rule:line-length + command: kubectl create secret generic mecm-mepm-jwt-public-secret --from-file=publicKey=/tmp/ssl-eg-keys-certs/encryptedtls.key + # yamllint disable rule:line-length + args: + chdir: /tmp/ssl-eg-keys-certs/ + +- name: Create mecm-mepm-ssl-secret secret + # yamllint disable rule:line-length + command: kubectl create secret generic mecm-mepm-ssl-secret --from-file=server_tls.key=/tmp/ssl-eg-keys-certs/tls.key --from-file=server_tls.crt=/tmp/ssl-eg-keys-certs/tls.crt --from-file=ca.crt=/tmp/ssl-eg-keys-certs/ca.crt + # yamllint disable rule:line-length + args: + chdir: /tmp/ssl-eg-keys-certs/ + +- name: Create edgegallery-mepm-secret secret with common pwd + # yamllint disable rule:line-length + command: kubectl create secret generic edgegallery-mepm-secret --from-file=postgres_init.sql=/tmp/eg_mecm-mepm/deploy/conf/keys/postgres_init.sql --from-literal=postgresPassword={{ vardata.common_pwd.name}} --from-literal=postgresLcmCntlrPassword={{ vardata.common_pwd.name}} --from-literal=postgresk8sPluginPassword={{ vardata.common_pwd.name}} + # yamllint disable rule:line-length + when: comm_pwd != "" + +- name: Create edgegallery-mepm-secret secret + # yamllint disable rule:line-length + command: kubectl create secret generic edgegallery-mepm-secret --from-file=postgres_init.sql=/tmp/eg_mecm-mepm/deploy/conf/keys/postgres_init.sql --from-literal=postgresPassword={{ vardata.mecm_mepm_postgresPassword.name}} --from-literal=postgresLcmCntlrPassword={{ vardata.mecm_mepm_postgresLcmCntlrPassword.name}} --from-literal=postgresk8sPluginPassword={{ vardata.mecm_mepm_postgresk8sPluginPassword.name}} + # yamllint disable rule:line-length + when: comm_pwd == "" + +- name: Create mepm service account + command: kubectl apply -f /tmp/eg_mecm-mepm/deploy/conf/manifest/mepm/mepm-service-account.yaml + args: + chdir: /tmp/eg_mecm-mepm/deploy/ + +- name: Install mecm-mepm + # yamllint disable rule:line-length + command: helm install mecm-mepm-edgegaller edgegallery/mecm-mepm --set jwt.publicKeySecretName=mecm-mepm-jwt-public-secret --set mepm.secretName=edgegallery-mepm-secret --set ssl.secretName=mecm-mepm-ssl-secret --set images.lcmcontroller.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/mecm-applcm --set images.k8splugin.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/mecm-applcm-k8splugin --set images.postgres.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/postgres --set images.lcmcontroller.tag={{ vardata.eg_image_tag.name}} --set images.k8splugin.tag={{ vardata.eg_image_tag.name}} --set images.postgres.tag=12.3 --set images.lcmcontroller.pullPolicy=IfNotPresent --set images.k8splugin.pullPolicy=IfNotPresent --set images.postgres.pullPolicy=IfNotPresent + # yamllint disable rule:line-length diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/main.yml new file mode 100644 index 0000000..7faf1bd --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/main.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +# tasks file for eg_mecm-mepm +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/uninstall.yml new file mode 100644 index 0000000..699ef18 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/uninstall.yml @@ -0,0 +1,35 @@ +# +# 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. +# + +--- + +- name: Delete mecm-mepm secret + command: helm uninstall mecm-mepm-edgegallery + ignore_errors: yes + no_log: True + +- name: Mecm mepm jwt delete + # yamllint disable rule:line-length + command: kubectl delete secret mecm-mepm-jwt-public-secret mecm-mepm-ssl-secret edgegallery-mepm-secret + # yamllint disable rule:line-length + ignore_errors: yes + no_log: True + +- name: Delete mep-service-account + # yamllint disable rule:line-length + command: kubectl delete -f /tmp/eg_mecm-mepm/deploy/conf/manifest/mepm/mepm-service-account.yaml + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/config-map.yaml b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/config-map.yaml new file mode 100644 index 0000000..f913463 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/config-map.yaml @@ -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. +# +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: metallb-system + name: config +data: + config: | + address-pools: + - name: address-pool-1 + protocol: layer2 + addresses: + - 192.168.100.120/32 diff --git a/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/metallb.yaml b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/metallb.yaml new file mode 100644 index 0000000..8594115 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/metallb.yaml @@ -0,0 +1,406 @@ +# +# 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. +# +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + labels: + app: metallb + name: controller + namespace: metallb-system +spec: + allowPrivilegeEscalation: false + allowedCapabilities: [] + allowedHostPaths: [] + defaultAddCapabilities: [] + defaultAllowPrivilegeEscalation: false + fsGroup: + ranges: + - max: 65535 + min: 1 + rule: MustRunAs + hostIPC: false + hostNetwork: false + hostPID: false + privileged: false + readOnlyRootFilesystem: true + requiredDropCapabilities: + - ALL + runAsUser: + ranges: + - max: 65535 + min: 1 + rule: MustRunAs + seLinux: + rule: RunAsAny + supplementalGroups: + ranges: + - max: 65535 + min: 1 + rule: MustRunAs + volumes: + - configMap + - secret + - emptyDir +--- +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + labels: + app: metallb + name: speaker + namespace: metallb-system +spec: + allowPrivilegeEscalation: false + allowedCapabilities: + - NET_ADMIN + - NET_RAW + - SYS_ADMIN + allowedHostPaths: [] + defaultAddCapabilities: [] + defaultAllowPrivilegeEscalation: false + fsGroup: + rule: RunAsAny + hostIPC: false + hostNetwork: true + hostPID: false + hostPorts: + - max: 7472 + min: 7472 + privileged: true + readOnlyRootFilesystem: true + requiredDropCapabilities: + - ALL + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - configMap + - secret + - emptyDir +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app: metallb + name: controller + namespace: metallb-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app: metallb + name: speaker + namespace: metallb-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app: metallb + name: metallb-system:controller +rules: + - apiGroups: + - '' + resources: + - services + verbs: + - get + - list + - watch + - update + - apiGroups: + - '' + resources: + - services/status + verbs: + - update + - apiGroups: + - '' + resources: + - events + verbs: + - create + - patch + - apiGroups: + - policy + resourceNames: + - controller + resources: + - podsecuritypolicies + verbs: + - use +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app: metallb + name: metallb-system:speaker +rules: + - apiGroups: + - '' + resources: + - services + - endpoints + - nodes + verbs: + - get + - list + - watch + - apiGroups: + - '' + resources: + - events + verbs: + - create + - patch + - apiGroups: + - policy + resourceNames: + - speaker + resources: + - podsecuritypolicies + verbs: + - use +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app: metallb + name: config-watcher + namespace: metallb-system +rules: + - apiGroups: + - '' + resources: + - configmaps + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app: metallb + name: pod-lister + namespace: metallb-system +rules: + - apiGroups: + - '' + resources: + - pods + verbs: + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app: metallb + name: metallb-system:controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: metallb-system:controller +subjects: + - kind: ServiceAccount + name: controller + namespace: metallb-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app: metallb + name: metallb-system:speaker +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: metallb-system:speaker +subjects: + - kind: ServiceAccount + name: speaker + namespace: metallb-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app: metallb + name: config-watcher + namespace: metallb-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: config-watcher +subjects: + - kind: ServiceAccount + name: controller + - kind: ServiceAccount + name: speaker +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app: metallb + name: pod-lister + namespace: metallb-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: pod-lister +subjects: + - kind: ServiceAccount + name: speaker +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + labels: + app: metallb + component: speaker + name: speaker + namespace: metallb-system +spec: + selector: + matchLabels: + app: metallb + component: speaker + template: + metadata: + annotations: + prometheus.io/port: '7472' + prometheus.io/scrape: 'true' + labels: + app: metallb + component: speaker + spec: + containers: + - args: + - --port=7472 + - --config=config + env: + - name: METALLB_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: METALLB_HOST + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: METALLB_ML_BIND_ADDR + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: METALLB_ML_LABELS + value: "app=metallb,component=speaker" + - name: METALLB_ML_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: METALLB_ML_SECRET_KEY + valueFrom: + secretKeyRef: + name: memberlist + key: secretkey + image: metallb/speaker:v0.9.3 + imagePullPolicy: IfNotPresent + name: speaker + ports: + - containerPort: 7472 + name: monitoring + resources: + limits: + cpu: 100m + memory: 100Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_ADMIN + drop: + - ALL + readOnlyRootFilesystem: true + hostNetwork: true + nodeSelector: + beta.kubernetes.io/os: linux + serviceAccountName: speaker + terminationGracePeriodSeconds: 2 + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: metallb + component: controller + name: controller + namespace: metallb-system +spec: + revisionHistoryLimit: 3 + selector: + matchLabels: + app: metallb + component: controller + template: + metadata: + annotations: + prometheus.io/port: '7472' + prometheus.io/scrape: 'true' + labels: + app: metallb + component: controller + spec: + containers: + - args: + - --port=7472 + - --config=config + image: metallb/controller:v0.9.3 + imagePullPolicy: IfNotPresent + name: controller + ports: + - containerPort: 7472 + name: monitoring + resources: + limits: + cpu: 100m + memory: 100Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - all + readOnlyRootFilesystem: true + nodeSelector: + beta.kubernetes.io/os: linux + securityContext: + runAsNonRoot: true + runAsUser: 65534 + serviceAccountName: controller + terminationGracePeriodSeconds: 0 diff --git a/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/namespace.yaml b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/namespace.yaml new file mode 100644 index 0000000..d090488 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/metallb/namespace.yaml @@ -0,0 +1,21 @@ +# +# 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. +# +apiVersion: v1 +kind: Namespace +metadata: + name: metallb-system + labels: + app: metallb diff --git a/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/eg-sp-controller.yaml b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/eg-sp-controller.yaml new file mode 100644 index 0000000..95fd455 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/eg-sp-controller.yaml @@ -0,0 +1,28 @@ +# +# 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. +# +kind: Pod +apiVersion: v1 +metadata: + name: edgegallery-secondary-ep-controller + namespace: kube-system +spec: + serviceAccount: edgegallery-secondary-ep-controller + containers: + - name: edgegallery-secondary-ep-controller + image: edgegallery/edgegallery-secondary-ep-controller:latest + imagePullPolicy: IfNotPresent + command: ["/bin/sh", "-c", "--"] + args: ["edgegallery-secondary-ep-controller"] diff --git a/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/eg-sp-rbac.yaml b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/eg-sp-rbac.yaml new file mode 100644 index 0000000..aa0fa63 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/eg-sp-rbac.yaml @@ -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. +# + +kind: ServiceAccount +apiVersion: v1 +metadata: + name: edgegallery-secondary-ep-controller + namespace: kube-system +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: multi-ip-controller +rules: + - apiGroups: [""] + resources: ["services", "pods"] + verbs: ["get", "watch", "list"] + - apiGroups: [""] + resources: ["endpoints", "events"] + verbs: ["*"] + - apiGroups: ["k8s.cni.cncf.io"] + resources: ["network-attachment-definitions"] + verbs: ["*"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: watch-update-secondary-endpoints +subjects: + - kind: ServiceAccount + name: edgegallery-secondary-ep-controller + namespace: kube-system +roleRef: + kind: ClusterRole + name: multi-ip-controller + apiGroup: rbac.authorization.k8s.io diff --git a/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/multus.yaml b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/multus.yaml new file mode 100644 index 0000000..20a6016 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mep/files/deploy/conf/edge/network-isolation/multus.yaml @@ -0,0 +1,358 @@ +# +# 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. +# + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: network-attachment-definitions.k8s.cni.cncf.io +spec: + group: k8s.cni.cncf.io + scope: Namespaced + names: + plural: network-attachment-definitions + singular: network-attachment-definition + kind: NetworkAttachmentDefinition + shortNames: + - net-attach-def + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + # yamllint disable rule:line-length + description: 'NetworkAttachmentDefinition is a CRD schema specified by the Network Plumbing + Working Group to express the intent for attaching pods to one or more logical or physical + networks. More information available at: https://github.com/k8snetworkplumbingwg/multi-net-spec' + # yamllint disable rule:line-length + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this represen + tation of an object. Servers should convert recognized schemas to the + latest internal value, and may reject unrecognized values. More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: 'NetworkAttachmentDefinition spec defines the desired state of a network attachment' + type: object + properties: + config: + description: 'NetworkAttachmentDefinition config is a JSON-formatted CNI configuration' + type: string +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: multus +rules: + - apiGroups: ["k8s.cni.cncf.io"] + resources: + - '*' + verbs: + - '*' + - apiGroups: + - "" + resources: + - pods + - pods/status + verbs: + - get + - update + - apiGroups: + - "" + - events.k8s.io + resources: + - events + verbs: + - create + - patch + - update +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: multus +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: multus +subjects: + - kind: ServiceAccount + name: multus + namespace: kube-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: multus + namespace: kube-system +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: multus-cni-config + namespace: kube-system + labels: + tier: node + app: multus +data: + # NOTE: If you'd prefer to manually apply a configuration file, you may create one here. + # In the case you'd like to customize the Multus installation, you should change the arguments to the Multus pod + # change the "args" line below from + # - "--multus-conf-file=auto" + # to: + # "--multus-conf-file=/tmp/multus-conf/70-multus.conf" + # Additionally -- you should ensure that the name "70-multus.conf" is the alphabetically first name in the + # /etc/cni/net.d/ directory on each node, otherwise, it will not be used by the Kubelet. + cni-conf.json: | + { + "name": "multus-cni-network", + "type": "multus", + "capabilities": { + "portMappings": true + }, + "delegates": [ + { + "cniVersion": "0.3.1", + "name": "default-cni-network", + "plugins": [ + { + "type": "flannel", + "name": "flannel.1", + "delegate": { + "isDefaultGateway": true, + "hairpinMode": true + } + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + } + ] + } + ], + "kubeconfig": "/etc/cni/net.d/multus.d/multus.kubeconfig" + } +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: kube-multus-ds-amd64 + namespace: kube-system + labels: + tier: node + app: multus + name: multus +spec: + selector: + matchLabels: + name: multus + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + tier: node + app: multus + name: multus + spec: + hostNetwork: true + nodeSelector: + kubernetes.io/arch: amd64 + tolerations: + - operator: Exists + effect: NoSchedule + serviceAccountName: multus + containers: + - name: kube-multus + image: docker.io/nfvpe/multus:stable + command: ["/entrypoint.sh"] + args: + - "--multus-conf-file=auto" + - "--cni-version=0.3.1" + resources: + requests: + cpu: "100m" + memory: "50Mi" + limits: + cpu: "100m" + memory: "50Mi" + securityContext: + privileged: true + volumeMounts: + - name: cni + mountPath: /host/etc/cni/net.d + - name: cnibin + mountPath: /host/opt/cni/bin + - name: multus-cfg + mountPath: /tmp/multus-conf + volumes: + - name: cni + hostPath: + path: /etc/cni/net.d + - name: cnibin + hostPath: + path: /opt/cni/bin + - name: multus-cfg + configMap: + name: multus-cni-config + items: + - key: cni-conf.json + path: 70-multus.conf +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: kube-multus-ds-ppc64le + namespace: kube-system + labels: + tier: node + app: multus + name: multus +spec: + selector: + matchLabels: + name: multus + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + tier: node + app: multus + name: multus + spec: + hostNetwork: true + nodeSelector: + kubernetes.io/arch: ppc64le + tolerations: + - operator: Exists + effect: NoSchedule + serviceAccountName: multus + containers: + - name: kube-multus + # ppc64le support requires multus:latest for now. support 3.3 or later. + image: docker.io/nfvpe/multus:stable-ppc64le + command: ["/entrypoint.sh"] + args: + - "--multus-conf-file=auto" + - "--cni-version=0.3.1" + resources: + requests: + cpu: "100m" + memory: "90Mi" + limits: + cpu: "100m" + memory: "90Mi" + securityContext: + privileged: true + volumeMounts: + - name: cni + mountPath: /host/etc/cni/net.d + - name: cnibin + mountPath: /host/opt/cni/bin + - name: multus-cfg + mountPath: /tmp/multus-conf + volumes: + - name: cni + hostPath: + path: /etc/cni/net.d + - name: cnibin + hostPath: + path: /opt/cni/bin + - name: multus-cfg + configMap: + name: multus-cni-config + items: + - key: cni-conf.json + path: 70-multus.conf +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: kube-multus-ds-arm64v8 + namespace: kube-system + labels: + tier: node + app: multus + name: multus +spec: + selector: + matchLabels: + name: multus + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + tier: node + app: multus + name: multus + spec: + hostNetwork: true + nodeSelector: + kubernetes.io/arch: arm64 + tolerations: + - operator: Exists + effect: NoSchedule + serviceAccountName: multus + containers: + - name: kube-multus + image: docker.io/nfvpe/multus:stable-arm64v8 + command: ["/entrypoint.sh"] + args: + - "--multus-conf-file=auto" + - "--cni-version=0.3.1" + resources: + requests: + cpu: "100m" + memory: "90Mi" + limits: + cpu: "100m" + memory: "90Mi" + securityContext: + privileged: true + volumeMounts: + - name: cni + mountPath: /host/etc/cni/net.d + - name: cnibin + mountPath: /host/opt/cni/bin + - name: multus-cfg + mountPath: /tmp/multus-conf + volumes: + - name: cni + hostPath: + path: /etc/cni/net.d + - name: cnibin + hostPath: + path: /opt/cni/bin + - name: multus-cfg + configMap: + name: multus-cni-config + items: + - key: cni-conf.json + path: 70-multus.conf diff --git a/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/install.yml new file mode 100644 index 0000000..f33094d --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/install.yml @@ -0,0 +1,273 @@ +# 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. +# + +--- + +- name: Doing deployment setup for edge gallery + copy: + src: deploy + dest: /tmp/eg_mep/ + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Set a variable + ansible.builtin.set_fact: + comm_pwd: "{{ vardata.common_pwd.name }}" + +- name: Remove old dir + command: rm -rf /tmp/.mep_tmp_cer + args: + chdir: /tmp/ + +- name: Make dir + command: mkdir -p /tmp/.mep_tmp_cer + args: + chdir: /tmp/ + +- name: Openssl genrsa + command: openssl genrsa -out ca.key 2048 + args: + chdir: /tmp/.mep_tmp_cer/ + +- name: Opnessl req + # yamllint disable rule:line-length + command: openssl req -new -key ca.key -subj /C=CN/ST=Peking/L=Beijing/O=edgegallery/CN=edgegallery -out ca.csr + # yamllint disable rule:line-length + args: + chdir: /tmp/.mep_tmp_cer/ + +- name: Sing key with ca key and ca crt + # yamllint disable rule:line-length + command: openssl x509 -req -days 365 -in ca.csr -extensions v3_ca -signkey ca.key -out ca.crt + # yamllint disable rule:line-length + args: + chdir: /tmp/.mep_tmp_cer/ + +- name: Openssl genrsa + command: openssl genrsa -out mepserver_tls.key 2048 + args: + chdir: /tmp/.mep_tmp_cer/ + +- name: Openssl rsa mep tls with common pwd + # yamllint disable rule:line-length + command: openssl rsa -in /tmp/.mep_tmp_cer/mepserver_tls.key -aes256 -passout pass:{{ vardata.common_pwd.name}} -out /tmp/.mep_tmp_cer/mepserver_encryptedtls.key + # yamllint disable rule:line-length + when: comm_pwd != "" + +- name: Openssl rsa mep tls + # yamllint disable rule:line-length + command: openssl rsa -in /tmp/.mep_tmp_cer/mepserver_tls.key -aes256 -passout pass:{{ vardata.mep_cert_pwd.name}} -out /tmp/.mep_tmp_cer/mepserver_encryptedtls.key + # yamllint disable rule:line-length + when: comm_pwd == "" + +- name: Openssl req new key mepserver tls key + # yamllint disable rule:line-length + command: openssl req -new -key mepserver_tls.key -subj /C=CN/ST=Beijing/L=Beijing/O=edgegallery/CN=edgegallery -out mepserver_tls.csr + # yamllint disable rule:line-length + args: + chdir: /tmp/.mep_tmp_cer/ + +- name: Openssl mepserver tls csr + # yamllint disable rule:line-length + command: openssl x509 -req -in mepserver_tls.csr -extensions v3_req -CA ca.crt -CAkey ca.key -CAcreateserial -out mepserver_tls.crt + # yamllint disable rule:line-length + args: + chdir: /tmp/.mep_tmp_cer/ + +- name: Openssl genrsa out + command: openssl genrsa -out jwt_privatekey 2048 + args: + chdir: /tmp/.mep_tmp_cer/ + +- name: Openssl rsa jwt privatekey + command: openssl rsa -in jwt_privatekey -pubout -out jwt_publickey + args: + chdir: /tmp/.mep_tmp_cer/ + +- name: Openssl rsa in jwt with common pwd + # yamllint disable rule:line-length + command: openssl rsa -in /tmp/.mep_tmp_cer/jwt_privatekey -aes256 -passout pass:{{ vardata.common_pwd.name}} -out /tmp/.mep_tmp_cer/jwt_encrypted_privatekey + ignore_errors: yes + no_log: True + # yamllint disable rule:line-length + when: comm_pwd != "" + +- name: Openssl rsa in jwt + # yamllint disable rule:line-length + command: openssl rsa -in /tmp/.mep_tmp_cer/jwt_privatekey -aes256 -passout pass:{{ vardata.mep_cert_pwd.name}} -out /tmp/.mep_tmp_cer/jwt_encrypted_privatekey + # yamllint disable rule:line-length + ignore_errors: yes + no_log: True + when: comm_pwd == "" + +- name: Create mep namespace + command: kubectl create ns mep + args: + chdir: /tmp/ + +- name: Create generic pg secret with common pwd + # yamllint disable rule:line-length + command: kubectl -n mep create secret generic pg-secret --from-literal=pg_admin_pwd={{ vardata.common_pwd.name}} --from-literal=kong_pg_pwd={{ vardata.mep_kong_pg_pwd.name}} + --from-file=server.key=/tmp/.mep_tmp_cer/mepserver_tls.key --from-file=server.crt=/tmp/.mep_tmp_cer/mepserver_tls.crt + ignore_errors: yes + no_log: True + # yamllint disable rule:line-length + when: comm_pwd != "" + +- name: Create generic pg secret + # yamllint disable rule:line-length + command: kubectl -n mep create secret generic pg-secret --from-literal=pg_admin_pwd={{ vardata.mep_pg_admin_pwd.name}} --from-literal=kong_pg_pwd={{ vardata.mep_kong_pg_pwd.name}} + --from-file=server.key=/tmp/.mep_tmp_cer/mepserver_tls.key --from-file=server.crt=/tmp/.mep_tmp_cer/mepserver_tls.crt + ignore_errors: yes + no_log: True + # yamllint disable rule:line-length + when: comm_pwd == "" + +- name: Create mep generic for mep ssl with common pwd + # yamllint disable rule:line-length + command: kubectl -n mep create secret generic mep-ssl --from-literal=cert_pwd={{ vardata.common_pwd.name}} --from-file=server.cer=/tmp/.mep_tmp_cer/mepserver_tls.crt + --from-file=server_key.pem=/tmp/.mep_tmp_cer/mepserver_encryptedtls.key --from-file=trust.cer=/tmp/.mep_tmp_cer/ca.crt + ignore_errors: yes + no_log: True + # yamllint disable rule:line-length + when: comm_pwd != "" + +- name: Create mep generic for mep ssl + # yamllint disable rule:line-length + command: kubectl -n mep create secret generic mep-ssl --from-literal=cert_pwd={{ vardata.mep_cert_pwd.name}} --from-file=server.cer=/tmp/.mep_tmp_cer/mepserver_tls.crt + --from-file=server_key.pem=/tmp/.mep_tmp_cer/mepserver_encryptedtls.key --from-file=trust.cer=/tmp/.mep_tmp_cer/ca.crt + # yamllint disable rule:line-length + when: comm_pwd == "" + +- name: Create mep seret generic + # yamllint disable rule:line-length + command: kubectl -n mep create secret generic mepauth-secret --from-file=server.crt=/tmp/.mep_tmp_cer/mepserver_tls.crt --from-file=server.key=/tmp/.mep_tmp_cer/mepserver_tls.key + --from-file=ca.crt=/tmp/.mep_tmp_cer/ca.crt --from-file=jwt_publickey=/tmp/.mep_tmp_cer/jwt_publickey --from-file=jwt_encrypted_privatekey=/tmp/.mep_tmp_cer/jwt_encrypted_privatekey + # yamllint disable rule:line-length + args: + chdir: /tmp/ + +- name: Remove directory + command: rm -rf /tmp/.mep_tmp_cer + args: + chdir: /tmp/ + +- debug: + msg: Deploy_dns_metallb execution start + +- name: Eg_Mep deployment execution of namesapce + command: kubectl apply -f /tmp/eg_mep/deploy/conf/edge/metallb/namespace.yaml + args: + chdir: /tmp/eg_mep/deploy/ + +- name: Eg_Mep deployment execution of metallb + command: kubectl apply -f /tmp/eg_mep/deploy/conf/edge/metallb/metallb.yaml + args: + chdir: /tmp/eg_mep/deploy/ + +- name: Eg_Mep deployment create secret + # yamllint disable rule:line-length + command: kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)" + # yamllint disable rule:line-length + args: + chdir: /tmp/eg_mep/deploy/ + +- name: Eg_Mep deployment execution of config-mep + command: kubectl apply -f /tmp/eg_mep/deploy/conf/edge/metallb/config-map.yaml + args: + chdir: /tmp/eg_mep/deploy/ + +- debug: + msg: Deploy_network_isolation_multus execution start + +- name: Running multus yaml files + command: kubectl apply -f /tmp/eg_mep/deploy/conf/edge/network-isolation/multus.yaml + args: + chdir: /tmp/eg_mep/deploy/ + +- name: Running eg-sp-rbac yaml files + command: kubectl apply -f /tmp/eg_mep/deploy/conf/edge/network-isolation/eg-sp-rbac.yaml + args: + chdir: /tmp/eg_mep/deploy/ + +- name: Replacing image + replace: + path: /tmp/eg_mep/deploy/conf/edge/network-isolation/eg-sp-controller.yaml + regexp: 'edgegallery/edgegallery-secondary-ep-controller:latest' + replace: "{{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/edgegallery-secondary-ep-controller:latest" + +- name: Running eg-sp-controller yaml files + # yamllint disable rule:line-length + command: kubectl apply -f /tmp/eg_mep/deploy/conf/edge/network-isolation/eg-sp-controller.yaml + args: + chdir: /tmp/eg_mep/deploy/ + +- debug: + msg: Setup_interfaces execution start + +- name: Link eg mep macvlan + # yamllint disable rule:line-length + command: ip link add eg-mp1 link {{ vardata.edge_management_interface.name}} type macvlan mode bridge + args: + chdir: /tmp/eg_mep/deploy/ + ignore_errors: yes + no_log: True + +- name: Link eg mep macvlan + command: ip addr add {{ vardata.eg-management-address.name}} dev eg-mp1 + args: + chdir: /tmp/eg_mep/deploy/ + ignore_errors: yes + no_log: True + +- name: Link eg me1 up + command: ip link set dev eg-mp1 up + args: + chdir: /tmp/eg_mep/deploy/ + ignore_errors: yes + no_log: True + +- name: Link eg eg mm5 with eth1 + # yamllint disable rule:line-length + command: ip link add eg-mm5 link {{ vardata.edge_dataplane_interface.name}} type macvlan mode bridge + args: + chdir: /tmp/eg_mep/deploy/ + ignore_errors: yes + no_log: True + +- name: Link eg eg mm5 ip addr + command: ip addr add {{ vardata.eg-dataplane-address.name}} dev eg-mm5 + args: + chdir: /tmp/eg_mep/deploy/ + ignore_errors: yes + no_log: True + +- name: Link eg eg mm5 set dev + command: ip link set dev eg-mm5 up + args: + chdir: /tmp/eg_mep/deploy/ + ignore_errors: yes + no_log: True + +- debug: + msg: Pull helm repo start + +- name: Edge gallery mep installation pull chart and image + # yamllint disable rule:line-length + command: helm install mep-edgegallery edgegallery/mep --set networkIsolation.phyInterface.mp1={{ vardata.edge_management_interface.name}} --set networkIsolation.phyInterface.mm5={{ vardata.edge_dataplane_interface.name}} --set images.mep.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/mep --set images.mepauth.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/mepauth --set images.dns.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/mep-dns-server --set images.kong.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/kong --set images.postgres.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/postgres --set images.mep.tag={{ vardata.eg_image_tag.name}} --set images.mepauth.tag={{ vardata.eg_image_tag.name}} --set images.dns.tag={{ vardata.eg_image_tag.name}} --set images.mep.pullPolicy=IfNotPresent --set images.mepauth.pullPolicy=IfNotPresent --set images.dns.pullPolicy=IfNotPresent --set images.kong.pullPolicy=IfNotPresent --set images.postgres.pullPolicy=IfNotPresent --set ssl.secretName=mep-ssl + # yamllint disable rule:line-length diff --git a/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/main.yml new file mode 100644 index 0000000..70416a7 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/main.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +# tasks file for eg_mep +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/uninstall.yml new file mode 100644 index 0000000..fba5576 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/uninstall.yml @@ -0,0 +1,107 @@ +# 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. +# + +--- + +- name: Uninstall ssl config mep helm chart + command: helm uninstall mep-edgegallery + ignore_errors: yes + no_log: True + +- name: Delete ssl config pg secret + command: kubectl delete secret pg-secret -n mep + ignore_errors: yes + no_log: True + +- name: Delete ssl config mep ssl + command: kubectl delete secret mep-ssl -n mep + ignore_errors: yes + no_log: True + +- name: Delete ssl config mep mep auth + command: kubectl delete secret mepauth-secret -n mep + ignore_errors: yes + no_log: True + +- name: Delete ssl config namesapce mep + command: kubectl delete ns mep + ignore_errors: yes + no_log: True + +- name: Delete network isolation multus eg sp controller + # yamllint disable rule:line-length + command: kubectl delete -f /tmp/eg_mep/deploy/conf/edge/network-isolation/eg-sp-controller.yaml + ignore_errors: yes + no_log: True + +- name: Delete network isolation multus eg sp rbac + # yamllint disable rule:line-length + command: kubectl delete -f /tmp/eg_mep/deploy/conf/edge/network-isolation/eg-sp-rbac.yaml + ignore_errors: yes + no_log: True + +- name: Delete network isolation multus + # yamllint disable rule:line-length + command: kubectl delete -f /tmp/eg_mep/deploy/conf/edge/network-isolation/multus.yaml + ignore_errors: yes + no_log: True + +- name: Delete network isolation eg mp1 + command: ip link set dev eg-mp1 down + ignore_errors: yes + no_log: True + +- name: Delete nnetwork isolation eg mp1 link + command: ip link delete eg-mp1 + ignore_errors: yes + no_log: True + +- name: Delete network isolation eg mm5 + command: ip link set dev eg-mm5 down + ignore_errors: yes + no_log: True + +- name: Delete network isolation eg mm5 link + command: ip link delete eg-mm5 + ignore_errors: yes + no_log: True + +- name: Delete network isolation multus rm + command: rm -rf /opt/cni/bin/multus + ignore_errors: yes + no_log: True + +- name: Uninstall dns metallb config mep + # yamllint disable rule:line-length + command: kubectl delete -f /tmp/eg_mep/deploy/conf/edge/metallb/config-map.yaml + ignore_errors: yes + no_log: True + +- name: Delete dns metallb + # yamllint disable rule:line-length + command: kubectl delete -f /tmp/eg_mep/deploy/conf/edge/metallb/metallb.yaml + ignore_errors: yes + no_log: True + +- name: Delete dns metallb namespace + # yamllint disable rule:line-length + command: kubectl delete -f /tmp/eg_mep/deploy/conf/edge/metallb/namespace.yaml + ignore_errors: yes + no_log: True + +- name: Delete dns namesapce metallb + command: kubectl delete secret memberlist -n metallb-system + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/eg_prerequisite/files/deploy/eg_daemon.sh b/blueprints/iotgateway/playbooks/roles/eg_prerequisite/files/deploy/eg_daemon.sh new file mode 100644 index 0000000..61842b2 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_prerequisite/files/deploy/eg_daemon.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +function _help_insecure_registry() +{ + grep -i "insecure-registries" /etc/docker/daemon.json | grep "REGISTRIES_IP:REGISTRIES_PORT" >/dev/null 2>&1 + if [ $? != 0 ]; then + mkdir -p /etc/docker +cat </dev/null + if [ $? != 0 ]; then + cd "$TARBALL_PATH"/registry + docker load --input registry-2.tar.gz + docker run -d -p 5000:5000 --restart=always --name registry registry:2 + fi +} + +function _load_swr_images_and_push_to_private_registry() +{ + IP=REGISTRIES_IP + PORT="REGISTRIES_PORT" + cd "$TARBALL_PATH"/eg_swr_images + + for f in *.tar.gz; + do + cat $f | docker load + IMAGE_NAME=`echo $f|rev|cut -c8-|rev|sed -e "s/\#/:/g" | sed -e "s/\@/\//g"`; + docker image tag $IMAGE_NAME $IP:$PORT/$IMAGE_NAME + docker push $IP:$PORT/$IMAGE_NAME + done +} + +############################################################## +############################################ +function main(){ + _load_and_run_docker_registry + _load_swr_images_and_push_to_private_registry +} +######################################### +#skip main in case of source + main $@ +###################### diff --git a/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/install.yml new file mode 100644 index 0000000..443365d --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/install.yml @@ -0,0 +1,106 @@ +# +# 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. +# + +--- + +- name: Doing deployment setup for edge gallery + copy: + src: deploy + dest: /tmp/eg_registry/ + mode: 750 + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Make dir for arm images + command: mkdir -p /tmp/eg_registry/armtarball + args: + chdir: /tmp/ + +- name: Set a variable + ansible.builtin.set_fact: + processor: "{{ vardata.master_edge_processor.name}}" + +- name: Downloading based on master_edge_processor value x86_64 tarball + command: wget http://release.edgegallery.org/x86/all/0.9.tar.gz + args: + chdir: /tmp/eg_registry/deploy/ + when: processor == "x86_64" + +- name: Download 0.9 tar arms based on master_edge_processor value + command: wget http://release.edgegallery.org/arm64/all/0.9.tar.gz + args: + chdir: /tmp/eg_registry/armtarball/ + when: ansible_architecture == 'aarch64' and processor == "x86_64" + +- name: Download 0.9 tar arms + command: wget http://release.edgegallery.org/arm64/all/0.9.tar.gz + args: + chdir: /tmp/eg_registry/deploy/ + when: ansible_architecture == 'aarch64' and processor != "x86_64" + +- name: Download 0.9 tar x86 + command: wget http://release.edgegallery.org/x86/all/0.9.tar.gz + args: + chdir: /tmp/eg_registry/deploy/ + when: ansible_architecture == 'x86_64' + +- name: Untar the donwloaded tar + command: tar -zxf 0.9.tar.gz + args: + chdir: /tmp/eg_registry/deploy/ + +- name: Untar the donwloaded tar + command: tar -zxf 0.9.tar.gz + args: + chdir: /tmp/eg_registry/armtarball/ + when: processor == "x86_64" + +- name: Registry replaced for cross playform + command: rm -rf /tmp/eg_registry/deploy/registry + when: processor == "x86_64" + +- name: Docker image replaced for cross playform + command: rm -rf /tmp/eg_registry/deploy/eg_swr_images/nginx#stable.tar.gz + when: processor == "x86_64" + +- name: Copy registry from x86 tarball + command: cp -r /tmp/eg_registry/armtarball/registry /tmp/eg_registry/deploy/ + when: processor == "x86_64" + +- name: Copy docker image from x86 tarball + # yamllint disable rule:line-length + command: cp -r /tmp/eg_registry/armtarball/eg_swr_images/nginx#stable.tar.gz /tmp/eg_registry/deploy/eg_swr_images/ + # yamllint disable rule:line-length + when: processor == "x86_64" + +- name: Replacing private ip + replace: + path: /tmp/eg_registry/deploy/load-images.sh + regexp: 'REGISTRIES_IP' + replace: "{{ vardata.private_repo_ip.name }}" + +- name: Replacing private port + replace: + path: /tmp/eg_registry/deploy/load-images.sh + regexp: 'REGISTRIES_PORT' + replace: "{{ vardata.docker_registry_port.name }}" + +- name: Execute the script + shell: + cmd: /tmp/eg_registry/deploy/load-images.sh diff --git a/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/main.yml new file mode 100644 index 0000000..81aba29 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/main.yml @@ -0,0 +1,25 @@ +# 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. +# + +--- + +# tasks file for eg_load-iamges +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/uninstall.yml new file mode 100644 index 0000000..111b1e3 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/uninstall.yml @@ -0,0 +1,32 @@ +# +# 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. +# + +--- + +- name: Stop registry + command: docker stop registry + ignore_errors: yes + no_log: True + +- name: Remove registry + command: docker rm -v registry + ignore_errors: yes + no_log: True + +- name: Remove tmp file + command: rm -rf /tmp/eg_registry + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/eg_secret/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_secret/tasks/install.yml new file mode 100644 index 0000000..60e6a1a --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_secret/tasks/install.yml @@ -0,0 +1,28 @@ +# +# 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. +# + +--- + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Generate secret + # yamllint disable rule:line-length + command: kubectl create secret generic edgegallery-ssl-secret --from-file=keystore.p12=/tmp/ssl-eg-keys-certs/keystore.p12 --from-literal=keystorePassword={{ vardata.common_pwd.name}} --from-literal=keystoreType=PKCS12 --from-literal=keyAlias=edgegallery --from-file=trust.cer=/tmp/ssl-eg-keys-certs/ca.crt --from-file=server.cer=/tmp/ssl-eg-keys-certs/tls.crt --from-file=server_key.pem=/tmp/ssl-eg-keys-certs/encryptedtls.key --from-literal=cert_pwd={{ vardata.common_pwd.name}} + args: + chdir: /tmp/ssl-eg-keys-certs/ diff --git a/blueprints/iotgateway/playbooks/roles/eg_secret/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_secret/tasks/main.yml new file mode 100644 index 0000000..bd61315 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_secret/tasks/main.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +# tasks file for eg_secret +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_secret/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_secret/tasks/uninstall.yml new file mode 100644 index 0000000..ea33726 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_secret/tasks/uninstall.yml @@ -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. +# + +--- + +- name: Delete edgegallery ssl secret + command: kubectl delete secret edgegallery-ssl-secret + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/eg_set-helm-repo/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_set-helm-repo/tasks/install.yml new file mode 100644 index 0000000..6e517b1 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_set-helm-repo/tasks/install.yml @@ -0,0 +1,30 @@ +# +# 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. +# + +--- + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Helm repo add edgegallery + # yamllint disable rule:line-length + command: helm repo add edgegallery http://{{ vardata.private_repo_ip.name}}:8080/edgegallery + +- name: Helm repo add stable + # yamllint disable rule:line-length + command: helm repo add stable http://{{ vardata.private_repo_ip.name}}:8080/stable diff --git a/blueprints/iotgateway/playbooks/roles/eg_set-helm-repo/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_set-helm-repo/tasks/main.yml new file mode 100644 index 0000000..2c506fb --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_set-helm-repo/tasks/main.yml @@ -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. +# + +--- + +# tasks file for eg_set-helm-repo +- include: "install.yml" + static: false + when: operation == 'install' diff --git a/blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/install.yml new file mode 100644 index 0000000..e215dab --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/install.yml @@ -0,0 +1,42 @@ +# +# 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. +# + +--- + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Set a variable + ansible.builtin.set_fact: + comm_pwd: "{{ vardata.common_pwd.name }}" + +- name: Create certificates for usermanagment with common pwd + # yamllint disable rule:line-length + command: kubectl create secret generic user-mgmt-jwt-secret --from-file=publicKey=/tmp/ssl-eg-keys-certs/rsa_public_key.pem --from-file=encryptedPrivateKey=/tmp/ssl-eg-keys-certs/encrypted_rsa_private_key.pem --from-literal=encryptPassword={{ vardata.common_pwd.name}} + # yamllint disable rule:line-length + when: comm_pwd != "" + +- name: Generating certificates for usermanagment + # yamllint disable rule:line-length + command: kubectl create secret generic user-mgmt-jwt-secret --from-file=publicKey=/tmp/ssl-eg-keys-certs/rsa_public_key.pem --from-file=encryptedPrivateKey=/tmp/ssl-eg-keys-certs/encrypted_rsa_private_key.pem --from-literal=encryptPassword={{ vardata.user_mgmt_encryptPassword.name}} + # yamllint disable rule:line-length + when: comm_pwd == "" + +- name: Install user-mgmt + # yamllint disable rule:line-length + command: helm install user-mgmt-edgegallery edgegallery/usermgmt --set global.oauth2.clients.appstore.clientUrl=https://{{ ansible_host }}:{{vardata.appstore_port.name}},global.oauth2.clients.developer.clientUrl=https://{{ ansible_host }}:{{vardata.developer_port.name}},global.oauth2.clients.mecm.clientUrl=https://{{ ansible_host }}:{{vardata.mecm_port.name}}, --set jwt.secretName=user-mgmt-jwt-secret --set images.usermgmt.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/user-mgmt --set images.postgres.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/postgres --set images.redis.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/redis --set images.initservicecenter.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/curl --set images.usermgmt.tag={{ vardata.eg_image_tag.name}} --set images.usermgmt.pullPolicy=IfNotPresent --set images.postgres.pullPolicy=IfNotPresent --set images.redis.pullPolicy=IfNotPresent --set images.initservicecenter.pullPolicy=IfNotPresent --set global.ssl.enabled=true --set global.ssl.secretName=edgegallery-ssl-secret diff --git a/blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/main.yml new file mode 100644 index 0000000..6545b6a --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/main.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +# tasks file for eg_user-mgmt +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/uninstall.yml new file mode 100644 index 0000000..60eb052 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/eg_user-mgmt/tasks/uninstall.yml @@ -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. +# + +--- + +- name: Uninstall user management + command: helm uninstall user-mgmt-edgegallery + ignore_errors: yes + no_log: True + +- name: Delete user-mgmt-jwt-secret + command: kubectl delete secret user-mgmt-jwt-secret + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/grafana/files/values.yaml b/blueprints/iotgateway/playbooks/roles/grafana/files/values.yaml new file mode 100644 index 0000000..dfa6f8c --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/grafana/files/values.yaml @@ -0,0 +1,2757 @@ +--- +env: + # GF_USERS_DEFAULT_THEME: 'light' + GF_SECURITY_ALLOW_EMBEDDING: 'true' + GF_AUTH_ANONYMOUS_ENABLED: 'true' + GF_AUTH_ANONYMOUS_ORG_ROLE: 'Editor' + +service: + type: NodePort + nodePort: 30000 + +image: + repository: grafana/grafana-arm64v8-linux + tag: 6.5.2-ubuntu + +datasources: + datasources.yaml: + apiVersion: 1 + datasources: + - name: MEP + type: prometheus + access: proxy + url: http://mep-prometheus-server.default.svc.cluster.local:80 + +downloadDashboardsImage: + repository: lucashalbert/curl + tag: arm64v8-7.66.0-r0 + +dashboardProviders: + dashboardproviders.yaml: + apiVersion: 1 + providers: + - name: 'default' + orgId: 1 + folder: '' + type: file + disableDeletion: false + editable: true + options: + path: /var/lib/grafana/dashboards/default + +dashboards: + default: + cluster-metrics: + # yamllint disable rule:line-length + json: | + { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Summary metrics about containers running on Kubernetes nodes.\r\n\r\nDashboard was taken from here. This version does not reqiure you to\r\nsetup the Kubernetes-app plugin. (https://github.com/grafana/kubernetes-app)\r\n\r\nUse this Helm chart to launch Grafana into a Kubernetes cluster. It will include this dashboard and many more dashboards to give you visibility into the Kubernetes Cluster. (https://github.com/sekka1/cloud-public/tree/master/kubernetes/pods/grafana-helm)", + "editable": true, + "gnetId": 6417, + "graphTooltip": 1, + "id": 2, + "iteration": 1574675114940, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": false, + "tags": [ + "kubernetes-app" + ], + "title": "Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "panels": [], + "title": "Cluster Health", + "type": "row" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_info{node=~\"$node\"}) / sum(kube_node_status_allocatable_pods{node=~\".*\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "80,90", + "title": "Cluster Pod Usage", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 1 + }, + "id": 5, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_container_resource_requests_cpu_cores{node=~\"$node\"}) / sum(kube_node_status_allocatable_cpu_cores{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "80,90", + "title": "Cluster CPU Usage", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 1 + }, + "id": 6, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_container_resource_requests_memory_bytes{node=~\"$node\"}) / sum(kube_node_status_allocatable_memory_bytes{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "80,90", + "title": "Cluster Memory Usage", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 1 + }, + "id": 7, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "(sum (node_filesystem_size_bytes{kubernetes_node=~\"$node\"}) - sum (node_filesystem_free_bytes{kubernetes_node=~\"$node\"})) / sum (node_filesystem_size_bytes{kubernetes_node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "80,90", + "title": "Cluster Disk Usage", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "MEP", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 5 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(kube_node_status_allocatable_pods{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "allocatable", + "refId": "A" + }, + { + "expr": "sum(kube_node_status_capacity_pods{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "capacity", + "refId": "B" + }, + { + "expr": "sum(kube_pod_info{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "requested", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Cluster Pod Capacity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "pods", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "MEP", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 5 + }, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(kube_node_status_capacity_cpu_cores{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "allocatable", + "refId": "A" + }, + { + "expr": "sum(kube_node_status_allocatable_cpu_cores{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "capacity", + "refId": "B" + }, + { + "expr": "sum(kube_pod_container_resource_requests_cpu_cores{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "requested", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Cluster CPU Capacity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": "cores", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "MEP", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 5 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(kube_node_status_allocatable_memory_bytes{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "allocatable", + "refId": "A" + }, + { + "expr": "sum(kube_node_status_capacity_memory_bytes{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "capacity", + "refId": "B" + }, + { + "expr": "sum(kube_pod_container_resource_requests_memory_bytes{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "requested", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Cluster Mem Capacity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "MEP", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 5 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(node_filesystem_size_bytes{kubernetes_node=~\"$node\"}) - sum(node_filesystem_free_bytes{kubernetes_node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "usage", + "refId": "A" + }, + { + "expr": "sum(node_filesystem_size_bytes{kubernetes_node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "limit", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Cluster Disk Capacity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 14, + "panels": [], + "title": "Deployments", + "type": "row" + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "MEP", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 16, + "links": [], + "options": {}, + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 1, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "colorMode": "row", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 0, + "pattern": "Metric", + "thresholds": [ + "0", + "0", + ".9" + ], + "type": "string", + "unit": "none" + }, + { + "alias": "", + "colorMode": "row", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "link": false, + "pattern": "Value", + "thresholds": [ + "0", + "1" + ], + "type": "number", + "unit": "none" + } + ], + "targets": [ + { + "expr": "kube_deployment_status_replicas{namespace=~\"$namespace\"}", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ deployment }}", + "refId": "A" + } + ], + "title": "Deployment Replicas - Up To Date", + "transform": "timeseries_to_rows", + "type": "table" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 18, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_deployment_status_replicas{namespace=~\"$namespace\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Deployment Replicas", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 11 + }, + "id": 19, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_deployment_status_replicas_updated{namespace=~\"$namespace\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Deployment Replicas - Updated", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 11 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_deployment_status_replicas_unavailable{namespace=~\"$namespace\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Deployment Replicas - Unavailable", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 22, + "panels": [], + "title": "Node", + "type": "row" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 0, + "y": 17 + }, + "id": 24, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_node_info{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Number Of Nodes", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": true, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 8, + "y": 17 + }, + "id": 25, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_node_status_condition{condition=\"OutOfDisk\", node=~\"$node\", status=\"true\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "1", + "title": "Nodes Out of Disk", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": true, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 16, + "y": 17 + }, + "id": 26, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_node_spec_unschedulable{node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "1", + "title": "Nodes Unavailable", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 28, + "panels": [], + "title": "Pods", + "type": "row" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 30, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(78, 203, 42, 0.28)", + "full": false, + "lineColor": "#629e51", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_status_phase{namespace=~\"$namespace\", phase=\"Running\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Pods Running", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 31, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(78, 203, 42, 0.28)", + "full": false, + "lineColor": "#629e51", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_status_phase{namespace=~\"$namespace\", phase=\"Pending\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Pods Pending", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 0, + "y": 24 + }, + "id": 32, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(78, 203, 42, 0.28)", + "full": false, + "lineColor": "#629e51", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_status_phase{namespace=~\"$namespace\", phase=\"Failed\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Pods Failed", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 8, + "y": 24 + }, + "id": 33, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(78, 203, 42, 0.28)", + "full": false, + "lineColor": "#629e51", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_status_phase{namespace=~\"$namespace\", phase=\"Succeeded\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Pods Succeeded", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 16, + "y": 24 + }, + "id": 34, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(78, 203, 42, 0.28)", + "full": false, + "lineColor": "#629e51", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_status_phase{namespace=~\"$namespace\", phase=\"Unknown\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Pods Unknown", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 36, + "panels": [], + "title": "Containers", + "type": "row" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 28 + }, + "id": 38, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_container_status_running{namespace=~\"$namespace\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Containers Running", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 28 + }, + "id": 39, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_container_status_waiting{namespace=~\"$namespace\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Containers Waiting", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 28 + }, + "id": 40, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_container_status_terminated{namespace=~\"$namespace\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Containers Terminated", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 28 + }, + "id": 41, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(delta(kube_pod_container_status_restarts_total{namespace=\"kube-system\"}[30m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Containers Restarts (Last 30 Minutes)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 0, + "y": 31 + }, + "id": 43, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_container_resource_requests_cpu_cores{kubernetes_namespace=~\"$namespace\", node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "CPU Cores Requested by Containers", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "MEP", + "format": "decbytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 12, + "y": 31 + }, + "id": 42, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_pod_container_resource_requests_memory_bytes{namespace=~\"kube-system\", node=~\"$node\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "title": "Memory Requested By Containers", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + } + ], + "refresh": false, + "schemaVersion": 20, + "style": "dark", + "tags": [ + "kubernetes", + "kubernetes-app" + ], + "templating": { + "list": [ + { + "current": { + "text": "No data sources found", + "value": "" + }, + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "/$ds/", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": ".*", + "current": { + "tags": [], + "text": "All", + "value": "$__all" + }, + "datasource": "MEP", + "definition": "label_values(kube_pod_info, kubernetes_node)", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "node", + "options": [], + "query": "label_values(kube_pod_info, kubernetes_node)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "MEP", + "definition": "label_values(kube_pod_info, kubernetes_namespace)", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(kube_pod_info, kubernetes_namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "MEP Cluster Metrics", + "uid": "4XuMd2Iiz", + "version": 10 + } + pod-metrics: + json: | + { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "A dashboard to view pod metrics by namespace and pod names.\r\n\r\nUse this Helm chart to launch Grafana into a Kubernetes cluster. It will include this dashboard and many more dashboards to give you visibility into the Kubernetes Cluster. (https://github.com/sekka1/cloud-public/tree/master/kubernetes/pods/grafana-helm)", + "editable": true, + "gnetId": 6336, + "graphTooltip": 0, + "id": 4, + "iteration": 1574675785610, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "MEP", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 23, + "x": 0, + "y": 0 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(irate(container_cpu_usage_seconds_total{pod!=\"\", pod=~\"[[pod_name]].*\", namespace=~\"[[namespace]].*\"}[5m]) * 100) by (pod)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "MEP", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 23, + "x": 0, + "y": 9 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum (container_memory_working_set_bytes{pod!=\"\", pod=~\"[[pod_name]].*\", namespace=~\"[[namespace]].*\"}) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": false, + "schemaVersion": 20, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": ".*", + "current": { + "tags": [], + "text": "All", + "value": "$__all" + }, + "datasource": "MEP", + "definition": "label_values(kube_pod_info, kubernetes_namespace)", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(kube_pod_info, kubernetes_namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "MEP", + "definition": "label_values(kube_pod_info{namespace=\"$namespace\"}, pod)", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "pod_name", + "options": [], + "query": "label_values(kube_pod_info{namespace=\"$namespace\"}, pod)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "MEP Pods Metrics", + "uid": "-7mPcYniz", + "version": 10 + } diff --git a/blueprints/iotgateway/playbooks/roles/grafana/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/grafana/tasks/install.yml new file mode 100644 index 0000000..46245cb --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/grafana/tasks/install.yml @@ -0,0 +1,47 @@ +# 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. + +--- +- name: check if grafana is already installed + shell: + cmd: helm status mec-grafana + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: grafana is already present + when: result.stdout != "" + +- debug: +# yamllint disable rule:line-length + msg: Ignore Uninstall Log , Grafana not installed continue with Installation +# yamllint disable rule:line-length + when: result.stdout == "" + +- name: "INSTALL: Install grafana on x86_64" + shell: + cmd: helm install mec-grafana stable/grafana + when: result is failed and ansible_architecture == 'x86_64' + +- name: "INSTALL: copy values.yaml to host" + copy: + src: values.yaml + dest: /tmp/grafana/ + when: result is failed and ansible_architecture == 'aarch64' + +- name: "INSTALL: Install grafana on aarch64" + shell: + cmd: helm install mec-grafana stable/grafana -f /tmp/grafana/values.yaml + when: result is failed and ansible_architecture == 'aarch64' diff --git a/blueprints/iotgateway/playbooks/roles/grafana/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/grafana/tasks/main.yml new file mode 100644 index 0000000..db34791 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/grafana/tasks/main.yml @@ -0,0 +1,21 @@ +# 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. + +--- +- include: "install.yml" + static: false + when: operation == 'install' + + #- include: "uninstall.yml" + #when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/grafana/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/grafana/tasks/uninstall.yml new file mode 100644 index 0000000..6f08c57 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/grafana/tasks/uninstall.yml @@ -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. + +--- +- name: check if grafana is installed before deleting + shell: + cmd: helm status mec-grafana + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: Uninstalling docker... + when: result.stdout != "" + +- debug: + msg: Ignore Uninstall Log , Grafana not installed + when: result.stdout == "" + +- name: Uninstall grafana + shell: + cmd: helm uninstall mec-grafana + when: result is succeeded diff --git a/blueprints/iotgateway/playbooks/roles/helm/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/helm/tasks/install.yml new file mode 100644 index 0000000..f855091 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/helm/tasks/install.yml @@ -0,0 +1,68 @@ +# 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. +--- + +- name: check whether helm is already installed + command: which helm + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: helm is already present + when: result.stdout != "" + +- debug: +# yamllint disable rule:line-length + msg: Ignore Uninstall Log , Helm not installed continue with Installation +# yamllint disable rule:line-length + when: result.stdout == "" + +- name: "INSTALL: Helm download command on x86_64" + command: wget https://get.helm.sh/helm-v3.0.2-linux-amd64.tar.gz + when: result is failed and ansible_architecture == 'x86_64' + +- name: "INSTALL: Untar helm on x86_64" + command: tar -zxvf helm-v3.0.2-linux-amd64.tar.gz + when: result is failed and ansible_architecture == 'x86_64' + +- name: "INSTALL: Helm move to bin folder on x86_64" + command: mv linux-amd64/helm /usr/local/bin/ + when: result is failed and ansible_architecture == 'x86_64' + +- name: "INSTALL: Helm download command on aarch64" + command: wget https://get.helm.sh/helm-v3.0.2-linux-arm64.tar.gz + when: result is failed and ansible_architecture == 'aarch64' + +- name: "INSTALL: Untar helm on aarch64" + command: tar -zxvf helm-v3.0.2-linux-arm64.tar.gz + when: result is failed and ansible_architecture == 'aarch64' + +- name: "INSTALL: Helm move to bin folder on aarch64" + command: mv linux-arm64/helm /usr/local/bin/ + when: result is failed and ansible_architecture == 'aarch64' + +- name: "INSTALL: Add helm repo" +# yamllint disable rule:line-length + command: helm repo add stable https://kubernetes-charts.storage.googleapis.com/ +# yamllint disable rule:line-length + when: result is failed + +- name: "INSTALL: Updated helm repo" + command: helm repo update + when: result is failed + +- name: "INSTALLED List helm repo" + command: helm repo list + when: result is failed diff --git a/blueprints/iotgateway/playbooks/roles/helm/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/helm/tasks/main.yml new file mode 100644 index 0000000..9619418 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/helm/tasks/main.yml @@ -0,0 +1,23 @@ +# 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. +--- + +# tasks file for helm +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/helm/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/helm/tasks/uninstall.yml new file mode 100644 index 0000000..78db3d1 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/helm/tasks/uninstall.yml @@ -0,0 +1,54 @@ +# 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. + +--- +- name: check whether helm is installed before deleting + command: which helm + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: Uninstalling helm... + when: result.stdout != "" + +- debug: + msg: Ignore Uninstall Log ,Helm not installed + when: result.stdout == "" + +- name: "UNINSTALL: Helm Uninstall on x86_64" + command: rm -rf linux-amd64/helm + when: result is succeeded and ansible_architecture == 'x86_64' + +- name: "UNINSTALL: Remove download helm file on x86_64" + command: rm ~/helm-v3.0.2-linux-amd64.tar.gz + when: result is succeeded and ansible_architecture == 'x86_64' + +- name: "UNINSTALL: Helm Uninstall on aarch64" + command: rm -rf linux-arm64/helm + ignore_errors: yes + no_log: True + when: result is succeeded and ansible_architecture == 'aarch64' + +- name: "UNINSTALL: Remove download helm file on aarch64" + command: rm helm-v3.0.2-linux-arm64.tar.gz + ignore_errors: yes + no_log: True + when: result is succeeded and ansible_architecture == 'aarch64' + +- name: "UNINSTALL: Remove helm from bin" + command: rm /usr/local/bin/helm + ignore_errors: yes + no_log: True + when: result is succeeded diff --git a/blueprints/iotgateway/playbooks/roles/k3s/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/k3s/tasks/install.yml new file mode 100644 index 0000000..87de5dd --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/k3s/tasks/install.yml @@ -0,0 +1,74 @@ +# 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. + +--- +- name: check whether k3s is already installed + shell: + cmd: which k3s + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: k3s is already present + when: result.stdout != "" + +- debug: +# yamllint disable rule:line-length + msg: Ignore Uninstall Log , k3s not installed continue with Installation +# yamllint disable rule:line-length + when: result.stdout == "" + +- debug: + msg: K3 Installation started on {{ ansible_facts['distribution'] }} MEP Node + +- name: "INSTALL: Disabling firewall for successfull k3s installation on CentOs" + shell: + cmd: systemctl stop firewalld + when: ansible_facts['distribution'] == "CentOS" and result is failed + +- name: "INSTALL: install container-selinux" + shell: + cmd: yum install -y container-selinux selinux-policy-base + when: ansible_facts['distribution'] == "CentOS" and result is failed + ignore_errors: true + +- name: "INSTALL: get interface name" + shell: + cmd: ip a |grep {{ ansible_host }} |awk '{print $NF}' + register: ifName + when: result is failed + +# yamllint disable rule:line-length +- name: "INSTALL: install k3s" + shell: + cmd: curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--node-ip={{ ansible_host }} --node-external-ip={{ ansible_host }} --bind-address={{ ansible_host }} --flannel-iface=eth0 --docker --no-deploy=servicelb --no-deploy=traefik --write-kubeconfig-mode 644 --kube-apiserver-arg="service-node-port-range=30000-36000"" sh - + when: result is failed + +# yamllint disable rule:line-length + +#- name: "INSTALL: install k3s" +# shell: +# cmd: curl -sfL https://get.k3s.io | sh - +# when: result is failed + +- name: "INSTALL: create .kube dir" + shell: + cmd: mkdir -p $HOME/.kube/ + when: result is failed + +- name: "INSTALL: copy kubeconfig" + shell: + cmd: cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config + when: result is failed diff --git a/blueprints/iotgateway/playbooks/roles/k3s/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/k3s/tasks/main.yml new file mode 100644 index 0000000..22746d8 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/k3s/tasks/main.yml @@ -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. + +--- +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/k3s/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/k3s/tasks/uninstall.yml new file mode 100644 index 0000000..d58b1bb --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/k3s/tasks/uninstall.yml @@ -0,0 +1,39 @@ +# 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. + +--- +- name: check whether k3s is already installed + shell: + cmd: which k3s + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: Uninstalling k3s... + when: result.stdout != "" + +- debug: + msg: "UNINSTALL: Ignore Uninstall Log , K3s not installed" + when: result.stdout == "" + +- name: "UNINSTALL: kill k3s" + shell: + cmd: k3s-killall.sh + when: result is succeeded + +- name: "UNINSTALL: uninstall k3s" + shell: + cmd: k3s-uninstall.sh + when: result is succeeded diff --git a/blueprints/iotgateway/playbooks/roles/k8s/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/k8s/tasks/install.yml new file mode 100644 index 0000000..8388770 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/k8s/tasks/install.yml @@ -0,0 +1,38 @@ +# 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. + +--- +# tasks file for k8s +- name: Check whether k8s is already installed + command: which k8s + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: k8s is already present + when: result.stdout != "" + +- debug: +# yamllint disable rule:line-length + msg: Ignore Uninstall Log , k8s not installed continue with Installation +# yamllint disable rule:line-length + when: result.stdout == "" + +- name: Install k8s + shell: +# yamllint disable rule:line-length + cmd: ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root cluster.yml +# yamllint disable rule:line-length + chdir: /root/eliotkubesprey/kubespray/ diff --git a/blueprints/iotgateway/playbooks/roles/k8s/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/k8s/tasks/main.yml new file mode 100644 index 0000000..a0ff36d --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/k8s/tasks/main.yml @@ -0,0 +1,23 @@ +# 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. + +--- +# tasks file for k8s +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/k8s/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/k8s/tasks/uninstall.yml new file mode 100644 index 0000000..3ff9e4a --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/k8s/tasks/uninstall.yml @@ -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. + +--- +# Uninstall file for k8s +- name: Check whether k8s is already installed + command: kubectl version + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: k8s is already present + when: result.stdout != "" + +- name: Remove k8s + shell: + cmd: yes | ansible-playbook -i inventory/mycluster/hosts.yaml reset.yml + chdir: /root/eliotkubesprey/kubespray/ + when: result.stdout != "" diff --git a/blueprints/iotgateway/playbooks/roles/kubeconfig/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/kubeconfig/tasks/install.yml new file mode 100644 index 0000000..53ad150 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/kubeconfig/tasks/install.yml @@ -0,0 +1,25 @@ +# 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. + +--- +# tasks file for transferring kubeconfig files +- name: debug msg + debug: + msg: transfering config file to OCD Host + +- name: Fetch the file from the controller and edge nodes to ocd-host + fetch: + src: /root/.kube/config + dest: /root/.kube/config-{{ ansible_host }} + flat: yes diff --git a/blueprints/iotgateway/playbooks/roles/kubeconfig/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/kubeconfig/tasks/main.yml new file mode 100644 index 0000000..a3fc9af --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/kubeconfig/tasks/main.yml @@ -0,0 +1,21 @@ +# 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. + +--- +# tasks file for kubeconfig transfer +- include: "install.yml" + when: operation == 'install' + +#- include: "uninstall.yml" + #when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/mepkubeconfig/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/mepkubeconfig/tasks/install.yml new file mode 100644 index 0000000..587f32b --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/mepkubeconfig/tasks/install.yml @@ -0,0 +1,25 @@ +# 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. + +--- +# tasks file for k3s kube-config file transfer +- name: debug msg + debug: + msg: transfering mep config file to OCD Host + +- name: Fetch the file from the mep edge nodes to ocd-host + fetch: + src: /root/.kube/config + dest: /root/.kube/kubeconfig/{{ ansible_host }} + flat: yes diff --git a/blueprints/iotgateway/playbooks/roles/mepkubeconfig/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/mepkubeconfig/tasks/main.yml new file mode 100644 index 0000000..1f281b4 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/mepkubeconfig/tasks/main.yml @@ -0,0 +1,18 @@ +# 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. + +--- +# tasks file for kubeconfig transfer +- include: "install.yml" + when: operation == 'install' diff --git a/blueprints/iotgateway/playbooks/roles/prometheus/files/values.yaml b/blueprints/iotgateway/playbooks/roles/prometheus/files/values.yaml new file mode 100644 index 0000000..b26d74b --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/prometheus/files/values.yaml @@ -0,0 +1,26 @@ +--- +alertmanager: + image: + tag: v0.18.0 + +kubeStateMetrics: + image: + repository: carlosedp/kube-state-metrics + tag: v1.7.2 + +pushgateway: + image: + tag: v1.0.1 + +server: + image: + tag: v2.15.2 + +nodeExporter: + image: + tag: v0.18.1 + +configmapReload: + image: + repository: jimmidyson/configmap-reload + tag: latest-arm64 diff --git a/blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml new file mode 100644 index 0000000..f8472b4 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml @@ -0,0 +1,48 @@ +# 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. + +--- +- name: check if prometheus is already installed + shell: + cmd: helm status mep-prometheus + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: prometheus is already present + when: result.stdout != "" + +- debug: +# yamllint disable rule:line-length + msg: Ignore Uninstall Log , prometheus not installed continue with Installation +# yamllint disable rule:line-length + when: result.stdout == "" + +- name: "INSTALL: Install prometheus on x86_64" + shell: + cmd: helm install mep-prometheus stable/prometheus --version v9.3.1 + when: result is failed and ansible_architecture == 'x86_64' + +- name: "INSTALL: copy values.yaml to host" + copy: + src: values.yaml + dest: /tmp/prometheus/ + when: result is failed and ansible_architecture == 'aarch64' + +- name: "INSTALL: Install prometheus on aarch64" + shell: + cmd: 'helm install mep-prometheus + stable/prometheus -f /tmp/prometheus/values.yaml --version v9.3.1' + when: result is failed and ansible_architecture == 'aarch64' diff --git a/blueprints/iotgateway/playbooks/roles/prometheus/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/prometheus/tasks/main.yml new file mode 100644 index 0000000..7daf37b --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/prometheus/tasks/main.yml @@ -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. + +--- +- include: "install.yml" + static: false + when: operation == 'install' + + #- include: "uninstall.yml" + #static: false + #when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/prometheus/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/prometheus/tasks/uninstall.yml new file mode 100644 index 0000000..c6436c5 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/prometheus/tasks/uninstall.yml @@ -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. + +--- +- name: check if prometheus is installed before deleting + shell: + cmd: helm status mep-prometheus + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: Uninstalling prometheus... + when: result.stdout != "" + +- debug: + msg: Ignore Uninstall Log , Prometheus not installed + when: result.stdout == "" + +- name: Uninstall prometheus + shell: + cmd: helm uninstall mep-prometheus + when: result is succeeded diff --git a/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/configmap.yaml b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/configmap.yaml new file mode 100644 index 0000000..f62ae33 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/configmap.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: rabbitmq-config + namespace: default +data: + enabled_plugins: | + [rabbitmq_management,rabbitmq_peer_discovery_k8s]. + rabbitmq.conf: | + cluster_formation.peer_discovery_backend = rabbit_peer_discovery_k8s + cluster_formation.k8s.host = kubernetes.default.svc.cluster.local + cluster_formation.k8s.address_type = hostname + cluster_formation.node_cleanup.interval = 30 + cluster_formation.node_cleanup.only_log_warning = true + cluster_partition_handling = autoheal + queue_master_locator=min-masters + loopback_users.guest = false + default_user=admin + default_pass=admin diff --git a/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/namespace_yaml b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/namespace_yaml new file mode 100644 index 0000000..05afb83 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/namespace_yaml @@ -0,0 +1,5 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: default diff --git a/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/rbac.yaml b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/rbac.yaml new file mode 100644 index 0000000..074dc46 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/rbac.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: rabbitmq + namespace: default +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rabbitmq-peer-discovery-rbac + namespace: default +rules: + - apiGroups: [""] + resources: ["endpoints"] + verbs: ["get"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: rabbitmq-peer-discovery-rbac + namespace: default +subjects: + - kind: ServiceAccount + name: rabbitmq +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: rabbitmq-peer-discovery-rbac diff --git a/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/services.yaml b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/services.yaml new file mode 100644 index 0000000..d2c0d62 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/common/services.yaml @@ -0,0 +1,24 @@ +--- +kind: Service +apiVersion: v1 +metadata: + namespace: default + name: rabbitmq + labels: + app: rabbitmq + type: LoadBalancer +spec: + type: NodePort + ports: + - name: http + protocol: TCP + port: 15672 + targetPort: 15672 + nodePort: 31672 + - name: amqp + protocol: TCP + port: 5672 + targetPort: 5672 + nodePort: 30672 + selector: + app: rabbitmq diff --git a/blueprints/iotgateway/playbooks/roles/rabbitmq/files/statefulset_arm.yaml b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/statefulset_arm.yaml new file mode 100644 index 0000000..d031e91 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/statefulset_arm.yaml @@ -0,0 +1,78 @@ +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: rabbitmq + namespace: default +spec: + serviceName: rabbitmq + replicas: 3 + selector: + matchLabels: + app: rabbitmq + template: + metadata: + labels: + app: rabbitmq + spec: + serviceAccountName: rabbitmq + terminationGracePeriodSeconds: 10 + nodeSelector: + kubernetes.io/os: linux + containers: + - name: rabbitmq-k8s + image: arm64v8/rabbitmq:3.7-management-alpine + volumeMounts: + - name: config-volume + mountPath: /etc/rabbitmq + ports: + - name: http + protocol: TCP + containerPort: 15672 + - name: amqp + protocol: TCP + containerPort: 5672 + livenessProbe: + exec: + command: ["rabbitmq-diagnostics", "status"] + initialDelaySeconds: 60 + periodSeconds: 60 + timeoutSeconds: 15 + readinessProbe: + exec: + command: ["rabbitmq-diagnostics", "status"] + initialDelaySeconds: 20 + periodSeconds: 60 + timeoutSeconds: 10 + imagePullPolicy: Always + env: + - name: MY_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: RABBITMQ_USE_LONGNAME + value: "true" + - name: K8S_SERVICE_NAME + value: rabbitmq + - name: RABBITMQ_NODENAME + # yamllint disable rule:line-length + value: rabbit@$(MY_POD_NAME).$(K8S_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.cluster.local + # yamllint enable rule:line-length + - name: K8S_HOSTNAME_SUFFIX + value: .$(K8S_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.cluster.local + - name: RABBITMQ_ERLANG_COOKIE + value: "dW5pcXVlLWVybGFuZy1jb29raWU=" + volumes: + - name: config-volume + configMap: + name: rabbitmq-config + items: + - key: rabbitmq.conf + path: rabbitmq.conf + - key: enabled_plugins + path: enabled_plugins diff --git a/blueprints/iotgateway/playbooks/roles/rabbitmq/files/statefulset_x86.yaml b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/statefulset_x86.yaml new file mode 100644 index 0000000..0ec9ff9 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/rabbitmq/files/statefulset_x86.yaml @@ -0,0 +1,78 @@ +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: rabbitmq + namespace: default +spec: + serviceName: rabbitmq + replicas: 3 + selector: + matchLabels: + app: rabbitmq + template: + metadata: + labels: + app: rabbitmq + spec: + serviceAccountName: rabbitmq + terminationGracePeriodSeconds: 10 + nodeSelector: + kubernetes.io/os: linux + containers: + - name: rabbitmq-k8s + image: rabbitmq:3.7-management-alpine + volumeMounts: + - name: config-volume + mountPath: /etc/rabbitmq + ports: + - name: http + protocol: TCP + containerPort: 15672 + - name: amqp + protocol: TCP + containerPort: 5672 + livenessProbe: + exec: + command: ["rabbitmq-diagnostics", "status"] + initialDelaySeconds: 60 + periodSeconds: 60 + timeoutSeconds: 15 + readinessProbe: + exec: + command: ["rabbitmq-diagnostics", "status"] + initialDelaySeconds: 20 + periodSeconds: 60 + timeoutSeconds: 10 + imagePullPolicy: Always + env: + - name: MY_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: RABBITMQ_USE_LONGNAME + value: "true" + - name: K8S_SERVICE_NAME + value: rabbitmq + - name: RABBITMQ_NODENAME + # yamllint disable rule:line-length + value: rabbit@$(MY_POD_NAME).$(K8S_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.cluster.local + # yamllint enable rule:line-length + - name: K8S_HOSTNAME_SUFFIX + value: .$(K8S_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.cluster.local + - name: RABBITMQ_ERLANG_COOKIE + value: "dW5pcXVlLWVybGFuZy1jb29raWU=" + volumes: + - name: config-volume + configMap: + name: rabbitmq-config + items: + - key: rabbitmq.conf + path: rabbitmq.conf + - key: enabled_plugins + path: enabled_plugins diff --git a/blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/install.yml new file mode 100644 index 0000000..d3113d3 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/install.yml @@ -0,0 +1,64 @@ +# 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. + +--- +- name: check if rabbitmq is already installed + shell: + cmd: kubectl get pods rabbitmq-0 + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: rabbitmq is already present + when: result.stdout != "" + +- debug: +# yamllint disable rule:line-length + msg: Ignore Uninstall Log , rabbitmq not installed continue with Installation +# yamllint disable rule:line-length + when: result.stdout == "" + +- name: "INSTALL: copy common folder to host for rabbitmq installation" + copy: + src: common + dest: /tmp/rabbitmq/ + when: result is failed + +- name: "INSTALL: Install common for rabbitmq installation" + shell: + cmd: kubectl apply -f /tmp/rabbitmq/common + when: result is failed + +- name: "INSTALL: copy statefulset_x86.yaml to host for rabbitmq installation" + copy: + src: statefulset_x86.yaml + dest: /tmp/rabbitmq/ + when: result is failed and ansible_architecture == 'x86_64' + +- name: "INSTALL: Install rabbitmq on x86_64" + shell: + cmd: kubectl apply -f /tmp/rabbitmq/statefulset_x86.yaml + when: result is failed and ansible_architecture == 'x86_64' + +- name: "INSTALL: copy statefulset_arm.yaml to host for rabbitmq installation" + copy: + src: statefulset_arm.yaml + dest: /tmp/rabbitmq/ + when: result is failed and ansible_architecture == 'aarch64' + +- name: "INSTALL: Install rabbitmq on aarch64" + shell: + cmd: kubectl apply -f /tmp/rabbitmq/statefulset_arm.yaml + when: result is failed and ansible_architecture == 'aarch64' diff --git a/blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/main.yml new file mode 100644 index 0000000..7daf37b --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/main.yml @@ -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. + +--- +- include: "install.yml" + static: false + when: operation == 'install' + + #- include: "uninstall.yml" + #static: false + #when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/uninstall.yml new file mode 100644 index 0000000..14c1276 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/rabbitmq/tasks/uninstall.yml @@ -0,0 +1,44 @@ +# 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. + +--- +- name: check if rabbitmq is installed before deleting + shell: + cmd: kubectl get pods rabbitmq-0 + register: result + ignore_errors: yes + no_log: True + +- debug: + msg: Uninstalling rabbitmq... + when: result.stdout != "" + +- debug: + msg: Ignore Uninstall Log , Rabbitmq not installed + when: result.stdout == "" + +- name: Uninstalling rabbitmq + shell: + cmd: kubectl delete -f /tmp/rabbitmq/common + when: result is succeeded + +- name: Uninstall rabbitmq on x86_64 + shell: + cmd: kubectl delete -f /tmp/rabbitmq/statefulset_x86.yaml + when: result is succeeded and ansible_architecture == 'x86_64' + +- name: Uninstall rabbitmq on aarch64 + shell: + cmd: kubectl delete -f /tmp/rabbitmq/statefulset_arm.yaml + when: result is succeeded and ansible_architecture == 'aarch64' diff --git a/blueprints/iotgateway/playbooks/roles/service_center/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/service_center/tasks/install.yml new file mode 100644 index 0000000..f32c163 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/service_center/tasks/install.yml @@ -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. +# + +--- + +- name: Import config file + include_vars: + file: ../../../config.yml + name: vardata + +- name: Install service center + # yamllint disable rule:line-length + command: helm install service-center-edgegallery edgegallery/servicecenter --set images.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/service-center --set images.pullPolicy=IfNotPresent --set global.ssl.enabled=true --set global.ssl.secretName=edgegallery-ssl-secret + # yamllint disable rule:line-length diff --git a/blueprints/iotgateway/playbooks/roles/service_center/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/service_center/tasks/main.yml new file mode 100644 index 0000000..a79c680 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/service_center/tasks/main.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +# tasks file for service-center +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/service_center/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/service_center/tasks/uninstall.yml new file mode 100644 index 0000000..0df700f --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/service_center/tasks/uninstall.yml @@ -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. +# + +--- + +- name: Uninstall service center + command: helm uninstall service-center-edgegallery + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/vault/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/vault/tasks/install.yml new file mode 100644 index 0000000..38e1fa2 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/vault/tasks/install.yml @@ -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. + +- name: "INSTALL: Add Vault repo" +# yamllint disable rule:line-length + command: helm repo add hashicorp https://helm.releases.hashicorp.com +# yamllint disable rule:line-length + +- name: "INSTALL: Vault " + command: helm install vault hashicorp/vault + + +- name: "Installing ...Vault " + command: sleep 10 + +- name: "Initialize Vault POD and Unseal Key" + shell: +# yamllint disable rule:line-length + cmd: kubectl exec -ti vault-0 -- vault operator unseal $(kubectl exec vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format="" | grep -i "unseal key 1" | awk '{print $4}') +# yamllint enable rule:line-length diff --git a/blueprints/iotgateway/playbooks/roles/vault/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/vault/tasks/main.yml new file mode 100644 index 0000000..aedb1c1 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/vault/tasks/main.yml @@ -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. + +--- +# tasks file for Vault +- include: "install.yml" + static: false + when: operation == 'install' + +#- include: "uninstall.yml" + #when: operation == 'uninstall' -- 2.16.6 From f75c64c6e0356812802c13fcce14b3d4c7569d47 Mon Sep 17 00:00:00 2001 From: arvindpatel Date: Mon, 30 Nov 2020 18:17:18 +0530 Subject: [PATCH 08/16] Adgex and hawkbit added Signed-off-by: arvindpatel Change-Id: Id12ffd49215ef0e9167d6e2a82e2fe8ef7bddb21 --- .../iotgateway/playbooks/eliot-all-uninstall.yml | 1 + .../playbooks/{eloit-all.yml => eliot-all.yml} | 2 ++ .../roles/el_edgex/files/deploy/edgexonk8s.sh | 41 ++++++++++++++++++++++ .../playbooks/roles/el_edgex/tasks/install.yml | 27 ++++++++++++++ .../playbooks/roles/el_edgex/tasks/main.yml | 21 +++++++++++ .../playbooks/roles/el_hawkbit/tasks/install.yml | 26 ++++++++++++++ .../playbooks/roles/el_hawkbit/tasks/main.yml | 26 ++++++++++++++ .../playbooks/roles/el_hawkbit/tasks/uninstall.yml | 20 +++++++++++ 8 files changed, 164 insertions(+) rename blueprints/iotgateway/playbooks/{eloit-all.yml => eliot-all.yml} (98%) create mode 100644 blueprints/iotgateway/playbooks/roles/el_edgex/files/deploy/edgexonk8s.sh create mode 100644 blueprints/iotgateway/playbooks/roles/el_edgex/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/el_edgex/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/uninstall.yml diff --git a/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml b/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml index b58890e..4b5f671 100644 --- a/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml +++ b/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml @@ -59,6 +59,7 @@ roles: - grafana + - el_hawkbit ### Pre-Requisites ### diff --git a/blueprints/iotgateway/playbooks/eloit-all.yml b/blueprints/iotgateway/playbooks/eliot-all.yml similarity index 98% rename from blueprints/iotgateway/playbooks/eloit-all.yml rename to blueprints/iotgateway/playbooks/eliot-all.yml index 2ea2dec..294a138 100644 --- a/blueprints/iotgateway/playbooks/eloit-all.yml +++ b/blueprints/iotgateway/playbooks/eliot-all.yml @@ -57,6 +57,7 @@ roles: - grafana + - el_hawkbit ### EdgeGallery related ### @@ -115,6 +116,7 @@ - kubeconfig - mepkubeconfig - cadvisor + - el_edgex ### EdgeGallery related ### diff --git a/blueprints/iotgateway/playbooks/roles/el_edgex/files/deploy/edgexonk8s.sh b/blueprints/iotgateway/playbooks/roles/el_edgex/files/deploy/edgexonk8s.sh new file mode 100644 index 0000000..40a69be --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_edgex/files/deploy/edgexonk8s.sh @@ -0,0 +1,41 @@ +#!/bin/bash -ex +############################################################################# +# Copyright (c) 2019 Huawei Tech and others. # +# All rights reserved. This program and the accompanying materials # +# are made available under the terms of the Apache License, Version 2.0 # +# which accompanies this distribution, and is available at # +# http://www.apache.org/licenses/LICENSE-2.0 # +############################################################################# + +####################################################################################### +# The script is to setup the Edgex Foundry application as POD in Kubernetes. # +####################################################################################### + +echo "**********************************************************************" +echo "Edgex Platform Deployment--------------------------------------STARTED" + +echo "Deploying Edgex Platform on IOT-Gateway Edge Node" +edgexPath=`pwd` +git clone https://github.com/edgexfoundry-holding/edgex-kubernetes-support.git +cd edgex-kubernetes-support/releases/edinburgh/kubernetes +ls +kubectl create -k . +cd ${edgexPath} +echo "-----------------------------------------------------------" +echo "Edgex platform PODs" +kubectl get pod +echo "-----------------------------------------------------------" +echo "-----------------------------------------------------------" +echo "Edge platform Kubernetes Services" +kubectl get svc +echo "-----------------------------------------------------------" +kubectl expose deployment edgex-core-consul --type=NodePort --name=consulnodeport +kubectl expose deployment edgex-core-command --type=NodePort --name=commandnodeport +kubectl expose deployment edgex-core-data --type=NodePort --name=datanodeport +kubectl expose deployment edgex-core-metadata --type=NodePort --name=metadatanodeport +kubectl expose deployment edgex-support-rulesengine --type=NodePort --name=rulesenginenodeport +kubectl expose deployment edgex-support-logging --type=NodePort --name=loggingnodeport +kubectl get svc | grep NodePort + +echo "**********************************************************************" +echo "Edgex Platform Deployment--------------------------------------SUCCESS" diff --git a/blueprints/iotgateway/playbooks/roles/el_edgex/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/el_edgex/tasks/install.yml new file mode 100644 index 0000000..15dd508 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_edgex/tasks/install.yml @@ -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. +# + +--- + +- name: Doing deployment setup for eliot + copy: + src: deploy + dest: /tmp/el_edgex/ + mode: 777 + +- name: Execute edgex script + shell: + cmd: /tmp/el_edgex/deploy/edgexonk8s.sh diff --git a/blueprints/iotgateway/playbooks/roles/el_edgex/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/el_edgex/tasks/main.yml new file mode 100644 index 0000000..e10d37e --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_edgex/tasks/main.yml @@ -0,0 +1,21 @@ +# +# 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. +# + +--- +# tasks file for el_edgex +- include: "install.yml" + static: false + when: operation == 'install' diff --git a/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/install.yml new file mode 100644 index 0000000..b9d2714 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/install.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +- name: Hawkbit add repo + command: helm repo add eclipse-iot https://eclipse.org/packages/charts + +- name: Update helm repo + command: helm repo update + +- name: Install hackbit + command: helm install eclipse-hawkbit eclipse-iot/hawkbit diff --git a/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/main.yml new file mode 100644 index 0000000..056af82 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/main.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- +# tasks file for el_hawkbit + +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/uninstall.yml new file mode 100644 index 0000000..bec510c --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/uninstall.yml @@ -0,0 +1,20 @@ +# +# 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. +# + +--- + +- name: Uninstall hawkbit + command: helm delete eclipse-hawkbit -- 2.16.6 From 0550d851c9a4708aa367564fce9fe70e42e10f56 Mon Sep 17 00:00:00 2001 From: arvindpatel Date: Tue, 1 Dec 2020 01:58:50 +0530 Subject: [PATCH 09/16] Edgex ci changes added Signed-off-by: arvindpatel Change-Id: Ibe905404bee0ab9630337c3f0a161015be2ef329 --- blueprints/iotgateway/playbooks/roles/el_edgex/tasks/install.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/blueprints/iotgateway/playbooks/roles/el_edgex/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/el_edgex/tasks/install.yml index 15dd508..5c4feed 100644 --- a/blueprints/iotgateway/playbooks/roles/el_edgex/tasks/install.yml +++ b/blueprints/iotgateway/playbooks/roles/el_edgex/tasks/install.yml @@ -25,3 +25,5 @@ - name: Execute edgex script shell: cmd: /tmp/el_edgex/deploy/edgexonk8s.sh + ignore_errors: yes + no_log: True -- 2.16.6 From 1516141fcce8e2b27c741fa17f7f0d62919084bc Mon Sep 17 00:00:00 2001 From: arvindpatel Date: Tue, 1 Dec 2020 12:03:25 +0530 Subject: [PATCH 10/16] Resolved Ci issue Signed-off-by: arvindpatel Change-Id: I051ff2b6071971fae42ed82916d51bde47a4734b --- blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/install.yml | 7 +++++++ .../iotgateway/playbooks/roles/el_hawkbit/tasks/uninstall.yml | 2 ++ 2 files changed, 9 insertions(+) diff --git a/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/install.yml index b9d2714..44907e4 100644 --- a/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/install.yml +++ b/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/install.yml @@ -18,9 +18,16 @@ - name: Hawkbit add repo command: helm repo add eclipse-iot https://eclipse.org/packages/charts + ignore_errors: yes + no_log: True - name: Update helm repo command: helm repo update + ignore_errors: yes + no_log: True + - name: Install hackbit command: helm install eclipse-hawkbit eclipse-iot/hawkbit + ignore_errors: yes + no_log: True diff --git a/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/uninstall.yml index bec510c..fae50ea 100644 --- a/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/uninstall.yml +++ b/blueprints/iotgateway/playbooks/roles/el_hawkbit/tasks/uninstall.yml @@ -18,3 +18,5 @@ - name: Uninstall hawkbit command: helm delete eclipse-hawkbit + ignore_errors: yes + no_log: True -- 2.16.6 From 68b365b097590f156f08b840fac9953e1e93f379 Mon Sep 17 00:00:00 2001 From: arvindpatel Date: Wed, 2 Dec 2020 17:52:10 +0530 Subject: [PATCH 11/16] Opc-au client and server added Signed-off-by: arvindpatel Change-Id: Iaa210d7662df1c09c0f8af7137597801759895c8 --- blueprints/iotgateway/playbooks/eliot-all.yml | 1 + .../files/deploy/opc-au_client/Dockerfile | 15 +++++++++ .../el_opc-au/files/deploy/opc-au_client/build.sh | 38 ++++++++++++++++++++++ .../files/deploy/opc-au_server/Dockerfile | 15 +++++++++ .../el_opc-au/files/deploy/opc-au_server/build.sh | 38 ++++++++++++++++++++++ .../playbooks/roles/el_opc-au/tasks/install.yml | 33 +++++++++++++++++++ .../playbooks/roles/el_opc-au/tasks/main.yml | 26 +++++++++++++++ .../playbooks/roles/el_opc-au/tasks/uninstall.yml | 24 ++++++++++++++ 8 files changed, 190 insertions(+) create mode 100644 blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_client/Dockerfile create mode 100644 blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_client/build.sh create mode 100644 blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_server/Dockerfile create mode 100644 blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_server/build.sh create mode 100644 blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/install.yml create mode 100644 blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/main.yml create mode 100644 blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/uninstall.yml diff --git a/blueprints/iotgateway/playbooks/eliot-all.yml b/blueprints/iotgateway/playbooks/eliot-all.yml index 294a138..430ff9d 100644 --- a/blueprints/iotgateway/playbooks/eliot-all.yml +++ b/blueprints/iotgateway/playbooks/eliot-all.yml @@ -117,6 +117,7 @@ - mepkubeconfig - cadvisor - el_edgex + - el_opc-au ### EdgeGallery related ### diff --git a/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_client/Dockerfile b/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_client/Dockerfile new file mode 100644 index 0000000..33704b5 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_client/Dockerfile @@ -0,0 +1,15 @@ +FROM centos:centos7 +ADD ./work/ /root/work +RUN yum install -y gcc git +RUN yum groupinstall -y 'Development Tools' +RUN cd /root/work && ls -al && tar xzf cmake-3.15.2.tar.gz && \ + rpm -Uvh scons-2.3.0-1.el7.centos.noarch.rpm && \ + python get-pip.py && \ + cd cmake-3.15.2 && ./bootstrap && \ + make && \ + make install && \ + cd ../protocol-opcua-c/ && \ + ./build.sh + +# Execute script +ENTRYPOINT ["sh", "./client"] diff --git a/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_client/build.sh b/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_client/build.sh new file mode 100644 index 0000000..1888565 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_client/build.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2019 Huawei Tech and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +set -o errexit + +# set the docker name and docker tag when you build +DOCKER_NAME= +DOCKER_TAG= + +export ELIOT_DIR=$(cd $(dirname $0); pwd) +export WORK_DIR=$ELIOT_DIR/work +export CMAKE_URL=https://github.com/Kitware/CMake/releases/download/v3.15.2/cmake-3.15.2.tar.gz +export SCONS_PPA_URL=http://repo.okay.com.mx/centos/7/x86_64/release//scons-2.3.0-1.el7.centos.noarch.rpm +export GET_PIP_URL=https://bootstrap.pypa.io/get-pip.py +export OPCUA_REPO=https://github.com/edgexfoundry-holding/protocol-opcua-c.git +export DOCKER_NAME=${DOCKER_NAME:-"eliot/opc-ua-client"} +export DOCKER_TAG=${DOCKER_TAG:-"latest"} + + +rm -rf $WORK_DIR +mkdir -p $WORK_DIR + +cd $WORK_DIR +wget $CMAKE_URL +wget $SCONS_PPA_URL +wget $GET_PIP_URL +git clone $OPCUA_REPO + +cd $ELIOT_DIR +docker build ./ -t $DOCKER_NAME:$DOCKER_TAG diff --git a/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_server/Dockerfile b/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_server/Dockerfile new file mode 100644 index 0000000..7a5239a --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_server/Dockerfile @@ -0,0 +1,15 @@ +FROM centos:centos7 +ADD ./work/ /root/work +RUN yum install -y gcc git +RUN yum groupinstall -y 'Development Tools' +RUN cd /root/work && ls -al && tar xzf cmake-3.15.2.tar.gz && \ + rpm -Uvh scons-2.3.0-1.el7.centos.noarch.rpm && \ + python get-pip.py && \ + cd cmake-3.15.2 && ./bootstrap && \ + make && \ + make install && \ + cd ../protocol-opcua-c/ && \ + ./build.sh + +# Execute script +ENTRYPOINT ["sh", "./server] diff --git a/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_server/build.sh b/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_server/build.sh new file mode 100644 index 0000000..4ce672f --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_opc-au/files/deploy/opc-au_server/build.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2019 Huawei Tech and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +set -o errexit + +# set the docker name and docker tag when you build +DOCKER_NAME= +DOCKER_TAG= + +export ELIOT_DIR=$(cd $(dirname $0); pwd) +export WORK_DIR=$ELIOT_DIR/work +export CMAKE_URL=https://github.com/Kitware/CMake/releases/download/v3.15.2/cmake-3.15.2.tar.gz +export SCONS_PPA_URL=http://repo.okay.com.mx/centos/7/x86_64/release//scons-2.3.0-1.el7.centos.noarch.rpm +export GET_PIP_URL=https://bootstrap.pypa.io/get-pip.py +export OPCUA_REPO=https://github.com/edgexfoundry-holding/protocol-opcua-c.git +export DOCKER_NAME=${DOCKER_NAME:-"eliot/opc-ua-server"} +export DOCKER_TAG=${DOCKER_TAG:-"latest"} + + +rm -rf $WORK_DIR +mkdir -p $WORK_DIR + +cd $WORK_DIR +wget $CMAKE_URL +wget $SCONS_PPA_URL +wget $GET_PIP_URL +git clone $OPCUA_REPO + +cd $ELIOT_DIR +docker build ./ -t $DOCKER_NAME:$DOCKER_TAG diff --git a/blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/install.yml new file mode 100644 index 0000000..4d62990 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/install.yml @@ -0,0 +1,33 @@ +# +# 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. +# + +--- + +- name: Doing deployment setup for el_opc-au + copy: + src: deploy + dest: /tmp/el_opc-au/ + +- name: Changing permisiion + command: chmod -R 755 /tmp/el_opc-au + +- name: Execute script for install opc-au-server + shell: + cmd: /tmp/el_opc-au/deploy/opc-au_server/build.sh + +- name: Execute script opc-ua-client build + shell: + cmd: /tmp/el_opc-au/deploy/opc-au_client/build.sh diff --git a/blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/main.yml new file mode 100644 index 0000000..ca0b525 --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/main.yml @@ -0,0 +1,26 @@ +# +# 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. +# + +--- + +# tasks file for el_opc-au +- include: "install.yml" + static: false + when: operation == 'install' + +- include: "uninstall.yml" + static: false + when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/uninstall.yml new file mode 100644 index 0000000..b44eb1a --- /dev/null +++ b/blueprints/iotgateway/playbooks/roles/el_opc-au/tasks/uninstall.yml @@ -0,0 +1,24 @@ +# +# 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. +# + +--- + +- name: Remove el_opc-au tmp folder + command: rm -rf /tmp/el_opc-au + args: + chdir: /tmp/ + ignore_errors: yes + no_log: True -- 2.16.6 From 162f27446c3a4b3d3d4b9834086738c11325d8e3 Mon Sep 17 00:00:00 2001 From: "arvind.patel@huawei.com" Date: Fri, 4 Dec 2020 12:29:46 +0530 Subject: [PATCH 12/16] Docker issue Signed-off-by: arvind.patel@huawei.com Change-Id: Ia6752ed0e3665bb3c12bc17c4ffd37f175aff472 --- blueprints/iotgateway/playbooks/config.yml | 2 ++ blueprints/iotgateway/playbooks/eliot-all-uninstall.yml | 1 + blueprints/iotgateway/playbooks/eliot-all.yml | 1 + .../playbooks/roles/prometheus/tasks/install.yml | 17 ++++++++++++++--- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/blueprints/iotgateway/playbooks/config.yml b/blueprints/iotgateway/playbooks/config.yml index da7eaf2..ed5ee5b 100644 --- a/blueprints/iotgateway/playbooks/config.yml +++ b/blueprints/iotgateway/playbooks/config.yml @@ -72,6 +72,8 @@ mecm_port: name: 30093 docker_registry_port: name: 5000 +prometheus_node_port: + name: 30009 # All Master related password which needs to be specified if user # doesn't need common password for security purpose diff --git a/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml b/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml index 4b5f671..7fb6742 100644 --- a/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml +++ b/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml @@ -29,6 +29,7 @@ - eg_certs - helm - k8s + - docker ############ Master ############ diff --git a/blueprints/iotgateway/playbooks/eliot-all.yml b/blueprints/iotgateway/playbooks/eliot-all.yml index 430ff9d..0721b5c 100644 --- a/blueprints/iotgateway/playbooks/eliot-all.yml +++ b/blueprints/iotgateway/playbooks/eliot-all.yml @@ -27,6 +27,7 @@ roles: - k8s - helm + - docker - eg_certs - eg_registry - eg_helm-repo diff --git a/blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml index f8472b4..bdb4c66 100644 --- a/blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml +++ b/blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml @@ -42,7 +42,18 @@ when: result is failed and ansible_architecture == 'aarch64' - name: "INSTALL: Install prometheus on aarch64" - shell: - cmd: 'helm install mep-prometheus - stable/prometheus -f /tmp/prometheus/values.yaml --version v9.3.1' + # yamllint disable rule:line-length + command: helm install mep-prometheus stable/prometheus -f /tmp/prometheus/values.yaml --version v9.3.1 --set alertmanager.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/prom/alertmanager --set configmapReload.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/jimmidyson/configmap-reload --set nodeExporter.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/prom/node-exporter --set server.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/prom/prometheus --set pushgateway.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/prom/pushgateway --set kubeStateMetrics.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/carlosedp/kube-state-metrics --set alertmanager.image.pullPolicy=IfNotPresent --set configmapReload.image.pullPolicy=IfNotPresent --set nodeExporter.image.pullPolicy=IfNotPresent --set server.image.pullPolicy=IfNotPresent --set pushgateway.image.pullPolicy=IfNotPresent --set kubeStateMetrics.image.pullPolicy=IfNotPresent + # yamllint disable rule:line-length when: result is failed and ansible_architecture == 'aarch64' + +- name: Expose promethious server + # yamllint disable rule:line-length + command: kubectl expose deployment mep-prometheus-server --type=NodePort --name nodeport-mep-prometheus-server + # yamllint disable rule:line-length + +- name: Execute patch service with given port + shell: + # yamllint disable rule:line-length + cmd: "kubectl patch service nodeport-mep-prometheus-server --type='json' --patch='[{ \"op\": \"replace\", \"path\": \"/spec/ports/0/nodePort\", \"value\":{{ vardata.prometheus_node_port.name }}}]'" + # yamllint disable rule:line-length -- 2.16.6 From 6246cb1fb8bcd410c6df05ebf9972277ad3010ea Mon Sep 17 00:00:00 2001 From: "arvind.patel@huawei.com" Date: Mon, 7 Dec 2020 19:00:16 +0530 Subject: [PATCH 13/16] New logic added cert and other Signed-off-by: arvind.patel@huawei.com Change-Id: I755bad6af4969e9becd3f151ef13521d2dbdce16 --- blueprints/iotgateway/playbooks/config.yml | 6 ------ blueprints/iotgateway/playbooks/roles/eg_certs/tasks/install.yml | 2 +- .../iotgateway/playbooks/roles/eg_mecm-meo/tasks/install.yml | 4 ++-- .../iotgateway/playbooks/roles/prometheus/tasks/install.yml | 8 ++++++++ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/blueprints/iotgateway/playbooks/config.yml b/blueprints/iotgateway/playbooks/config.yml index ed5ee5b..c45dc1d 100644 --- a/blueprints/iotgateway/playbooks/config.yml +++ b/blueprints/iotgateway/playbooks/config.yml @@ -55,12 +55,6 @@ mecm_mepm_postgresk8sPluginPassword: name: ########### Master config ########### -######### Mandatory ######### -mecm_meo_edgeRepoUserName: - name: -mecm_meo_edgeRepoPassword: - name: - ######### Optional ######### usermgmt_port: name: 30067 diff --git a/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/install.yml index 4aa99bf..1aa05cf 100644 --- a/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/install.yml +++ b/blueprints/iotgateway/playbooks/roles/eg_certs/tasks/install.yml @@ -33,5 +33,5 @@ - name: generate cert # yamllint disable rule:line-length - command: docker run -e CERT_VALIDITY_IN_DAYS=365 -v /tmp/ssl-eg-keys-certs:/certs swr.ap-southeast-1.myhuaweicloud.com/edgegallery/deploy-tool:latest + command: docker run -e CERT_VALIDITY_IN_DAYS=365 -v /tmp/ssl-eg-keys-certs:/certs {{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/edgegallery/deploy-tool:latest # yamllint disable rule:line-length diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/install.yml index e6c2fc7..ecbd950 100644 --- a/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/install.yml +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-meo/tasks/install.yml @@ -50,7 +50,7 @@ - name: Create certificate edgegallery-mecm-secret with common pwd # yamllint disable rule:line-length - command: kubectl create secret generic edgegallery-mecm-secret --from-file=postgres_init.sql=/tmp/eg_mecm-meo/deploy/conf/keys/postgres_init.sql --from-literal=postgresPassword={{ vardata.common_pwd.name}} --from-literal=postgresApmPassword={{ vardata.common_pwd.name}} --from-literal=postgresAppoPassword={{ vardata.common_pwd.name}} --from-literal=postgresInventoryPassword={{ vardata.common_pwd.name}} --from-literal=edgeRepoUserName={{ vardata.mecm_meo_edgeRepoUserName.name}} --from-literal=edgeRepoPassword={{ vardata.mecm_meo_edgeRepoPassword.name}} + command: kubectl create secret generic edgegallery-mecm-secret --from-file=postgres_init.sql=/tmp/eg_mecm-meo/deploy/conf/keys/postgres_init.sql --from-literal=postgresPassword={{ vardata.common_pwd.name}} --from-literal=postgresApmPassword={{ vardata.common_pwd.name}} --from-literal=postgresAppoPassword={{ vardata.common_pwd.name}} --from-literal=postgresInventoryPassword={{ vardata.common_pwd.name}} --from-literal=edgeRepoUserName=admin --from-literal=edgeRepoPassword={{ vardata.common_pwd.name}} # yamllint disable rule:line-length args: chdir: /tmp/eg_mecm-meo/deploy/ @@ -58,7 +58,7 @@ - name: Generates certificate edgegallery-mecm-secret # yamllint disable rule:line-length - command: kubectl create secret generic edgegallery-mecm-secret --from-file=postgres_init.sql=/tmp/eg_mecm-meo/deploy/conf/keys/postgres_init.sql --from-literal=postgresPassword={{ vardata.mecm_meo_postgresPassword.name}} --from-literal=postgresApmPassword={{ vardata.mecm_meo_postgresApmPassword.name}} --from-literal=postgresAppoPassword={{ vardata.mecm_meo_postgresAppoPassword.name}} --from-literal=postgresInventoryPassword={{ vardata.mecm_meo_postgresInventoryPassword.name}} --from-literal=edgeRepoUserName={{ vardata.mecm_meo_edgeRepoUserName.name}} --from-literal=edgeRepoPassword={{ vardata.mecm_meo_edgeRepoPassword.name}} + command: kubectl create secret generic edgegallery-mecm-secret --from-file=postgres_init.sql=/tmp/eg_mecm-meo/deploy/conf/keys/postgres_init.sql --from-literal=postgresPassword={{ vardata.mecm_meo_postgresPassword.name}} --from-literal=postgresApmPassword={{ vardata.mecm_meo_postgresApmPassword.name}} --from-literal=postgresAppoPassword={{ vardata.mecm_meo_postgresAppoPassword.name}} --from-literal=postgresInventoryPassword={{ vardata.mecm_meo_postgresInventoryPassword.name}} --from-literal=edgeRepoUserName=admin --from-literal=edgeRepoPassword={{ vardata.common_pwd.name}} # yamllint disable rule:line-length args: chdir: /tmp/eg_mecm-meo/deploy/ diff --git a/blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml index bdb4c66..2c0d05a 100644 --- a/blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml +++ b/blueprints/iotgateway/playbooks/roles/prometheus/tasks/install.yml @@ -33,6 +33,8 @@ - name: "INSTALL: Install prometheus on x86_64" shell: cmd: helm install mep-prometheus stable/prometheus --version v9.3.1 + ignore_errors: yes + no_log: True when: result is failed and ansible_architecture == 'x86_64' - name: "INSTALL: copy values.yaml to host" @@ -45,15 +47,21 @@ # yamllint disable rule:line-length command: helm install mep-prometheus stable/prometheus -f /tmp/prometheus/values.yaml --version v9.3.1 --set alertmanager.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/prom/alertmanager --set configmapReload.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/jimmidyson/configmap-reload --set nodeExporter.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/prom/node-exporter --set server.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/prom/prometheus --set pushgateway.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/prom/pushgateway --set kubeStateMetrics.image.repository={{ vardata.private_repo_ip.name}}:{{ vardata.docker_registry_port.name}}/carlosedp/kube-state-metrics --set alertmanager.image.pullPolicy=IfNotPresent --set configmapReload.image.pullPolicy=IfNotPresent --set nodeExporter.image.pullPolicy=IfNotPresent --set server.image.pullPolicy=IfNotPresent --set pushgateway.image.pullPolicy=IfNotPresent --set kubeStateMetrics.image.pullPolicy=IfNotPresent # yamllint disable rule:line-length + ignore_errors: yes + no_log: True when: result is failed and ansible_architecture == 'aarch64' - name: Expose promethious server # yamllint disable rule:line-length command: kubectl expose deployment mep-prometheus-server --type=NodePort --name nodeport-mep-prometheus-server # yamllint disable rule:line-length + ignore_errors: yes + no_log: True - name: Execute patch service with given port shell: # yamllint disable rule:line-length cmd: "kubectl patch service nodeport-mep-prometheus-server --type='json' --patch='[{ \"op\": \"replace\", \"path\": \"/spec/ports/0/nodePort\", \"value\":{{ vardata.prometheus_node_port.name }}}]'" # yamllint disable rule:line-length + ignore_errors: yes + no_log: True -- 2.16.6 From 85a634b1ba537e55c8b65404fd4467ad3732c683 Mon Sep 17 00:00:00 2001 From: "arvind.patel@huawei.com" Date: Mon, 7 Dec 2020 22:19:00 +0530 Subject: [PATCH 14/16] Log issue Signed-off-by: arvind.patel@huawei.com Change-Id: I3cf6c2d57937527a9005741430c08bd5b29f393e --- .../iotgateway/playbooks/eliot-all-uninstall.yml | 32 +++++++++++----------- .../playbooks/roles/docker/tasks/uninstall.yml | 21 ++++++++++++++ .../playbooks/roles/eg_mep/tasks/uninstall.yml | 10 +++---- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml b/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml index 7fb6742..6062bd2 100644 --- a/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml +++ b/blueprints/iotgateway/playbooks/eliot-all-uninstall.yml @@ -15,22 +15,6 @@ --- -############ OCD ############ - -- hosts: ocdconsolidated - become: yes - tags: - - ocdhost - - ocdconsolidated - - roles: - - eg_helm-repo - - eg_registry - - eg_certs - - helm - - k8s - - docker - ############ Master ############ ### EdgeGallery related ### @@ -125,3 +109,19 @@ roles: - k3s - docker + +############ OCD ############ + +- hosts: ocdconsolidated + become: yes + tags: + - ocdhost + - ocdconsolidated + + roles: + - eg_helm-repo + - eg_registry + - eg_certs + - helm + - k8s + - docker diff --git a/blueprints/iotgateway/playbooks/roles/docker/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/docker/tasks/uninstall.yml index f756489..f5a40f7 100644 --- a/blueprints/iotgateway/playbooks/roles/docker/tasks/uninstall.yml +++ b/blueprints/iotgateway/playbooks/roles/docker/tasks/uninstall.yml @@ -57,6 +57,26 @@ when: result is succeeded and ansible_architecture == 'aarch64' #when: result is succeeded +- name: "UNINSTALL: Uninstall docker engine" + command: apt-get purge -y docker-engine + ignore_errors: yes + when: result is succeeded and ansible_architecture == 'x86_64' + +- name: "UNINSTALL: Uninstall docker" + command: apt-get purge -y docker + ignore_errors: yes + when: result is succeeded and ansible_architecture == 'x86_64' + +- name: "UNINSTALL: Uninstall docker.io" + command: apt-get purge -y docker.io + ignore_errors: yes + when: result is succeeded and ansible_architecture == 'x86_64' + +- name: "UNINSTALL: Uninstall docker.io" + command: apt-get purge docker-ce docker-ce-cli containerd.io + ignore_errors: yes + when: result is succeeded and ansible_architecture == 'x86_64' + - debug: msg: "CentOS commands start" @@ -65,3 +85,4 @@ cmd: yes | yum remove docker-ce docker-ce-cli containerd.io ignore_errors: yes no_log: true + when: ansible_facts['distribution'] == "CentOS" diff --git a/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/uninstall.yml index fba5576..3cf66ef 100644 --- a/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/uninstall.yml +++ b/blueprints/iotgateway/playbooks/roles/eg_mep/tasks/uninstall.yml @@ -35,6 +35,11 @@ ignore_errors: yes no_log: True +- name: Delete dns namesapce metallb + command: kubectl delete secret memberlist -n metallb-system + ignore_errors: yes + no_log: True + - name: Delete ssl config namesapce mep command: kubectl delete ns mep ignore_errors: yes @@ -100,8 +105,3 @@ command: kubectl delete -f /tmp/eg_mep/deploy/conf/edge/metallb/namespace.yaml ignore_errors: yes no_log: True - -- name: Delete dns namesapce metallb - command: kubectl delete secret memberlist -n metallb-system - ignore_errors: yes - no_log: True -- 2.16.6 From d8852a70dc0f83c3500e91108a339554856e2ea0 Mon Sep 17 00:00:00 2001 From: "arvind.patel@huawei.com" Date: Tue, 15 Dec 2020 12:13:43 +0530 Subject: [PATCH 15/16] Docker issue and log Signed-off-by: arvind.patel@huawei.com Change-Id: Iaaef6d62f4ab5b432e5a6f9752970f380ec9622f --- blueprints/iotgateway/playbooks/roles/docker/tasks/main.yml | 6 +++--- .../iotgateway/playbooks/roles/eg_mecm-mepm/tasks/uninstall.yml | 5 ----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/blueprints/iotgateway/playbooks/roles/docker/tasks/main.yml b/blueprints/iotgateway/playbooks/roles/docker/tasks/main.yml index b8f4286..01147f4 100644 --- a/blueprints/iotgateway/playbooks/roles/docker/tasks/main.yml +++ b/blueprints/iotgateway/playbooks/roles/docker/tasks/main.yml @@ -18,6 +18,6 @@ static: false when: operation == 'install' -- include: "uninstall.yml" - static: false - when: operation == 'uninstall' +#- include: "uninstall.yml" +# static: false +# when: operation == 'uninstall' diff --git a/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/uninstall.yml b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/uninstall.yml index 699ef18..4ee0c36 100644 --- a/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/uninstall.yml +++ b/blueprints/iotgateway/playbooks/roles/eg_mecm-mepm/tasks/uninstall.yml @@ -16,11 +16,6 @@ --- -- name: Delete mecm-mepm secret - command: helm uninstall mecm-mepm-edgegallery - ignore_errors: yes - no_log: True - - name: Mecm mepm jwt delete # yamllint disable rule:line-length command: kubectl delete secret mecm-mepm-jwt-public-secret mecm-mepm-ssl-secret edgegallery-mepm-secret -- 2.16.6 From 140ab71354801c7f38b7936b7534bd70e4a70b0b Mon Sep 17 00:00:00 2001 From: "arvind.patel@huawei.com" Date: Tue, 15 Dec 2020 15:36:57 +0530 Subject: [PATCH 16/16] Cert issue fixed Signed-off-by: arvind.patel@huawei.com Change-Id: Ie25a2e02b9615ca528a6f5fe196cf08131504f59 --- blueprints/iotgateway/playbooks/eliot-all.yml | 2 +- .../iotgateway/playbooks/roles/eg_registry/tasks/install.yml | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/blueprints/iotgateway/playbooks/eliot-all.yml b/blueprints/iotgateway/playbooks/eliot-all.yml index 0721b5c..148acaf 100644 --- a/blueprints/iotgateway/playbooks/eliot-all.yml +++ b/blueprints/iotgateway/playbooks/eliot-all.yml @@ -28,9 +28,9 @@ - k8s - helm - docker - - eg_certs - eg_registry - eg_helm-repo + - eg_certs ############ Master ############ diff --git a/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/install.yml b/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/install.yml index 443365d..def9fc6 100644 --- a/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/install.yml +++ b/blueprints/iotgateway/playbooks/roles/eg_registry/tasks/install.yml @@ -79,6 +79,12 @@ command: rm -rf /tmp/eg_registry/deploy/eg_swr_images/nginx#stable.tar.gz when: processor == "x86_64" +- name: Docker image replaced for cross playform tool chain + # yamllint disable rule:line-length + command: rm -rf /tmp/eg_registry/deploy/eg_swr_images/edgegallery@deploy-tool#latest.tar.gz + # yamllint disable rule:line-length + when: processor == "x86_64" + - name: Copy registry from x86 tarball command: cp -r /tmp/eg_registry/armtarball/registry /tmp/eg_registry/deploy/ when: processor == "x86_64" @@ -89,6 +95,12 @@ # yamllint disable rule:line-length when: processor == "x86_64" +- name: Copy docker image from x86 tarball tool chain + # yamllint disable rule:line-length + command: cp -r /tmp/eg_registry/armtarball/eg_swr_images/edgegallery@deploy-tool#latest.tar.gz /tmp/eg_registry/deploy/eg_swr_images/ + # yamllint disable rule:line-length + when: processor == "x86_64" + - name: Replacing private ip replace: path: /tmp/eg_registry/deploy/load-images.sh -- 2.16.6