d8cf963b5471ca6afa25edcb8036fab07300a62c
[ccsdk/sli.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                      reserved.
7  * ================================================================================
8  * Licensed 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  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.ccsdk.sli.northbound.asdcapi;
23
24 import com.google.common.base.Optional;
25 import com.google.common.util.concurrent.FluentFuture;
26 import com.google.common.util.concurrent.Futures;
27 import com.google.common.util.concurrent.ListenableFuture;
28 import java.util.Properties;
29 import java.util.concurrent.ExecutionException;
30 import java.util.concurrent.ExecutorService;
31 import java.util.concurrent.Executors;
32 import org.eclipse.jdt.annotation.NonNull;
33 import org.opendaylight.mdsal.binding.api.DataBroker;
34 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
35 import org.opendaylight.mdsal.binding.api.ReadTransaction;
36 import org.opendaylight.mdsal.binding.api.RpcProviderService;
37 import org.opendaylight.mdsal.binding.api.WriteTransaction;
38 import org.opendaylight.mdsal.common.api.CommitInfo;
39 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
40 import org.opendaylight.yang.gen.v1.http.xmlns.onap.org.asdc.license.model._1._0.rev160427.vf.license.model.grouping.VfLicenseModel;
41 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.ASDCAPIService;
42 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.Artifacts;
43 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.ArtifactsBuilder;
44 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.VfLicenseModelUpdateInput;
45 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.VfLicenseModelUpdateInputBuilder;
46 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.VfLicenseModelUpdateOutput;
47 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.VfLicenseModelUpdateOutputBuilder;
48 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.VfLicenseModelVersions;
49 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.VfLicenseModelVersionsBuilder;
50 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.artifacts.Artifact;
51 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.artifacts.ArtifactBuilder;
52 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.artifacts.ArtifactKey;
53 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.vf.license.model.versions.VfLicenseModelVersion;
54 import org.opendaylight.yang.gen.v1.org.onap.ccsdk.rev170201.vf.license.model.versions.VfLicenseModelVersionBuilder;
55 import org.opendaylight.yangtools.concepts.ObjectRegistration;
56 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
57 import org.opendaylight.yangtools.yang.common.RpcResult;
58 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 /**
63  * Defines a base implementation for your provider. This class extends from a helper class
64  * which provides storage for the most commonly used components of the MD-SAL. Additionally the
65  * base class provides some basic logging and initialization / clean up methods.
66  *
67  * To use this, copy and paste (overwrite) the following method into the TestApplicationProviderModule
68  * class which is auto generated under src/main/java in this project
69  * (created only once during first compilation):
70  *
71  * <pre>
72
73     @Override
74     public java.lang.AutoCloseable createInstance() {
75
76          final asdcApiProvider provider = new asdcApiProvider();
77          provider.setDataBroker( getDataBrokerDependency() );
78          provider.setNotificationService( getNotificationServiceDependency() );
79          provider.setRpcRegistry( getRpcRegistryDependency() );
80          provider.initialize();
81          return new AutoCloseable() {
82
83             @Override
84             public void close() throws Exception {
85                 //TODO: CLOSE ANY REGISTRATION OBJECTS CREATED USING ABOVE BROKER/NOTIFICATION
86                 //SERVIE/RPC REGISTRY
87                 provider.close();
88             }
89         };
90     }
91
92
93     </pre>
94  */
95 public class AsdcApiProvider implements AutoCloseable, ASDCAPIService {
96
97     private static final Logger LOG = LoggerFactory.getLogger(AsdcApiProvider.class);
98
99     private static final String ACTIVE_VERSION = "active";
100
101     private static final String APPLICATION_NAME = "asdcApi";
102
103     private final ExecutorService executor;
104     protected DataBroker dataBroker;
105     protected NotificationPublishService notificationService;
106     protected RpcProviderService rpcRegistry;
107     private final AsdcApiSliClient asdcApiSliClient;
108
109     protected ObjectRegistration<ASDCAPIService> rpcRegistration;
110
111     public AsdcApiProvider(final DataBroker dataBroker,
112                            final NotificationPublishService notificationPublishService,
113                            final RpcProviderService rpcProviderRegistry,
114                            final AsdcApiSliClient asdcApiSliClient) {
115
116         LOG.info("Creating provider for {}", APPLICATION_NAME);
117         executor = Executors.newFixedThreadPool(1);
118         this.dataBroker = dataBroker;
119         notificationService = notificationPublishService;
120         rpcRegistry = rpcProviderRegistry;
121         this.asdcApiSliClient= asdcApiSliClient;
122         initialize();
123     }
124
125     public void initialize(){
126         LOG.info("Initializing {} for {}", this.getClass().getName(), APPLICATION_NAME);
127
128         createContainers();
129
130         if (rpcRegistration == null) {
131             if (rpcRegistry != null) {
132                 rpcRegistration = rpcRegistry.registerRpcImplementation(
133                         ASDCAPIService.class, this);
134                 LOG.info("Initialization complete for {}", APPLICATION_NAME);
135             } else {
136                 LOG.warn("Error initializing {} : rpcRegistry unset", APPLICATION_NAME);
137             }
138         }
139     }
140
141     private void createContainers() {
142
143         if (dataBroker != null) {
144         final WriteTransaction t = dataBroker.newReadWriteTransaction();
145
146         // Create the vf-model-license-versions and artifacts containers
147         t.merge(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(VfLicenseModelVersions.class),
148         new VfLicenseModelVersionsBuilder().build());
149
150         t.merge(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Artifacts.class), new ArtifactsBuilder().build());
151
152
153         try {
154             FluentFuture<? extends @NonNull CommitInfo> checkedFuture = t.commit();
155             checkedFuture.get();
156             LOG.info("Create Containers succeeded!: ");
157
158         } catch (InterruptedException | ExecutionException e) {
159             LOG.error("Create Containers Failed: ", e);
160         }
161         } else {
162             LOG.warn("createContainers : cannot find dataBroker to create containers");
163         }
164     }
165     protected void initializeChild() {
166         //Override if you have custom initialization intelligence
167     }
168
169     @Override
170     public void close() throws Exception {
171         LOG.info( "Closing provider for " + APPLICATION_NAME);
172         executor.shutdown();
173         rpcRegistration.close();
174         LOG.info( "Successfully closed provider for " + APPLICATION_NAME);
175     }
176
177     protected boolean artifactVersionExists(String aName, String aVersion) {
178         InstanceIdentifier artifactInstanceId =
179                 InstanceIdentifier.<Artifacts>builder(Artifacts.class)
180                 .child(Artifact.class, new ArtifactKey(aName, aVersion)).build();
181         Optional<Artifact> data = null;
182         try(ReadTransaction readTx = dataBroker.newReadOnlyTransaction()) {
183             data = (Optional<Artifact>) readTx.read(LogicalDatastoreType.CONFIGURATION, artifactInstanceId).get();
184         } catch (InterruptedException | ExecutionException e) {
185             LOG.error("Caught Exception reading MD-SAL for ["+aName+","+ aVersion+"] " ,e);
186             return false;
187         }
188
189         return data.isPresent();
190     }
191
192     protected void addArtifactVersion(String aName, String aVersion) {
193
194
195         try {
196             ArtifactBuilder aBuilder = new ArtifactBuilder();
197
198             aBuilder.setArtifactName(aName);
199             aBuilder.setArtifactVersion(aVersion);
200
201             Artifact artifact = aBuilder.build();
202
203             InstanceIdentifier.InstanceIdentifierBuilder<Artifact> aIdBuilder = InstanceIdentifier
204                     .<Artifacts> builder(Artifacts.class)
205                     .child(Artifact.class, artifact.key());
206
207             InstanceIdentifier<Artifact> path = aIdBuilder.build();
208
209             WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
210
211             tx.merge(LogicalDatastoreType.CONFIGURATION, path,
212                     artifact);
213             tx.commit().get();
214         } catch (Exception e) {
215             LOG.error("Caught exception trying to add artifact entry", e);
216         }
217
218     }
219
220
221     private void applyVfLicenseModelUpdate(VfLicenseModelUpdateInput input) {
222
223     String aName = input.getArtifactName();
224     String aVersion = input.getArtifactVersion();
225     VfLicenseModel vfLicenseModel = input.getVfLicenseModel();
226
227
228     // Add new version (version = artifact-version)
229     try {
230
231         VfLicenseModelVersionBuilder vBuilder = new VfLicenseModelVersionBuilder();
232         vBuilder.setArtifactName(aName);
233         vBuilder.setArtifactVersion(aVersion);
234         vBuilder.setVfLicenseModel(vfLicenseModel);
235
236         VfLicenseModelVersion version = vBuilder.build();
237
238         InstanceIdentifier.InstanceIdentifierBuilder<VfLicenseModelVersion> versionIdBuilder = InstanceIdentifier
239                 .<VfLicenseModelVersions> builder(VfLicenseModelVersions.class)
240                 .child(VfLicenseModelVersion.class, version.key());
241
242         InstanceIdentifier<VfLicenseModelVersion> path = versionIdBuilder.build();
243
244         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
245   tx.merge(LogicalDatastoreType.CONFIGURATION, path,
246                 version);
247         tx.commit().get();
248     } catch (Exception e) {
249         LOG.error(
250                 "Caught exception trying to save entry to MD-SAL",
251                 e);
252     }
253
254
255     // Add "active" version (version = "active")
256     try {
257
258         VfLicenseModelVersionBuilder vBuilder = new VfLicenseModelVersionBuilder();
259         vBuilder.setArtifactName(aName);
260         vBuilder.setArtifactVersion(ACTIVE_VERSION);
261         vBuilder.setVfLicenseModel(vfLicenseModel);
262
263         VfLicenseModelVersion version = vBuilder.build();
264         InstanceIdentifier.InstanceIdentifierBuilder<VfLicenseModelVersion> versionIdBuilder = InstanceIdentifier
265                 .<VfLicenseModelVersions> builder(VfLicenseModelVersions.class)
266                 .child(VfLicenseModelVersion.class, version.key());
267
268         InstanceIdentifier<VfLicenseModelVersion> path = versionIdBuilder.build();
269
270         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
271
272         tx.merge(LogicalDatastoreType.CONFIGURATION, path,
273                 version);
274         tx.commit().get();
275     } catch (Exception e) {
276         LOG.error(
277                 "Caught exception trying to save entry to MD-SAL",
278                 e);
279     }
280
281 }
282
283 @Override
284 public ListenableFuture<RpcResult<VfLicenseModelUpdateOutput>> vfLicenseModelUpdate(VfLicenseModelUpdateInput input) {
285     final String svcOperation = "vf-license-model-update";
286
287     Properties parms = new Properties();
288
289     LOG.info( svcOperation +" called." );
290
291     if(input == null ) {
292         LOG.debug("exiting " +svcOperation+ " because of invalid input");
293         return null;
294     }
295
296     VfLicenseModelUpdateInputBuilder inputBuilder = new VfLicenseModelUpdateInputBuilder(input);
297
298     VfLicenseModelUpdateInput inputVfLic = inputBuilder.build();
299
300     String errorMessage = "Success";
301     String errorCode = "200";
302
303     // If this artifact already exists, reject this update
304     if (artifactVersionExists(inputVfLic.getArtifactName(), inputVfLic.getArtifactVersion())) {
305         errorCode = "409";
306         errorMessage = "Artifact version already exists";
307     } else {
308         // Translate input object into SLI-consumable properties
309         LOG.info("Adding INPUT data for "+svcOperation+" input: " + inputVfLic);
310         AsdcApiUtil.toProperties(parms, inputVfLic);
311
312
313         // Call directed graph
314         Properties respProps = null;
315         try
316         {
317             if (asdcApiSliClient.hasGraph("ASDC-API", svcOperation , null, "sync"))
318             {
319
320                 try
321                 {
322                     respProps = asdcApiSliClient.execute("ASDC-API", svcOperation, null, "sync", parms);
323                 }
324                 catch (Exception e)
325                 {
326                     LOG.error("Caught exception executing service logic for "+ svcOperation, e);
327                 }
328             } else {
329                 errorMessage = "No service logic active for ASDC-API: '" + svcOperation + "'";
330                 errorCode = "503";
331             }
332         }
333         catch (Exception e)
334         {
335             errorCode = "500";
336             errorMessage = e.getMessage();
337             LOG.error("Caught exception looking for service logic", e);
338         }
339
340
341         if (respProps != null)
342         {
343             errorCode = respProps.getProperty("error-code");
344             errorMessage = respProps.getProperty("error-message", "");
345         }
346     }
347
348
349     if ("200".equals(errorCode)) {
350         LOG.info("ASDC update succeeded");
351
352         // Update config tree
353         applyVfLicenseModelUpdate(inputVfLic);
354         addArtifactVersion(inputVfLic.getArtifactName(), inputVfLic.getArtifactVersion());
355
356     } else {
357         LOG.info("ASDC update failed ("+errorCode+" : "+errorMessage);
358     }
359
360     // Send response
361     VfLicenseModelUpdateOutputBuilder respBuilder = new VfLicenseModelUpdateOutputBuilder();
362     respBuilder.setAsdcApiResponseCode(errorCode);
363     if (errorMessage != null && errorMessage.length() > 0) {
364         respBuilder.setAsdcApiResponseText(errorMessage);
365     }
366
367     RpcResult<VfLicenseModelUpdateOutput> rpcResult;
368
369
370     rpcResult = RpcResultBuilder.<VfLicenseModelUpdateOutput> status(true).withResult(respBuilder.build()).build();
371
372
373
374     return Futures.immediateFuture(rpcResult);
375 }
376
377
378 }