cryostatio / cryostat-web

Web front-end for Cryostat: Secure JDK Flight Recorder management for containerized JVMs
https://cryostat.io/
Other
10 stars 20 forks source link

build(deps): upgrade to Patternfly 5 #1303

Closed andrewazores closed 1 month ago

andrewazores commented 3 months ago

Welcome to Cryostat! 👋

Before contributing, make sure you have:

To recreate commits with GPG signature git fetch upstream && git rebase --force --gpg-sign upstream/main


Fixes: #1110

TODO update from PF 5.1.0 to 5.3.0

Notably broken things:

github-actions[bot] commented 3 months ago

Hi @andrewazores! Add at least one of the required labels to this PR

Required labels are : chore,ci,cleanup,docs,feat,fix,perf,refactor,style,test

github-actions[bot] commented 3 months ago

Build Error! No Linked Issue found. Please link an issue or mention it in the body using #

andrewazores commented 3 months ago

Dropdown menu heights look like a PF 5.3.0 feature:

https://github.com/patternfly/patternfly-react/releases/tag/v5.3.0

feat(Dropdown): Added support for setting height for dropdown

https://github.com/patternfly/patternfly-react/pull/10149

tthvo commented 2 months ago

about modal has strange image rendering:

I think the .png image no longer fits. We would need some new design for an .svg, specifically to render in the bottom-right of the modal. For example, this PF6 example looks rather nice.

https://staging-v6.patternfly.org/components/about-modal/react/basic/

andrewazores commented 2 months ago

Ah, okay. That PNG was actually made for the upstream https://cryostat.io website and was introduced in this PR. I can ask James if he still has the design file for that and if he's able to provide an SVG version, but considering the design of it with a lot of gradient colours and texture, I don't think it will lend itself well to being vectorized.

If we can restyle the modal with some CSS to get the existing PNG to fit again, that would be great. Otherwise we might need to get a whole new SVG asset just for this background, or else simply reuse one of the SVG icons we have.

andrewazores commented 2 months ago

Actually, given the styling of the PF5 About Modal component, the right move looks like it would be to just use the Cryostat icon SVG in both locations of the modal, except a desaturated/monochrome version and maybe partially cut off or outside of the viewport.

image

https://www.patternfly.org/components/background-image

tthvo commented 2 months ago

Actually, given the styling of the PF5 About Modal component, the right move looks like it would be to just use the Cryostat icon SVG in both locations of the modal, except a desaturated/monochrome version and maybe partially cut off or outside of the viewport.

Sounds good to me! Though, maybe James or the team can provide one here that matches the requirements above?

andrewazores commented 2 months ago

I can ask. But, I'm not convinced we really need to have this. The About Modal component says that "the modal image should be the same as the background image you use for your application," but we don't use an application background image.

https://www.patternfly.org/components/about-modal/design-guidelines

tthvo commented 2 months ago

I can ask. But, I'm not convinced we really need to have this. The About Modal component says that "the modal image should be the same as the background image you use for your application," but we don't use an application background image.

https://www.patternfly.org/components/about-modal/design-guidelines

Oh, does this mean we can remove the background for the About modal for this upgrade?

Btw, I played around with the icon a bit and get this. Just that confirmed svg is required here with either a cryostat icon or others. I can remove it the background if we decide it that way.

Editted: Updated screenshot since last comment.

image

SVG: cryostat_icon_bg.zip

andrewazores commented 2 months ago

Well, since you've invested the time into it, let's go ahead and use that :-) thanks for doing that!

tthvo commented 2 months ago

Upgrades for QuickStarts are currently blocked by a small issue with admonition block: https://github.com/patternfly/patternfly-quickstarts/issues/323.

tthvo commented 1 month ago

Upgrades for QuickStarts are currently blocked by a small issue with admonition block: patternfly/patternfly-quickstarts#323.

The issue seems to be put into 2024 Q3 so hopefully it will be fixed right when we finished upgrading and fixing tests :D

andrewazores commented 1 month ago

