Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(build): bump mysql driver and liquibase-core to latest #937

Closed

Conversation

juanpabloprado
Copy link
Contributor

I see there is no liquibase-core version specified, I've tested on clouddriver running locally, I had problems during the migration by liquibase, when using latest mysql driver i.e.

Caused by: java.lang.ClassCastException: class java.time.LocalDateTime cannot be cast to class java.lang.String (java.time.LocalDateTime and java.lang.String are in module java.base of loader 'bootstrap')
	at liquibase.changelog.StandardChangeLogHistoryService.getRanChangeSets(StandardChangeLogHistoryService.java:328) ~[liquibase-core-3.8.9.jar:na]
	at liquibase.changelog.AbstractChangeLogHistoryService.upgradeChecksums(AbstractChangeLogHistoryService.java:66) ~[liquibase-core-3.8.9.jar:na]
	at liquibase.changelog.StandardChangeLogHistoryService.upgradeChecksums(StandardChangeLogHistoryService.java:297) ~[liquibase-core-3.8.9.jar:na]
	at liquibase.Liquibase.checkLiquibaseTables(Liquibase.java:1228) ~[liquibase-core-3.8.9.jar:na]
	at liquibase.Liquibase.update(Liquibase.java:193) ~[liquibase-core-3.8.9.jar:na]
	at liquibase.Liquibase.update(Liquibase.java:179) ~[liquibase-core-3.8.9.jar:na]
	at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:366) ~[liquibase-core-3.8.9.jar:na]
	at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:314) ~[liquibase-core-3.8.9.jar:na]
	at com.netflix.spinnaker.kork.sql.migration.SpringLiquibaseProxy.afterPropertiesSet(SpringLiquibaseProxy.kt:65) ~[kork-sql-7.131.0.jar:7.131.0]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1790) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
	... 150 common frames omitted

and by upgrading the liquibase version, I got it working
See discussion on stackoverflow

@spinnakerbot
Copy link
Contributor

The following commits need their title changed:

  • debcd0d: chore(build) bump mysql driver and liquibase-core to latest

Please format your commit title into the form:

<type>(<scope>): <subject>, e.g. fix(kubernetes): address NPE in status check

This allows us to easily generate changelogs & determine semantic version numbers when cutting releases. You can read more about commit conventions here.

@juanpabloprado juanpabloprado changed the title chore(build) bump mysql driver and liquibase-core to latest chore(build): bump mysql driver and liquibase-core to latest Mar 9, 2022
@juanpabloprado juanpabloprado deleted the bump-liquibase branch March 14, 2022 15:14
@nicolasff
Copy link

I encountered this issue on my Spinnaker instance, using MySQL as the Front50 backend.

