Accept only Whitelisted Repos from Tosca Template 08/127308/3
authorLathish <lathishbabu.ganesan@est.tech>
Thu, 24 Feb 2022 13:26:01 +0000 (13:26 +0000)
committerLathish <lathishbabu.ganesan@est.tech>
Tue, 1 Mar 2022 09:27:40 +0000 (09:27 +0000)
Issue-ID: POLICY-3894
Change-Id: Iaffaf3f1243f6070c600a58891899e9e1e326732
Signed-off-by: Lathish <lathishbabu.ganesan@est.tech>
participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/configurations/HelmRepositoryConfig.java [new file with mode: 0644]
participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandler.java
participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/HelmClient.java
participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/models/HelmRepository.java
participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/service/ChartService.java
participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/application.yaml
participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandlerTest.java
participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/rest/ChartControllerTest.java
participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/service/ChartServiceTest.java
participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json

diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/configurations/HelmRepositoryConfig.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/configurations/HelmRepositoryConfig.java
new file mode 100644 (file)
index 0000000..4d00e38
--- /dev/null
@@ -0,0 +1,41 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.acm.participant.kubernetes.configurations;
+
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.Data;
+import org.onap.policy.clamp.acm.participant.kubernetes.models.HelmRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "helm")
+@Data
+public class HelmRepositoryConfig {
+
+    private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+    private List<HelmRepository> repos = new ArrayList<>();
+}
index 7536086..b4cca3a 100644 (file)
@@ -146,13 +146,14 @@ public class AutomationCompositionElementHandler implements AutomationCompositio
         LOGGER.info("Installation request received for the Helm Chart {} ", chartData);
         try {
             var chartInfo = CODER.convert(chartData, ChartInfo.class);
-            chartService.installChart(chartInfo);
-            chartMap.put(element.getId(), chartInfo);
-
-            var config = CODER.convert(nodeTemplate.getProperties(), ThreadConfig.class);
-            checkPodStatus(automationCompositionId, element.getId(), chartInfo, config.uninitializedToPassiveTimeout,
-                    config.podStatusCheckInterval);
-
+            if (chartService.installChart(chartInfo)) {
+                chartMap.put(element.getId(), chartInfo);
+
+                var config = CODER.convert(nodeTemplate.getProperties(),
+                        ThreadConfig.class);
+                checkPodStatus(automationCompositionId, element.getId(), chartInfo,
+                        config.uninitializedToPassiveTimeout, config.podStatusCheckInterval);
+            }
         } catch (ServiceException | CoderException | IOException | ExecutionException
                 | InterruptedException e) {
             LOGGER.warn("Installation of Helm chart failed", e);
index 6a7c62b..f3f7d34 100644 (file)
@@ -190,18 +190,14 @@ public class HelmClient {
         if (StringUtils.isEmpty(repo.getAddress())) {
             throw new ServiceException("Repository Should have valid address");
         }
-        var url = repo.getProtocol() + "://" + repo.getAddress();
-        if (repo.getPort() != null) {
-            url =  url + ":" + repo.getPort();
-        }
         // @formatter:off
         List<String> helmArguments = new ArrayList<>(
                 List.of(
                         "helm",
                         "repo",
-                        "add", repo.getRepoName(), url
+                        "add", repo.getRepoName(), repo.getAddress()
                 ));
-        if (repo.getUserName() != null && repo.getPassword() != null) {
+        if (!StringUtils.isEmpty(repo.getUserName()) && !StringUtils.isEmpty(repo.getPassword())) {
             helmArguments.addAll(List.of("--username", repo.getUserName(), "--password",  repo.getPassword()));
         }
         return new ProcessBuilder().command(helmArguments);
index 2e25e42..ff3b9e3 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ========================LICENSE_START=================================
- * Copyright (C) 2021 Nordix Foundation. All rights reserved.
+ * Copyright (C) 2021-2022 Nordix Foundation. 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.
 
 package org.onap.policy.clamp.acm.participant.kubernetes.models;
 
+import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 @Data
 @Builder
+@NoArgsConstructor
+@AllArgsConstructor
 public class HelmRepository {
 
     private String repoName;
 
-    private String protocol;
-
     private String address;
 
-    private String port;
-
     private String userName;
 
     private String password;
index dc4762d..e9cd8a2 100644 (file)
@@ -21,6 +21,7 @@ package org.onap.policy.clamp.acm.participant.kubernetes.service;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.Collection;
+import org.onap.policy.clamp.acm.participant.kubernetes.configurations.HelmRepositoryConfig;
 import org.onap.policy.clamp.acm.participant.kubernetes.exception.ServiceException;
 import org.onap.policy.clamp.acm.participant.kubernetes.helm.HelmClient;
 import org.onap.policy.clamp.acm.participant.kubernetes.models.ChartInfo;
@@ -41,6 +42,9 @@ public class ChartService {
     @Autowired
     private HelmClient helmClient;
 
+    @Autowired
+    private HelmRepositoryConfig helmRepositoryConfig;
+
     /**
      * Get all the installed charts.
      * @return list of charts.
@@ -84,25 +88,40 @@ public class ChartService {
     /**
      * Install a helm chart.
      * @param chart name and version.
+     * @return boolean flag to indicate success or failure
      * @throws ServiceException in case of error
      * @throws IOException in case of IO errors
      */
-    public void installChart(ChartInfo chart) throws ServiceException, IOException {
+    public boolean installChart(ChartInfo chart) throws ServiceException, IOException {
+        boolean whiteListed = false;
         if (chart.getRepository() == null) {
             String repoName = findChartRepo(chart);
             if (repoName == null) {
                 logger.error("Chart repository could not be found. Skipping chart Installation "
                     + "for the chart {} ", chart.getChartId().getName());
-                return;
+                return false;
             } else {
                 HelmRepository repo = HelmRepository.builder().repoName(repoName).build();
                 chart.setRepository(repo);
             }
         } else {
             // Add remote repository if passed via TOSCA
-            configureRepository(chart.getRepository());
+            // check whether the repo is whitelisted
+            for (HelmRepository repo : helmRepositoryConfig.getRepos()) {
+                if (repo.getAddress().equals(chart.getRepository().getAddress())
+                        && chart.getRepository().getAddress().contains("https")) {
+                    configureRepository(chart.getRepository());
+                    whiteListed = true;
+                    break;
+                }
+            }
+            if (!whiteListed) {
+                logger.error("Repository is not Whitelisted / plain http in not allowed");
+                return false;
+            }
         }
         helmClient.installChart(chart);
+        return true;
     }
 
 
index 3be0fb2..3718fed 100644 (file)
@@ -13,7 +13,7 @@ participant:
     reportingTimeIntervalMs: 120000
     description: Participant Description
     participantId:
-      name: org.onap.policy.clamp.acm.KubernetesParticipant
+      name: K8sParticipant0
       version: 2.3.4
     participantType:
       name: org.onap.k8s.acm.K8SAutomationCompositionParticipant
@@ -46,7 +46,7 @@ server:
 logging:
   # Configuration of logging
   level:
-    ROOT: ERROR
+    ROOT: INFO
     org.springframework: ERROR
     org.springframework.data: ERROR
     org.springframework.web.reactive.function.client.ExchangeFunctions: ERROR
@@ -58,3 +58,12 @@ logging:
 chart:
   api:
     enabled: false
+
+helm:
+  repos:
+    -
+      repoName: kong
+      address: https://charts.konghq.com
+    -
+      repoName: bitnami
+      address: https://charts.bitnami.com/bitnami
\ No newline at end of file
index dc74afc..6124060 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation.
+ *  Copyright (C) 2021-2022 Nordix Foundation.
  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -132,6 +132,7 @@ class AutomationCompositionElementHandlerTest {
     @Test
     void test_AutomationCompositionElementUpdate() throws PfModelException, IOException, ServiceException,
         ExecutionException, InterruptedException {
+        doReturn(true).when(chartService).installChart(any());
         doNothing().when(automationCompositionElementHandler).checkPodStatus(any(), any(), any(), anyInt(), anyInt());
         UUID elementId1 = UUID.randomUUID();
         AutomationCompositionElement element = new AutomationCompositionElement();
index c59e7fb..7105c23 100644 (file)
@@ -24,6 +24,7 @@ package org.onap.policy.clamp.acm.participant.kubernetes.rest;
 import static org.hamcrest.CoreMatchers.is;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
@@ -130,7 +131,7 @@ class ChartControllerTest {
         RequestBuilder requestBuilder;
 
         //Mocking successful installation for void install method
-        doNothing().when(chartService).installChart(charts.get(0));
+        doReturn(true).when(chartService).installChart(charts.get(0));
 
         requestBuilder = MockMvcRequestBuilders.post(INSTALL_CHART_URL).accept(MediaType.APPLICATION_JSON_VALUE)
             .content(getInstallationJson(charts.get(0).getChartId().getName(), charts.get(0).getChartId().getVersion()))
index f5b6093..4fc045d 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation.
+ *  Copyright (C) 2021-2022 Nordix Foundation.
  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,6 +34,7 @@ import static org.mockito.Mockito.doThrow;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import org.junit.jupiter.api.BeforeAll;
@@ -42,10 +43,12 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
+import org.onap.policy.clamp.acm.participant.kubernetes.configurations.HelmRepositoryConfig;
 import org.onap.policy.clamp.acm.participant.kubernetes.exception.ServiceException;
 import org.onap.policy.clamp.acm.participant.kubernetes.helm.HelmClient;
 import org.onap.policy.clamp.acm.participant.kubernetes.models.ChartInfo;
 import org.onap.policy.clamp.acm.participant.kubernetes.models.ChartList;
+import org.onap.policy.clamp.acm.participant.kubernetes.models.HelmRepository;
 import org.onap.policy.common.utils.coder.Coder;
 import org.onap.policy.common.utils.coder.CoderException;
 import org.onap.policy.common.utils.coder.StandardCoder;
@@ -69,6 +72,9 @@ class ChartServiceTest {
     @Mock
     private HelmClient helmClient;
 
+    @Mock
+    private HelmRepositoryConfig helmRepositoryConfig;
+
     @BeforeAll
     static void init() throws CoderException {
         charts = CODER.decode(new File(CHART_INFO_YAML), ChartList.class).getCharts();
@@ -114,6 +120,9 @@ class ChartServiceTest {
 
     @Test
     void test_installChart() throws IOException, ServiceException {
+        List<HelmRepository> helmRepositoryList = new ArrayList<>();
+        helmRepositoryList.add(HelmRepository.builder().address("https://localhost:8080").build());
+        doReturn(helmRepositoryList).when(helmRepositoryConfig).getRepos();
         assertDoesNotThrow(() -> chartService.installChart(charts.get(0)));
         doThrow(ServiceException.class).when(helmClient).installChart(any());
         assertThatThrownBy(() -> chartService.installChart(charts.get(0))).isInstanceOf(ServiceException.class);
index 9822846..d4cd5de 100644 (file)
@@ -7,7 +7,8 @@
       },
       "namespace" : "onap",
       "repository" : {
-        "repoName": "chartMuseum"
+        "repoName": "chartMuseum",
+        "address" : "https://localhost:8080"
       },
       "releaseName" : "helloworld"
     },