2 * ========================LICENSE_START=================================
3 * Copyright (C) 2021 Nordix Foundation. All rights reserved.
4 * ======================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ========================LICENSE_END===================================
19 package org.onap.policy.clamp.controlloop.participant.kubernetes.service;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.PrintStream;
25 import java.lang.invoke.MethodHandles;
26 import java.nio.file.FileVisitResult;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.nio.file.SimpleFileVisitor;
31 import java.nio.file.attribute.BasicFileAttributes;
32 import java.util.ArrayList;
33 import java.util.List;
35 import java.util.concurrent.ConcurrentHashMap;
36 import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException;
37 import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo;
38 import org.onap.policy.clamp.controlloop.participant.kubernetes.parameters.ParticipantK8sParameters;
39 import org.onap.policy.common.utils.coder.CoderException;
40 import org.onap.policy.common.utils.coder.StandardCoder;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43 import org.springframework.stereotype.Component;
44 import org.springframework.util.FileSystemUtils;
45 import org.springframework.web.multipart.MultipartFile;
48 public class ChartStore {
49 private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
51 private static final StandardCoder STANDARD_CODER = new StandardCoder();
53 private final ParticipantK8sParameters participantK8sParameters;
56 * The chartStore map contains chart name as key & ChartInfo as value.
58 private Map<String, ChartInfo> localChartMap = new ConcurrentHashMap<>();
63 public ChartStore(ParticipantK8sParameters participantK8sParameters) {
64 this.participantK8sParameters = participantK8sParameters;
65 this.restoreFromLocalFileSystem();
69 * Get local helm chart file.
71 * @param chart ChartInfo
72 * @return the chart file.
74 public File getHelmChartFile(ChartInfo chart) {
75 var appPath = getAppPath(chart.getChartName(), chart.getVersion());
76 return new File(appPath.toFile(), chart.getChartName());
80 * Get the override yaml file.
82 * @param chart ChartInfo
83 * @return the override yaml file
85 public File getOverrideFile(ChartInfo chart) {
86 var appPath = getAppPath(chart.getChartName(), chart.getVersion());
87 return new File(appPath.toFile(), "values.yaml");
92 * Saves the helm chart.
94 * @param chartInfo chartInfo
95 * @param chartFile helm chart file.
96 * @param overrideFile override file.
98 * @throws IOException incase of IO error
99 * @throws ServiceException incase of error.
101 public synchronized ChartInfo saveChart(ChartInfo chartInfo, MultipartFile chartFile, MultipartFile overrideFile)
102 throws IOException, ServiceException {
103 if (localChartMap.containsKey(key(chartInfo.getChartName(), chartInfo.getVersion()))) {
104 throw new ServiceException("Chart already exist");
106 var appPath = getAppPath(chartInfo.getChartName(), chartInfo.getVersion());
107 Files.createDirectories(appPath);
109 chartFile.transferTo(getHelmChartFile(chartInfo));
110 if (overrideFile != null) {
111 overrideFile.transferTo(getOverrideFile(chartInfo));
114 localChartMap.put(key(chartInfo), chartInfo);
115 storeChartInFile(chartInfo);
120 * Get the chart info.
122 * @param name name of the chart
123 * @param version version of the chart
126 public synchronized ChartInfo getChart(String name, String version) {
127 return localChartMap.get(key(name, version));
131 * Get all the charts installed.
133 * @return list of charts.
135 public synchronized List<ChartInfo> getAllCharts() {
136 return new ArrayList<>(localChartMap.values());
142 * @param chart chart info
144 public synchronized void deleteChart(ChartInfo chart) {
145 var appPath = getAppPath(chart.getChartName(), chart.getVersion());
147 FileSystemUtils.deleteRecursively(appPath);
148 } catch (IOException exc) {
149 LOGGER.warn("Could not delete chart from local file system : {}", appPath, exc);
152 localChartMap.remove(key(chart));
156 * Fetch the local chart directory of specific chart.
158 * @param chartName name of the chart
159 * @param chartVersion version of the chart
162 public Path getAppPath(String chartName, String chartVersion) {
163 return Path.of(participantK8sParameters.getLocalChartDirectory(), chartName, chartVersion);
166 private void storeChartInFile(ChartInfo chart) {
167 try (var out = new PrintStream(new FileOutputStream(getFile(chart)))) {
168 out.print(STANDARD_CODER.encode(chart));
169 } catch (Exception exc) {
170 LOGGER.warn("Could not store chart: {} {}", chart.getChartName(), exc);
174 private File getFile(ChartInfo chart) {
175 var appPath = getAppPath(chart.getChartName(), chart.getVersion()).toString();
176 return Path.of(appPath, participantK8sParameters.getInfoFileName()).toFile();
179 private synchronized void restoreFromLocalFileSystem() {
181 Path localChartDirectoryPath = Paths.get(participantK8sParameters.getLocalChartDirectory());
182 Files.createDirectories(localChartDirectoryPath);
183 restoreFromLocalFileSystem(localChartDirectoryPath);
184 } catch (Exception ioe) {
185 LOGGER.warn("Could not restore charts from local file system: {}", ioe);
189 private synchronized void restoreFromLocalFileSystem(Path localChartDirectoryPath)
192 Files.walkFileTree(localChartDirectoryPath, new SimpleFileVisitor<Path>() {
194 public FileVisitResult visitFile(Path localChartFile, BasicFileAttributes attrs) throws IOException {
196 // Decode only the json file excluding the helm charts
197 if (localChartFile.endsWith(participantK8sParameters.getInfoFileName())) {
198 ChartInfo chart = STANDARD_CODER.decode(localChartFile.toFile(), ChartInfo.class);
199 localChartMap.put(key(chart), chart);
201 return FileVisitResult.CONTINUE;
202 } catch (CoderException ce) {
203 throw new IOException("Error decoding chart file", ce);
209 private String key(ChartInfo chart) {
210 return key(chart.getChartName(), chart.getVersion());
213 private String key(String chartName, String chartVersion) {
214 return chartName + "_" + chartVersion;