From d54223e7cd3026e260e06df39dd52c4368e7053d Mon Sep 17 00:00:00 2001 From: awudzins Date: Wed, 19 Feb 2020 13:34:32 +0100 Subject: Load CMP Servers config from volume Create Kubernetes secret to store Cmp Server config file and mount it to container as volume Issue-ID: AAF-997 Signed-off-by: Adam Wudzinski Change-Id: I163b720ce14729328af34dd61e6eb0108c76d58b --- certService/README.md | 175 ++++++++++----------- .../aaf-cert-service/resources/cmpServers.json | 24 +++ .../aaf-cert-service/templates/deployment.yaml | 8 + .../helm/aaf-cert-service/templates/secret.yaml | 7 + certService/helm/aaf-cert-service/values.yaml | 8 +- .../configuration/CmpServersConfig.java | 21 ++- .../configuration/CmpServersConfigLoader.java | 26 ++- .../src/main/resources/application.properties | 9 +- certService/src/main/resources/cmpServers.json | 24 --- .../configuration/CmpServersConfigLoaderTest.java | 85 ++++++++++ .../configuration/CmpServersConfigTest.java | 40 ++++- 11 files changed, 279 insertions(+), 148 deletions(-) create mode 100644 certService/helm/aaf-cert-service/resources/cmpServers.json create mode 100644 certService/helm/aaf-cert-service/templates/secret.yaml delete mode 100644 certService/src/main/resources/cmpServers.json create mode 100644 certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoaderTest.java diff --git a/certService/README.md b/certService/README.md index 5a650f1c..f9478bed 100644 --- a/certService/README.md +++ b/certService/README.md @@ -13,138 +13,129 @@ More information about the project and all its functionalities you can find unde For IntelliJ use [https://plugins.jetbrains.com/plugin/8527-google-java-format] For other IDEs use []https://github.com/google/google-java-format] -### Running Locally - ``` - mvn spring-boot:run +### Local project configuration + * Create directory on your system /etc/onap/aaf/certservice + * Copy sample configuration test/resources/cmpServers.json to that directory - ``` - +### Running Locally +MANDATORY SEE 'Local project configuration' section +``` +mvn spring-boot:run +``` + ### Running Locally with Developer Tools - ``` - mvn spring-boot:run -Pdev - - ``` +MANDATORY SEE 'Local project configuration' section +``` +mvn spring-boot:run -Pdev +``` ### Project building - ``` - mvn clean package - - ``` +``` +mvn clean package +``` ### Building Docker image manually Go to the certService subfolder and execute following statement (1.0.0-SNAPSHOT is related to a current project.version parameter): - ``` - docker build --build-arg VERSION=1.0.0-SNAPSHOT -t onap/org.onap.aaf.certservice.aaf-certservice-api . - ``` +``` +docker build --build-arg VERSION=1.0.0-SNAPSHOT -t onap/org.onap.aaf.certservice.aaf-certservice-api . +``` ### Install the package into the local repository - ``` - mvn clean install - - ``` +``` +mvn clean install +``` ### Building Docker image and install the package into the local repository - ``` - mvn clean install -P docker - - ``` +``` +mvn clean install -P docker +``` ### Running Docker container local - ``` - docker run -p 8080:8080 --name aaf-certservice-api onap/org.onap.aaf.certservice.aaf-certservice-api - - ``` +``` +docker run -p 8080:8080 --name aaf-certservice-api onap/org.onap.aaf.certservice.aaf-certservice-api +``` ### Running Docker container from nexus - ``` - docker run -p 8080:8080 --name aaf-certservice-api nexus3.onap.org:10001/onap/org.onap.aaf.certservice.aaf-certservice-api:1.0.0 - - ``` +``` +docker run -p 8080:8080 --name aaf-certservice-api nexus3.onap.org:10001/onap/org.onap.aaf.certservice.aaf-certservice-api:1.0.0 +``` ### Running Docker container from docker-compose with EJBCA - Docker-compose uses nexus image of certservice. - - ``` - docker-compose up - - ``` +Docker-compose uses nexus image of certservice. +``` +docker-compose up +``` + +### Running with Helm +1. Use environment/server with installed kubernetes and helm. +2. Copy helm/aaf-cert-service directory to that environment. +3. Enter that environment +4. Run ```helm install ./aaf-cert-service``` ### Health Check - Browser: - - ``` - http://:8080/actuator/health +Browser: +``` +http://:8080/actuator/health +``` - ``` - - Curl: - - ``` - curl localhost:8080/actuator/health - - ``` +Curl: +``` +curl localhost:8080/actuator/health +``` Should return {"status":"UP"} ### Running CSITs Pull csit repository - - ``` - https://gerrit.onap.org/r/admin/repos/integration/csit - - ``` +``` +https://gerrit.onap.org/r/admin/repos/integration/csit +``` Go to created directory and run - - ``` - sudo ./run-csit.sh plans/aaf/cert-service - - ``` +``` +sudo ./run-csit.sh plans/aaf/cert-service +``` ### Logs locally path: - - ``` - var/log/onap/aaf/certservice/ - ``` +``` +var/log/onap/aaf/certservice/ +``` ### Logs in Docker container - ``` - docker exec -it aaf-certservice-api bash - ``` +``` +docker exec -it aaf-certservice-api bash +``` path: - - ``` - cd /var/log/onap/aaf/certservice - ``` +``` +cd /var/log/onap/aaf/certservice +``` You should see: audit.log error.log trace.log ### Sonar results - ``` - https://sonarcloud.io/dashboard?id=onap_aaf-certservice - ``` +``` +https://sonarcloud.io/dashboard?id=onap_aaf-certservice +``` - ### Maven artifacts - All maven artifacts are deployed under nexus uri: - ``` - https://nexus.onap.org/content/repositories/snapshots/org/onap/aaf/certservice/ - ``` +### Maven artifacts +All maven artifacts are deployed under nexus uri: +``` +https://nexus.onap.org/content/repositories/snapshots/org/onap/aaf/certservice/ +``` - ### Docker artifacts - All docker images are hosted under nexus3 uri: - ``` - https://nexus3.onap.org/repository/docker.snapshot/v2/onap/org.onap.aaf.certservice.aaf-certservice-api/ - ``` +### Docker artifacts +All docker images are hosted under nexus3 uri: +``` +https://nexus3.onap.org/repository/docker.snapshot/v2/onap/org.onap.aaf.certservice.aaf-certservice-api/ +``` ### RestAPI API is described by Swagger ( OpenAPI 3.0 ) on endpoint /docs ( endpoint is defined in properties as springdoc.swagger-ui.path ) - - ``` - http://localchost:8080/docs - - ``` +``` +http://localchost:8080/docs +``` ### Sonar results - ``` - https://sonarcloud.io/dashboard?id=onap_aaf-certservice - ``` +``` +https://sonarcloud.io/dashboard?id=onap_aaf-certservice +``` diff --git a/certService/helm/aaf-cert-service/resources/cmpServers.json b/certService/helm/aaf-cert-service/resources/cmpServers.json new file mode 100644 index 00000000..ee9e72b9 --- /dev/null +++ b/certService/helm/aaf-cert-service/resources/cmpServers.json @@ -0,0 +1,24 @@ +{ + "cmpv2Servers": [ + { + "caName": "TEST", + "url": "http://127.0.0.1/ejbca/publicweb/cmp/cmp", + "issuerDN": "CN=ManagementCA", + "caMode": "CLIENT", + "authentication": { + "iak": "xxx", + "rv": "yyy" + } + }, + { + "caName": "TEST2", + "url": "http://127.0.0.1/ejbca/publicweb/cmp/cmpRA", + "issuerDN": "CN=ManagementCA2", + "caMode": "RA", + "authentication": { + "iak": "xxx", + "rv": "yyy" + } + } + ] +} \ No newline at end of file diff --git a/certService/helm/aaf-cert-service/templates/deployment.yaml b/certService/helm/aaf-cert-service/templates/deployment.yaml index 0b64d730..2e16cbca 100644 --- a/certService/helm/aaf-cert-service/templates/deployment.yaml +++ b/certService/helm/aaf-cert-service/templates/deployment.yaml @@ -12,6 +12,10 @@ spec: labels: app: {{ .Values.appLabel }} spec: + volumes: + - name: {{ .Values.volume.name }} + secret: + secretName: {{ .Values.secret.name }} containers: - name: aaf-cert-service image: {{ .Values.repository }}/{{ .Values.image }} @@ -30,5 +34,9 @@ spec: path: {{ .Values.healthcheck.path }} initialDelaySeconds: {{ .Values.readiness.initialDelaySeconds }} periodSeconds: {{ .Values.readiness.periodSeconds }} + volumeMounts: + - name: {{ .Values.volume.name }} + mountPath: {{ .Values.volume.mountPath }} + readOnly: true resources: {{ toYaml .Values.resources }} diff --git a/certService/helm/aaf-cert-service/templates/secret.yaml b/certService/helm/aaf-cert-service/templates/secret.yaml new file mode 100644 index 00000000..77b25f4e --- /dev/null +++ b/certService/helm/aaf-cert-service/templates/secret.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.secret.name }} +type: Opaque +data: + {{ (.Files.Glob "resources/cmpServers.json").AsSecrets }} \ No newline at end of file diff --git a/certService/helm/aaf-cert-service/values.yaml b/certService/helm/aaf-cert-service/values.yaml index 9ec51c85..a971edd4 100644 --- a/certService/helm/aaf-cert-service/values.yaml +++ b/certService/helm/aaf-cert-service/values.yaml @@ -14,6 +14,9 @@ readiness: periodSeconds: 10 healthcheck: path: /actuator/health +volume: + name: aaf-cert-service-volume + mountPath: /etc/onap/aaf/certservice resources: limits: @@ -21,4 +24,7 @@ resources: memory: 2Gi requests: cpu: 1 - memory: 1Gi \ No newline at end of file + memory: 1Gi + +secret: + name: aaf-cert-service-secret diff --git a/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfig.java b/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfig.java index 105b10e7..414f38bb 100644 --- a/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfig.java +++ b/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfig.java @@ -20,21 +20,30 @@ package org.onap.aaf.certservice.certification.configuration; -import java.util.Collections; -import java.util.List; -import javax.annotation.PostConstruct; import org.onap.aaf.certservice.certification.configuration.model.Cmpv2Server; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; +import javax.annotation.PostConstruct; +import java.io.File; +import java.util.Collections; +import java.util.List; + @Configuration public class CmpServersConfig { - private static final String CMP_SERVERS_CONFIG_FILENAME = "cmpServers.json"; + + @Autowired + private CmpServersConfigLoader cmpServersConfigLoader; + @Value("${app.config.path}") + private String configPath; private List cmpServers; @PostConstruct - private void loadConfiguration() { - cmpServers = Collections.unmodifiableList(new CmpServersConfigLoader().load(CMP_SERVERS_CONFIG_FILENAME)); + void loadConfiguration() { + String configFilePath = configPath + File.separator + CMP_SERVERS_CONFIG_FILENAME; + this.cmpServers = Collections.unmodifiableList(cmpServersConfigLoader.load(configFilePath)); } public List getCmpServers() { diff --git a/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoader.java b/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoader.java index b31fbcad..c8415ac0 100644 --- a/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoader.java +++ b/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoader.java @@ -21,27 +21,26 @@ package org.onap.aaf.certservice.certification.configuration; import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import org.onap.aaf.certservice.certification.CertificationModelFactory; import org.onap.aaf.certservice.certification.configuration.model.CmpServers; import org.onap.aaf.certservice.certification.configuration.model.Cmpv2Server; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +@Component class CmpServersConfigLoader { - private static final Logger LOGGER = LoggerFactory.getLogger(CertificationModelFactory.class); + private static final Logger LOGGER = LoggerFactory.getLogger(CmpServersConfigLoader.class); List load(String path) { List result = new ArrayList<>(); try { result = loadConfigFromFile(path).getCmpv2Servers(); - } catch (FileNotFoundException e) { - LOGGER.error("CMP Servers configuration file not found: ", e); + LOGGER.info(String.format("CMP Servers configuration successfully loaded from file '%s'", path)); } catch (IOException e) { LOGGER.error("Exception occurred during CMP Servers configuration loading: ", e); } @@ -50,11 +49,6 @@ class CmpServersConfigLoader { private CmpServers loadConfigFromFile(String path) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); - URL resource = getClass().getClassLoader().getResource(path); - if (resource == null) { - throw new FileNotFoundException(); - } - String configFilePath = resource.getFile(); - return objectMapper.readValue(new File(configFilePath), CmpServers.class); + return objectMapper.readValue(new File(path), CmpServers.class); } } diff --git a/certService/src/main/resources/application.properties b/certService/src/main/resources/application.properties index b9ce108a..eab43c08 100644 --- a/certService/src/main/resources/application.properties +++ b/certService/src/main/resources/application.properties @@ -1,5 +1,10 @@ -#Actuator properties +# Actuator configuration management.endpoints.enabled-by-default=false management.endpoint.health.enabled=true -springdoc.swagger-ui.path=/docs springdoc.show-actuator=true + +# Swagger configuration +springdoc.swagger-ui.path=/docs + +# AAF CertService app specific configuration +app.config.path=/etc/onap/aaf/certservice \ No newline at end of file diff --git a/certService/src/main/resources/cmpServers.json b/certService/src/main/resources/cmpServers.json deleted file mode 100644 index ee9e72b9..00000000 --- a/certService/src/main/resources/cmpServers.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "cmpv2Servers": [ - { - "caName": "TEST", - "url": "http://127.0.0.1/ejbca/publicweb/cmp/cmp", - "issuerDN": "CN=ManagementCA", - "caMode": "CLIENT", - "authentication": { - "iak": "xxx", - "rv": "yyy" - } - }, - { - "caName": "TEST2", - "url": "http://127.0.0.1/ejbca/publicweb/cmp/cmpRA", - "issuerDN": "CN=ManagementCA2", - "caMode": "RA", - "authentication": { - "iak": "xxx", - "rv": "yyy" - } - } - ] -} \ No newline at end of file diff --git a/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoaderTest.java b/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoaderTest.java new file mode 100644 index 00000000..f4421ffe --- /dev/null +++ b/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoaderTest.java @@ -0,0 +1,85 @@ +/* + * ============LICENSE_START======================================================= + * PROJECT + * ================================================================================ + * Copyright (C) 2020 Nokia. 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.aaf.certservice.certification.configuration; + +import org.junit.jupiter.api.Test; +import org.onap.aaf.certservice.certification.configuration.model.Cmpv2Server; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class CmpServersConfigLoaderTest { + private static final String EXISTING_CONFIG_FILENAME = "cmpServers.json"; + private static final String NONEXISTING_CONFIG_FILENAME = "nonexisting_cmpServers.json"; + private static final Map EXPECTED_FIRST_CMP_SERVER = Map.of( + "CA_NAME", "TEST", + "URL", "http://127.0.0.1/ejbca/publicweb/cmp/cmp", + "ISSUER_DN", "CN=ManagementCA", + "CA_MODE", "CLIENT", + "IAK", "xxx", + "RV", "yyy" + ); + private static final Map EXPECTED_SECOND_CMP_SERVER = Map.of( + "CA_NAME", "TEST2", + "URL", "http://127.0.0.1/ejbca/publicweb/cmp/cmpRA", + "ISSUER_DN", "CN=ManagementCA2", + "CA_MODE", "RA", + "IAK", "xxx", + "RV", "yyy" + ); + + @Test + public void shouldLoadCmpServersConfigWhenFileAvailable() throws IOException { + // Given + String path = getClass().getClassLoader().getResource(EXISTING_CONFIG_FILENAME).getFile(); + + // When + List cmpServers = new CmpServersConfigLoader().load(path); + + // Then + assertThat(cmpServers).isNotNull(); + assertThat(cmpServers).hasSize(2); + verifyThatCmpServerEquals(cmpServers.get(0), EXPECTED_FIRST_CMP_SERVER); + verifyThatCmpServerEquals(cmpServers.get(1), EXPECTED_SECOND_CMP_SERVER); + } + + @Test() + public void shouldReturnEmptyListWhenFileMissing() { + // When + List cmpServers = new CmpServersConfigLoader().load(NONEXISTING_CONFIG_FILENAME); + + // Then + assertThat(cmpServers).isNotNull(); + assertThat(cmpServers).isEmpty(); + } + + private void verifyThatCmpServerEquals(Cmpv2Server cmpv2Server, Map expected) { + assertThat(cmpv2Server.getCaName()).isEqualTo(expected.get("CA_NAME")); + assertThat(cmpv2Server.getUrl()).isEqualTo(expected.get("URL")); + assertThat(cmpv2Server.getIssuerDN()).isEqualTo(expected.get("ISSUER_DN")); + assertThat(cmpv2Server.getCaMode().name()).isEqualTo(expected.get("CA_MODE")); + assertThat(cmpv2Server.getAuthentication().getIak()).isEqualTo(expected.get("IAK")); + assertThat(cmpv2Server.getAuthentication().getRv()).isEqualTo(expected.get("RV")); + } +} \ No newline at end of file diff --git a/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigTest.java b/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigTest.java index 4c9c5f66..43094f09 100644 --- a/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigTest.java +++ b/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigTest.java @@ -20,28 +20,54 @@ package org.onap.aaf.certservice.certification.configuration; -import static org.assertj.core.api.Assertions.assertThat; - import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; import org.onap.aaf.certservice.CertServiceApplication; +import org.onap.aaf.certservice.certification.configuration.model.Cmpv2Server; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.startsWith; + @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = CertServiceApplication.class) +@TestPropertySource(properties = {"app.config.path=/fake/path/to/config"}) class CmpServersConfigTest { + private static final List SAMPLE_CMP_SERVERS = List.of( + new Cmpv2Server(), + new Cmpv2Server() + ); + + @MockBean + private CmpServersConfigLoader cmpServersConfigLoader; + @Autowired private CmpServersConfig cmpServersConfig; @Test - public void shouldLoadCmpServersConfig() { + public void shouldCallLoaderWithPathFromPropertiesWhenCreated() { + Mockito.verify(cmpServersConfigLoader).load(startsWith("/fake/path/to/config")); + } + + @Test + public void shouldReturnLoadedServersWhenGetCalled() { + // Given + Mockito.when(cmpServersConfigLoader.load(any())).thenReturn(SAMPLE_CMP_SERVERS); + this.cmpServersConfig.loadConfiguration(); // Manual PostConstruct call + + // When + List receivedCmpServers = this.cmpServersConfig.getCmpServers(); + // Then - assertThat(cmpServersConfig.getCmpServers()).isNotNull(); - assertThat(cmpServersConfig.getCmpServers().size()).isEqualTo(2); - assertThat(cmpServersConfig.getCmpServers().get(0).getCaName()).isEqualTo("TEST"); - assertThat(cmpServersConfig.getCmpServers().get(1).getCaName()).isEqualTo("TEST2"); + assertThat(receivedCmpServers).hasSize(SAMPLE_CMP_SERVERS.size()); } } \ No newline at end of file -- cgit 1.2.3-korg