2 * ========================LICENSE_START=================================
3 * Copyright (C) 2021 Nordix Foundation. All rights reserved.
4 * ======================================================================
5 * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6 * ======================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ========================LICENSE_END===================================
21 package org.onap.policy.clamp.controlloop.participant.kubernetes.service;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.PrintStream;
27 import java.lang.invoke.MethodHandles;
28 import java.nio.file.FileVisitResult;
29 import java.nio.file.Files;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.nio.file.SimpleFileVisitor;
33 import java.nio.file.attribute.BasicFileAttributes;
34 import java.util.ArrayList;
35 import java.util.List;
37 import java.util.concurrent.ConcurrentHashMap;
38 import lombok.AccessLevel;
40 import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException;
41 import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo;
42 import org.onap.policy.clamp.controlloop.participant.kubernetes.parameters.ParticipantK8sParameters;
43 import org.onap.policy.common.utils.coder.CoderException;
44 import org.onap.policy.common.utils.coder.StandardCoder;
45 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.stereotype.Component;
49 import org.springframework.util.FileSystemUtils;
50 import org.springframework.web.multipart.MultipartFile;
53 public class ChartStore {
54 private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
56 private static final StandardCoder STANDARD_CODER = new StandardCoder();
58 private final ParticipantK8sParameters participantK8sParameters;
60 // ChartStore map contains chart name as key & ChartInfo as value.
61 @Getter(AccessLevel.PACKAGE)
62 private Map<String, ChartInfo> localChartMap = new ConcurrentHashMap<>();
67 public ChartStore(ParticipantK8sParameters participantK8sParameters) {
68 this.participantK8sParameters = participantK8sParameters;
69 this.restoreFromLocalFileSystem();
73 * Get local helm chart file.
75 * @param chart ChartInfo
76 * @return the chart file.
78 public File getHelmChartFile(ChartInfo chart) {
79 var appPath = getAppPath(chart.getChartId());
80 return new File(appPath.toFile(), chart.getChartId().getName());
84 * Get the override yaml file.
86 * @param chart ChartInfo
87 * @return the override yaml file
89 public File getOverrideFile(ChartInfo chart) {
90 var appPath = getAppPath(chart.getChartId());
91 return new File(appPath.toFile(), "values.yaml");
96 * Saves the helm chart.
98 * @param chartInfo chartInfo
99 * @param chartFile helm chart file.
100 * @param overrideFile override file.
102 * @throws IOException incase of IO error
103 * @throws ServiceException incase of error.
105 public synchronized ChartInfo saveChart(ChartInfo chartInfo, MultipartFile chartFile, MultipartFile overrideFile)
106 throws IOException, ServiceException {
107 if (localChartMap.containsKey(key(chartInfo))) {
108 throw new ServiceException("Chart already exist");
110 var appPath = getAppPath(chartInfo.getChartId());
111 Files.createDirectories(appPath);
113 chartFile.transferTo(getHelmChartFile(chartInfo));
114 if (overrideFile != null) {
115 overrideFile.transferTo(getOverrideFile(chartInfo));
118 localChartMap.put(key(chartInfo), chartInfo);
119 storeChartInFile(chartInfo);
124 * Get the chart info.
126 * @param name name of the chart
127 * @param version version of the chart
130 public synchronized ChartInfo getChart(String name, String version) {
131 return localChartMap.get(key(name, version));
135 * Get all the charts installed.
137 * @return list of charts.
139 public synchronized List<ChartInfo> getAllCharts() {
140 return new ArrayList<>(localChartMap.values());
146 * @param chart chart info
148 public synchronized void deleteChart(ChartInfo chart) {
149 var appPath = getAppPath(chart.getChartId());
151 FileSystemUtils.deleteRecursively(appPath);
152 } catch (IOException exc) {
153 LOGGER.warn("Could not delete chart from local file system : {}", appPath, exc);
156 localChartMap.remove(key(chart));
160 * Fetch the local chart directory of specific chart.
162 * @param chartId Id of the chart
165 public Path getAppPath(ToscaConceptIdentifier chartId) {
166 return Path.of(participantK8sParameters.getLocalChartDirectory(), chartId.getName(), chartId.getVersion());
169 private void storeChartInFile(ChartInfo chart) {
170 try (var out = new PrintStream(new FileOutputStream(getFile(chart)))) {
171 out.print(STANDARD_CODER.encode(chart));
172 } catch (Exception exc) {
173 LOGGER.warn("Could not store chart: {}", chart.getChartId(), exc);
177 private File getFile(ChartInfo chart) {
178 var appPath = getAppPath(chart.getChartId()).toString();
179 return Path.of(appPath, participantK8sParameters.getInfoFileName()).toFile();
182 private synchronized void restoreFromLocalFileSystem() {
184 var localChartDirectoryPath = Paths.get(participantK8sParameters.getLocalChartDirectory());
185 Files.createDirectories(localChartDirectoryPath);
186 restoreFromLocalFileSystem(localChartDirectoryPath);
187 } catch (Exception ioe) {
188 LOGGER.warn("Could not restore charts from local file system", ioe);
192 private synchronized void restoreFromLocalFileSystem(Path localChartDirectoryPath)
195 Files.walkFileTree(localChartDirectoryPath, new SimpleFileVisitor<Path>() {
197 public FileVisitResult visitFile(Path localChartFile, BasicFileAttributes attrs) throws IOException {
199 // Decode only the json file excluding the helm charts
200 if (localChartFile.endsWith(participantK8sParameters.getInfoFileName())) {
201 ChartInfo chart = STANDARD_CODER.decode(localChartFile.toFile(), ChartInfo.class);
202 localChartMap.put(key(chart), chart);
204 return FileVisitResult.CONTINUE;
205 } catch (CoderException ce) {
206 throw new IOException("Error decoding chart file", ce);
212 private String key(ChartInfo chart) {
213 return key(chart.getChartId().getName(), chart.getChartId().getVersion());
216 private String key(String chartName, String chartVersion) {
217 return chartName + "_" + chartVersion;