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

Commit 4befbab

Browse files
authored
Merge pull request #8 from builtamont-oss/chore/upstream_pr_17
Address upstream PR #17
2 parents 9c722a2 + ad12ddd commit 4befbab

File tree

14 files changed

+373
-63
lines changed

14 files changed

+373
-63
lines changed

.travis.yml

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
language: java
2-
jdk:
3-
- openjdk7
4-
- oraclejdk7
5-
- oraclejdk8
62
env:
73
global:
84
- secure: "q+fkZBCN8ET5RrgaG4RGt1t1aSjsL6LN6BSt/Yvx2H5a2DtGmNA/A/gcAEnKlyv0BgXAcrzAzCCIgXvt2P4om5DcBU/yOTEga+/46r7+iVnmfQGcW81NHQA1rlIYvuBqXGDo9yo1B3eRr8vTj3fzEE3K8jjchHQUlgRdUum3DNKeZwACodV2fpj9ZslyoX4HRpWg3ctqvB0R7/4NwtXnXrOw8hHDF8OrQK3JiCxAoZnA16/Fwc0d8yN4Or10N1XiWbNdLFek+Y3nVTdGRUZjsqp/VhvgIwzmtnuiCeF2iuMCpYy6C9SAFG4Tyn5VLmFzEqXMrbxuMBp8c2GCcFQb0jxEiWKsT0Nufqc1pYlUSl2S12D8yokEo5H9/NcH/2p2b5zqzcWzFe1c5YEn0Ktj8d/01GDYfkuPyoQ0UmjC6h68iozk5mogPT0t7eUf7i0wll72v4kGB2xOK3VY+53LA7DS+f/0HeDi47tXgPkA8bg2dGZTTD+JHXcqyMTt9Ey96a42cauLQ4PGfujc6fPJUw31sxx2IURj1USdxut/a5PEa+LL+xGrKKgOW4GMUwjrYMnLf9e3Y/uR4EoHmYYwsoNtD0g6bEt7C83JZrQd5Sp3mN6gEU0sjp2/iBPqS+tB3z6eRUur8ctnk6EC82WHmRwZHeoKLVOktAPCKumBnWY="
95
- secure: "04af3/9b67O5xd1U8GDhCqRQedHM3RP5HokdsOwAe8vN3EyyyKWXQafBkKsPvmDh5Uu/CYQppOYS4pQxB9ikweTfj34DbyyxpqJmjYE4KFvdQuFd0msyXhLCg6xfvS4KO6zjUQ8/c3rNQap4hx/icQ50/NES4rkUkxIZ/VKQ4jPXcBzPegEC6Le50Vw2tR8FT4erdNuABnGf1WnWGUUa3i6xdQQPyw8kdTIun08HxE6M9F+JJRH8jH3b7KizQhGdACAk4fnCOmFSgu7pm6ACXRJYqAfg055i5mr77yZXfeUIcIY3l45uY1uR8sxEbLUE/KwwlLGLVZWDI4xU6JIGisbrmMce+vz6YKUT9gHF3iAEJ5e4N18nJcRyHVrqcuRzv5Py0rFPZ70dr7aW/tk0JrTz6+FZ4FNIOdvIQe4qWy2TVns0EkERdtYGTdsigWfa/sKF/P5+/2foUOlnR06p55NHpIjaHRKy/XFVV1gyURUlRUGExVoIMX21bAMxGYMFMH7LfddRsly028lXwibRMkQGBeyVRYKQmqJvN3mTPbuAWmZZdaVpqn1jkgETlT6/qz43zv9y8jAOzZ22SeHEXe3NiexChqkAJWIH3cBYshMhy8H1fmYAIVYHvI+BPsbi+qDYSnAlAUDqoLWXPAvWUX89dAIXYRNcKplzpFsjWvM="
6+
matrix:
7+
include:
8+
- jdk: openjdk7
9+
script: mvn test
10+
- jdk: oraclejdk7
11+
script: mvn test
12+
- jdk: oraclejdk8
13+
script:
14+
- mvn test
15+
- mvn verify
1016
deploy:
1117
provider: script
1218
script: ./scripts/deploy.sh

