Load CMP Servers config from volume
authorawudzins <adam.wudzinski@nokia.com>
Wed, 19 Feb 2020 12:34:32 +0000 (13:34 +0100)
committerawudzins <adam.wudzinski@nokia.com>
Thu, 20 Feb 2020 11:43:59 +0000 (12:43 +0100)
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 <adam.wudzinski@nokia.com>
Change-Id: I163b720ce14729328af34dd61e6eb0108c76d58b

certService/README.md
certService/helm/aaf-cert-service/resources/cmpServers.json [moved from certService/src/main/resources/cmpServers.json with 100% similarity]
certService/helm/aaf-cert-service/templates/deployment.yaml
certService/helm/aaf-cert-service/templates/secret.yaml [new file with mode: 0644]
certService/helm/aaf-cert-service/values.yaml
certService/src/main/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfig.java
certService/src/main/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoader.java
certService/src/main/resources/application.properties
certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoaderTest.java [new file with mode: 0644]
certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigTest.java

index 5a650f1..f9478be 100644 (file)
@@ -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://<localhost>:8080/actuator/health
+Browser:
+```
+http://<localhost>: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
+```
index 0b64d73..2e16cbc 100644 (file)
@@ -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 (file)
index 0000000..77b25f4
--- /dev/null
@@ -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
index 9ec51c8..a971edd 100644 (file)
@@ -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
index 105b10e..414f38b 100644 (file)
 
 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<Cmpv2Server> 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<Cmpv2Server> getCmpServers() {
index b31fbca..c8415ac 100644 (file)
 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<Cmpv2Server> load(String path) {
         List<Cmpv2Server> 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);
     }
 }
index b9ce108..eab43c0 100644 (file)
@@ -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/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 (file)
index 0000000..f4421ff
--- /dev/null
@@ -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<String, String> 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<String, String> 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<Cmpv2Server> 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<Cmpv2Server> cmpServers = new CmpServersConfigLoader().load(NONEXISTING_CONFIG_FILENAME);
+
+        // Then
+        assertThat(cmpServers).isNotNull();
+        assertThat(cmpServers).isEmpty();
+    }
+
+    private void verifyThatCmpServerEquals(Cmpv2Server cmpv2Server, Map<String, String> 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
index 4c9c5f6..43094f0 100644 (file)
 
 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<Cmpv2Server> 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<Cmpv2Server> 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