2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 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=========================================================
20 package org.onap.aai.migration.v14;
22 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
23 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
24 import org.apache.tinkerpop.gremlin.process.traversal.P;
25 import org.apache.tinkerpop.gremlin.structure.*;
26 import org.janusgraph.core.attribute.Text;
27 import org.javatuples.Pair;
28 import org.onap.aai.db.props.AAIProperties;
29 import org.onap.aai.edges.EdgeIngestor;
30 import org.onap.aai.edges.enums.AAIDirection;
31 import org.onap.aai.edges.enums.EdgeProperty;
32 import org.onap.aai.exceptions.AAIException;
33 import org.onap.aai.introspection.LoaderFactory;
34 import org.onap.aai.migration.*;
35 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
36 import org.springframework.web.util.UriUtils;
38 import javax.ws.rs.core.UriBuilder;
40 import java.io.UnsupportedEncodingException;
43 import java.util.stream.Collectors;
45 import org.onap.aai.serialization.db.EdgeSerializer;
46 import org.onap.aai.setup.SchemaVersions;
47 import org.onap.aai.introspection.Introspector;
50 @MigrationPriority(10)
51 @MigrationDangerRating(100)
52 public class PserverDedupWithDifferentSourcesOfTruth extends EdgeSwingMigrator {
54 * Instantiates a new migrator.
58 private final String PARENT_NODE_TYPE = "pserver";
59 private boolean success = true;
60 protected Set<Object> seen = new HashSet<>();
61 private Map<String, UriBuilder> nodeTypeToUri;
62 private Map<String, Set<String>> nodeTypeToKeys;
63 private static List<String> dmaapMsgList = new ArrayList<String>();
64 private static List<Introspector> dmaapDeleteList = new ArrayList<Introspector>();
65 private static int pserversUpdatedCount = 0;
66 private static int pserversDeletedCount = 0;
69 private static String[] rctSourceOfTruth = new String[]{"AAIRctFeed", "RCT"};
70 private static String[] roSourceOfTruth = new String[]{"AAI-EXTENSIONS", "RO"};
72 List<Vertex> RemoveROList = new ArrayList<>();
74 public PserverDedupWithDifferentSourcesOfTruth(TransactionalGraphEngine engine , LoaderFactory loaderFactory, EdgeIngestor edgeIngestor, EdgeSerializer edgeSerializer, SchemaVersions schemaVersions) {
75 super(engine, loaderFactory, edgeIngestor, edgeSerializer, schemaVersions);
78 public void commit() {
80 createDmaapFiles(dmaapMsgList);
81 createDmaapFilesForDelete(dmaapDeleteList);
86 public Status getStatus() {
88 return Status.SUCCESS;
91 return Status.FAILURE;
96 public List<Pair<Vertex, Vertex>> getAffectedNodePairs() {
101 public String getNodeTypeRestriction() {
106 public String getEdgeLabelRestriction() {
111 public String getEdgeDirRestriction() {
116 public void cleanupAsAppropriate(List<Pair<Vertex, Vertex>> nodePairL) {
121 public Optional<String[]> getAffectedNodeTypes() {
126 public String getMigrationName() {
127 return "PserverDedupWithDifferentSourcesOfTruth";
134 nodeTypeToUri = loader.getAllObjects().entrySet().stream().filter(e -> e.getValue().getGenericURI().contains("{")).collect(
137 e -> UriBuilder.fromPath(e.getValue().getFullGenericURI().replaceAll("\\{"+ e.getKey() + "-", "{"))
140 nodeTypeToKeys = loader.getAllObjects().entrySet().stream().filter(e -> e.getValue().getGenericURI().contains("{")).collect(
143 e -> e.getValue().getKeys()
146 List<Vertex> rctList = graphTraversalSource().V().has("aai-node-type", "pserver").has("source-of-truth", P.within(rctSourceOfTruth)).toList();
147 List<Vertex> roList = graphTraversalSource().V().has("aai-node-type", "pserver").has("source-of-truth", P.within(roSourceOfTruth)).toList();
149 logger.info("Total number of RCT sourced pservers in A&AI :" +rctList.size());
150 logger.info("Total number of RO sourced pservers in A&AI :" +roList.size());
152 for(int i=0;i<rctList.size();i++){
153 Vertex currRct = rctList.get(i);
154 Object currRctFqdn = null;
155 if (currRct.property("fqdn").isPresent() && (currRct.property("fqdn").value() != null)){
156 currRctFqdn = currRct.property("fqdn").value();
158 logger.info("Current RCT Pserver hostname: " + currRct.property("hostname").value().toString() + " fqdn: " +currRct.property("fqdn").value().toString());
159 for(int j=0;j<roList.size();j++){
160 Vertex currRo = roList.get(j);
161 Object currRoHostname = null;
162 if (currRo.property("hostname").isPresent()){
163 currRoHostname = currRo.property("hostname").value();
165 if (currRoHostname != null){
166 String[] rctFqdnSplit = currRctFqdn.toString().split("\\.");
167 String[] roHostnameSplit = currRoHostname.toString().split("\\.");
168 if (rctFqdnSplit.length >0 && roHostnameSplit.length > 0){
169 if(!rctFqdnSplit[0].isEmpty() && !roHostnameSplit[0].isEmpty() && rctFqdnSplit[0].equals(roHostnameSplit[0])){
170 logger.info("\tPserver match found - RO Pserver with hostname: "+currRo.property("hostname").value().toString());
173 mergePservers(currRct,currRo);
175 } catch (UnsupportedEncodingException e) {
177 } catch (AAIException e) {
186 RemoveROList.forEach(v ->v.remove());
187 logger.info ("\n \n ******* Migration Summary Counts for Dedup of RCT and RO sourced pservers ********* \n");
188 logger.info(this.MIGRATION_SUMMARY_COUNT + "Total number of RCT: " +rctList.size());
189 logger.info(this.MIGRATION_SUMMARY_COUNT + "Total number of RO: " +roList.size());
190 logger.info(this.MIGRATION_SUMMARY_COUNT + "Duplicate pserver count: "+ dupCount);
191 logger.info(this.MIGRATION_SUMMARY_COUNT + "Number of RCT updated: "+pserversUpdatedCount);
192 logger.info(this.MIGRATION_SUMMARY_COUNT + "Number of RO deleted: "+ pserversDeletedCount +"\n");
194 private GraphTraversalSource graphTraversalSource() {
195 return this.engine.asAdmin().getTraversalSource();
199 public void mergePservers(Vertex rct, Vertex ro) throws UnsupportedEncodingException, AAIException {
200 Introspector obj = serializer.getLatestVersionView(ro);
201 dmaapDeleteList.add(obj);
202 rct.property("fqdn",ro.property("hostname").value().toString());
204 dropMatchingROPInterfaces(ro, rct);
205 dropMatchingROLagInterfaces(ro, rct);
206 swingEdges(ro, rct, null, null, "BOTH");
207 modifyChildrenUri(rct);
208 if(!(rct.property("pserver-id").isPresent())){
209 rct.property("pserver-id",UUID.randomUUID().toString());
211 String dmaapMsg = System.nanoTime() + "_" + rct.id().toString() + "_" + rct.value("resource-version").toString();
212 dmaapMsgList.add(dmaapMsg);
213 pserversUpdatedCount++;
214 logger.info("\tAdding RO pserver to the delete list....");
215 RemoveROList.add(ro);
216 pserversDeletedCount++;
219 private void dropMatchingROPInterfaces(Vertex ro, Vertex rct) {
220 Map<String, Vertex> removeROPIntMap = new HashMap<String, Vertex>();
221 List<Vertex> pIntList = graphTraversalSource().V(ro).in("tosca.relationships.network.BindsTo").has("aai-node-type","p-interface").toList();
222 if (pIntList != null && !pIntList.isEmpty()) {
223 Iterator<Vertex> pIntListItr = pIntList.iterator();
224 while(pIntListItr.hasNext()){
225 Vertex pInt = pIntListItr.next();
227 removeROPIntMap.put(pInt.property("interface-name").value().toString(), pInt);
229 Set<String> interfaceNameSet = removeROPIntMap.keySet();
230 List<Vertex> rctPIntList = graphTraversalSource().V(rct).in("tosca.relationships.network.BindsTo").has("aai-node-type","p-interface").toList();
231 if (rctPIntList != null && !rctPIntList.isEmpty()){
232 Iterator<Vertex> rctPIntListItr = rctPIntList.iterator();
233 while(rctPIntListItr.hasNext()){
234 Vertex rctPInt = rctPIntListItr.next();
235 String rctIntfName = rctPInt.property("interface-name").value().toString();
236 if (interfaceNameSet.contains(rctIntfName)){
237 Vertex pIntToRemoveFromROPserver = removeROPIntMap.get(rctIntfName);
238 String roPIntUri = "roPIntUri";
239 if (pIntToRemoveFromROPserver.property("aai-uri").isPresent()){
240 roPIntUri = pIntToRemoveFromROPserver.property("aai-uri").value().toString();
242 Edge roPIntToPserverEdge = pIntToRemoveFromROPserver.edges(Direction.OUT, "tosca.relationships.network.BindsTo").next();
243 roPIntToPserverEdge.remove();
244 pIntToRemoveFromROPserver.remove();
245 logger.info("\tRemoved p-interface "+roPIntUri + " and its edge to RO pserver, not swinging the p-interface to RCT pserver");
252 private void dropMatchingROLagInterfaces(Vertex ro, Vertex rct) {
253 Map<String, Vertex> removeROLagIntMap = new HashMap<String, Vertex>();
254 List<Vertex> lagIntList = graphTraversalSource().V(ro).in("tosca.relationships.network.BindsTo").has("aai-node-type","lag-interface").toList();
255 if (lagIntList != null && !lagIntList.isEmpty()) {
256 Iterator<Vertex> lagIntListItr = lagIntList.iterator();
257 while(lagIntListItr.hasNext()){
258 Vertex lagInt = lagIntListItr.next();
260 removeROLagIntMap.put(lagInt.property("interface-name").value().toString(), lagInt);
262 Set<String> interfaceNameSet = removeROLagIntMap.keySet();
263 List<Vertex> rctLagIntList = graphTraversalSource().V(rct).in("tosca.relationships.network.BindsTo").has("aai-node-type","lag-interface").toList();
264 if (rctLagIntList != null && !rctLagIntList.isEmpty()){
265 Iterator<Vertex> rctLagIntListItr = rctLagIntList.iterator();
266 while(rctLagIntListItr.hasNext()){
267 Vertex rctPInt = rctLagIntListItr.next();
268 String rctIntfName = rctPInt.property("interface-name").value().toString();
269 if (interfaceNameSet.contains(rctIntfName)){
270 Vertex lagIntToRemoveFromROPserver = removeROLagIntMap.get(rctIntfName);
271 String roLagIntUri = "roPIntUri";
272 if (lagIntToRemoveFromROPserver.property("aai-uri").isPresent()){
273 roLagIntUri = lagIntToRemoveFromROPserver.property("aai-uri").value().toString();
275 Edge roLagIntToPserverEdge = lagIntToRemoveFromROPserver.edges(Direction.OUT, "tosca.relationships.network.BindsTo").next();
276 roLagIntToPserverEdge.remove();
277 lagIntToRemoveFromROPserver.remove();
278 logger.info("\tRemoved lag-interface "+roLagIntUri + " and its edge to RO pserver, not swinging the lag-interface to RCT pserver");
285 public void dropComplexEdge(Vertex ro){
286 List<Vertex> locatedInEdgeVertexList = graphTraversalSource().V(ro).has("aai-node-type", "pserver").out("org.onap.relationships.inventory.LocatedIn").has("aai-node-type","complex").toList();
287 if (locatedInEdgeVertexList != null && !locatedInEdgeVertexList.isEmpty()){
288 Iterator<Vertex> locatedInEdgeVertexListItr = locatedInEdgeVertexList.iterator();
289 while (locatedInEdgeVertexListItr.hasNext()){
290 Vertex v = locatedInEdgeVertexListItr.next();
291 if ("complex".equalsIgnoreCase(v.property("aai-node-type").value().toString())){
292 Edge pserverToComplexEdge = v.edges(Direction.IN, "org.onap.relationships.inventory.LocatedIn").next();
293 pserverToComplexEdge.remove();
300 private void modifyChildrenUri(Vertex v) throws UnsupportedEncodingException, AAIException {
301 Set<Vertex> parentSet = new HashSet<>();
303 verifyOrAddUri("", parentSet);
307 protected void verifyOrAddUri(String parentUri, Set<Vertex> vertexSet) throws UnsupportedEncodingException, AAIException {
311 for (Vertex v : vertexSet) {
313 //if there is an issue generating the uri catch, log and move on;
315 correctUri = parentUri + this.getUriForVertex(v);
316 } catch (Exception e) {
317 logger.error("Vertex has issue generating uri " + e.getMessage() + "\n\t" + this.asString(v));
321 v.property(AAIProperties.AAI_URI, correctUri);
322 } catch (Exception e) {
323 logger.info("\t" + e.getMessage() + "\n\t" + this.asString(v));
325 if (!v.property(AAIProperties.AAI_UUID).isPresent()) {
326 v.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString());
328 this.verifyOrAddUri(correctUri, getChildren(v));
332 protected Set<Vertex> getChildren(Vertex v) {
334 Set<Vertex> children = graphTraversalSource().V(v).bothE().not(__.has(EdgeProperty.CONTAINS.toString(), AAIDirection.NONE.toString())).otherV().toSet();
336 return children.stream().filter(child -> !seen.contains(child.id())).collect(Collectors.toSet());
339 protected String getUriForVertex(Vertex v) {
340 String aaiNodeType = v.property(AAIProperties.NODE_TYPE).value().toString();
343 Map<String, String> parameters = this.nodeTypeToKeys.get(aaiNodeType).stream().collect(Collectors.toMap(
345 key -> encodeProp(v.property(key).value().toString())
348 return this.nodeTypeToUri.get(aaiNodeType).buildFromEncodedMap(parameters).toString();
350 private static String encodeProp(String s) {
352 return UriUtils.encode(s, "UTF-8");
353 } catch (UnsupportedEncodingException e) {