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

Address upstream PR #17 #8

Merged
merged 9 commits into from
Sep 8, 2016
14 changes: 10 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
language: java
jdk:
- openjdk7
- oraclejdk7
- oraclejdk8
env:
global:
- 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="
- secure: "04af3/9b67O5xd1U8GDhCqRQedHM3RP5HokdsOwAe8vN3EyyyKWXQafBkKsPvmDh5Uu/CYQppOYS4pQxB9ikweTfj34DbyyxpqJmjYE4KFvdQuFd0msyXhLCg6xfvS4KO6zjUQ8/c3rNQap4hx/icQ50/NES4rkUkxIZ/VKQ4jPXcBzPegEC6Le50Vw2tR8FT4erdNuABnGf1WnWGUUa3i6xdQQPyw8kdTIun08HxE6M9F+JJRH8jH3b7KizQhGdACAk4fnCOmFSgu7pm6ACXRJYqAfg055i5mr77yZXfeUIcIY3l45uY1uR8sxEbLUE/KwwlLGLVZWDI4xU6JIGisbrmMce+vz6YKUT9gHF3iAEJ5e4N18nJcRyHVrqcuRzv5Py0rFPZ70dr7aW/tk0JrTz6+FZ4FNIOdvIQe4qWy2TVns0EkERdtYGTdsigWfa/sKF/P5+/2foUOlnR06p55NHpIjaHRKy/XFVV1gyURUlRUGExVoIMX21bAMxGYMFMH7LfddRsly028lXwibRMkQGBeyVRYKQmqJvN3mTPbuAWmZZdaVpqn1jkgETlT6/qz43zv9y8jAOzZ22SeHEXe3NiexChqkAJWIH3cBYshMhy8H1fmYAIVYHvI+BPsbi+qDYSnAlAUDqoLWXPAvWUX89dAIXYRNcKplzpFsjWvM="
matrix:
include:
- jdk: openjdk7
script: mvn test
- jdk: oraclejdk7
script: mvn test
- jdk: oraclejdk8
script:
- mvn test
- mvn verify
deploy:
provider: script
script: ./scripts/deploy.sh
Expand Down
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Import this library as a dependency (Maven example):
</dependency>
```

***NOTE:** Integration test in Travis CI is only run against Oracle JDK 1.8, due to embedded Cassandra's dependencies on JDK 1.8*

### Migration version table

``` shell
Expand Down Expand Up @@ -140,7 +142,6 @@ Keyspace:

### Limitations

* Baselining not supported yet
* The tool does not roll back the database upon migration failure. You're expected to manually restore backup.

## Project Rationale
Expand All @@ -161,6 +162,14 @@ There are various reasons why Kotlin was chosen, but three main reasons are:
* stronger `null` checks (enforced at the compiler level), and
* better Java collection support (e.g. additional functional features)

## Testing

Run `mvn test` to run the unit tests.

Run `mvn verify` to run the integration tests.

***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).*

## Contributing

