diff options
10 files changed, 104 insertions, 26 deletions
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 index 000000000..4d00e38ec --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/configurations/HelmRepositoryConfig.java @@ -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<>(); +} diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandler.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandler.java index 753608686..b4cca3acf 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandler.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandler.java @@ -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); diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/HelmClient.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/HelmClient.java index 6a7c62b2e..f3f7d3427 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/HelmClient.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/HelmClient.java @@ -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); diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/models/HelmRepository.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/models/HelmRepository.java index 2e25e42a6..ff3b9e336 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/models/HelmRepository.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/models/HelmRepository.java @@ -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. @@ -18,21 +18,21 @@ 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; diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/service/ChartService.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/service/ChartService.java index dc4762d9a..e9cd8a2c3 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/service/ChartService.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/service/ChartService.java @@ -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; } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/application.yaml b/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/application.yaml index d7ab2e178..c12d4fb8e 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/application.yaml +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/resources/config/application.yaml @@ -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 diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandlerTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandlerTest.java index dc74afc1a..6124060cb 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandlerTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandlerTest.java @@ -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(); diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/rest/ChartControllerTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/rest/ChartControllerTest.java index c59e7fb5d..7105c2327 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/rest/ChartControllerTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/rest/ChartControllerTest.java @@ -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())) diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/service/ChartServiceTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/service/ChartServiceTest.java index f5b6093d3..4fc045d48 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/service/ChartServiceTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/service/ChartServiceTest.java @@ -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); diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json index 9822846f3..d4cd5de47 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json @@ -7,7 +7,8 @@ }, "namespace" : "onap", "repository" : { - "repoName": "chartMuseum" + "repoName": "chartMuseum", + "address" : "https://localhost:8080" }, "releaseName" : "helloworld" }, |