Skip to content
This repository was archived by the owner on Jul 22, 2020. It is now read-only.

Commit 4d73c53

Browse files
committed
Added changes from upstream PR #17
1 parent 9c722a2 commit 4d73c53

File tree

7 files changed

+243
-35
lines changed

7 files changed

+243
-35
lines changed

src/main/java/com/builtamont/cassandra/migration/CassandraMigration.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.builtamont.cassandra.migration.api.configuration.CassandraMigrationCo
2525
import com.builtamont.cassandra.migration.api.configuration.MigrationConfigs
2626
import com.builtamont.cassandra.migration.api.resolver.MigrationResolver
2727
import com.builtamont.cassandra.migration.config.Keyspace
28+
import com.builtamont.cassandra.migration.internal.command.Baseline
2829
import com.builtamont.cassandra.migration.internal.command.Initialize
2930
import com.builtamont.cassandra.migration.internal.command.Migrate
3031
import com.builtamont.cassandra.migration.internal.command.Validate
@@ -61,6 +62,16 @@ class CassandraMigration : CassandraMigrationConfiguration {
6162
*/
6263
lateinit var configs: MigrationConfigs
6364

65+
/**
66+
* The baseline version.
67+
*/
68+
private val baselineVersion = MigrationVersion.Companion.fromVersion("1")
69+
70+
/**
71+
* The baseline description.
72+
*/
73+
private val baselineDescription = "<< Cassandra Baseline >>"
74+
6475
/**
6576
* CassandraMigration initialization.
6677
*/
@@ -143,8 +154,14 @@ class CassandraMigration : CassandraMigrationConfiguration {
143154
* Baselines an existing database, excluding all migrations up to and including baselineVersion.
144155
*/
145156
fun baseline() {
146-
// TODO: Create the Cassandra migration implementation, refer to existing PR: https://github.com/Contrast-Security-OSS/cassandra-migration/pull/17
147-
throw NotImplementedException()
157+
execute(object : Action<Unit> {
158+
override fun execute(session: Session): Unit {
159+
val migrationResolver = createMigrationResolver()
160+
val schemaVersionDao = SchemaVersionDAO(session, keyspace, MigrationVersion.CURRENT.table)
161+
val baseline = Baseline(migrationResolver, baselineVersion, schemaVersionDao, baselineDescription)
162+
baseline.run()
163+
}
164+
})
148165
}
149166

150167
/**

src/main/java/com/builtamont/cassandra/migration/CommandLine.kt

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import com.builtamont.cassandra.migration.internal.util.logging.Log
2323
import com.builtamont.cassandra.migration.internal.util.logging.LogFactory
2424
import com.builtamont.cassandra.migration.internal.util.logging.console.ConsoleLog
2525
import com.builtamont.cassandra.migration.internal.util.logging.console.ConsoleLogCreator
26-
import java.util.*
2726

2827
/**
2928
* Cassandra migration command line runner.
@@ -40,6 +39,11 @@ object CommandLine {
4039
*/
4140
val VALIDATE = "validate"
4241

42+
/**
43+
* Command to trigger baseline action.
44+
*/
45+
val BASELINE = "baseline"
46+
4347
/**
4448
* Logging support.
4549
*/
@@ -69,22 +73,16 @@ object CommandLine {
6973
cm.migrate()
7074
} else if (VALIDATE.equals(operation, ignoreCase = true)) {
7175
cm.validate()
76+
} else if (BASELINE.equals(operation, ignoreCase = true)) {
77+
cm.baseline()
7278
}
7379
}
7480

7581
/**
7682
* Get a list of applicable operations.
7783
*/
7884
private fun determineOperations(args: Array<String>): List<String> {
79-
val operations = ArrayList<String>()
80-
81-
for (arg in args) {
82-
if (!arg.startsWith("-")) {
83-
operations.add(arg)
84-
}
85-
}
86-
87-
return operations
85+
return args.filterNot { it.startsWith("-") }
8886
}
8987

9088
/**
@@ -124,6 +122,7 @@ object CommandLine {
124122
LOG.info("========")
125123
LOG.info("migrate : Migrates the database")
126124
LOG.info("validate : Validates the applied migrations against the available ones")
125+
LOG.info("baseline : Baselines an existing database, excluding all migrations up to, and including baselineVersion")
127126
LOG.info("")
128127
LOG.info("Add -X to print debug output")
129128
LOG.info("Add -q to suppress all output, except for errors and warnings")
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* File : Baseline.kt
3+
* License :
4+
* Original - Copyright (c) 2015 - 2016 Contrast Security
5+
* Derivative - Copyright (c) 2016 Citadel Technology Solutions Pte Ltd
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
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
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+
*/
19+
package com.builtamont.cassandra.migration.internal.command
20+
21+
import com.builtamont.cassandra.migration.api.CassandraMigrationException
22+
import com.builtamont.cassandra.migration.api.MigrationVersion
23+
import com.builtamont.cassandra.migration.api.resolver.MigrationResolver
24+
import com.builtamont.cassandra.migration.internal.dbsupport.SchemaVersionDAO
25+
26+
/**
27+
* Handles the baseline command.
28+
*/
29+
class Baseline(
30+
private val migrationResolver: MigrationResolver,
31+
private val baselineVersion: MigrationVersion,
32+
private val schemaVersionDao: SchemaVersionDAO,
33+
private val baselineDescription: String
34+
) {
35+
36+
/**
37+
* Runs the migration baselining.
38+
*
39+
* @return The number of successfully applied migration baselining.
40+
* @throws CassandraMigrationException when migration baselining failed for any reason.
41+
*/
42+
@Throws(CassandraMigrationException::class)
43+
fun run() {
44+
val baselineMigration = schemaVersionDao.baselineMarker
45+
if (schemaVersionDao.hasAppliedMigrations()) {
46+
throw CassandraMigrationException("Unable to baseline metadata table " + schemaVersionDao.tableName + " as it already contains migrations");
47+
}
48+
49+
if (schemaVersionDao.hasBaselineMarker()) {
50+
if (!baselineMigration.version!!.equals(baselineVersion) || !baselineMigration.description.equals(baselineDescription)) {
51+
throw CassandraMigrationException("Unable to baseline metadata table " + schemaVersionDao.tableName + " with (" + baselineVersion +
52+
"," + baselineDescription + ") as it has already been initialized with (" + baselineMigration.version + "," + baselineMigration
53+
.description + ")")
54+
}
55+
} else {
56+
if (baselineVersion.equals(MigrationVersion.fromVersion("0"))) {
57+
throw CassandraMigrationException("Unable to baseline metadata table " + schemaVersionDao.tableName + " with version 0 as this " +
58+
"version was used for schema creation")
59+
}
60+
schemaVersionDao.addBaselineMarker(baselineVersion, baselineDescription)
61+
}
62+
}
63+
64+
}

src/main/java/com/builtamont/cassandra/migration/internal/dbsupport/SchemaVersionDAO.java

Lines changed: 113 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,7 @@
3030
import com.datastax.driver.core.querybuilder.QueryBuilder;
3131
import com.datastax.driver.core.querybuilder.Select;
3232

33-
import java.util.ArrayList;
34-
import java.util.Collections;
35-
import java.util.HashMap;
36-
import java.util.List;
33+
import java.util.*;
3734

3835
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
3936

@@ -59,6 +56,10 @@ public SchemaVersionDAO(Session session, Keyspace keyspace, String tableName) {
5956
session.getCluster().getMetadata().getAllHosts().size() > 1 ? ConsistencyLevel.ALL : ConsistencyLevel.ONE;
6057
}
6158

59+
public String getTableName() {
60+
return tableName;
61+
}
62+
6263
public Keyspace getKeyspace() {
6364
return this.keyspace;
6465
}
@@ -213,6 +214,102 @@ public List<AppliedMigration> findAppliedMigrations() {
213214
return resultsList;
214215
}
215216

217+
/**
218+
* Retrieve the applied migrations from the metadata table.
219+
*
220+
* @param migrationTypes The migration types to find.
221+
* @return The applied migrations.
222+
*/
223+
public List<AppliedMigration> findAppliedMigrations(MigrationType... migrationTypes) {
224+
if (!tablesExist()) {
225+
return new ArrayList<>();
226+
}
227+
228+
Select select = QueryBuilder
229+
.select()
230+
.column("version_rank")
231+
.column("installed_rank")
232+
.column("version")
233+
.column("description")
234+
.column("type")
235+
.column("script")
236+
.column("checksum")
237+
.column("installed_on")
238+
.column("installed_by")
239+
.column("execution_time")
240+
.column("success")
241+
.from(keyspace.getName(), tableName);
242+
243+
select.setConsistencyLevel(ConsistencyLevel.ALL);
244+
ResultSet results = session.execute(select);
245+
List<AppliedMigration> resultsList = new ArrayList<>();
246+
List<MigrationType> migTypeList = Arrays.asList(migrationTypes);
247+
for (Row row : results) {
248+
MigrationType migType = MigrationType.valueOf(row.getString("type"));
249+
if(migTypeList.contains(migType)){
250+
resultsList.add(new AppliedMigration(
251+
row.getInt("version_rank"),
252+
row.getInt("installed_rank"),
253+
MigrationVersion.Companion.fromVersion(row.getString("version")),
254+
row.getString("description"),
255+
migType,
256+
row.getString("script"),
257+
row.getInt("checksum"),
258+
row.getTimestamp("installed_on"),
259+
row.getString("installed_by"),
260+
row.getInt("execution_time"),
261+
row.getBool("success")
262+
));
263+
}
264+
}
265+
266+
//order by version_rank not necessary here as it eventually gets saved in TreeMap that uses natural ordering
267+
268+
return resultsList;
269+
}
270+
271+
public boolean hasAppliedMigrations() {
272+
if (!tablesExist()) {
273+
return false;
274+
}
275+
276+
createTablesIfNotExist();
277+
List<AppliedMigration> filteredMigrations = new ArrayList<>();
278+
List<AppliedMigration> appliedMigrations = findAppliedMigrations();
279+
for (AppliedMigration appliedMigration : appliedMigrations) {
280+
if (!appliedMigration.getType().equals(MigrationType.BASELINE)) {
281+
filteredMigrations.add(appliedMigration);
282+
}
283+
}
284+
return !filteredMigrations.isEmpty();
285+
}
286+
287+
public void addBaselineMarker(final MigrationVersion baselineVersion, final String baselineDescription) {
288+
addAppliedMigration(new AppliedMigration(
289+
baselineVersion,
290+
baselineDescription,
291+
MigrationType.BASELINE,
292+
baselineDescription,
293+
0,
294+
null,
295+
0,
296+
true
297+
));
298+
}
299+
300+
public AppliedMigration getBaselineMarker() {
301+
List<AppliedMigration> appliedMigrations = findAppliedMigrations(MigrationType.BASELINE);
302+
return appliedMigrations.isEmpty() ? null : appliedMigrations.get(0);
303+
}
304+
305+
public boolean hasBaselineMarker() {
306+
if (!tablesExist()) {
307+
return false;
308+
}
309+
createTablesIfNotExist();
310+
return !findAppliedMigrations(MigrationType.BASELINE).isEmpty();
311+
}
312+
216313
/**
217314
* Calculates the installed rank for the new migration to be inserted.
218315
*
@@ -233,18 +330,6 @@ private int calculateInstalledRank() {
233330
return (int) result.one().getLong("count");
234331
}
235332

236-
class MigrationMetaHolder {
237-
private int versionRank;
238-
239-
public MigrationMetaHolder(int versionRank) {
240-
this.versionRank = versionRank;
241-
}
242-
243-
public int getVersionRank() {
244-
return versionRank;
245-
}
246-
}
247-
248333
/**
249334
* Calculate the rank for this new version about to be inserted.
250335
*
@@ -294,4 +379,16 @@ private int calculateVersionRank(MigrationVersion version) {
294379
return migrationVersions.size() + 1;
295380
}
296381

382+
class MigrationMetaHolder {
383+
private int versionRank;
384+
385+
public MigrationMetaHolder(int versionRank) {
386+
this.versionRank = versionRank;
387+
}
388+
389+
public int getVersionRank() {
390+
return versionRank;
391+
}
392+
}
393+
297394
}

src/main/java/com/builtamont/cassandra/migration/internal/resolver/java/JavaMigrationResolver.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,11 @@ class JavaMigrationResolver(
8686
*/
8787
@Throws(CassandraMigrationException::class)
8888
fun extractMigrationInfo(javaMigration: JavaMigration): ResolvedMigration {
89-
var checksum: Int? = null
89+
val checksum: Int?
9090
if (javaMigration is MigrationChecksumProvider) {
9191
checksum = javaMigration.checksum
92+
} else {
93+
checksum = 0
9294
}
9395

9496
val version: MigrationVersion

0 commit comments

Comments
 (0)