diff options
Diffstat (limited to 'mod2/helm-generator/helmchartgenerator-core/src/main/java/org/onap/dcaegen2/platform/helmchartgenerator/chartbuilder/ComponentSpecParser.java')
-rw-r--r-- | mod2/helm-generator/helmchartgenerator-core/src/main/java/org/onap/dcaegen2/platform/helmchartgenerator/chartbuilder/ComponentSpecParser.java | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/mod2/helm-generator/helmchartgenerator-core/src/main/java/org/onap/dcaegen2/platform/helmchartgenerator/chartbuilder/ComponentSpecParser.java b/mod2/helm-generator/helmchartgenerator-core/src/main/java/org/onap/dcaegen2/platform/helmchartgenerator/chartbuilder/ComponentSpecParser.java new file mode 100644 index 0000000..942e5ae --- /dev/null +++ b/mod2/helm-generator/helmchartgenerator-core/src/main/java/org/onap/dcaegen2/platform/helmchartgenerator/chartbuilder/ComponentSpecParser.java @@ -0,0 +1,331 @@ +/* + * # ============LICENSE_START======================================================= + * # Copyright (c) 2021 AT&T Intellectual Property. All rights reserved. + * # ================================================================================ + * # 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. + * # ============LICENSE_END========================================================= + */ + +package org.onap.dcaegen2.platform.helmchartgenerator.chartbuilder; + +import org.jetbrains.annotations.NotNull; +import org.onap.dcaegen2.platform.helmchartgenerator.Utils; +import org.onap.dcaegen2.platform.helmchartgenerator.models.chartinfo.ChartInfo; +import org.onap.dcaegen2.platform.helmchartgenerator.models.chartinfo.Metadata; +import org.onap.dcaegen2.platform.helmchartgenerator.models.componentspec.base.ComponentSpec; +import org.onap.dcaegen2.platform.helmchartgenerator.models.componentspec.common.Artifacts; +import org.onap.dcaegen2.platform.helmchartgenerator.models.componentspec.common.HealthCheck; +import org.onap.dcaegen2.platform.helmchartgenerator.models.componentspec.common.Parameters; +import org.onap.dcaegen2.platform.helmchartgenerator.models.componentspec.common.Policy; +import org.onap.dcaegen2.platform.helmchartgenerator.models.componentspec.common.PolicyInfo; +import org.onap.dcaegen2.platform.helmchartgenerator.models.componentspec.common.Self; +import org.onap.dcaegen2.platform.helmchartgenerator.models.componentspec.common.Service; +import org.onap.dcaegen2.platform.helmchartgenerator.models.componentspec.common.TlsInfo; +import org.onap.dcaegen2.platform.helmchartgenerator.models.componentspec.common.Volumes; +import org.onap.dcaegen2.platform.helmchartgenerator.validation.ComponentSpecValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * ComponentSpecParser reads a componentspec file and collects useful data for helm chart generation. + * @author Dhrumin Desai + */ +@Component +public class ComponentSpecParser { + + @Autowired + private ComponentSpecValidator specValidator; + + /** + * Constructor for ComponentSpecParser + * @param specValidator ComponentSpecValidator implementation + */ + public ComponentSpecParser(ComponentSpecValidator specValidator) { + this.specValidator = specValidator; + } + + /** + * + * @param specFileLocation location of the application specification json file + * @param chartTemplateLocation location of the base helm chart template + * @param specSchemaLocation location of the specification json schema file to validate the application spec + * @return ChartInfo object populated with key-values + * @throws Exception + */ + public ChartInfo extractChartInfo(String specFileLocation, String chartTemplateLocation, String specSchemaLocation) throws Exception { + specValidator.validateSpecFile(specFileLocation, specSchemaLocation); + ComponentSpec cs = Utils.deserializeJsonFileToModel(specFileLocation, ComponentSpec.class); + ChartInfo chartInfo = new ChartInfo(); + chartInfo.setMetadata(extractMetadata(cs.getSelf())); + chartInfo.setValues(extractValues(cs, chartTemplateLocation)); + return chartInfo; + } + + private Map<String, Object> extractValues(ComponentSpec cs, String chartTemplateLocation) { + Map<String, Object> outerValues = new LinkedHashMap<>(); + if(cs.getAuxilary() != null && cs.getAuxilary().getTlsInfo() != null){ + Utils.putIfNotNull(outerValues,"certDirectory", cs.getAuxilary().getTlsInfo().getCertDirectory()); + Utils.putIfNotNull(outerValues, "tlsServer", cs.getAuxilary().getTlsInfo().getUseTls()); + } + if(cs.getAuxilary() != null && cs.getAuxilary().getLogInfo() != null) { + Utils.putIfNotNull(outerValues,"logDirectory", cs.getAuxilary().getLogInfo().get("log_directory")); + } + if(imageUriExistsForFirstArtifact(cs)){ + Utils.putIfNotNull(outerValues,"image", cs.getArtifacts()[0].getUri()); + } + populateApplicationConfigSection(outerValues, cs); + populateReadinessSection(outerValues, cs); + populateApplicationEnvSection(outerValues, cs); + populateServiceSection(outerValues, cs); + populateCertificatesSection(outerValues, cs, chartTemplateLocation); + populatePoliciesSection(outerValues, cs); + populateExternalVolumesSection(outerValues, cs); + populatePostgresSection(outerValues, cs); + populateSecretsSection(outerValues, cs); + return outerValues; + } + + private boolean imageUriExistsForFirstArtifact(ComponentSpec cs) { + final Artifacts[] artifacts = cs.getArtifacts(); + return artifacts != null && artifacts.length > 0 && artifacts[0].getUri() != null; + } + + private void populateApplicationConfigSection(Map<String, Object> outerValues, ComponentSpec cs) { + Map<String, Object> applicationConfig = new LinkedHashMap<>(); + Parameters[] parameters = cs.getParameters(); + for(Parameters param : parameters){ + applicationConfig.put(param.getName(), param.getValue()); + } + Utils.putIfNotNull(outerValues,"applicationConfig", applicationConfig); + } + + private void populateReadinessSection(Map<String, Object> outerValues, ComponentSpec cs) { + + if (!healthCheckExists(cs)) return; + + Map<String, Object> readiness = new LinkedHashMap<>(); + final HealthCheck healthcheck = cs.getAuxilary().getHealthcheck(); + Utils.putIfNotNull(readiness, "initialDelaySeconds", healthcheck.getInitialDelaySeconds()); + + if(healthcheck.getInterval() != null) { + readiness.put("periodSeconds", getSeconds(healthcheck.getInterval(), "interval")); + } + if(healthcheck.getTimeout() != null) { + readiness.put("timeoutSeconds", getSeconds(healthcheck.getTimeout(), "timeout")); + } + + readiness.put("path", healthcheck.getEndpoint()); + readiness.put("scheme", healthcheck.getType()); + readiness.put("port", healthcheck.getPort()); + + outerValues.put("readiness", readiness); + } + + private int getSeconds(String value, String field) { + int seconds = 0; + try { + seconds = Integer.parseInt(value.replaceAll("[^\\d.]", "")); + } + catch (NumberFormatException e){ + throw new RuntimeException(String.format("%s with %s is not given in a correct format", field, value)); + } + return seconds; + } + + private boolean healthCheckExists(ComponentSpec cs) { + return cs.getAuxilary() != null && + cs.getAuxilary().getHealthcheck() != null; + } + + private void populateApplicationEnvSection(Map<String, Object> outerValues, ComponentSpec cs){ + if(applicationEnvExists(cs)) { + Object applicationEnv = cs.getAuxilary().getHelm().getApplicationEnv(); + Utils.putIfNotNull(outerValues,"applicationEnv", applicationEnv); + } + } + + private boolean applicationEnvExists(ComponentSpec cs) { + return cs.getAuxilary() != null && + cs.getAuxilary().getHelm() != null && + cs.getAuxilary().getHelm().getApplicationEnv() != null; + } + + private void populateServiceSection(Map<String, Object> outerValues, ComponentSpec cs) { + if (!serviceExists(cs)) return; + + Map<String, Object> service = new LinkedHashMap<>(); + final Service serviceFromSpec = cs.getAuxilary().getHelm().getService(); + + if(serviceFromSpec.getPorts() != null){ + List<Object> ports = mapServicePorts(serviceFromSpec.getPorts()); + service.put("ports", ports); + Utils.putIfNotNull(service, "type", serviceFromSpec.getType()); + } + Utils.putIfNotNull(service,"name", serviceFromSpec.getName()); + Utils.putIfNotNull(service,"has_internal_only_ports", serviceFromSpec.getHasInternalOnlyPorts()); + outerValues.put("service", service); + } + + private boolean serviceExists(ComponentSpec cs) { + return cs.getAuxilary() != null && + cs.getAuxilary().getHelm() != null && + cs.getAuxilary().getHelm().getService() != null; + } + + private List<Object> mapServicePorts(Object[] ports) { + List<Object> portsList = new ArrayList<>(); + Collections.addAll(portsList, ports); + return portsList; + } + + private void populatePoliciesSection(Map<String, Object> outerValues, ComponentSpec cs) { + Map<String, Object> policies = new LinkedHashMap<>(); + final PolicyInfo policyInfo = cs.getPolicyInfo(); + if(policyInfo != null && policyInfo.getPolicy() != null) { + List<String> policyList = new ArrayList<>(); + for (Policy policyItem : policyInfo.getPolicy()) { + policyList.add('"' + policyItem.getPolicyID() + '"'); + } + policies.put("policyRelease", "onap"); + policies.put("duration", 300); + policies.put("policyID", "'" + policyList.toString() + "'\n"); + outerValues.put("policies", policies); + } + } + + private void populateCertificatesSection(Map<String, Object> outerValues, ComponentSpec cs, String chartTemplateLocation) { + Map<String, Object> certificate = new LinkedHashMap<>(); + Map<String, Object> keystore = new LinkedHashMap<>(); + Map<String, Object> passwordsSecretRef = new LinkedHashMap<>(); + TlsInfo tlsInfo = cs.getAuxilary().getTlsInfo(); + String componentName = getComponentNameWithOmitFirstWord(cs); + if(externalTlsExists(tlsInfo)) { + String mountPath = tlsInfo.getCertDirectory(); + if(tlsInfo.getUseExternalTls() != null && tlsInfo.getUseExternalTls()) { + checkCertificateYamlExists(chartTemplateLocation); + mountPath += "external"; + } + passwordsSecretRef.put("name", componentName + "-cmpv2-keystore-password"); + passwordsSecretRef.put("key", "password"); + passwordsSecretRef.put("create", true); + keystore.put("outputType", List.of("jks")); + keystore.put("passwordSecretRef", passwordsSecretRef); + certificate.put("mountPath", mountPath); + Utils.putIfNotNull(certificate,"commonName", cs.getSelf().getName()); + Utils.putIfNotNull(certificate,"dnsNames", List.of(cs.getSelf().getName())); + certificate.put("keystore", keystore); + outerValues.put("certificates", List.of(certificate)); + } + } + + private String getComponentNameWithOmitFirstWord(ComponentSpec cs) { + return cs.getSelf().getName().substring(cs.getSelf().getName().indexOf("-") + 1); + } + + private boolean externalTlsExists(TlsInfo tlsInfo) { + return tlsInfo != null && tlsInfo.getUseExternalTls() != null && tlsInfo.getUseExternalTls().equals(true); + } + + private void checkCertificateYamlExists(String chartTemplateLocation) { + Path certificateYaml = Paths.get(chartTemplateLocation, "addons/templates/certificates.yaml"); + if(!Files.exists(certificateYaml)) { + throw new RuntimeException("certificates.yaml not found under templates directory in addons"); + } + } + + private void populateExternalVolumesSection(Map<String, Object> outerValues, ComponentSpec cs) { + if(cs.getAuxilary().getVolumes() != null) { + List<Object> externalVolumes = new ArrayList<>(); + Volumes[] volumes = cs.getAuxilary().getVolumes(); + for (Volumes volume : volumes) { + if(volume.getHost() == null) { + Map<String, Object> tempVolume = new LinkedHashMap<>(); + tempVolume.put("name", volume.getConfigVolume().getName()); + tempVolume.put("type", "configMap"); + tempVolume.put("mountPath", volume.getContainer().getBind()); + tempVolume.put("optional", true); + externalVolumes.add(tempVolume); + } + } + if(!externalVolumes.isEmpty()) { + outerValues.put("externalVolumes", externalVolumes); + } + } + } + + private void populatePostgresSection(Map<String, Object> outerValues, ComponentSpec cs) { + if(cs.getAuxilary().getDatabases() != null) { + String componentFullName = cs.getSelf().getName(); + String component = getComponentNameWithOmitFirstWord(cs); + Map<String, Object> postgres = new LinkedHashMap<>(); + Map<String, Object> service = new LinkedHashMap<>(); + Map<String, Object> container = new LinkedHashMap<>(); + Map<String, Object> name = new LinkedHashMap<>(); + Map<String, Object> persistence = new LinkedHashMap<>(); + Map<String, Object> config = new LinkedHashMap<>(); + service.put("name", componentFullName + "-postgres"); + service.put("name2", componentFullName + "-pg-primary"); + service.put("name3", componentFullName + "-pg-replica"); + name.put("primary", componentFullName + "-pg-primary"); + name.put("replica", componentFullName + "-pg-replica"); + container.put("name", name); + persistence.put("mountSubPath", componentFullName + "/data"); + persistence.put("mountInitPath", componentFullName); + config.put("pgUserName", component); + config.put("pgDatabase", component); + config.put("pgUserExternalSecret", "{{ include \"common.release\" . }}-" + component + "-pg-user-creds"); + + postgres.put("enabled", true); + postgres.put("nameOverride", componentFullName + "-postgres"); + postgres.put("service", service); + postgres.put("container", container); + postgres.put("persistence", persistence); + postgres.put("config", config); + outerValues.put("postgres", postgres); + } + } + + private void populateSecretsSection(Map<String, Object> outerValues, ComponentSpec cs) { + if(cs.getAuxilary().getDatabases() != null) { + String component = getComponentNameWithOmitFirstWord(cs); + List<Object> secrets = new ArrayList<>(); + Map<String, Object> secret = new LinkedHashMap<>(); + secret.put("uid", "pg-user-creds"); + secret.put("name", "{{ include \"common.release\" . }}-" + component + "-pg-user-creds"); + secret.put("type", "basicAuth"); + secret.put("externalSecret", "{{ ternary \"\" (tpl (default \"\" .Values.postgres.config.pgUserExternalSecret) .) (hasSuffix \"" + component + "-pg-user-creds\" .Values.postgres.config.pgUserExternalSecret) }}"); + secret.put("login", "{{ .Values.postgres.config.pgUserName }}"); + secret.put("password", "{{ .Values.postgres.config.pgUserPassword }}"); + secret.put("passwordPolicy", "generate"); + secrets.add(secret); + outerValues.put("secrets", secrets); + } + } + + private Metadata extractMetadata(Self self) { + Metadata metadata = new Metadata(); + metadata.setName(self.getName()); + metadata.setDescription(self.getDescription()); + metadata.setVersion(self.getVersion()); + return metadata; + } +} |