diff options
Diffstat (limited to 'aai-resources/src/main/java/org/onap/aai/migration')
12 files changed, 999 insertions, 175 deletions
diff --git a/aai-resources/src/main/java/org/onap/aai/migration/EdgeMigrator.java b/aai-resources/src/main/java/org/onap/aai/migration/EdgeMigrator.java index 4e2fde4..ed29c84 100644 --- a/aai-resources/src/main/java/org/onap/aai/migration/EdgeMigrator.java +++ b/aai-resources/src/main/java/org/onap/aai/migration/EdgeMigrator.java @@ -39,16 +39,13 @@ import org.onap.aai.serialization.db.EdgeRules; * A migration template for migrating all edge properties between "from" and "to" node from the DbedgeRules.json * */ +@MigrationPriority(0) +@MigrationDangerRating(1) public abstract class EdgeMigrator extends Migrator { private boolean success = true; private EdgeRules rules; - public EdgeMigrator() { - // used for not great reflection implementation - super(); - } - public EdgeMigrator(TransactionalGraphEngine engine) { super(engine); rules = EdgeRules.getInstance(); @@ -140,20 +137,6 @@ public abstract class EdgeMigrator extends Migrator { } } - @Override - public int getPriority() { - return 0; - } - - /* - * Higher danger rating of 10 only for all edge property changes - * or when a quorum of edges change which can be overridden by inheritors - */ - @Override - public int getDangerRating() { - return 1; - } - /** * List of node pairs("from" and "to"), you would like EdgeMigrator to migrate from json files * @return diff --git a/aai-resources/src/main/java/org/onap/aai/migration/MigrationController.java b/aai-resources/src/main/java/org/onap/aai/migration/MigrationController.java index 93d58b3..6742c8a 100644 --- a/aai-resources/src/main/java/org/onap/aai/migration/MigrationController.java +++ b/aai-resources/src/main/java/org/onap/aai/migration/MigrationController.java @@ -21,10 +21,15 @@ */ package org.onap.aai.migration; +import java.util.UUID; + import org.onap.aai.dbmap.AAIGraph; +import org.onap.aai.logging.LoggingContext; +import org.onap.aai.logging.LoggingContext.StatusCode; +import org.onap.aai.util.AAIConstants; /** - * Wrapper class to allow {@link com.openecomp.aai.migration.MigrationControllerInternal MigrationControllerInternal} + * Wrapper class to allow {@link org.onap.aai.migration.MigrationControllerInternal MigrationControllerInternal} * to be run from a shell script */ public class MigrationController { @@ -36,15 +41,23 @@ public class MigrationController { * the arguments */ public static void main(String[] args) { - + LoggingContext.init(); + LoggingContext.partnerName("Migration"); + LoggingContext.serviceName(AAIConstants.AAI_RESOURCES_MS); + LoggingContext.component("MigrationController"); + LoggingContext.targetEntity(AAIConstants.AAI_RESOURCES_MS); + LoggingContext.targetServiceName("main"); + LoggingContext.requestId(UUID.randomUUID().toString()); + LoggingContext.statusCode(StatusCode.COMPLETE); + LoggingContext.responseCode(LoggingContext.SUCCESS); MigrationControllerInternal internal = new MigrationControllerInternal(); try { internal.run(args); } catch (Exception e) { - //ignore + e.printStackTrace(); } - AAIGraph.getInstance().getGraph().close(); + AAIGraph.getInstance().graphShutdown(); System.exit(0); } } diff --git a/aai-resources/src/main/java/org/onap/aai/migration/MigrationControllerInternal.java b/aai-resources/src/main/java/org/onap/aai/migration/MigrationControllerInternal.java index 6da9321..fbc4e03 100644 --- a/aai-resources/src/main/java/org/onap/aai/migration/MigrationControllerInternal.java +++ b/aai-resources/src/main/java/org/onap/aai/migration/MigrationControllerInternal.java @@ -29,10 +29,10 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Properties; import java.util.Set; +import java.util.stream.Collectors; import org.apache.activemq.broker.BrokerService; import org.apache.commons.configuration.ConfigurationException; @@ -48,6 +48,8 @@ import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.LoaderFactory; import org.onap.aai.introspection.ModelType; import org.onap.aai.introspection.Version; +import org.onap.aai.logging.LoggingContext; +import org.onap.aai.logging.LoggingContext.StatusCode; import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TitanDBEngine; import org.onap.aai.serialization.engines.TransactionalGraphEngine; @@ -63,20 +65,20 @@ import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; /** - * Runs a series of migrations from a defined directory based on the presence of - * the {@link com.openecomp.aai.migration.Enabled Enabled} annotation - * + * Runs a series of migrations from a defined directory based on the presence of + * the {@link org.onap.aai.migration.Enabled Enabled} annotation + * * It will also write a record of the migrations run to the database. */ public class MigrationControllerInternal { private EELFLogger logger; private final int DANGER_ZONE = 10; - private final String vertexType = "migration-list-1707"; + private static final String VERTEX_TYPE = "migration-list-" + Version.getLatest().toString(); private final List<String> resultsSummary = new ArrayList<>(); private BrokerService broker; private final List<NotificationHelper> notifications = new ArrayList<>(); - private final String snapshotLocation = AAIConstants.AAI_HOME + AAIConstants.AAI_FILESEP + "logs" + AAIConstants.AAI_FILESEP + "data" + AAIConstants.AAI_FILESEP + "migrationSnapshots"; + private static final String SNAPSHOT_LOCATION = AAIConstants.AAI_HOME + AAIConstants.AAI_FILESEP + "logs" + AAIConstants.AAI_FILESEP + "data" + AAIConstants.AAI_FILESEP + "migrationSnapshots"; /** * The main method. * @@ -85,6 +87,7 @@ public class MigrationControllerInternal { */ public void run(String[] args) { // Set the logging file properties to be used by EELFManager + System.setProperty("aai.service.name", MigrationController.class.getSimpleName()); Properties props = System.getProperties(); props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, "migration-logback.xml"); props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES); @@ -98,6 +101,7 @@ public class MigrationControllerInternal { JCommander jCommander = new JCommander(cArgs, args); jCommander.setProgramName(MigrationController.class.getSimpleName()); + // Set flag to load from snapshot based on the presence of snapshot and // graph storage backend of inmemory if (cArgs.dataSnapshot != null && !cArgs.dataSnapshot.isEmpty()) { @@ -109,6 +113,8 @@ public class MigrationControllerInternal { System.setProperty("snapshot.location", cArgs.dataSnapshot); } } catch (ConfigurationException e) { + LoggingContext.statusCode(StatusCode.ERROR); + LoggingContext.responseCode(LoggingContext.DATA_ERROR); logAndPrint("ERROR: Could not load titan configuration.\n" + ExceptionUtils.getFullStackTrace(e)); return; } @@ -123,80 +129,76 @@ public class MigrationControllerInternal { ModelType introspectorFactoryType = ModelType.MOXY; Loader loader = LoaderFactory.createLoaderForVersion(introspectorFactoryType, version); TransactionalGraphEngine engine = new TitanDBEngine(queryStyle, DBConnectionType.REALTIME, loader); - + if (cArgs.help) { jCommander.usage(); engine.rollback(); return; - } else if (cArgs.list) { - Reflections reflections = new Reflections("org.onap.aai.migration"); - Set<Class<? extends Migrator>> migratorClasses = findClasses(reflections); - List<Migrator> migratorList = createMigratorList(cArgs, migratorClasses); - - sortList(migratorList); - engine.startTransaction(); - System.out.println("---------- List of all migrations ----------"); - migratorList.forEach(migrator -> { - boolean enabledAnnotation = migrator.getClass().isAnnotationPresent(Enabled.class); - String enabled = enabledAnnotation ? "Enabled" : "Disabled"; - StringBuilder sb = new StringBuilder(); - sb.append(migrator.getClass().getSimpleName() + " " + enabled); - sb.append(" "); - sb.append("[" + getDbStatus(migrator.getClass().getSimpleName(), engine) + "]"); - System.out.println(sb.toString()); - }); - engine.rollback(); - System.out.println("---------- Done ----------"); - return; } - Reflections reflections = new Reflections("org.onap.aai.migration"); + List<Class<? extends Migrator>> migratorClasses = new ArrayList<>(findClasses(reflections)); + //Displays list of migration classes which needs to be executed.Pass flag "-l" following by the class names + if (cArgs.list) { + listMigrationWithStatus(cArgs, migratorClasses, engine); + return; + } logAndPrint("---------- Looking for migration scripts to be executed. ----------"); - Set<Class<? extends Migrator>> migratorClasses = findClasses(reflections); - List<Migrator> migratorList = createMigratorList(cArgs, migratorClasses); + //Excluding any migration class when run migration from script.Pass flag "-e" following by the class names + if (!cArgs.excludeClasses.isEmpty()) { + migratorClasses = filterMigrationClasses(cArgs.excludeClasses, migratorClasses); + listMigrationWithStatus(cArgs, migratorClasses, engine); + } + List<Class<? extends Migrator>> migratorClassesToRun = createMigratorList(cArgs, migratorClasses); - sortList(migratorList); + sortList(migratorClassesToRun); - if (!cArgs.scripts.isEmpty() && migratorList.size() == 0) { + if (!cArgs.scripts.isEmpty() && migratorClassesToRun.isEmpty()) { + LoggingContext.statusCode(StatusCode.ERROR); + LoggingContext.responseCode(LoggingContext.BUSINESS_PROCESS_ERROR); logAndPrint("\tERROR: Failed to find migrations " + cArgs.scripts + "."); logAndPrint("---------- Done ----------"); + LoggingContext.successStatusFields(); } - logAndPrint("\tFound " + migratorList.size() + " migration scripts."); + logAndPrint("\tFound " + migratorClassesToRun.size() + " migration scripts."); logAndPrint("---------- Executing Migration Scripts ----------"); - - - takeSnapshotIfRequired(engine, cArgs, migratorList); - for (Migrator migratorClass : migratorList) { - String name = migratorClass.getClass().getSimpleName(); + if (!cArgs.skipPreMigrationSnapShot) { + takePreSnapshotIfRequired(engine, cArgs, migratorClassesToRun); + } + + for (Class<? extends Migrator> migratorClass : migratorClassesToRun) { + String name = migratorClass.getSimpleName(); Migrator migrator; - if (migratorClass.getClass().isAnnotationPresent(Enabled.class)) { - + if (migratorClass.isAnnotationPresent(Enabled.class)) { + try { engine.startTransaction(); if (!cArgs.forced && hasAlreadyRun(name, engine)) { logAndPrint("Migration " + name + " has already been run on this database and will not be executed again. Use -f to force execution"); continue; } - migrator = migratorClass.getClass().getConstructor(TransactionalGraphEngine.class).newInstance(engine); + migrator = migratorClass.getConstructor(TransactionalGraphEngine.class).newInstance(engine); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { - logAndPrint("EXCEPTION caught initalizing migration class " + migratorClass.getClass().getSimpleName() + ".\n" + ExceptionUtils.getFullStackTrace(e)); + LoggingContext.statusCode(StatusCode.ERROR); + LoggingContext.responseCode(LoggingContext.DATA_ERROR); + logAndPrint("EXCEPTION caught initalizing migration class " + migratorClass.getSimpleName() + ".\n" + ExceptionUtils.getFullStackTrace(e)); + LoggingContext.successStatusFields(); engine.rollback(); continue; } - logAndPrint("\tRunning " + migratorClass.getClass().getSimpleName() + " migration script."); - logAndPrint("\t\t See " + System.getProperty("AJSC_HOME") + "/logs/migration/" + migratorClass.getClass().getSimpleName() + "/* for logs."); - MDC.put("logFilenameAppender", migratorClass.getClass().getSimpleName() + "/" + migratorClass.getClass().getSimpleName()); - + logAndPrint("\tRunning " + migratorClass.getSimpleName() + " migration script."); + logAndPrint("\t\t See " + System.getProperty("AJSC_HOME") + "/logs/migration/" + migratorClass.getSimpleName() + "/* for logs."); + MDC.put("logFilenameAppender", migratorClass.getSimpleName() + "/" + migratorClass.getSimpleName()); + migrator.run(); - + commitChanges(engine, migrator, cArgs); } else { - logAndPrint("\tSkipping " + migratorClass.getClass().getSimpleName() + " migration script because it has been disabled."); + logAndPrint("\tSkipping " + migratorClass.getSimpleName() + " migration script because it has been disabled."); } } MDC.put("logFilenameAppender", MigrationController.class.getSimpleName()); @@ -204,27 +206,76 @@ public class MigrationControllerInternal { try { notificationHelper.triggerEvents(); } catch (AAIException e) { + LoggingContext.statusCode(StatusCode.ERROR); + LoggingContext.responseCode(LoggingContext.AVAILABILITY_TIMEOUT_ERROR); logAndPrint("\tcould not event"); logger.error("could not event", e); + LoggingContext.successStatusFields(); } } logAndPrint("---------- Done ----------"); // Save post migration snapshot if snapshot was loaded - generateSnapshot(engine, "post"); - + if (!cArgs.skipPostMigrationSnapShot) { + generateSnapshot(engine, "post"); + } + outputResultsSummary(); } + /** + * This method is used to remove excluded classes from migration from the + * script command. + * + * @param excludeClasses + * : Classes to be removed from Migration + * @param migratorClasses + * : Classes to execute migration. + * @return + */ + private List<Class<? extends Migrator>> filterMigrationClasses( + List<String> excludeClasses, + List<Class<? extends Migrator>> migratorClasses) { + + List<Class<? extends Migrator>> filteredMigratorClasses = migratorClasses + .stream() + .filter(migratorClass -> !excludeClasses.contains(migratorClass + .getSimpleName())).collect(Collectors.toList()); + + return filteredMigratorClasses; + } + + private void listMigrationWithStatus(CommandLineArgs cArgs, + List<Class<? extends Migrator>> migratorClasses, TransactionalGraphEngine engine) { + sortList(migratorClasses); + engine.startTransaction(); + System.out.println("---------- List of all migrations ----------"); + migratorClasses.forEach(migratorClass -> { + boolean enabledAnnotation = migratorClass.isAnnotationPresent(Enabled.class); + String enabled = enabledAnnotation ? "Enabled" : "Disabled"; + StringBuilder sb = new StringBuilder(); + sb.append(migratorClass.getSimpleName()); + sb.append(" in package "); + sb.append(migratorClass.getPackage().getName().substring(migratorClass.getPackage().getName().lastIndexOf('.')+1)); + sb.append(" is "); + sb.append(enabled); + sb.append(" "); + sb.append("[" + getDbStatus(migratorClass.getSimpleName(), engine) + "]"); + System.out.println(sb.toString()); + }); + engine.rollback(); + System.out.println("---------- Done ----------"); + } + private String getDbStatus(String name, TransactionalGraphEngine engine) { if (hasAlreadyRun(name, engine)) { return "Already executed in this env"; } - return "Will be run on next execution"; + return "Will be run on next execution if Enabled"; } private boolean hasAlreadyRun(String name, TransactionalGraphEngine engine) { - return engine.asAdmin().getReadOnlyTraversalSource().V().has(AAIProperties.NODE_TYPE, vertexType).has(name, true).hasNext(); + return engine.asAdmin().getReadOnlyTraversalSource().V().has(AAIProperties.NODE_TYPE, VERTEX_TYPE).has(name, true).hasNext(); } private Set<Class<? extends Migrator>> findClasses(Reflections reflections) { Set<Class<? extends Migrator>> migratorClasses = reflections.getSubTypesOf(Migrator.class); @@ -232,85 +283,75 @@ public class MigrationControllerInternal { * TODO- Change this to make sure only classes in the specific $release are added in the runList * Or add a annotation like exclude which folks again need to remember to add ?? */ - + migratorClasses.remove(PropertyMigrator.class); migratorClasses.remove(EdgeMigrator.class); return migratorClasses; } - private void takeSnapshotIfRequired(TransactionalGraphEngine engine, CommandLineArgs cArgs, List<Migrator> migratorList) { + private void takePreSnapshotIfRequired(TransactionalGraphEngine engine, CommandLineArgs cArgs, List<Class<? extends Migrator>> migratorClassesToRun) { /*int sum = 0; - for (Migrator migrator : migratorList) { - if (migrator.getClass().isAnnotationPresent(Enabled.class)) { - sum += migrator.getDangerRating(); + for (Class<? extends Migrator> migratorClass : migratorClassesToRun) { + if (migratorClass.isAnnotationPresent(Enabled.class)) { + sum += migratorClass.getAnnotation(MigrationPriority.class).value(); } } - + if (sum >= DANGER_ZONE) { - + logAndPrint("Entered Danger Zone. Taking snapshot."); }*/ - + //always take snapshot for now + generateSnapshot(engine, "pre"); } - private List<Migrator> createMigratorList(CommandLineArgs cArgs, - Set<Class<? extends Migrator>> migratorClasses) { - List<Migrator> migratorList = new ArrayList<>(); + private List<Class<? extends Migrator>> createMigratorList(CommandLineArgs cArgs, + List<Class<? extends Migrator>> migratorClasses) { + List<Class<? extends Migrator>> migratorClassesToRun = new ArrayList<>(); for (Class<? extends Migrator> migratorClass : migratorClasses) { if (!cArgs.scripts.isEmpty() && !cArgs.scripts.contains(migratorClass.getSimpleName())) { continue; } else { - Migrator migrator; - try { - - migrator = migratorClass.getConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { - logAndPrint("EXCEPTION caught initalizing migration class " + migratorClass.getSimpleName() + ".\n" + ExceptionUtils.getFullStackTrace(e)); - continue; - } - migratorList.add(migrator); + migratorClassesToRun.add(migratorClass); } } - return migratorList; + return migratorClassesToRun; } - private void sortList(List<Migrator> migratorList) { - Collections.sort(migratorList, new Comparator<Migrator>() { - public int compare(Migrator m1, Migrator m2) { - try { - - if (m1.getPriority() > m2.getPriority()) { - return 1; - } else if (m1.getPriority() < m2.getPriority()) { - return -1; - } else { - return m1.getClass().getSimpleName().compareTo(m2.getClass().getSimpleName()); - } - } catch (Exception e) { - return 0; + private void sortList(List<Class<? extends Migrator>> migratorClasses) { + Collections.sort(migratorClasses, (m1, m2) -> { + try { + if (m1.getAnnotation(MigrationPriority.class).value() > m2.getAnnotation(MigrationPriority.class).value()) { + return 1; + } else if (m1.getAnnotation(MigrationPriority.class).value() < m2.getAnnotation(MigrationPriority.class).value()) { + return -1; + } else { + return m1.getSimpleName().compareTo(m2.getSimpleName()); } + } catch (Exception e) { + return 0; } }); } - + private void generateSnapshot(TransactionalGraphEngine engine, String phase) { - + FormatDate fd = new FormatDate("yyyyMMddHHmm", "GMT"); String dateStr= fd.getDateTime(); - String fileName = snapshotLocation + File.separator + phase + "Migration." + dateStr + ".graphson"; + String fileName = SNAPSHOT_LOCATION + File.separator + phase + "Migration." + dateStr + ".graphson"; logAndPrint("Saving snapshot of inmemory graph " + phase + " migration to " + fileName); Graph transaction = null; try { - + Path pathToFile = Paths.get(fileName); if (!pathToFile.toFile().exists()) { Files.createDirectories(pathToFile.getParent()); @@ -319,17 +360,18 @@ public class MigrationControllerInternal { transaction.io(IoCore.graphson()).writeGraph(fileName); engine.rollback(); } catch (IOException e) { + LoggingContext.statusCode(StatusCode.ERROR); + LoggingContext.responseCode(LoggingContext.AVAILABILITY_TIMEOUT_ERROR); logAndPrint("ERROR: Could not write in memory graph to " + phase + "Migration file. \n" + ExceptionUtils.getFullStackTrace(e)); + LoggingContext.successStatusFields(); engine.rollback(); - } + } logAndPrint( phase + " migration snapshot saved to " + fileName); } /** * Log and print. * - * @param logger - * the logger * @param msg * the msg */ @@ -341,12 +383,11 @@ public class MigrationControllerInternal { /** * Commit changes. * - * @param g - * the g + * @param engine + * the graph transaction * @param migrator * the migrator - * @param logger - * the logger + * @param cArgs */ protected void commitChanges(TransactionalGraphEngine engine, Migrator migrator, CommandLineArgs cArgs) { @@ -354,20 +395,26 @@ public class MigrationControllerInternal { String message; if (migrator.getStatus().equals(Status.FAILURE)) { message = "Migration " + simpleName + " Failed. Rolling back."; + LoggingContext.statusCode(StatusCode.ERROR); + LoggingContext.responseCode(LoggingContext.DATA_ERROR); logAndPrint("\t" + message); + LoggingContext.successStatusFields(); migrator.rollback(); } else if (migrator.getStatus().equals(Status.CHECK_LOGS)) { - message = "Migration " + simpleName + " encountered an anomily, check logs. Rolling back."; + message = "Migration " + simpleName + " encountered an anomaly, check logs. Rolling back."; + LoggingContext.statusCode(StatusCode.ERROR); + LoggingContext.responseCode(LoggingContext.DATA_ERROR); logAndPrint("\t" + message); + LoggingContext.successStatusFields(); migrator.rollback(); } else { - MDC.put("logFilenameAppender", simpleName + "/" + migrator.getClass().getSimpleName()); + MDC.put("logFilenameAppender", simpleName + "/" + simpleName); if (cArgs.commit) { - if (!engine.asAdmin().getTraversalSource().V().has(AAIProperties.NODE_TYPE, vertexType).hasNext()) { - engine.asAdmin().getTraversalSource().addV(AAIProperties.NODE_TYPE, vertexType).iterate(); + if (!engine.asAdmin().getTraversalSource().V().has(AAIProperties.NODE_TYPE, VERTEX_TYPE).hasNext()) { + engine.asAdmin().getTraversalSource().addV(AAIProperties.NODE_TYPE, VERTEX_TYPE).iterate(); } - engine.asAdmin().getTraversalSource().V().has(AAIProperties.NODE_TYPE, vertexType) + engine.asAdmin().getTraversalSource().V().has(AAIProperties.NODE_TYPE, VERTEX_TYPE) .property(simpleName, true).iterate(); MDC.put("logFilenameAppender", MigrationController.class.getSimpleName()); notifications.add(migrator.getNotificationHelper()); @@ -381,11 +428,11 @@ public class MigrationControllerInternal { } } - + resultsSummary.add(message); } - + private void outputResultsSummary() { logAndPrint("---------------------------------"); logAndPrint("-------------Summary-------------"); @@ -395,7 +442,7 @@ public class MigrationControllerInternal { logAndPrint("---------------------------------"); logAndPrint("---------------------------------"); } - + } class CommandLineArgs { @@ -411,14 +458,22 @@ class CommandLineArgs { @Parameter(names = "-l", description = "list the status of migrations") public boolean list = false; - + @Parameter(names = "-d", description = "location of data snapshot", hidden = true) public String dataSnapshot; - + @Parameter(names = "-f", description = "force migrations to be rerun") public boolean forced = false; - + @Parameter(names = "--commit", description = "commit changes to graph") public boolean commit = false; + @Parameter(names = "-e", description = "exclude list of migrator classes") + public List<String> excludeClasses = new ArrayList<>(); + + @Parameter(names = "--skipPreMigrationSnapShot", description = "skips taking the PRE migration snapshot") + public boolean skipPreMigrationSnapShot = false; + + @Parameter(names = "--skipPostMigrationSnapShot", description = "skips taking the POST migration snapshot") + public boolean skipPostMigrationSnapShot = false; } diff --git a/aai-resources/src/main/java/org/onap/aai/migration/MigrationDangerRating.java b/aai-resources/src/main/java/org/onap/aai/migration/MigrationDangerRating.java new file mode 100644 index 0000000..a1d456c --- /dev/null +++ b/aai-resources/src/main/java/org/onap/aai/migration/MigrationDangerRating.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.migration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * Used to enable a migration to be picked up by the {@link com.openecomp.aai.migration.MigrationControllerInternal MigrationController} + * + * The larger the number, the more danger + * + * Range is 0-10 + */ +@Target(ElementType.TYPE) +@Retention(value = RetentionPolicy.RUNTIME) +public @interface MigrationDangerRating { + + int value(); + +} diff --git a/aai-resources/src/main/java/org/onap/aai/migration/MigrationPriority.java b/aai-resources/src/main/java/org/onap/aai/migration/MigrationPriority.java new file mode 100644 index 0000000..fb7b06f --- /dev/null +++ b/aai-resources/src/main/java/org/onap/aai/migration/MigrationPriority.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.migration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * Used to enable a migration to be picked up by the {@link com.openecomp.aai.migration.MigrationControllerInternal MigrationController} + * + * The priority of the migration. + * + * Lower number has higher priority + */ +@Target(ElementType.TYPE) +@Retention(value = RetentionPolicy.RUNTIME) +public @interface MigrationPriority { + + int value(); + +} diff --git a/aai-resources/src/main/java/org/onap/aai/migration/Migrator.java b/aai-resources/src/main/java/org/onap/aai/migration/Migrator.java index 900c914..e5e4c52 100644 --- a/aai-resources/src/main/java/org/onap/aai/migration/Migrator.java +++ b/aai-resources/src/main/java/org/onap/aai/migration/Migrator.java @@ -21,6 +21,7 @@ */ package org.onap.aai.migration; +import java.util.Collections; import java.util.Iterator; import java.util.Optional; @@ -50,6 +51,8 @@ import com.att.eelf.configuration.EELFManager; /** * This class defines an A&AI Migration */ +@MigrationPriority(0) +@MigrationDangerRating(0) public abstract class Migrator implements Runnable { protected EELFLogger logger = null; @@ -59,10 +62,7 @@ public abstract class Migrator implements Runnable { protected TransactionalGraphEngine engine; protected NotificationHelper notificationHelper; - - public Migrator() { - //used for not great reflection implementation - } + /** * Instantiates a new migrator. * @@ -97,24 +97,8 @@ public abstract class Migrator implements Runnable { engine.commit(); } - /** - * Gets the priority. - * - * Lower number has higher priority - * - * @return the priority - */ - public abstract int getPriority(); /** - * The larger the number, the more danger - * - * Range is 0-10 - * - * @return danger rating - */ - public abstract int getDangerRating(); - /** * As string. * * @param v the v @@ -157,12 +141,48 @@ public abstract class Migrator implements Runnable { return result.toString(); } + + /** + * + * @param v + * @param numLeadingTabs number of leading \t char's + * @return + */ + protected String toStringForPrinting(Vertex v, int numLeadingTabs) { + String prefix = String.join("", Collections.nCopies(numLeadingTabs, "\t")); + if (v == null) { + return ""; + } + final StringBuilder sb = new StringBuilder(); + sb.append(prefix + v + "\n"); + v.properties().forEachRemaining(prop -> sb.append(prefix + prop + "\n")); + return sb.toString(); + } + + /** + * + * @param e + * @param numLeadingTabs number of leading \t char's + * @return + */ + protected String toStringForPrinting(Edge e, int numLeadingTabs) { + String prefix = String.join("", Collections.nCopies(numLeadingTabs, "\t")); + if (e == null) { + return ""; + } + final StringBuilder sb = new StringBuilder(); + sb.append(prefix + e + "\n"); + sb.append(prefix + e.label() + "\n"); + e.properties().forEachRemaining(prop -> sb.append(prefix + "\t" + prop + "\n")); + return sb.toString(); + } + /** * Checks for edge between. * - * @param vertex a - * @param vertex b - * @param direction d + * @param a a + * @param b b + * @param d d * @param edgeLabel the edge label * @return true, if successful */ @@ -179,7 +199,7 @@ public abstract class Migrator implements Runnable { /** * Creates the edge * - * @param edgeType the edge type - COUSIN or TREE + * @param type the edge type - COUSIN or TREE * @param out the out * @param in the in * @return the edge diff --git a/aai-resources/src/main/java/org/onap/aai/migration/PropertyMigrator.java b/aai-resources/src/main/java/org/onap/aai/migration/PropertyMigrator.java index c42862a..28c78ea 100644 --- a/aai-resources/src/main/java/org/onap/aai/migration/PropertyMigrator.java +++ b/aai-resources/src/main/java/org/onap/aai/migration/PropertyMigrator.java @@ -36,6 +36,8 @@ import com.thinkaurelius.titan.core.schema.TitanManagement; /** * A migration template for migrating a property from one name to another */ +@MigrationPriority(0) +@MigrationDangerRating(1) public abstract class PropertyMigrator extends Migrator { protected final String OLD_FIELD; @@ -43,15 +45,7 @@ public abstract class PropertyMigrator extends Migrator { protected final Class<?> fieldType; protected final Cardinality cardinality; protected final TitanManagement graphMgmt; - public PropertyMigrator() { - //used for not great reflection implementation - super(); - this.OLD_FIELD = null; - this.NEW_FIELD = null; - this.fieldType = null; - this.cardinality = null; - this.graphMgmt = null; - } + public PropertyMigrator(TransactionalGraphEngine engine, String oldName, String newName, Class<?> type, Cardinality cardinality) { super(engine); this.OLD_FIELD = oldName; @@ -111,17 +105,7 @@ public abstract class PropertyMigrator extends Migrator { return Status.FAILURE; } } - - @Override - public int getPriority() { - return 0; - } - @Override - public int getDangerRating() { - return 1; - } - protected Optional<PropertyKey> addProperty() { if (!graphMgmt.containsPropertyKey(this.NEW_FIELD)) { diff --git a/aai-resources/src/main/java/org/onap/aai/migration/v12/ContainmentDeleteOtherVPropertyMigration.java b/aai-resources/src/main/java/org/onap/aai/migration/v12/ContainmentDeleteOtherVPropertyMigration.java new file mode 100644 index 0000000..643517d --- /dev/null +++ b/aai-resources/src/main/java/org/onap/aai/migration/v12/ContainmentDeleteOtherVPropertyMigration.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.migration.v12; + +import java.util.Optional; + +import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.onap.aai.migration.MigrationDangerRating; +import org.onap.aai.migration.Enabled; +import org.onap.aai.migration.MigrationPriority; +import org.onap.aai.migration.Migrator; +import org.onap.aai.migration.Status; +import org.onap.aai.serialization.db.AAIDirection; +import org.onap.aai.serialization.db.EdgeProperty; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; + + + +@Enabled +@MigrationPriority(-100) +@MigrationDangerRating(10) +public class ContainmentDeleteOtherVPropertyMigration extends Migrator { + + private boolean success = true; + + public ContainmentDeleteOtherVPropertyMigration(TransactionalGraphEngine engine) { + super(engine); + } + + //just for testing using test edge rule files + public ContainmentDeleteOtherVPropertyMigration(TransactionalGraphEngine engine, String edgeRulesFile) { + super(engine); + } + + @Override + public void run() { + try { + engine.asAdmin().getTraversalSource().E().sideEffect(t -> { + Edge e = t.get(); + logger.info("out vertex: " + e.outVertex().property("aai-node-type").value() + + " in vertex: " + e.inVertex().property("aai-node-type").value() + + " label : " + e.label()); + if (e.property(EdgeProperty.CONTAINS.toString()).isPresent() && + e.property(EdgeProperty.DELETE_OTHER_V.toString()).isPresent()) { + //in case of orphans + if (!("constrained-element-set".equals(e.inVertex().property("aai-node-type").value()) + && "model-element".equals(e.outVertex().property("aai-node-type").value()))) { + //skip the weird horrible problem child edge + String containment = (String) e.property(EdgeProperty.CONTAINS.toString()).value(); + if (AAIDirection.OUT.toString().equalsIgnoreCase(containment) || + AAIDirection.IN.toString().equalsIgnoreCase(containment) || + AAIDirection.BOTH.toString().equalsIgnoreCase(containment)) { + logger.info("updating delete-other-v property"); + e.property(EdgeProperty.DELETE_OTHER_V.toString(), containment); + } + } + } + }).iterate(); + } catch (Exception e) { + logger.info("error encountered " + e.getClass() + " " + e.getMessage() + " " + ExceptionUtils.getFullStackTrace(e)); + logger.error("error encountered " + e.getClass() + " " + e.getMessage() + " " + ExceptionUtils.getFullStackTrace(e)); + success = false; + } + + } + + @Override + public Status getStatus() { + if (success) { + return Status.SUCCESS; + } else { + return Status.FAILURE; + } + } + + @Override + public Optional<String[]> getAffectedNodeTypes() { + return Optional.empty(); + } + + @Override + public String getMigrationName() { + return "migrate-containment-delete-other-v"; + } + +} diff --git a/aai-resources/src/main/java/org/onap/aai/migration/v12/EdgeReportForToscaMigration.java b/aai-resources/src/main/java/org/onap/aai/migration/v12/EdgeReportForToscaMigration.java new file mode 100644 index 0000000..859e52f --- /dev/null +++ b/aai-resources/src/main/java/org/onap/aai/migration/v12/EdgeReportForToscaMigration.java @@ -0,0 +1,142 @@ +package org.onap.aai.migration.v12; +/*- + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.onap.aai.migration.*; +import org.onap.aai.serialization.db.EdgeRules; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; + +import java.util.*; + +@Enabled +@MigrationPriority(0) +@MigrationDangerRating(0) +public class EdgeReportForToscaMigration extends Migrator { + + private boolean success = true; + EdgeRules ers = EdgeRules.getInstance(); + + public EdgeReportForToscaMigration(TransactionalGraphEngine graphEngine){ + super(graphEngine); + } + + @Override + public Status getStatus() { + if (success) { + return Status.SUCCESS; + } else { + return Status.FAILURE; + } + } + + @Override + public void run() { + Vertex out = null; + Vertex in = null; + String label = ""; + String outURI = ""; + String inURI = ""; + String parentCousinIndicator = "NONE"; + String oldEdgeString = null; + List<String> edgeMissingParentProperty = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + Set<String> noURI = new HashSet<>(); + sb.append("----------EDGES----------\n"); + + GraphTraversalSource g = engine.asAdmin().getTraversalSource(); + + try { + Set<Edge> edges = g.E().toSet(); + for (Edge edge : edges) { + out = edge.outVertex(); + in = edge.inVertex(); + label = edge.label(); + outURI = this.getVertexURI(out); + inURI = this.getVertexURI(in); + parentCousinIndicator = "NONE"; + oldEdgeString = this.toStringForPrinting(edge, 1); + + if (!outURI.startsWith("/")) { + noURI.add(outURI); + } + if (!inURI.startsWith("/")) { + noURI.add(inURI); + } + + if (out == null || in == null) { + logger.error(edge.id() + " invalid because one vertex was null: out=" + edge.outVertex() + " in=" + edge.inVertex()); + } else { + + if (edge.property("contains-other-v").isPresent()) { + parentCousinIndicator = edge.property("contains-other-v").value().toString(); + } else if (edge.property("isParent").isPresent()) { + if ((Boolean)edge.property("isParent").value()) { + parentCousinIndicator = "OUT"; + } else if (edge.property("isParent-REV").isPresent() && (Boolean)edge.property("isParent-REV").value()) { + parentCousinIndicator = "IN"; + } + } else { + edgeMissingParentProperty.add(this.toStringForPrinting(edge, 1)); + } + + sb.append(outURI + "|" + label + "|" + inURI + "|" + parentCousinIndicator + "\n"); + } + } + } catch(Exception ex){ + logger.error("exception occurred during migration, failing: out=" + out + " in=" + in + "edge=" + oldEdgeString, ex); + success = false; + } + sb.append("--------EDGES END--------\n"); + + logger.info(sb.toString()); + edgeMissingParentProperty.forEach(s -> logger.warn("Edge Missing Parent Property: " + s)); + logger.info("Edge Missing Parent Property Count: " + edgeMissingParentProperty.size()); + logger.info("Vertex Missing URI Property Count: " + noURI.size()); + + } + + private String getVertexURI(Vertex v) { + if (v.property("aai-uri").isPresent()) { + return v.property("aai-uri").value().toString(); + } else { + return v.id().toString() + "(" + v.property("aai-node-type").value().toString() + ")"; + } + } + + @Override + public Optional<String[]> getAffectedNodeTypes() { + return Optional.empty(); + } + + @Override + public String getMigrationName() { + return "edge-report-for-tosca-migration"; + } + + @Override + public void commit() { + engine.rollback(); + } + +} diff --git a/aai-resources/src/main/java/org/onap/aai/migration/v12/MigrateDataFromASDCToConfiguration.java b/aai-resources/src/main/java/org/onap/aai/migration/v12/MigrateDataFromASDCToConfiguration.java new file mode 100644 index 0000000..5185db3 --- /dev/null +++ b/aai-resources/src/main/java/org/onap/aai/migration/v12/MigrateDataFromASDCToConfiguration.java @@ -0,0 +1,107 @@ +package org.onap.aai.migration.v12; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.migration.*; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.util.AAIConstants; + +import java.io.*; +import java.util.Optional; + +@MigrationPriority(20) +@MigrationDangerRating(2) +@Enabled +public class MigrateDataFromASDCToConfiguration extends Migrator { + private final String PARENT_NODE_TYPE = "generic-vnf"; + private boolean success = true; + private String entitlementPoolUuid = ""; + private String VNT = ""; + + + public MigrateDataFromASDCToConfiguration(TransactionalGraphEngine engine) { + super(engine); + } + + + @Override + public void run() { + String csvFile = AAIConstants.AAI_HOME_ETC + "VNT-migration-data" + AAIConstants.AAI_FILESEP + "VNT-migration-input.csv"; + logger.info("Reading Csv file: " + csvFile); + BufferedReader br = null; + String line = ""; + String cvsSplitBy = "\t"; + try { + + br = new BufferedReader(new FileReader(new File(csvFile))); + while ((line = br.readLine()) != null) { + line = line.replaceAll("\"", ""); + String[] temp = line.split(cvsSplitBy); + if ("entitlement-pool-uuid".equals(temp[0]) || "vendor-allowed-max-bandwidth (VNT)".equals(temp[1])) { + continue; + } + entitlementPoolUuid = temp[0]; + VNT = temp[1]; + GraphTraversal<Vertex, Vertex> f = this.engine.asAdmin().getTraversalSource().V().has(AAIProperties.NODE_TYPE, "entitlement").has("group-uuid", entitlementPoolUuid) + .out("org.onap.relationships.inventory.BelongsTo").has(AAIProperties.NODE_TYPE, "generic-vnf") + .has("vnf-type", "vHNF").in("org.onap.relationships.inventory.ComposedOf").has(AAIProperties.NODE_TYPE, "service-instance").out("org.onap.relationships.inventory.Uses").has(AAIProperties.NODE_TYPE, "configuration"); + + modify(f); + } + + } catch (FileNotFoundException e) { + success = false; + logger.error("Found Exception" , e); + } catch (IOException e) { + success = false; + logger.error("Found Exception" , e); + } catch (Exception a) { + success= false; + logger.error("Found Exception" , a); + } finally { + try { + br.close(); + } catch (IOException e) { + success = false; + logger.error("Found Exception" , e); + } + } + + } + + public void modify(GraphTraversal<Vertex, Vertex> g) { + int count = 0; + while (g.hasNext()) { + Vertex v = g.next(); + logger.info("Found node type " + v.property("aai-node-type").value().toString() + " with configuration id: " + v.property("configuration-id").value().toString()); + v.property("vendor-allowed-max-bandwidth", VNT); + logger.info("VNT val after migration: " + v.property("vendor-allowed-max-bandwidth").value().toString()); + count++; + } + + logger.info("modified " + count + " configuration nodes related to Entitlement UUID: " +entitlementPoolUuid); + + } + + @Override + public Status getStatus() { + if (success) { + return Status.SUCCESS; + } else { + return Status.FAILURE; + } + } + + @Override + public Optional<String[]> getAffectedNodeTypes() { + return Optional.of(new String[]{PARENT_NODE_TYPE}); + } + + @Override + public String getMigrationName() { + return "MigrateDataFromASDCToConfiguration"; + } + + +} diff --git a/aai-resources/src/main/java/org/onap/aai/migration/v12/MigrateServiceInstanceToConfiguration.java b/aai-resources/src/main/java/org/onap/aai/migration/v12/MigrateServiceInstanceToConfiguration.java new file mode 100644 index 0000000..f36fb2d --- /dev/null +++ b/aai-resources/src/main/java/org/onap/aai/migration/v12/MigrateServiceInstanceToConfiguration.java @@ -0,0 +1,171 @@ +package org.onap.aai.migration.v12; + +import java.io.UnsupportedEncodingException; +import java.util.Iterator; +import java.util.Optional; +import java.util.UUID; + +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; +import org.onap.aai.migration.Enabled; +import org.onap.aai.migration.MigrationDangerRating; +import org.onap.aai.migration.MigrationPriority; +import org.onap.aai.migration.Migrator; +import org.onap.aai.migration.Status; +import org.onap.aai.serialization.db.EdgeType; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; + +@Enabled +@MigrationPriority(10) +@MigrationDangerRating(10) +public class MigrateServiceInstanceToConfiguration extends Migrator { + + private boolean success = true; + private final String CONFIGURATION_NODE_TYPE = "configuration"; + private final String SERVICE_INSTANCE_NODE_TYPE = "service-instance"; + private Introspector configObj; + + public MigrateServiceInstanceToConfiguration(TransactionalGraphEngine engine) { + super(engine); + try { + this.configObj = this.loader.introspectorFromName(CONFIGURATION_NODE_TYPE); + } catch (AAIUnknownObjectException e) { + this.configObj = null; + } + } + + @Override + public void run() { + Vertex serviceInstance = null; + Vertex configuration = null; + String serviceInstanceId = "", tunnelBandwidth = ""; + String bandwidthTotal, configType, nodeType; + GraphTraversal<Vertex, Vertex> serviceInstanceItr; + Iterator<Vertex> configurationItr; + + try { + serviceInstanceItr = this.engine.asAdmin().getTraversalSource().V() + .has(AAIProperties.NODE_TYPE, P.within(getAffectedNodeTypes().get())) + .where(this.engine.getQueryBuilder() + .createEdgeTraversal(EdgeType.TREE, "service-instance", "service-subscription") + .getVerticesByProperty("service-type", "DHV") + .<GraphTraversal<?, ?>>getQuery()); + + if (serviceInstanceItr == null || !serviceInstanceItr.hasNext()) { + logger.info("No servince-instance nodes found with service-type of DHV"); + return; + } + + // iterate through all service instances of service-type DHV + while (serviceInstanceItr.hasNext()) { + serviceInstance = serviceInstanceItr.next(); + + if (serviceInstance != null && serviceInstance.property("bandwidth-total").isPresent()) { + serviceInstanceId = serviceInstance.value("service-instance-id"); + logger.info("Processing service instance with id=" + serviceInstanceId); + bandwidthTotal = serviceInstance.value("bandwidth-total"); + + if (bandwidthTotal != null && !bandwidthTotal.isEmpty()) { + + // check for existing edges to configuration nodes + configurationItr = serviceInstance.vertices(Direction.OUT, "has"); + + // create new configuration node if service-instance does not have existing ones + if (!configurationItr.hasNext()) { + logger.info(serviceInstanceId + " has no existing configuration nodes, creating new node"); + createConfigurationNode(serviceInstance, bandwidthTotal); + continue; + } + + // in case if configuration nodes exist, but none are DHV + boolean hasDHVConfig = false; + + // service-instance has existing configuration nodes + while (configurationItr.hasNext()) { + configuration = configurationItr.next(); + nodeType = configuration.value("aai-node-type").toString(); + + if (configuration != null && "configuration".equalsIgnoreCase(nodeType)) { + logger.info("Processing configuration node with id=" + configuration.property("configuration-id").value()); + configType = configuration.value("configuration-type"); + logger.info("Configuration type: " + configType); + + // if configuration-type is DHV, update tunnel-bandwidth to bandwidth-total value + if ("DHV".equalsIgnoreCase(configType)) { + if (configuration.property("tunnel-bandwidth").isPresent()) { + tunnelBandwidth = configuration.value("tunnel-bandwidth"); + } else { + tunnelBandwidth = ""; + } + + logger.info("Existing tunnel-bandwidth: " + tunnelBandwidth); + configuration.property("tunnel-bandwidth", bandwidthTotal); + touchVertexProperties(configuration, false); + logger.info("Updated tunnel-bandwidth: " + configuration.value("tunnel-bandwidth")); + hasDHVConfig = true; + } + } + } + + // create new configuration node if none of existing config nodes are of type DHV + if (!hasDHVConfig) { + logger.info(serviceInstanceId + " has existing configuration nodes, but none are DHV, create new node"); + createConfigurationNode(serviceInstance, bandwidthTotal); + } + } + } + } + } catch (AAIException | UnsupportedEncodingException e) { + logger.error("Caught exception while processing service instance with id=" + serviceInstanceId + " | " + e.toString()); + success = false; + } + } + + private void createConfigurationNode(Vertex serviceInstance, String bandwidthTotal) throws UnsupportedEncodingException, AAIException { + // create new vertex + Vertex configurationNode = serializer.createNewVertex(configObj); + + // configuration-id: UUID format + String configurationUUID = UUID.randomUUID().toString(); + configObj.setValue("configuration-id", configurationUUID); + + // configuration-type: DHV + configObj.setValue("configuration-type", "DHV"); + + // migrate the bandwidth-total property from the service-instance to the + // tunnel-bandwidth property of the related configuration object + configObj.setValue("tunnel-bandwidth", bandwidthTotal); + + // create edge between service instance and configuration: cousinEdge(out, in) + createCousinEdge(serviceInstance, configurationNode); + + // serialize edge & vertex, takes care of everything + serializer.serializeSingleVertex(configurationNode, configObj, "migrations"); + logger.info("Created configuration node with uuid=" + configurationUUID + ", tunnel-bandwidth=" + bandwidthTotal); + } + + @Override + public Status getStatus() { + if (success) { + return Status.SUCCESS; + } else { + return Status.FAILURE; + } + } + + @Override + public Optional<String[]> getAffectedNodeTypes() { + return Optional.of(new String[] {SERVICE_INSTANCE_NODE_TYPE}); + } + + @Override + public String getMigrationName() { + return "service-instance-to-configuration"; + } +} diff --git a/aai-resources/src/main/java/org/onap/aai/migration/v12/ToscaMigration.java b/aai-resources/src/main/java/org/onap/aai/migration/v12/ToscaMigration.java new file mode 100644 index 0000000..274f1b6 --- /dev/null +++ b/aai-resources/src/main/java/org/onap/aai/migration/v12/ToscaMigration.java @@ -0,0 +1,160 @@ +package org.onap.aai.migration.v12; +/*- + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + + +import java.util.*; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.migration.Enabled; +import org.onap.aai.migration.MigrationDangerRating; +import org.onap.aai.migration.MigrationPriority; +import org.onap.aai.migration.Migrator; +import org.onap.aai.migration.Status; +import org.onap.aai.serialization.db.*; +import org.onap.aai.serialization.db.exceptions.EdgeMultiplicityException; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; + +@Enabled + +@MigrationPriority(0) +@MigrationDangerRating(1000) +public class ToscaMigration extends Migrator { + + private boolean success = true; + EdgeRules ers = EdgeRules.getInstance(); + + public ToscaMigration(TransactionalGraphEngine graphEngine){ + super(graphEngine); + } + + @Override + public Status getStatus() { + if (success) { + return Status.SUCCESS; + } else { + return Status.FAILURE; + } + } + + @Override + public void run() { + Vertex out = null; + Vertex in = null; + boolean isCousin = false; + String oldEdgeString = null; + Map<String,Integer> edgeMultiplicityExceptionCtr = new HashMap<>(); + List<String> edgeMissingParentProperty = new ArrayList<>(); + + GraphTraversalSource g = engine.asAdmin().getTraversalSource(); + + try { + Set<Edge> edges = g.E().toSet(); + for (Edge edge : edges) { + // skip if this edge was migrated in a previous run + if (edge.label().contains("org.") || edge.label().contains("tosca.")) { + continue; + } + out = edge.outVertex(); + in = edge.inVertex(); + isCousin = false; + + if (out == null || in == null) { + logger.error(edge.id() + " invalid because one vertex was null: out=" + edge.outVertex() + " in=" + edge.inVertex()); + } else { + + if (edge.property("contains-other-v").isPresent()) { + isCousin = "NONE".equals(edge.property("contains-other-v").value()); + } else if (edge.property("isParent").isPresent()) { + isCousin = !(Boolean)edge.property("isParent").value(); + } else { + edgeMissingParentProperty.add(this.toStringForPrinting(edge, 1)); + } + + String inVertexNodeType = in.value(AAIProperties.NODE_TYPE); + String outVertexNodeType = out.value(AAIProperties.NODE_TYPE); + String label = null; + + + Set<String> edgeLabels = ers.getEdgeRules(outVertexNodeType,inVertexNodeType).keySet(); + + if (edgeLabels.isEmpty()) { + logger.error(edge.id() + " did not migrate as no edge rule found for: out=" + outVertexNodeType + " in=" + inVertexNodeType); + continue; + } else if (edgeLabels.size() > 1) { + if (edgeLabels.contains("org.onap.relationships.inventory.Source")) { + if ("sourceLInterface".equals(edge.label())) { + label = "org.onap.relationships.inventory.Source"; + } else if ("targetLInterface".equals(edge.label())) { + label = "org.onap.relationships.inventory.Destination"; + } else { + label = "tosca.relationships.network.LinksTo"; + } + } + } + + try { + if (isCousin) { + ers.addEdgeIfPossible(g, in, out, label); + } else { + ers.addTreeEdge(g, out, in); + } + edge.remove(); + } catch (EdgeMultiplicityException edgeMultiplicityException) { + logger.warn("Edge Multiplicity Exception: " + + "\nInV:\n" + this.toStringForPrinting(in, 1) + + "Edge:\n" + this.toStringForPrinting(edge, 1) + + "OutV:\n" + this.toStringForPrinting(out, 1) + ); + + final String mapKey = "OUT:" + outVertexNodeType + " " + (isCousin ? EdgeType.COUSIN.toString():EdgeType.TREE.toString()) + " " + "IN:" + inVertexNodeType; + if (edgeMultiplicityExceptionCtr.containsKey(mapKey)) { + edgeMultiplicityExceptionCtr.put(mapKey, edgeMultiplicityExceptionCtr.get(mapKey)+1); + } else { + edgeMultiplicityExceptionCtr.put(mapKey, 1); + } + } + } + } + } catch(Exception ex){ + logger.error("exception occurred during migration, failing: out=" + out + " in=" + in + "edge=" + oldEdgeString, ex); + success = false; + } + + logger.info("Edge Missing Parent Property Count: " + edgeMissingParentProperty.size()); + logger.info("Edge Multiplicity Exception Count : " + edgeMultiplicityExceptionCtr.values().stream().mapToInt(Number::intValue).sum()); + logger.info("Edge Multiplicity Exception Breakdown : " + edgeMultiplicityExceptionCtr); + + } + + @Override + public Optional<String[]> getAffectedNodeTypes() { + return Optional.empty(); + } + + @Override + public String getMigrationName() { + return "migrate-all-edges"; + } + +} |