I don't think that is necessarily a blocker anyway. We have other reasons to upgrade to PF5 that are more important, so if some minor styling is missing at first, I say we go ahead regardless and let that get fixed later.

tthvo commented 1 month ago

I think the views are pretty much in good shape now (i.e. just need to a quick check on quickstarts)? Here are the list of available tests by directory with assignments:

Just in case anyone is also fixing the tests to void duplicating work :D

Editted: All test fixes will now be included in #1347 :D

andrewazores commented 1 month ago

Thanks for all your hard work on this @tthvo , I really appreciate it.

andrewazores commented 1 month ago

@tthvo any other planned work for this PR or can I start looking to review and merge this thing? If there are any minor updates (ex. a minor or patch version upgrade for Patternfly) etc. those can be done as follow-ups.

tthvo commented 1 month ago

I think this is ready for review, other than the @patternfly/quickstart version bump later on :D

tthvo commented 1 month ago

We do have one issue with credential table though where credential notification returns 0 match. I found this comment from cryostat source:

https://github.com/cryostatio/cryostat/blob/317ae48a8d9593ce36d03962f09f430bd1a1cb11/src/main/java/io/cryostat/credentials/Credentials.java#L108

For the time being, is this issue tolerable? Or some workaround desired?

andrewazores commented 1 month ago

We do have one issue with credential table though where credential notification returns 0 match. I found this comment from cryostat source:

https://github.com/cryostatio/cryostat/blob/317ae48a8d9593ce36d03962f09f430bd1a1cb11/src/main/java/io/cryostat/credentials/Credentials.java#L108

For the time being, is this issue tolerable? Or some workaround desired?

https://github.com/cryostatio/cryostat/pull/584/files#diff-58bcb5d27231eedec09ab4aecc0aca9cbcbc4f2b250db1ec942c7d3344ddf7a6R156

In API v4 I think this bug is going to go away naturally anyway.

tthvo commented 1 month ago

https://github.com/cryostatio/cryostat/pull/584/files#diff-58bcb5d27231eedec09ab4aecc0aca9cbcbc4f2b250db1ec942c7d3344ddf7a6R156

In API v4 I think this bug is going to go away naturally anyway.

Very nice! Then, this should be good then :D

andrewazores commented 1 month ago

Actually, that bug is unfortunately not solved with the V4 work. I also thought it might be with the Quarkus 3.8 upgrade, but it's still present there too - and even with Quarkus 3.8 + API v4.

The bug looks something like this in the server logs:

