2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021 Nordix Foundation
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.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.openecomp.sdc.be.csar.storage;
23 import static org.openecomp.sdc.common.errors.Messages.EXTERNAL_CSAR_STORE_CONFIGURATION_FAILURE_MISSING;
25 import io.minio.BucketExistsArgs;
26 import io.minio.CopyObjectArgs;
27 import io.minio.CopySource;
28 import io.minio.GetObjectArgs;
29 import io.minio.MakeBucketArgs;
30 import io.minio.MinioClient;
31 import io.minio.MinioClient.Builder;
32 import io.minio.PutObjectArgs;
33 import io.minio.RemoveObjectArgs;
34 import java.io.InputStream;
36 import java.util.Optional;
37 import java.util.UUID;
39 import org.openecomp.sdc.be.csar.storage.MinIoStorageArtifactStorageConfig.Credentials;
40 import org.openecomp.sdc.be.csar.storage.MinIoStorageArtifactStorageConfig.EndPoint;
41 import org.openecomp.sdc.be.csar.storage.exception.ArtifactStorageException;
42 import org.openecomp.sdc.common.CommonConfigurationManager;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
46 public class MinIoStorageArtifactStorageManager implements ArtifactStorageManager {
48 private static final Logger LOGGER = LoggerFactory.getLogger(MinIoStorageArtifactStorageManager.class);
49 private static final String EXTERNAL_CSAR_STORE = "externalCsarStore";
52 private final MinIoStorageArtifactStorageConfig storageConfiguration;
53 private final MinioClient minioClient;
55 public MinIoStorageArtifactStorageManager() {
56 this.storageConfiguration = readMinIoStorageArtifactStorageConfig();
57 minioClient = initMinioClient();
61 MinIoStorageArtifactStorageManager(final ArtifactStorageConfig storageConfiguration) {
62 this.storageConfiguration = (MinIoStorageArtifactStorageConfig) storageConfiguration;
63 minioClient = initMinioClient();
67 public ArtifactInfo persist(final String vspId, final String versionId, final ArtifactInfo uploadedArtifactInfo) {
68 final MinIoArtifactInfo minioObjectTemp = (MinIoArtifactInfo) uploadedArtifactInfo;
70 minioClient.getObject(
71 GetObjectArgs.builder()
72 .bucket(minioObjectTemp.getBucket())
73 .object(minioObjectTemp.getObjectName())
76 } catch (final Exception e) {
77 LOGGER.error("Failed to retrieve uploaded artifact with bucket '{}' and name '{}' while persisting", minioObjectTemp.getBucket(),
78 minioObjectTemp.getObjectName(), e);
79 throw new ArtifactStorageException(
80 String.format("Failed to retrieve uploaded artifact with bucket '%s' and name '%s' while persisting",
81 minioObjectTemp.getBucket(), minioObjectTemp.getObjectName()), e);
84 final var backupPath = backupPreviousVersion(vspId, versionId).orElse(null);
86 moveFile(minioObjectTemp, vspId, versionId);
87 } catch (final Exception e) {
88 rollback(minioObjectTemp, vspId, versionId);
89 LOGGER.error("Could not persist artifact for bucket '{}', object '{}'", vspId, versionId, e);
90 final var errorMsg = String.format("Could not persist artifact for VSP '%s', version '%s'", vspId, versionId);
91 throw new ArtifactStorageException(errorMsg, e);
94 removePreviousVersion(backupPath);
96 return new MinIoArtifactInfo(vspId, versionId);
100 public ArtifactInfo upload(final String vspId, final String versionId, final InputStream fileToUpload) {
102 final String name = versionId + "--" + UUID.randomUUID();
104 // Make bucket if not exist.
105 final boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(vspId).build());
108 // Make a new bucket ${vspId} .
109 minioClient.makeBucket(MakeBucketArgs.builder().bucket(vspId).build());
111 LOGGER.info("Bucket '{}' already exists.", vspId);
114 put(vspId, name, fileToUpload);
116 } catch (final Exception e) {
117 LOGGER.error("Failed to upload artifact - bucket: '{}', object: '{}'", vspId, name, e);
118 throw new ArtifactStorageException("Failed to upload artifact", e);
121 return new MinIoArtifactInfo(vspId, name);
125 public void put(final String vspId, final String name, final InputStream fileToUpload) {
127 minioClient.putObject(
128 PutObjectArgs.builder()
131 .stream(fileToUpload, fileToUpload.available(), -1)
134 } catch (final Exception e) {
135 LOGGER.error("Failed to put - bucket: '{}', object: '{}'", vspId, name, e);
136 throw new ArtifactStorageException("Failed to upload artifact", e);
141 public boolean isEnabled() {
142 return storageConfiguration != null && storageConfiguration.isEnabled();
146 public InputStream get(final ArtifactInfo artifactInfo) {
147 final MinIoArtifactInfo minioObject = (MinIoArtifactInfo) artifactInfo;
149 return get(minioObject.getBucket(), minioObject.getObjectName());
150 } catch (final Exception e) {
151 LOGGER.error("Failed to get - bucket: '{}', object: '{}'", minioObject.getBucket(), minioObject.getObjectName(), e);
152 throw new ArtifactStorageException("Failed to get Object", e);
157 public InputStream get(final String bucketID, final String objectID) {
159 return minioClient.getObject(GetObjectArgs.builder()
163 } catch (final Exception e) {
164 LOGGER.error("Failed to get - bucket: '{}', object: '{}'", bucketID, objectID, e);
165 throw new ArtifactStorageException("Failed to get Object", e);
170 public void delete(final ArtifactInfo artifactInfo) {
171 final MinIoArtifactInfo minioObject = (MinIoArtifactInfo) artifactInfo;
173 minioClient.removeObject(RemoveObjectArgs.builder()
174 .bucket(minioObject.getBucket())
175 .object(minioObject.getObjectName())
176 .bypassGovernanceMode(true)
178 } catch (final Exception e) {
179 LOGGER.error("Failed to delete - bucket: '{}', object: '{}'", minioObject.getBucket(), minioObject.getObjectName(), e);
180 throw new ArtifactStorageException(String.format("Failed to delete '%s'", minioObject.getObjectName()), e);
185 private Optional<MinIoArtifactInfo> backupPreviousVersion(final String vspId, final String versionId) {
187 final String tempName = versionId + "--" + UUID.randomUUID().toString();
189 copy(vspId, tempName, versionId);
190 } catch (final Exception e) {
191 LOGGER.error("Failed to copy - bucket: '{}', object: '{}'", vspId, versionId, e);
192 return Optional.empty();
195 return Optional.of(new MinIoArtifactInfo(vspId, tempName));
198 private void rollback(final MinIoArtifactInfo minioObject, final String vspId, final String versionId) {
200 moveFile(minioObject, vspId, versionId);
201 } catch (final Exception ex) {
202 LOGGER.warn("Could not rollback the backup '{}' to the original '{}'", versionId, minioObject.getObjectName(), ex);
206 private void removePreviousVersion(final MinIoArtifactInfo minioObject) {
207 if (minioObject == null) {
213 private void moveFile(final MinIoArtifactInfo minioObject, final String vspId, final String versionId) {
215 copy(vspId, versionId, minioObject.getObjectName());
216 } catch (final Exception e) {
217 LOGGER.error("Failed to copy - bucket: '{}', object: '{}'", vspId, versionId, e);
218 throw new ArtifactStorageException("Failed to move", e);
223 private void copy(final String vspId, final String versionId, final String objectName) throws Exception {
224 minioClient.copyObject(
225 CopyObjectArgs.builder()
228 .source(CopySource.builder()
235 private MinIoStorageArtifactStorageConfig readMinIoStorageArtifactStorageConfig() {
236 final var commonConfigurationManager = CommonConfigurationManager.getInstance();
238 final Map<String, Object> endpoint = commonConfigurationManager.getConfigValue(EXTERNAL_CSAR_STORE, "endpoint", null);
239 final Map<String, Object> credentials = commonConfigurationManager.getConfigValue(EXTERNAL_CSAR_STORE, "credentials", null);
240 final String tempPath = commonConfigurationManager.getConfigValue(EXTERNAL_CSAR_STORE, "tempPath", null);
242 if (endpoint == null) {
243 LOGGER.error(EXTERNAL_CSAR_STORE_CONFIGURATION_FAILURE_MISSING.formatMessage("endpoint"));
244 throw new ArtifactStorageException(EXTERNAL_CSAR_STORE_CONFIGURATION_FAILURE_MISSING.formatMessage("endpoint"));
246 if (credentials == null) {
247 LOGGER.error(EXTERNAL_CSAR_STORE_CONFIGURATION_FAILURE_MISSING.formatMessage("credentials"));
248 throw new ArtifactStorageException(EXTERNAL_CSAR_STORE_CONFIGURATION_FAILURE_MISSING.formatMessage("credentials"));
250 if (tempPath == null) {
251 LOGGER.error(EXTERNAL_CSAR_STORE_CONFIGURATION_FAILURE_MISSING.formatMessage("tempPath"));
252 throw new ArtifactStorageException(EXTERNAL_CSAR_STORE_CONFIGURATION_FAILURE_MISSING.formatMessage("tempPath"));
254 LOGGER.info("ArtifactConfig.endpoint: '{}'", endpoint);
255 LOGGER.info("ArtifactConfig.credentials: '{}'", credentials);
256 LOGGER.info("ArtifactConfig.tempPath: '{}'", tempPath);
258 final String host = (String) endpoint.getOrDefault("host", null);
259 final int port = (int) endpoint.getOrDefault("port", 0);
260 final boolean secure = (boolean) endpoint.getOrDefault("secure", false);
262 final String accessKey = (String) credentials.getOrDefault("accessKey", null);
263 final String secretKey = (String) credentials.getOrDefault("secretKey", null);
265 return new MinIoStorageArtifactStorageConfig(true, new EndPoint(host, port, secure), new Credentials(accessKey, secretKey), tempPath);
268 private MinioClient initMinioClient() {
269 final EndPoint endPoint = storageConfiguration.getEndPoint();
270 final Credentials credentials = storageConfiguration.getCredentials();
272 final Builder builder = MinioClient.builder();
274 .endpoint(endPoint.getHost(), endPoint.getPort(), endPoint.isSecure())
275 .credentials(credentials.getAccessKey(), credentials.getSecretKey())