As @juanpabloprado figured out, this is related to Liquibase. Specifically, Liquibase fails to process the entries in its DATABASECHANGELOG table when MySQL is used. The code in StandardChangeLogHistoryService reads these entries at startup, and looks at the DATEEXECUTED column, which is defined as a datetime column on my instance. When the row is read, Liquibase uses this date/time as a Date object if it is of that type, otherwise it tries to parse it as a string (see the code in context here):

                    if (tmpDateExecuted instanceof Date) {
                        dateExecuted = (Date) tmpDateExecuted;
                    } else {
                        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        try {
                            dateExecuted = df.parse((String) tmpDateExecuted);

In my case, the tmpDateExecuted variable was a LocalDateTime instance (I'm guessing this is what is produced for datetime columns in MySQL specifically?). The else branch is taken, and this is where the cast from LocalDateTime to String happens:

java.lang.ClassCastException: class java.time.LocalDateTime cannot be cast to class java.lang.String

A change was made to Liquibase on February 3, 2021 to support LocalDateTime. The updated code now checks for LocalDateTime in addition to Date:

                    if (tmpDateExecuted instanceof Date) {
                        dateExecuted = (Date) tmpDateExecuted;
                    } else if (tmpDateExecuted instanceof LocalDateTime) {
                        dateExecuted = Date.from(((LocalDateTime) tmpDateExecuted).atZone(ZoneId.systemDefault()).toInstant());
                    } else {
                        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        try {
                            dateExecuted = df.parse((String) tmpDateExecuted);

From what I can tell this fix was first integrated into Liquibase v4.3.1, but this commit show many more tags that include it.

@juanpabloprado why was the PR closed? Your proposed changes resolved the issue for me.

@dbyron-sf
Copy link
Contributor

I don't know if this the reason why the PR was closed, but the build did fail:

> Task :kork-sql:test
WARNING: All illegal access operations will be denied in a future release

Two pools with different dialect. > should have 2 JOOQ configured one for each H2 and MySQL() FAILED
    java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
        Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1794
            Caused by: liquibase.exception.ChangeLogParseException at YamlChangeLogParser.java:89
                Caused by: java.io.IOException at AbstractResourceAccessor.java:25

Two pools with single MYSQL(default) dialect. > should have 1 JOOQ configured for MYSQL() FAILED
    java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
        Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1794
            Caused by: liquibase.exception.ChangeLogParseException at YamlChangeLogParser.java:89
                Caused by: java.io.IOException at AbstractResourceAccessor.java:25

SpringStartupTests > uses SqlHealthIndicator FAILED
    java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
        Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1794
            Caused by: liquibase.exception.ChangeLogParseException at YamlChangeLogParser.java:89
                Caused by: java.io.IOException at AbstractResourceAccessor.java:25

I've been working on upgrading liquibase locally and I believe I'm seeing the same thing:

Caused by: liquibase.exception.ChangeLogParseException: Error parsing classpath:classpath:db/healthcheck.yml
	at liquibase.parser.core.yaml.YamlChangeLogParser.parse(YamlChangeLogParser.java:82)
	at liquibase.Liquibase.getDatabaseChangeLog(Liquibase.java:223)
	at liquibase.Liquibase$1.run(Liquibase.java:194)
	at liquibase.Scope.lambda$child$0(Scope.java:159)
	at liquibase.Scope.child(Scope.java:170)
	at liquibase.Scope.child(Scope.java:158)
	at liquibase.Scope.child(Scope.java:137)
	at liquibase.Liquibase.runInScope(Liquibase.java:1790)
	at liquibase.Liquibase.update(Liquibase.java:183)
	at liquibase.Liquibase.update(Liquibase.java:179)
	at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:322)
	at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:270)
	at com.netflix.spinnaker.kork.sql.migration.SpringLiquibaseProxy.afterPropertiesSet(SpringLiquibaseProxy.kt:65)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1790)
	... 107 more
Caused by: java.io.IOException: Found 2 files that match classpath:classpath:db/healthcheck.yml: file:/Users/dbyron/src/spinnaker/salesforce/kork/kork-sql/build/resources/main/db/healthcheck.yml, jar:file:/Users/dbyron/src/spinnaker/salesforce/kork/kork-sql/build/libs/kork-sql.jar!/db/healthcheck.yml
	at liquibase.resource.AbstractResourceAccessor.openStream(AbstractResourceAccessor.java:24)
	at liquibase.parser.core.yaml.YamlChangeLogParser.parse(YamlChangeLogParser.java:25)

I'm trying to track it down.

@nicolasff
Copy link

@dbyron-sf have you tried v4.3.1? This is the earliest tag that contains the fix. The further you go from the current version, the more incompatibilities you're likely to encounter.

@dbyron-sf
Copy link
Contributor

I have....or at least it's still broken with v4.0.0.

@dbyron-sf
Copy link
Contributor

See also liquibase/liquibase#1916

@dbyron-sf
Copy link
Contributor

Actually, I did some more testing and 4.3.1 does appear to work....at least the tests in kork-sql pass. More details in liquibase/liquibase#1916 (comment). I haven't actually tested it in a real environment, and at the moment I'm not planning to...since I'm really looking for a version that fixes CVE-2022-0839 which requires >= 4.8.0.

@dbyron-sf
Copy link
Contributor

I filed liquibase/liquibase#2818.

@luispollo
Copy link
Contributor

Hi folks! I landed here from the various related liquibase issues. I started seeing this same error building keel today, but pinning to 4.3.1 or lower doesn't fix the issue for me. Any other clues you may have found by chance?

@dbyron-sf
Copy link
Contributor

Not sure how helpful this is, but in the testing I've done, newer liquibases (e.g. 4.10.0, 4.11.0, and older ones...not sure how much older) work everywhere in spinnaker except kork. Like, the only failures are from kork-sql:test that I wrote about above, but if I skip those tests and build the spinnaker microservices with the resulting kork jars, all the tests pass there. Not sure I got far enough to actually exercise the resulting docker images, but I suspect those work fine.

@mattgogerly
Copy link
Member

@luispollo @dbyron-sf do you know if anybody is looking at fixing this in Kork?

As you say, the actual Spinnaker services run fine - we're able to deploy them using 8.0.29/4.13.0 respectively, but kork-sql tests fail because of the issue linked above.

Reading through it seems like we should just be able to set the duplicateFile property and bump them? Although I'm not sure where that property needs to be set - I still see errors with the property set in the test class and in application-test.yml.

@dbyron-sf
Copy link
Contributor

I have most of the changes done to move to liquibase 4.13.0...no change to the mysql driver.

The current (and I think last) snag is that orca has tests that use postgres and postgres doesn't support afterColumn... so it either means removing afterColumn from the migrations, or finding a way to add custom sql for mysql only to do it. I thought I had that figured out, but I don't... The existing version of liquibase has nicer (in my opinion) behavior here...it uses afterColumn in mysql, and leaves it out for postgres. Instead of leaving it out, liquibase 4.13.0 fails when asked to migrate a postgres database...

@dbyron-sf
Copy link
Contributor

See liquibase/liquibase#3091.

@dbyron-sf
Copy link
Contributor

And #970.

@dbyron-sf
Copy link
Contributor

And finally, #1117.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
6 participants