cryostat_1  | 2024-09-13 21:08:28,820 DEBUG [org.hib.SQL] (executor-thread-4) 
cryostat_1  |     insert 
cryostat_1  |     into
cryostat_1  |         MatchExpression
cryostat_1  |         (script, id) 
cryostat_1  |     values
cryostat_1  |         (?, ?)
cryostat_1  | Hibernate: 
cryostat_1  |     insert 
cryostat_1  |     into
cryostat_1  |         MatchExpression
cryostat_1  |         (script, id) 
cryostat_1  |     values
cryostat_1  |         (?, ?)
cryostat_1  | 2024-09-13 21:08:28,823 DEBUG [org.hib.SQL] (executor-thread-4) 
cryostat_1  |     insert 
cryostat_1  |     into
cryostat_1  |         Credential
cryostat_1  |         (matchExpression, password, username, id) 
cryostat_1  |     values
cryostat_1  |         (?, pgp_sym_encrypt(?, current_setting('encrypt.key')), pgp_sym_encrypt(?, current_setting('encrypt.key')), ?)
cryostat_1  | Hibernate: 
cryostat_1  |     insert 
cryostat_1  |     into
cryostat_1  |         Credential
cryostat_1  |         (matchExpression, password, username, id) 
cryostat_1  |     values
cryostat_1  |         (?, pgp_sym_encrypt(?, current_setting('encrypt.key')), pgp_sym_encrypt(?, current_setting('encrypt.key')), ?)
cryostat_1  | 2024-09-13 21:08:28,824 DEBUG [org.hib.eve.int.AbstractFlushingEventListener] (executor-thread-4) Processing flush-time cascades
cryostat_1  | 2024-09-13 21:08:28,825 DEBUG [org.hib.eve.int.AbstractFlushingEventListener] (executor-thread-4) Dirty checking collections
cryostat_1  | 2024-09-13 21:08:28,825 DEBUG [org.hib.eng.int.Collections] (executor-thread-4) Collection found: [io.cryostat.discovery.DiscoveryNode.children#7], was: [<unreferenced>] (initialized)
cryostat_1  | 2024-09-13 21:08:28,825 DEBUG [org.hib.eng.int.Collections] (executor-thread-4) Collection found: [io.cryostat.targets.Target.activeRecordings#1], was: [<unreferenced>] (initialized)
cryostat_1  | 2024-09-13 21:08:28,825 DEBUG [org.hib.eve.int.AbstractFlushingEventListener] (executor-thread-4) Flushed: 4 insertions, 2 updates, 0 deletions to 4 objects
cryostat_1  | 2024-09-13 21:08:28,825 DEBUG [org.hib.eve.int.AbstractFlushingEventListener] (executor-thread-4) Flushed: 4 (re)creations, 0 updates, 0 removals to 2 collections
cryostat_1  | 2024-09-13 21:08:28,825 DEBUG [org.hib.int.uti.EntityPrinter] (executor-thread-4) Listing entities:
cryostat_1  | 2024-09-13 21:08:28,825 DEBUG [org.hib.int.uti.EntityPrinter] (executor-thread-4) io.cryostat.discovery.DiscoveryNode{parent=null, children=[], name=service:jmx:rmi:///jndi/rmi://localhost:0/jmxrmi, id=7, nodeType=JVM, labels={}, target=io.cryostat.targets.Target#1}
cryostat_1  | 2024-09-13 21:08:28,825 DEBUG [org.hib.int.uti.EntityPrinter] (executor-thread-4) io.cryostat.credentials.Credential{discoveryPlugin=null, matchExpression=io.cryostat.expressions.MatchExpression#1, password=pass, id=1, username=user}
cryostat_1  | 2024-09-13 21:08:28,825 DEBUG [org.hib.int.uti.EntityPrinter] (executor-thread-4) io.cryostat.expressions.MatchExpression{id=1, script=target.connectUrl == "service:jmx:rmi:///jndi/rmi://localhost:0/jmxrmi"}
cryostat_1  | 2024-09-13 21:08:28,825 DEBUG [org.hib.int.uti.EntityPrinter] (executor-thread-4) io.cryostat.targets.Target{connectUrl=service:jmx:rmi:///jndi/rmi://localhost:0/jmxrmi, jvmId=hY4ZlLUqaJAKFR3eR1Bstw7eHnK0Xb8NP3CLPVtUOCA=, discoveryNode=io.cryostat.discovery.DiscoveryNode#7, alias=localhost%3A0, annotations=Annotations[platform={}, cryostat={REALM=Custom Targets}], activeRecordings=[], id=1, labels={}}
cryostat_1  | 2024-09-13 21:08:28,825 DEBUG [org.hib.SQL] (executor-thread-4) 
cryostat_1  |     insert 
cryostat_1  |     into
cryostat_1  |         MatchExpression
cryostat_1  |         (script, id) 
cryostat_1  |     values
cryostat_1  |         (?, ?)
cryostat_1  | Hibernate: 
cryostat_1  |     insert 
cryostat_1  |     into
cryostat_1  |         MatchExpression
cryostat_1  |         (script, id) 
cryostat_1  |     values
cryostat_1  |         (?, ?)
db_1        | 2024-09-13 21:08:28.825 UTC [71] ERROR:  duplicate key value violates unique constraint "matchexpression_pkey"
db_1        | 2024-09-13 21:08:28.825 UTC [71] DETAIL:  Key (id)=(1) already exists.
db_1        | 2024-09-13 21:08:28.825 UTC [71] STATEMENT:  insert into MatchExpression (script,id) values ($1,$2)
cryostat_1  | 2024-09-13 21:08:28,827 DEBUG [io.cry.ws.MessagingServer] (executor-thread-2) Broadcasting: {"message":"target.connectUrl == \"service:jmx:rmi:///jndi/rmi://localhost:0/jmxrmi\"","meta":{"category":"ExpressionCreated"}}
cryostat_1  | 2024-09-13 21:08:28,828 DEBUG [org.hib.eng.jdb.spi.SqlExceptionHelper] (executor-thread-4) could not execute statement [insert into MatchExpression (script,id) values (?,?)]: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "matchexpression_pkey"
cryostat_1  |   Detail: Key (id)=(1) already exists.
cryostat_1  |   at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2725)
cryostat_1  |   at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2412)
cryostat_1  |   at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:371)
cryostat_1  |   at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:502)
cryostat_1  |   at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:419)
cryostat_1  |   at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:194)
cryostat_1  |   at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:155)
cryostat_1  |   at io.agroal.pool.wrapper.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:90)
cryostat_1  |   at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:194)
cryostat_1  |   at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:108)
cryostat_1  |   at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:40)
cryostat_1  |   at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:52)
cryostat_1  |   at org.hibernate.persister.entity.mutation.InsertCoordinator.doStaticInserts(InsertCoordinator.java:175)
cryostat_1  |   at org.hibernate.persister.entity.mutation.InsertCoordinator.coordinateInsert(InsertCoordinator.java:113)
cryostat_1  |   at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2863)
cryostat_1  |   at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:104)
cryostat_1  |   at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:632)
cryostat_1  |   at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:499)
cryostat_1  |   at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:363)
cryostat_1  |   at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:61)
cryostat_1  |   at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
cryostat_1  |   at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1370)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$2(ConcreteSqmSelectQueryPlan.java:136)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:381)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:303)
cryostat_1  |   at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:509)
cryostat_1  |   at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:427)
cryostat_1  |   at org.hibernate.query.Query.getResultList(Query.java:120)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.common.runtime.CommonPanacheQueryImpl.list(CommonPanacheQueryImpl.java:280)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.runtime.PanacheQueryImpl.list(PanacheQueryImpl.java:149)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.runtime.JpaOperations.list(JpaOperations.java:24)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.runtime.JpaOperations.list(JpaOperations.java:10)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.listAll(AbstractJpaOperations.java:305)
cryostat_1  |   at io.cryostat.targets.Target.listAll(Target.java)
cryostat_1  |   at io.cryostat.expressions.TargetMatcher.match(TargetMatcher.java:50)
cryostat_1  |   at io.cryostat.expressions.TargetMatcher_ClientProxy.match(Unknown Source)
cryostat_1  |   at io.cryostat.credentials.Credentials.safeResult(Credentials.java:158)
cryostat_1  |   at io.cryostat.credentials.Credential$Listener.postPersist(Credential.java:101)
cryostat_1  |   at io.cryostat.credentials.Credential_Listener_ClientProxy.postPersist(Unknown Source)
cryostat_1  |   at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
cryostat_1  |   at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
cryostat_1  |   at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
cryostat_1  |   at java.base/java.lang.reflect.Method.invoke(Method.java:569)
cryostat_1  |   at org.hibernate.jpa.event.internal.ListenerCallback.performCallback(ListenerCallback.java:55)
cryostat_1  |   at org.hibernate.jpa.event.internal.CallbackRegistryImpl.callback(CallbackRegistryImpl.java:123)
cryostat_1  |   at org.hibernate.jpa.event.internal.CallbackRegistryImpl.postCreate(CallbackRegistryImpl.java:81)
cryostat_1  |   at org.hibernate.event.internal.PostInsertEventListenerStandardImpl.onPostInsert(PostInsertEventListenerStandardImpl.java:31)
cryostat_1  |   at org.hibernate.event.service.internal.EventListenerGroupImpl.fireLazyEventOnEachListener(EventListenerGroupImpl.java:116)
cryostat_1  |   at org.hibernate.action.internal.EntityInsertAction.postInsert(EntityInsertAction.java:191)
cryostat_1  |   at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:117)
cryostat_1  |   at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:632)
cryostat_1  |   at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:499)
cryostat_1  |   at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:363)
cryostat_1  |   at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:61)
cryostat_1  |   at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
cryostat_1  |   at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1370)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$2(ConcreteSqmSelectQueryPlan.java:136)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:381)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:303)
cryostat_1  |   at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:509)
cryostat_1  |   at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:427)
cryostat_1  |   at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:564)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.common.runtime.CommonPanacheQueryImpl.singleResult(CommonPanacheQueryImpl.java:309)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.runtime.PanacheQueryImpl.singleResult(PanacheQueryImpl.java:169)
cryostat_1  |   at io.cryostat.discovery.DiscoveryNode.getUniverse(DiscoveryNode.java:110)
cryostat_1  |   at io.cryostat.discovery.DiscoveryNode.getRealm(DiscoveryNode.java:114)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery.doCreate(CustomDiscovery.java:211)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery.createForm(CustomDiscovery.java:125)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery_Subclass.createForm$$superforward(Unknown Source)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery_Subclass$$function$$2.apply(Unknown Source)
cryostat_1  |   at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:73)
cryostat_1  |   at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:62)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:136)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:107)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.doIntercept(TransactionalInterceptorRequired.java:38)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.intercept(TransactionalInterceptorBase.java:61)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.intercept(TransactionalInterceptorRequired.java:32)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired_Bean.intercept(Unknown Source)
cryostat_1  |   at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:42)
cryostat_1  |   at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:30)
cryostat_1  |   at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:27)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery_Subclass.createForm(Unknown Source)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery_ClientProxy.createForm(Unknown Source)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery$quarkusrestinvoker$createForm_f4044472152fe54bbb4ecf74155604fed0b3a814.invoke(Unknown Source)
cryostat_1  |   at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
cryostat_1  |   at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141)
cryostat_1  |   at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
cryostat_1  |   at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:582)
cryostat_1  |   at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
cryostat_1  |   at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
cryostat_1  |   at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
cryostat_1  |   at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
cryostat_1  |   at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
cryostat_1  |   at java.base/java.lang.Thread.run(Thread.java:840)
cryostat_1  | 
cryostat_1  | 2024-09-13 21:08:28,828 WARN  [org.hib.eng.jdb.spi.SqlExceptionHelper] (executor-thread-4) SQL Error: 0, SQLState: 23505
cryostat_1  | 2024-09-13 21:08:28,828 ERROR [org.hib.eng.jdb.spi.SqlExceptionHelper] (executor-thread-4) ERROR: duplicate key value violates unique constraint "matchexpression_pkey"
cryostat_1  |   Detail: Key (id)=(1) already exists.
cryostat_1  | 2024-09-13 21:08:28,831 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Pre-invalidating space [Credential], timestamp: 1726261768831
cryostat_1  | 2024-09-13 21:08:28,831 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Pre-invalidating space [DiscoveryNode], timestamp: 1726261768831
cryostat_1  | 2024-09-13 21:08:28,831 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Pre-invalidating space [Target], timestamp: 1726261768831
cryostat_1  | 2024-09-13 21:08:28,831 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Pre-invalidating space [MatchExpression], timestamp: 1726261768831
cryostat_1  | 2024-09-13 21:08:28,860 DEBUG [org.hib.eng.tra.int.TransactionImpl] (executor-thread-4) On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false
cryostat_1  | 2024-09-13 21:08:28,860 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Pre-invalidating space [Credential], timestamp: 1726261768860
cryostat_1  | 2024-09-13 21:08:28,860 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Pre-invalidating space [DiscoveryNode], timestamp: 1726261768860
cryostat_1  | 2024-09-13 21:08:28,860 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Pre-invalidating space [Target], timestamp: 1726261768860
cryostat_1  | 2024-09-13 21:08:28,860 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Pre-invalidating space [MatchExpression], timestamp: 1726261768860
cryostat_1  | 2024-09-13 21:08:28,861 FINE  [org.pos.jdb.PgConnection] (executor-thread-4)   setAutoCommit = true
cryostat_1  | 2024-09-13 21:08:28,861 DEBUG [org.hib.res.jdb.int.LogicalConnectionManagedImpl] (executor-thread-4) Initiating JDBC connection release from afterTransaction
cryostat_1  | 2024-09-13 21:08:28,862 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Invalidating space [Credential], timestamp: 1726261708862
cryostat_1  | 2024-09-13 21:08:28,862 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Invalidating space [DiscoveryNode], timestamp: 1726261708862
cryostat_1  | 2024-09-13 21:08:28,862 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Invalidating space [Target], timestamp: 1726261708862
cryostat_1  | 2024-09-13 21:08:28,862 DEBUG [org.hib.cac.int.TimestampsCacheEnabledImpl] (executor-thread-4) Invalidating space [MatchExpression], timestamp: 1726261708862
cryostat_1  | 2024-09-13 21:08:28,862 DEBUG [org.jbo.res.rea.com.cor.AbstractResteasyReactiveContext] (executor-thread-4) Restarting handler chain for exception exception: org.hibernate.exception.ConstraintViolationException: could not execute statement [ERROR: duplicate key value violates unique constraint "matchexpression_pkey"
cryostat_1  |   Detail: Key (id)=(1) already exists.] [insert into MatchExpression (script,id) values (?,?)]
cryostat_1  |   at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:97)
cryostat_1  |   at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:58)
cryostat_1  |   at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:108)
cryostat_1  |   at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
cryostat_1  |   at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:108)
cryostat_1  |   at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:40)
cryostat_1  |   at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:52)
cryostat_1  |   at org.hibernate.persister.entity.mutation.InsertCoordinator.doStaticInserts(InsertCoordinator.java:175)
cryostat_1  |   at org.hibernate.persister.entity.mutation.InsertCoordinator.coordinateInsert(InsertCoordinator.java:113)
cryostat_1  |   at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2863)
cryostat_1  |   at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:104)
cryostat_1  |   at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:632)
cryostat_1  |   at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:499)
cryostat_1  |   at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:363)
cryostat_1  |   at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:61)
cryostat_1  |   at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
cryostat_1  |   at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1370)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$2(ConcreteSqmSelectQueryPlan.java:136)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:381)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:303)
cryostat_1  |   at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:509)
cryostat_1  |   at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:427)
cryostat_1  |   at org.hibernate.query.Query.getResultList(Query.java:120)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.common.runtime.CommonPanacheQueryImpl.list(CommonPanacheQueryImpl.java:280)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.runtime.PanacheQueryImpl.list(PanacheQueryImpl.java:149)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.runtime.JpaOperations.list(JpaOperations.java:24)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.runtime.JpaOperations.list(JpaOperations.java:10)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.listAll(AbstractJpaOperations.java:305)
cryostat_1  |   at io.cryostat.targets.Target.listAll(Target.java)
cryostat_1  |   at io.cryostat.expressions.TargetMatcher.match(TargetMatcher.java:50)
cryostat_1  |   at io.cryostat.expressions.TargetMatcher_ClientProxy.match(Unknown Source)
cryostat_1  |   at io.cryostat.credentials.Credentials.safeResult(Credentials.java:158)
cryostat_1  |   at io.cryostat.credentials.Credential$Listener.postPersist(Credential.java:101)
cryostat_1  |   at io.cryostat.credentials.Credential_Listener_ClientProxy.postPersist(Unknown Source)
cryostat_1  |   at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
cryostat_1  |   at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
cryostat_1  |   at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
cryostat_1  |   at java.base/java.lang.reflect.Method.invoke(Method.java:569)
cryostat_1  |   at org.hibernate.jpa.event.internal.ListenerCallback.performCallback(ListenerCallback.java:55)
cryostat_1  |   at org.hibernate.jpa.event.internal.CallbackRegistryImpl.callback(CallbackRegistryImpl.java:123)
cryostat_1  |   at org.hibernate.jpa.event.internal.CallbackRegistryImpl.postCreate(CallbackRegistryImpl.java:81)
cryostat_1  |   at org.hibernate.event.internal.PostInsertEventListenerStandardImpl.onPostInsert(PostInsertEventListenerStandardImpl.java:31)
cryostat_1  |   at org.hibernate.event.service.internal.EventListenerGroupImpl.fireLazyEventOnEachListener(EventListenerGroupImpl.java:116)
cryostat_1  |   at org.hibernate.action.internal.EntityInsertAction.postInsert(EntityInsertAction.java:191)
cryostat_1  |   at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:117)
cryostat_1  |   at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:632)
cryostat_1  |   at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:499)
cryostat_1  |   at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:363)
cryostat_1  |   at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:61)
cryostat_1  |   at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
cryostat_1  |   at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1370)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$2(ConcreteSqmSelectQueryPlan.java:136)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:381)
cryostat_1  |   at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:303)
cryostat_1  |   at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:509)
cryostat_1  |   at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:427)
cryostat_1  |   at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:564)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.common.runtime.CommonPanacheQueryImpl.singleResult(CommonPanacheQueryImpl.java:309)
cryostat_1  |   at io.quarkus.hibernate.orm.panache.runtime.PanacheQueryImpl.singleResult(PanacheQueryImpl.java:169)
cryostat_1  |   at io.cryostat.discovery.DiscoveryNode.getUniverse(DiscoveryNode.java:110)
cryostat_1  |   at io.cryostat.discovery.DiscoveryNode.getRealm(DiscoveryNode.java:114)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery.doCreate(CustomDiscovery.java:211)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery.createForm(CustomDiscovery.java:125)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery_Subclass.createForm$$superforward(Unknown Source)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery_Subclass$$function$$2.apply(Unknown Source)
cryostat_1  |   at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:73)
cryostat_1  |   at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:62)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:136)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:107)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.doIntercept(TransactionalInterceptorRequired.java:38)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.intercept(TransactionalInterceptorBase.java:61)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.intercept(TransactionalInterceptorRequired.java:32)
cryostat_1  |   at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired_Bean.intercept(Unknown Source)
cryostat_1  |   at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:42)
cryostat_1  |   at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:30)
cryostat_1  |   at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:27)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery_Subclass.createForm(Unknown Source)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery_ClientProxy.createForm(Unknown Source)
cryostat_1  |   at io.cryostat.discovery.CustomDiscovery$quarkusrestinvoker$createForm_f4044472152fe54bbb4ecf74155604fed0b3a814.invoke(Unknown Source)
cryostat_1  |   at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
cryostat_1  |   at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141)
cryostat_1  |   at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
cryostat_1  |   at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:582)
cryostat_1  |   at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
cryostat_1  |   at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
cryostat_1  |   at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
cryostat_1  |   at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
cryostat_1  |   at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
cryostat_1  |   at java.base/java.lang.Thread.run(Thread.java:840)
cryostat_1  | Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "matchexpression_pkey"
cryostat_1  |   Detail: Key (id)=(1) already exists.
cryostat_1  |   at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2725)
cryostat_1  |   at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2412)
cryostat_1  |   at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:371)
cryostat_1  |   at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:502)
cryostat_1  |   at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:419)
cryostat_1  |   at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:194)
cryostat_1  |   at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:155)
cryostat_1  |   at io.agroal.pool.wrapper.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:90)
cryostat_1  |   at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:194)
cryostat_1  |   ... 85 more

In short, something about the Credential/MatchExpression relationship, or the @PostPersist on Credentials, somehow results in two identical MatchExpression entities getting persisted, with the same ID, therefore colliding on the primary key and failing the request.

tthvo commented 1 month ago

Actually, that bug is unfortunately not solved with the V4 work. I also thought it might be with the Quarkus 3.8 upgrade, but it's still present there too - and even with Quarkus 3.8 + API v4.

Ahh that's unfortunate. For the time being, I have a simple workaround for this issue. Basically just send a follow-up API request to get the updated credential instance: https://github.com/cryostatio/cryostat-web/pull/1350