Change content download rest template config.
[federation.git] / gateway / src / main / java / org / acumos / federation / gateway / service / impl / ContentServiceImpl.java
1 /*-
2  * ===============LICENSE_START=======================================================
3  * Acumos
4  * ===================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
6  * ===================================================================================
7  * This Acumos software file is distributed by AT&T and Tech Mahindra
8  * under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *  
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *  
14  * This file 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=========================================================
19  */
20
21 /**
22  * 
23  */
24 package org.acumos.federation.gateway.service.impl;
25
26 import java.io.ByteArrayInputStream;
27 import java.io.ByteArrayOutputStream;
28 import java.lang.invoke.MethodHandles;
29
30 import org.acumos.cds.AccessTypeCode;
31 import org.acumos.cds.domain.MLPDocument;
32 import org.acumos.cds.domain.MLPArtifact;
33 import org.acumos.federation.gateway.cds.ArtifactType;
34 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
35 import org.acumos.federation.gateway.config.NexusConfiguration;
36 import org.acumos.federation.gateway.config.DockerConfiguration;
37 import org.acumos.federation.gateway.service.ContentService;
38 import org.acumos.federation.gateway.service.ServiceContext;
39 import org.acumos.federation.gateway.service.ServiceException;
40 import org.acumos.nexus.client.NexusArtifactClient;
41 import org.acumos.nexus.client.data.UploadArtifactInfo;
42 import org.springframework.core.io.InputStreamResource;
43 import org.springframework.core.io.Resource;
44 import org.springframework.stereotype.Service;
45 import org.springframework.beans.factory.annotation.Autowired;
46
47 import com.github.dockerjava.api.DockerClient;
48 import com.github.dockerjava.api.model.Identifier;
49 import com.github.dockerjava.api.model.Repository;
50 import com.github.dockerjava.core.command.PullImageResultCallback;
51 import com.github.dockerjava.core.command.PushImageResultCallback;
52
53
54 /**
55  * Nexus based implementation of the ContentService.
56  *
57  */
58 @Service
59 public class ContentServiceImpl extends AbstractServiceImpl
60                                                                                                                                         implements ContentService {
61
62         private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(MethodHandles.lookup().lookupClass());
63
64   @Autowired
65   private NexusConfiguration nexusConfig;
66   @Autowired
67   private DockerConfiguration dockerConfig;
68
69         @Override
70         public InputStreamResource getArtifactContent(
71                 String theSolutionId, String theRevisionId, MLPArtifact theArtifact, ServiceContext theContext)
72                                                                                                                                                                                                                                                                                                                                                                                         throws ServiceException {
73                 if (theArtifact.getUri() == null) {
74                         throw new ServiceException("No artifact uri available for " + theArtifact);
75                 }
76                 log.info(EELFLoggerDelegate.debugLogger, "Retrieving artifact content for {}", theArtifact);
77
78                 if (ArtifactType.DockerImage == ArtifactType.forCode(theArtifact.getArtifactTypeCode())) {
79                         try {
80                                 //pull followed by save
81                                 DockerClient docker = this.dockerConfig.getDockerClient();
82
83                                 try (PullImageResultCallback pullResult = new PullImageResultCallback()) {
84                                         docker.pullImageCmd(theArtifact.getUri())
85                                                                 .exec(pullResult);
86                                         pullResult.awaitCompletion();
87                                 }
88
89                                 return new InputStreamResource(docker.saveImageCmd(theArtifact.getUri()).exec());
90                         }
91                         catch (Exception x) {
92                                 log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve artifact content for docker artifact " + theArtifact, x);
93                                 throw new ServiceException("Failed to retrieve artifact content for docker artifact " + theArtifact, x);
94                         }
95                 }
96                 else {  
97                         return getNexusContent(theArtifact.getUri());
98                 }
99         }
100
101         @Override
102         public void putArtifactContent(
103                 String theSolutionId, String theRevisionId, MLPArtifact theArtifact, Resource theResource, ServiceContext theContext)
104                                                                                                                                                                                                                                                                                                                                                                                 throws ServiceException {
105
106                 if (ArtifactType.DockerImage == ArtifactType.forCode(theArtifact.getArtifactTypeCode())) {
107                         try {
108                                 //load followed by push
109                                 DockerClient docker = this.dockerConfig.getDockerClient();
110
111                                 docker.loadImageCmd(theResource.getInputStream())
112                                                         .exec(); //sync xecution
113
114                                 // there is an assumption here that the repo info was stripped from the artifact name by the originator
115                                 Identifier imageId =
116                                         new Identifier(
117                                                 new Repository(dockerConfig.getRegistryUrl().toString()),
118                                                                                                          theArtifact.getName() /*the tag*/);
119                                 try (PushImageResultCallback pushResult = new PushImageResultCallback()) {
120                                         docker.pushImageCmd(imageId)
121                                                                 .exec(pushResult);
122                                         pushResult.awaitCompletion();
123                                 }       
124                                 // update artifact with local repo reference. we also update the name and description in order to stay
125                                 // alligned with on-boarding's unwritten rules
126                                 theArtifact.setUri(imageId.toString());
127                                 theArtifact.setName(imageId.toString());
128                                 theArtifact.setDescription(imageId.toString());
129                         }
130                         catch (Exception x) {
131                                 log.error(EELFLoggerDelegate.errorLogger,
132                                                                         "Failed to push docker artifact content to Nexus repo", x);
133                                 throw new ServiceException("Failed to push docker artifact content to Nexus repo", x);
134                         }
135                 }
136                 else {
137                         String[] nameParts = splitName(theArtifact.getName());
138                         UploadArtifactInfo info = putNexusContent(
139                                 nexusPrefix(theSolutionId, theRevisionId), nameParts[0], theArtifact.getVersion(), nameParts[1], theResource);
140                         // update artifact with local repo reference
141                         theArtifact.setUri(info.getArtifactMvnPath());
142                 }
143         }
144
145         @Override
146         public InputStreamResource getDocumentContent(
147                 String theSolutionId, String theRevisionId, MLPDocument theDocument, ServiceContext theContext)
148                                                                                                                                                                                                                                                                                                                                                 throws ServiceException {
149                 if (theDocument.getUri() == null) {
150                         throw new ServiceException("No document uri available for " + theDocument);
151                 }
152                 log.info(EELFLoggerDelegate.debugLogger, "Retrieving document content for {}", theDocument);
153                 return getNexusContent(theDocument.getUri());
154         }
155
156         @Override
157         public void putDocumentContent(
158                 String theSolutionId, String theRevisionId, MLPDocument theDocument, Resource theResource, ServiceContext theContext)
159                                                                                                                                                                                                                                                                                                                                                 throws ServiceException {
160                 String[] nameParts = splitName(theDocument.getName());
161                 UploadArtifactInfo info = putNexusContent(
162                         nexusPrefix(theSolutionId, theRevisionId), nameParts[0], AccessTypeCode.PB.name(), nameParts[1], theResource);
163                 theDocument.setUri(info.getArtifactMvnPath());
164         }
165
166         protected InputStreamResource getNexusContent(String theUri) throws ServiceException {
167                 try {
168                         NexusArtifactClient artifactClient = this.nexusConfig.getNexusClient();
169                         ByteArrayOutputStream artifactContent = artifactClient.getArtifact(theUri);
170                         log.info(EELFLoggerDelegate.debugLogger, "Retrieved {} bytes of content from {}", artifactContent.size(), theUri);
171                         return new InputStreamResource(
172                                                                                 new ByteArrayInputStream(
173                                                                                         artifactContent.toByteArray()
174                                                                         ));
175                 }
176                 catch (Exception x) {
177                         log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve content from  " + theUri, x);
178                         throw new ServiceException("Failed to retrieve content from " + theUri, x);
179                 }
180         }
181
182         protected UploadArtifactInfo putNexusContent(
183                 String theGroupId, String theContentId, String theVersion, String thePackaging, Resource theResource) throws ServiceException {
184
185                 try {
186                         UploadArtifactInfo info = this.nexusConfig.getNexusClient()
187                                                                                                                                         .uploadArtifact(theGroupId, theContentId, theVersion, thePackaging,
188                                                                                                                                                                                                         theResource.contentLength(), theResource.getInputStream());
189
190                         log.info(EELFLoggerDelegate.debugLogger, "Wrote artifact content to {}", info.getArtifactMvnPath());
191                         return info;
192                 }
193                 catch (Exception x) {
194                         log.error(EELFLoggerDelegate.errorLogger,       "Failed to push content to Nexus repo", x);
195                         throw new ServiceException("Failed to push content to Nexus repo", x);
196                 }
197         }
198
199         private String nexusPrefix(String theSolutionId, String theRevisionId) {
200                 return String.join(nexusConfig.getNameSeparator(), nexusConfig.getGroupId(), theSolutionId, theRevisionId);
201         }
202
203         /**
204          * Split a file name into its core name and extension parts.
205          * @param theName file name to split
206          * @return a string array containing the 2 part or null if the part was missing
207          */
208         private String[] splitName(String theName) {
209                 int pos = theName.lastIndexOf('.');
210                 return (pos < 0) ?
211                         new String[] {theName, "" /*null: better coding but does not facilitate callers*/} :
212                         pos == theName.length() - 1 ? new String[] {theName.substring(0,pos), ""} :
213                                                                                                                                                 new String[] {theName.substring(0,pos), theName.substring(pos+1)};
214         }
215 }