README.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ Import this library as a dependency (Maven example):
2525
</dependency>
2626
```
2727

28+
***NOTE:** Integration test in Travis CI is only run against Oracle JDK 1.8, due to embedded Cassandra's dependencies on JDK 1.8*
29+
2830
### Migration version table
2931

3032
``` shell
@@ -140,7 +142,6 @@ Keyspace:
140142
141143
### Limitations
142144
143-
* Baselining not supported yet
144145
* The tool does not roll back the database upon migration failure. You're expected to manually restore backup.
145146
146147
## Project Rationale
@@ -161,6 +162,14 @@ There are various reasons why Kotlin was chosen, but three main reasons are:
161162
* stronger `null` checks (enforced at the compiler level), and
162163
* better Java collection support (e.g. additional functional features)
163164
165+
## Testing
166+
167+
Run `mvn test` to run the unit tests.
168+
169+
Run `mvn verify` to run the integration tests.
170+
171+
***NOTE:** The integration test might complain about some missing SIGAR binaries, this can be safely ignored. If you wish, you can download the missing binaries and set `java.library.path` parameter to point to the containing folder (e.g. `mvn verify -Djava.library.path=lib` where `lib` is the `/lib` folder relative to the project root).*
172+
164173
## Contributing
165174
166175
We follow the "[fork-and-pull]" Git workflow.
@@ -207,4 +216,5 @@ https://github.com/builtamont/cassandra-migration/releases
207216
[Flyway]: https://flywaydb.org/
208217
[Flyway's project license page]: https://github.com/flyway/flyway/blob/master/LICENSE
209218
[fork-and-pull]: https://help.github.com/articles/using-pull-requests
210-
[LICENSE]: LICENSE
219+
[LICENSE]: LICENSE
220+
[SIGAR]: https://support.hyperic.com/display/SIGAR/Home

pom.xml

+7-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,13 @@
194194
<plugin>
195195
<groupId>org.apache.maven.plugins</groupId>
196196
<artifactId>maven-failsafe-plugin</artifactId>
197-
<version>2.19</version>
197+
<version>2.19.1</version>
198+
<!-- NOTE: Configuration as per http://stackoverflow.com/a/33757854 -->
199+
<configuration>
200+
<forkCount>3</forkCount>
201+
<reuseForks>true</reuseForks>
202+
<argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
203+
</configuration>
198204
<executions>
199205
<execution>
200206
<goals>

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

+24-7
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
*/
@@ -104,7 +115,7 @@ class CassandraMigration : CassandraMigrationConfiguration {
104115
*/
105116
fun info(): MigrationInfoService {
106117
return execute(object : Action<MigrationInfoService> {
107-
override fun execute(session: Session): MigrationInfoService? {
118+
override fun execute(session: Session): MigrationInfoService {
108119
val migrationResolver = createMigrationResolver()
109120
val schemaVersionDAO = SchemaVersionDAO(session, keyspace, MigrationVersion.CURRENT.table)
110121
val migrationInfoService = MigrationInfoServiceImpl(migrationResolver, schemaVersionDAO, configs.target, false, true)
@@ -128,8 +139,8 @@ class CassandraMigration : CassandraMigrationConfiguration {
128139
val validationError = execute(object : Action<String?> {
129140
override fun execute(session: Session): String? {
130141
val migrationResolver = createMigrationResolver()
131-
val schemaVersionDao = SchemaVersionDAO(session, keyspace, MigrationVersion.CURRENT.table)
132-
val validate = Validate(migrationResolver, configs.target, schemaVersionDao, true, false)
142+
val schemaVersionDAO = SchemaVersionDAO(session, keyspace, MigrationVersion.CURRENT.table)
143+
val validate = Validate(migrationResolver, configs.target, schemaVersionDAO, true, false)
133144
return validate.run()
134145
}
135146
})
@@ -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, keyspace.cluster.username)
162+
baseline.run()
163+
}
164+
})
148165
}
149166

150167
/**
@@ -197,7 +214,7 @@ class CassandraMigration : CassandraMigrationConfiguration {
197214
else
198215
throw CassandraMigrationException("Keyspace: " + keyspace.name + " does not exist.")
199216

200-
result = action.execute(session)!!
217+
result = action.execute(session)
201218
} finally {
202219
if (null != session && !session.isClosed)
203220
try {
@@ -259,7 +276,7 @@ class CassandraMigration : CassandraMigrationConfiguration {
259276
* @param session The Cassandra session connection to use to execute the migration.
260277
* @return The action result.
261278
*/
262-
fun execute(session: Session): T?
279+
fun execute(session: Session): T
263280

264281
}
265282

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

+9-10
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")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
* @param migrationResolver The Cassandra migration resolver.
30+
* @param baselineVersion The baseline version of the migration.
31+
* @param schemaVersionDAO The Cassandra migration schema version DAO.
32+
* @param baselineDescription The baseline version description / comments.
33+
* @param user The user to execute the migration as.
34+
*/
35+
class Baseline(
36+
private val migrationResolver: MigrationResolver,
37+
private val baselineVersion: MigrationVersion,
38+
private val schemaVersionDAO: SchemaVersionDAO,
39+
private val baselineDescription: String,
40+
private val user: String
41+
) {
42+
43+
/**
44+
* Runs the migration baselining.
45+
*
46+
* @return The number of successfully applied migration baselining.
47+
* @throws CassandraMigrationException when migration baselining failed for any reason.
48+
*/
49+
@Throws(CassandraMigrationException::class)
50+
fun run() {
51+
val baselineMigration = schemaVersionDAO.baselineMarker
52+
if (schemaVersionDAO.hasAppliedMigrations()) {
53+
val msg = "Unable to baseline metadata table ${schemaVersionDAO.tableName} as it already contains migrations"
54+
throw CassandraMigrationException(msg)
55+
}
56+
57+
if (schemaVersionDAO.hasBaselineMarker()) {
58+
val isNotBaselineByVersion = !(baselineMigration.version?.equals(baselineVersion) ?: false)
59+
val isNotBaselineByDescription = !baselineMigration.description.equals(baselineDescription)
60+
if (isNotBaselineByVersion || isNotBaselineByDescription) {
61+
val msg = "Unable to baseline metadata table ${schemaVersionDAO.tableName} with ($baselineVersion, $baselineDescription)" +
62+
" as it has already been initialized with (${baselineMigration.version}, ${baselineMigration.description})"
63+
throw CassandraMigrationException(msg)
64+
}
65+
} else {
66+
if (baselineVersion.equals(MigrationVersion.fromVersion("0"))) {
67+
val msg = "Unable to baseline metadata table ${schemaVersionDAO.tableName} with version 0 as this version was used for schema creation"
68+
throw CassandraMigrationException(msg)
69+
}
70+
schemaVersionDAO.addBaselineMarker(baselineVersion, baselineDescription, user)
71+
}
72+
}
73+
74+
}

src/main/java/com/builtamont/cassandra/migration/internal/command/Migrate.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ class Migrate(
219219
* @return The migration success log message.
220220
*/
221221
fun successLogMsg(): String {
222-
return "Successfully applied $count migration to keyspace $keyspaceName (execution time ${TimeFormat.format(executionTime)})"
222+
return "Successfully applied $count migration(s) to keyspace $keyspaceName (execution time ${TimeFormat.format(executionTime)})"
223223
}
224224

225225
when (count) {

src/main/java/com/builtamont/cassandra/migration/internal/command/Validate.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ class Validate(
7272
* @param executionTime The total time taken to perform this migration run (in ms).
7373
*/
7474
private fun logSummary(count: Int, executionTime: Long) {
75-
LOG.info("Validated %d migrations (execution time %s)".format(count, TimeFormat.format(executionTime)))
75+
val time = TimeFormat.format(executionTime)
76+
LOG.info("Validated $count migrations (execution time $time)")
7677
}
7778

7879
/**

0 commit comments

Comments
 (0)