We follow the "[fork-and-pull]" Git workflow.
Expand Down Expand Up @@ -207,4 +216,5 @@ https://github.com/builtamont/cassandra-migration/releases
[Flyway]: https://flywaydb.org/
[Flyway's project license page]: https://github.com/flyway/flyway/blob/master/LICENSE
[fork-and-pull]: https://help.github.com/articles/using-pull-requests
[LICENSE]: LICENSE
[LICENSE]: LICENSE
[SIGAR]: https://support.hyperic.com/display/SIGAR/Home
8 changes: 7 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,13 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19</version>
<version>2.19.1</version>
<!-- NOTE: Configuration as per http://stackoverflow.com/a/33757854 -->
<configuration>
<forkCount>3</forkCount>
<reuseForks>true</reuseForks>
<argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
</configuration>
<executions>
<execution>
<goals>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.builtamont.cassandra.migration.api.configuration.CassandraMigrationCo
import com.builtamont.cassandra.migration.api.configuration.MigrationConfigs
import com.builtamont.cassandra.migration.api.resolver.MigrationResolver
import com.builtamont.cassandra.migration.config.Keyspace
import com.builtamont.cassandra.migration.internal.command.Baseline
import com.builtamont.cassandra.migration.internal.command.Initialize
import com.builtamont.cassandra.migration.internal.command.Migrate
import com.builtamont.cassandra.migration.internal.command.Validate
Expand Down Expand Up @@ -61,6 +62,16 @@ class CassandraMigration : CassandraMigrationConfiguration {
*/
lateinit var configs: MigrationConfigs

/**
* The baseline version.
*/
private val baselineVersion = MigrationVersion.Companion.fromVersion("1")

/**
* The baseline description.
*/
private val baselineDescription = "<< Cassandra Baseline >>"

/**
* CassandraMigration initialization.
*/
Expand Down Expand Up @@ -104,7 +115,7 @@ class CassandraMigration : CassandraMigrationConfiguration {
*/
fun info(): MigrationInfoService {
return execute(object : Action<MigrationInfoService> {
override fun execute(session: Session): MigrationInfoService? {
override fun execute(session: Session): MigrationInfoService {
val migrationResolver = createMigrationResolver()
val schemaVersionDAO = SchemaVersionDAO(session, keyspace, MigrationVersion.CURRENT.table)
val migrationInfoService = MigrationInfoServiceImpl(migrationResolver, schemaVersionDAO, configs.target, false, true)
Expand All @@ -128,8 +139,8 @@ class CassandraMigration : CassandraMigrationConfiguration {
val validationError = execute(object : Action<String?> {
override fun execute(session: Session): String? {
val migrationResolver = createMigrationResolver()
val schemaVersionDao = SchemaVersionDAO(session, keyspace, MigrationVersion.CURRENT.table)
val validate = Validate(migrationResolver, configs.target, schemaVersionDao, true, false)
val schemaVersionDAO = SchemaVersionDAO(session, keyspace, MigrationVersion.CURRENT.table)
val validate = Validate(migrationResolver, configs.target, schemaVersionDAO, true, false)
return validate.run()
}
})
Expand All @@ -143,8 +154,14 @@ class CassandraMigration : CassandraMigrationConfiguration {
* Baselines an existing database, excluding all migrations up to and including baselineVersion.
*/
fun baseline() {
// TODO: Create the Cassandra migration implementation, refer to existing PR: https://github.com/Contrast-Security-OSS/cassandra-migration/pull/17
throw NotImplementedException()
execute(object : Action<Unit> {
override fun execute(session: Session): Unit {
val migrationResolver = createMigrationResolver()
val schemaVersionDAO = SchemaVersionDAO(session, keyspace, MigrationVersion.CURRENT.table)
val baseline = Baseline(migrationResolver, baselineVersion, schemaVersionDAO, baselineDescription, keyspace.cluster.username)
baseline.run()
}
})
}

/**
Expand Down Expand Up @@ -197,7 +214,7 @@ class CassandraMigration : CassandraMigrationConfiguration {
else
throw CassandraMigrationException("Keyspace: " + keyspace.name + " does not exist.")

result = action.execute(session)!!
result = action.execute(session)
} finally {
if (null != session && !session.isClosed)
try {
Expand Down Expand Up @@ -259,7 +276,7 @@ class CassandraMigration : CassandraMigrationConfiguration {
* @param session The Cassandra session connection to use to execute the migration.
* @return The action result.
*/
fun execute(session: Session): T?
fun execute(session: Session): T

}

Expand Down
19 changes: 9 additions & 10 deletions src/main/java/com/builtamont/cassandra/migration/CommandLine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import com.builtamont.cassandra.migration.internal.util.logging.Log
import com.builtamont.cassandra.migration.internal.util.logging.LogFactory
import com.builtamont.cassandra.migration.internal.util.logging.console.ConsoleLog
import com.builtamont.cassandra.migration.internal.util.logging.console.ConsoleLogCreator
import java.util.*

/**
* Cassandra migration command line runner.
Expand All @@ -40,6 +39,11 @@ object CommandLine {
*/
val VALIDATE = "validate"

/**
* Command to trigger baseline action.
*/
val BASELINE = "baseline"

/**
* Logging support.
*/
Expand Down Expand Up @@ -69,22 +73,16 @@ object CommandLine {
cm.migrate()
} else if (VALIDATE.equals(operation, ignoreCase = true)) {
cm.validate()
} else if (BASELINE.equals(operation, ignoreCase = true)) {
cm.baseline()
}
}

/**
* Get a list of applicable operations.
*/
private fun determineOperations(args: Array<String>): List<String> {
val operations = ArrayList<String>()

for (arg in args) {
if (!arg.startsWith("-")) {
operations.add(arg)
}
}

return operations
return args.filterNot { it.startsWith("-") }
}

/**
Expand Down Expand Up @@ -124,6 +122,7 @@ object CommandLine {
LOG.info("========")
LOG.info("migrate : Migrates the database")
LOG.info("validate : Validates the applied migrations against the available ones")
LOG.info("baseline : Baselines an existing database, excluding all migrations up to, and including baselineVersion")
LOG.info("")
LOG.info("Add -X to print debug output")
LOG.info("Add -q to suppress all output, except for errors and warnings")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* File : Baseline.kt
* License :
* Original - Copyright (c) 2015 - 2016 Contrast Security
* Derivative - Copyright (c) 2016 Citadel Technology Solutions Pte Ltd
*
* 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.
*/
package com.builtamont.cassandra.migration.internal.command

import com.builtamont.cassandra.migration.api.CassandraMigrationException
import com.builtamont.cassandra.migration.api.MigrationVersion
import com.builtamont.cassandra.migration.api.resolver.MigrationResolver
import com.builtamont.cassandra.migration.internal.dbsupport.SchemaVersionDAO

/**
* Handles the baseline command.
*
* @param migrationResolver The Cassandra migration resolver.
* @param baselineVersion The baseline version of the migration.
* @param schemaVersionDAO The Cassandra migration schema version DAO.
* @param baselineDescription The baseline version description / comments.
* @param user The user to execute the migration as.
*/
class Baseline(
private val migrationResolver: MigrationResolver,
private val baselineVersion: MigrationVersion,
private val schemaVersionDAO: SchemaVersionDAO,
private val baselineDescription: String,
private val user: String
) {

/**
* Runs the migration baselining.
*
* @return The number of successfully applied migration baselining.
* @throws CassandraMigrationException when migration baselining failed for any reason.
*/
@Throws(CassandraMigrationException::class)
fun run() {
val baselineMigration = schemaVersionDAO.baselineMarker
if (schemaVersionDAO.hasAppliedMigrations()) {
val msg = "Unable to baseline metadata table ${schemaVersionDAO.tableName} as it already contains migrations"
throw CassandraMigrationException(msg)
}

if (schemaVersionDAO.hasBaselineMarker()) {
val isNotBaselineByVersion = !(baselineMigration.version?.equals(baselineVersion) ?: false)
val isNotBaselineByDescription = !baselineMigration.description.equals(baselineDescription)
if (isNotBaselineByVersion || isNotBaselineByDescription) {
val msg = "Unable to baseline metadata table ${schemaVersionDAO.tableName} with ($baselineVersion, $baselineDescription)" +
" as it has already been initialized with (${baselineMigration.version}, ${baselineMigration.description})"
throw CassandraMigrationException(msg)
}
} else {
if (baselineVersion.equals(MigrationVersion.fromVersion("0"))) {
val msg = "Unable to baseline metadata table ${schemaVersionDAO.tableName} with version 0 as this version was used for schema creation"
throw CassandraMigrationException(msg)
}
schemaVersionDAO.addBaselineMarker(baselineVersion, baselineDescription, user)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ class Migrate(
* @return The migration success log message.
*/
fun successLogMsg(): String {
return "Successfully applied $count migration to keyspace $keyspaceName (execution time ${TimeFormat.format(executionTime)})"
return "Successfully applied $count migration(s) to keyspace $keyspaceName (execution time ${TimeFormat.format(executionTime)})"
}

when (count) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ class Validate(
* @param executionTime The total time taken to perform this migration run (in ms).
*/
private fun logSummary(count: Int, executionTime: Long) {
LOG.info("Validated %d migrations (execution time %s)".format(count, TimeFormat.format(executionTime)))
val time = TimeFormat.format(executionTime)
LOG.info("Validated $count migrations (execution time $time)")
}

/**
Expand Down
Loading