Skip to content

Commit 9df5945

Browse files
committed
[#48] Add migration feature to migrate output products forward from MMTC 1.5.1 onward
MMTC output products changed significantly since 1.5.1. Specifically, the Run History File and Time History File both had changes that would take some time and verification for our users to do manually. Therefore, as part of MMTC 1.6.0 maintenance, we're added a simple migration capability to check the version of the built-in output products and migrat them. Output plugins are not yet included in this functionality. For MMTC commands that are sensitive to the structure of the built-in output products, the output product versions are now checked before proceeding. If they are found not to be up to date, MMTC will halt and ask users to manually run the 'migrate' command. When users run `mmtc migrate`, MMTC will copy all existing output files into a zip archive, and then perform the mgration. After migration is complete, MMTC will exit, at which time the user (or automation) can run MMTC as normal. Closes #48.
1 parent 27d649a commit 9df5945

15 files changed

+581
-15
lines changed

docs/MMTC_Users_Guide.adoc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -421,13 +421,15 @@ Note that the MMTC RPM currently does not have special handling for configuratio
421421

422422
If a user named “mmtc” does not already exist, the RPM installation will also create the mmtc user and group. All files installed by the RPM are world-readable; however, only the mmtc user and members of the mmtc group can modify configuration files and add or create files (such as new log files or additional telemetry source plugins) in the conf, log, and lib/plugins directories.
423423

424-
After installing the RPM, do the following steps as needed:
424+
After installing the RPM, perform the following steps as needed:
425425

426426
* Add users to the mmtc group.
427427
* To use a telemetry source other than AMPCS, add an appropriate telemetry source plugin to the lib/plugins folder.
428428
* Update the configuration files, in particular TimeCorrelationConfigProperties.xml, in the conf folder to suit the mission.
429429
* Place a seed SCLK kernel file in the output folder.
430430

431+
After upgrading an MMTC installation, run `bin/mmtc migrate` in order to migrate output product structures forward to their new versions, where applicable. A backup archive in ZIP format will be created, should the prior state of the files be needed.
432+
431433
MMTC can then be invoked from the command line. Change the working directory to the MMTC installation directory (`/opt/local/mmtc` by default), and then run:
432434

433435
[source, bash]
@@ -1444,6 +1446,10 @@ Defaults to 9 digits if key isn't included in config or if the value provided ca
14441446
|STR
14451447
|A comma-separated list of names that uniquely identify plugin-provided (custom) output product types. If this parameter is populated, additional per-custom-product parameters are also required. Please reference <<_configuring_custom_output_products>> for details.
14461448

1449+
|product.archive.directory
1450+
|OPTIONAL
1451+
|STR
1452+
|The path to a directory where zip archives of output products will be made before MMTC executes product migration or rollback commands. If left blank, defaults to a new directory named 'output-archives', created within the same directory as the Run History File location.
14471453

14481454
|===
14491455

@@ -1968,7 +1974,7 @@ Please note that a single plugin jar may include more than one _OutputProductDef
19681974

19691975
== Output Product Rollback
19701976
MMTC 1.5.0 and later provides a simple system for users to revert all of MMTC's output products back to an earlier state. Rollback makes use of the Run History File to determine which output products and
1971-
records should and shouldn't be present after rolling back to the state MMTC's products were in after a prior run. Rollback is irreversible and should only be used when backup copies have been made of all relevant files.
1977+
records should and shouldn't be present after rolling back to the state MMTC's products were in after a prior run. Rollback may be complicated to reverse; please use caution. A backup archive in ZIP format will be created before output products are adjusted, which can be used to help restore the pre-rollback state if necessary.
19721978

19731979
=== Executing Rollback
19741980
MMTC enters the rollback interface any time "rollback" is provided as the very first argument when invoking MMTC regardless of subsequent flags or arguments, i.e. `bin/mmtc rollback`. Users will immediately be provided with
@@ -1980,12 +1986,12 @@ output files that will be deleted (SCLK kernels, SCLKSCET files, and/or Uplink C
19801986
After listing the effects of rollback, MMTC will ask users for Y/N confirmation to proceed. This marks the "point of no return" after which files will potentially be permanently deleted, so users are again reminded to make backups
19811987
of *all* output products before initiating a rollback.
19821988

1983-
After positive confirmation is received (only a "y" or "Y" is considered confirmation), MMTC will delete or truncate any output files necessary to return its products to the state they had after the specified prior run.
1989+
After positive confirmation is received (only a "y" or "Y" is considered confirmation), MMTC will create a backup archive, and will then delete or truncate any output files necessary to return its products to the state they had after the specified prior run.
19841990
MMTC will print out the names of all files modified (or potentially files that failed to be modified) and MMTC will exit with status code 0 if rollback was successful.
19851991

19861992
Prior runs that were rolled back are not deleted from the Run History File but are flagged as previously involved in rollback and will be ignored by any future rollbacks.
19871993

1988-
Insufficient system permissions to remove relevant files are the most likely source of rollback failures, so it is recommended that users verify that they have the requisite permissions to modify MMTC output products prior to initiating rollback.
1994+
Insufficient system permissions to remove relevant files can be a source of rollback failures, so it is recommended that users verify that they have the requisite permissions to modify MMTC output products prior to initiating rollback.
19891995

19901996
== Telemetry Caching
19911997

mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/app/BuildInfo.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ public BuildInfo() {
2828
commit = buildProperties.getProperty(COMMIT_KEY, UNKNOWN_VALUE);
2929
}
3030

31+
public String getNumericalVersion() {
32+
return version.replace("-SNAPSHOT", "");
33+
}
34+
3135
public String toString() {
3236
return String.format("Version: %s\nBuild date: %s\nCommit: %s", version, buildDate, commit);
3337
}

mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/app/MmtcCli.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package edu.jhuapl.sd.sig.mmtc.app;
22

3+
import edu.jhuapl.sd.sig.mmtc.products.util.BuiltInOutputProductMigrationManager;
34
import edu.jhuapl.sd.sig.mmtc.rollback.TimeCorrelationRollback;
45
import edu.jhuapl.sd.sig.mmtc.sandbox.MmtcSandboxCreator;
56
import edu.jhuapl.sd.sig.mmtc.tlm.persistence.cache.TelemetryCacheUserOperations;
@@ -24,8 +25,9 @@ public enum ApplicationCommand {
2425
CORRELATION,
2526
ROLLBACK,
2627
CREATE_SANDBOX,
28+
MIGRATE,
2729
PRECACHE,
28-
CACHE_STATS,
30+
CACHE_STATS
2931
}
3032

3133
private static class ApplicationInvocation {
@@ -46,7 +48,7 @@ private static ApplicationInvocation determineApplicationCommand(String... cliAr
4648

4749
if (Arrays.asList("-h", "--help").contains(cliArgs[0])) {
4850
final String helpMessage =
49-
"usage: mmtc [correlation|rollback|create-sandbox|precache|cache-stats] [options] <additional arguments>\n" +
51+
"usage: mmtc [correlation|rollback|create-sandbox|migrate|precache|cache-stats] [options] <additional arguments>\n" +
5052
" -h,--help Print this message.\n" +
5153
" -v,--version Print the MMTC version.\n" +
5254
"\n" +
@@ -56,6 +58,7 @@ private static ApplicationInvocation determineApplicationCommand(String... cliAr
5658
"- rollback: roll back (undo) one or many correlations\n" +
5759
"- create-sandbox: create a copy of this MMTC installation to run locally,\n" +
5860
"without affecting this installation\n" +
61+
"- migrate: migrate MMTC's output products from a prior version of MMTC\n" +
5962
"- precache: query the configured telemetry source to proactively retrieve\n" +
6063
"and store time correlation telemetry into a local cache\n" +
6164
"- cache-stats: log statistics about the locally-cached telemetry\n" +
@@ -71,6 +74,8 @@ private static ApplicationInvocation determineApplicationCommand(String... cliAr
7174
return new ApplicationInvocation(ApplicationCommand.CREATE_SANDBOX, removeFirstElement(cliArgs));
7275
} else if (cliArgs[0].equalsIgnoreCase("correlation")) {
7376
return new ApplicationInvocation(ApplicationCommand.CORRELATION, removeFirstElement(cliArgs));
77+
} else if (cliArgs[0].equalsIgnoreCase("migrate")) {
78+
return new ApplicationInvocation(ApplicationCommand.MIGRATE, removeFirstElement(cliArgs));
7479
} else if (cliArgs[0].equalsIgnoreCase("precache")) {
7580
return new ApplicationInvocation(ApplicationCommand.PRECACHE, removeFirstElement(cliArgs));
7681
} else if (cliArgs[0].equalsIgnoreCase("cache-stats")) {
@@ -126,6 +131,15 @@ public static void main(String[] args) {
126131
}
127132
break;
128133
}
134+
case MIGRATE: {
135+
try {
136+
new BuiltInOutputProductMigrationManager(appInvoc.args).migrate();
137+
} catch (Exception e) {
138+
logger.fatal("Output product migration failed.", e);
139+
System.exit(1);
140+
}
141+
break;
142+
}
129143
case PRECACHE: {
130144
try {
131145
TelemetryCacheUserOperations.precache(appInvoc.args);
@@ -145,7 +159,8 @@ public static void main(String[] args) {
145159
break;
146160
}
147161
default: {
148-
throw new RuntimeException("No such command: " + appInvoc.command);
162+
logger.fatal("Unrecognized command: " + appInvoc.command);
163+
System.exit(1);
149164
}
150165
}
151166
}

mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/app/TimeCorrelationApp.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import edu.jhuapl.sd.sig.mmtc.products.definition.SclkKernelProductDefinition;
1616
import edu.jhuapl.sd.sig.mmtc.products.definition.util.ProductWriteResult;
1717
import edu.jhuapl.sd.sig.mmtc.products.model.*;
18+
import edu.jhuapl.sd.sig.mmtc.products.util.BuiltInOutputProductMigrationManager;
1819
import edu.jhuapl.sd.sig.mmtc.tlm.FrameSample;
1920
import edu.jhuapl.sd.sig.mmtc.tlm.TelemetrySource;
2021
import edu.jhuapl.sd.sig.mmtc.tlm.selection.SamplingTelemetrySelectionStrategy;
@@ -72,6 +73,8 @@ public TimeCorrelationApp(String... args) throws Exception {
7273
private void init() throws Exception {
7374
config.validate();
7475

76+
new BuiltInOutputProductMigrationManager(config).assertExistingProductsDoNotRequireMigration();
77+
7578
logger.debug("Loading SPICE library");
7679
TimeConvert.loadSpiceLib();
7780
TimeConvert.loadSpiceKernels(config.getKernelsToLoad());
@@ -207,11 +210,14 @@ private void recordRunHistoryFilePreRunValues() throws MmtcException {
207210
ctx.runId.set(newRunId);
208211

209212
// Run info
210-
newRunHistoryFileRecord.setValue(RunHistoryFile.RUN_TIME, ctx.appRunTime.toString());
211-
newRunHistoryFileRecord.setValue(RunHistoryFile.RUN_ID, String.format("%05d",newRunId));
212-
newRunHistoryFileRecord.setValue(RunHistoryFile.ROLLEDBACK, "false");
213-
newRunHistoryFileRecord.setValue(RunHistoryFile.RUN_USER, System.getProperty("user.name"));
214-
newRunHistoryFileRecord.setValue(RunHistoryFile.CLI_ARGS, String.join(" ", config.getCliArgs()));
213+
final String mmtcVersion = new BuildInfo().getNumericalVersion();
214+
newRunHistoryFileRecord.setValue(RunHistoryFile.RUN_TIME, ctx.appRunTime.toString());
215+
newRunHistoryFileRecord.setValue(RunHistoryFile.RUN_ID, String.format("%05d",newRunId));
216+
newRunHistoryFileRecord.setValue(RunHistoryFile.MMTC_VERSION, mmtcVersion);
217+
newRunHistoryFileRecord.setValue(RunHistoryFile.MMTC_BUILT_IN_OUTPUT_PRODUCT_VERSION, mmtcVersion);
218+
newRunHistoryFileRecord.setValue(RunHistoryFile.ROLLEDBACK, "false");
219+
newRunHistoryFileRecord.setValue(RunHistoryFile.RUN_USER, System.getProperty("user.name"));
220+
newRunHistoryFileRecord.setValue(RunHistoryFile.CLI_ARGS, String.join(" ", config.getCliArgs()));
215221

216222
// Output products
217223
for (OutputProductDefinition<?> prodDef : config.getAllOutputProductDefs()) {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package edu.jhuapl.sd.sig.mmtc.cfg;
2+
3+
import edu.jhuapl.sd.sig.mmtc.app.MmtcException;
4+
import org.apache.commons.cli.*;
5+
6+
public class MigrationConfig extends MmtcConfig {
7+
public MigrationConfig(String... args) throws Exception {
8+
super();
9+
10+
final Options opts = new Options();
11+
opts.addOption("h", "help", false, "Print this message.");
12+
13+
final CommandLineParser parser = new DefaultParser();
14+
final CommandLine cmdLine = parser.parse(opts, args);
15+
16+
if (cmdLine.hasOption("h") || cmdLine.hasOption("help")) {
17+
final HelpFormatter help = new HelpFormatter();
18+
final String helpFooter = "\nInvoke the MMTC migration feature on the console. Takes no CLI arguments.";
19+
help.printHelp("mmtc migrate", "", opts, helpFooter);
20+
System.exit(0);
21+
}
22+
23+
if (cmdLine.getArgList().size() != 0) {
24+
throw new MmtcException("Error parsing command line arguments.");
25+
}
26+
}
27+
}

mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/cfg/MmtcConfig.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,17 @@ public int getOscTempFractionDigits() throws MmtcException {
917917
return numDigits;
918918
}
919919

920+
/**
921+
* Gets the path at which to write zip archives containing backups of MMTC output products.
922+
* @return the path as described above
923+
*/
924+
public Path getProductArchiveLocation() {
925+
if (containsKey("product.archive.directory")) {
926+
return Paths.get(getString("product.archive.directory"));
927+
} else {
928+
return getRunHistoryFilePath().getParent().resolve("output-archives");
929+
}
930+
}
920931

921932
public enum SclkScetFileLeapSecondSclkRate {
922933
ONE,

mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/OutputProductDefinition.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@
55
import edu.jhuapl.sd.sig.mmtc.cfg.RollbackConfig;
66
import edu.jhuapl.sd.sig.mmtc.correlation.TimeCorrelationContext;
77
import edu.jhuapl.sd.sig.mmtc.products.definition.util.ProductWriteResult;
8+
import edu.jhuapl.sd.sig.mmtc.products.definition.util.ResolvedProductDirPrefixSuffix;
89
import edu.jhuapl.sd.sig.mmtc.products.definition.util.ResolvedProductLocation;
10+
import edu.jhuapl.sd.sig.mmtc.products.definition.util.ResolvedProductPath;
911
import edu.jhuapl.sd.sig.mmtc.products.model.TextProductException;
1012
import edu.jhuapl.sd.sig.mmtc.rollback.TimeCorrelationRollback;
1113
import edu.jhuapl.sd.sig.mmtc.util.Settable;
1214
import edu.jhuapl.sd.sig.mmtc.util.TimeConvertException;
1315

1416
import java.io.IOException;
17+
import java.nio.file.Files;
1518
import java.nio.file.Path;
16-
import java.util.Map;
17-
import java.util.Optional;
19+
import java.util.*;
1820

1921
/**
2022
* Defines common fields and methods common across all OutputProductDefinition implementations.
@@ -106,4 +108,26 @@ public final boolean isBuiltIn() {
106108
*/
107109
public abstract Map<String, String> getSandboxConfigUpdates(MmtcConfig originalConfig, Path newProductOutputDir);
108110

111+
/**
112+
* Resolve all filepaths related to this product that currently exist on disk
113+
*
114+
* @param config the loaded MMTC configuration
115+
* @return the resolved product filepaths
116+
* @throws MmtcException if any problem is encountered while determining the resolved product paths
117+
*/
118+
public Set<Path> resolveAllExistingPaths(MmtcConfig config) throws MmtcException, IOException {
119+
T resolvedLocation = resolveLocation(config);
120+
if (resolvedLocation instanceof ResolvedProductPath) {
121+
Path singlePath = ((ResolvedProductPath) resolvedLocation).pathToProduct;
122+
if (Files.exists(singlePath)) {
123+
return new HashSet<>(Arrays.asList(singlePath));
124+
} else {
125+
return Collections.emptySet();
126+
}
127+
} else if (resolvedLocation instanceof ResolvedProductDirPrefixSuffix) {
128+
return new HashSet<>(((ResolvedProductDirPrefixSuffix) resolvedLocation).findAllMatching());
129+
} else {
130+
throw new IllegalStateException("Unrecognized resolved location: " + resolvedLocation);
131+
}
132+
}
109133
}

mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/definition/util/ResolvedProductDirPrefixSuffix.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package edu.jhuapl.sd.sig.mmtc.products.definition.util;
22

3+
import java.io.IOException;
4+
import java.nio.file.Files;
35
import java.nio.file.Path;
6+
import java.util.List;
7+
import java.util.stream.Collectors;
48

59
public class ResolvedProductDirPrefixSuffix implements ResolvedProductLocation {
610
public final Path containingDirectory;
@@ -12,4 +16,11 @@ public ResolvedProductDirPrefixSuffix(Path containingDirectory, String filenameP
1216
this.filenamePrefix = filenamePrefix;
1317
this.filenameSuffix = filenameSuffix;
1418
}
19+
20+
public List<Path> findAllMatching() throws IOException {
21+
return Files.list(containingDirectory)
22+
.filter(p -> p.getFileName().toString().startsWith(filenamePrefix))
23+
.filter(p -> p.getFileName().toString().endsWith(filenameSuffix))
24+
.collect(Collectors.toList());
25+
}
1526
}

mmtc-core/src/main/java/edu/jhuapl/sd/sig/mmtc/products/model/RunHistoryFile.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public class RunHistoryFile extends AbstractTimeCorrelationTable {
2222

2323
public static final String RUN_TIME = "Run Time";
2424
public static final String RUN_ID = "Run ID";
25+
public static final String MMTC_VERSION = "MMTC Version";
26+
public static final String MMTC_BUILT_IN_OUTPUT_PRODUCT_VERSION = "Built-In Output Product Version";
2527
public static final String ROLLEDBACK = "Rolled Back?";
2628
public static final String RUN_USER = "Run User";
2729
public static final String CLI_ARGS = "MMTC Invocation Args Used";
@@ -90,6 +92,8 @@ public RunHistoryFile(Path path, List<OutputProductDefinition<?>> allOutputProdD
9092
final List<String> headers = new ArrayList<>(Arrays.asList(
9193
RUN_TIME,
9294
RUN_ID,
95+
MMTC_VERSION,
96+
MMTC_BUILT_IN_OUTPUT_PRODUCT_VERSION,
9397
ROLLEDBACK,
9498
RUN_USER,
9599
CLI_ARGS,

0 commit comments

Comments
 (0)