-
Notifications
You must be signed in to change notification settings - Fork 10
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
feat(API): remove API endpoints that redirect clients to newer API versioned endpoints #584
Changes from 36 commits
f680496
d816ae3
6df1c5c
b92a525
a784a5a
69f7183
dac2561
f76bb3e
db05ecb
ac788df
9ead30b
1be6449
3fb7647
3ae570e
8eb9ecd
a13d9bd
341afa3
87a2be2
7b11672
abc1c2b
7cfe3c2
310d698
b36924d
48f8fce
b021f6d
026656f
e0f1f76
9a22394
4280409
507aa2b
dcf3105
64ee073
eefdfec
1e72415
99cbae3
151e26e
0b39a72
44efc99
a5059cf
bc3b9fd
92fb3bf
38b2967
619571e
82b8af7
9268b79
12f7bea
932b1da
8eb70e8
f9b744a
f03063e
4208b3c
3e6b525
341008c
c2581cd
18dd343
304514e
b97d4e0
e5af31b
5499c95
0112785
b2760f7
1b5bf10
7f72b91
527b26d
88b8a77
1b2f8a2
e7cd344
68569d1
7cf8548
cc694f0
af0e0eb
1a69601
11d2341
9239f84
d4b8bc2
d212993
bb41533
d5383cc
a2d9102
7757ff5
5a9a347
a1fbb9f
06c38e2
7f79e59
3509828
9107b55
ca9efdd
9488092
9aea517
98366eb
0c27f07
62c0bc6
b161a2b
9cac11a
ddf6624
4c284e5
e573617
e47d2f2
d6dc5d5
9e20ebc
8b7b747
035010e
2056007
0725e07
9ed15b5
2bbff45
c580afd
f66c160
eb0c418
4f1bf09
0c063f7
bd929fe
de63dea
95ed1b8
f958f25
9ec970d
02b86f2
a76af08
22e7b59
6603da8
ab2cfd4
92b59ec
6ba5215
cef7606
fd01abf
cdd481f
bf14cdf
7656162
f5555d4
5f030bb
d0f87e6
56dea2b
8e45fe0
d9d17f3
7f2f69a
f0cd4fe
aa0dbdf
70566da
5b6faf0
eb52cd6
5d6413f
93d3703
08bb790
5a2acc3
d486c73
8df6dab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,6 @@ | |
import java.net.URISyntaxException; | ||
import java.util.Optional; | ||
|
||
import io.cryostat.V2Response; | ||
import io.cryostat.targets.Target; | ||
import io.cryostat.targets.TargetConnectionManager; | ||
|
||
|
@@ -29,7 +28,6 @@ | |
import jakarta.inject.Inject; | ||
import jakarta.ws.rs.POST; | ||
import jakarta.ws.rs.Path; | ||
import jakarta.ws.rs.core.Response.Status; | ||
import org.jboss.resteasy.reactive.RestForm; | ||
import org.jboss.resteasy.reactive.RestPath; | ||
|
||
|
@@ -42,7 +40,7 @@ public class CredentialCheck { | |
@Blocking | ||
@RolesAllowed("read") | ||
@Path("/api/beta/credentials/{connectUrl}") | ||
public Uni<V2Response> checkCredentialForTarget( | ||
public Uni<CredentialTestResult> checkCredentialForTarget( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @aali309 take a look at this change please - in this case it's better to just return the result type directly, rather than wrapping it in a JAX-RS Response. Quarkus will automatically set the Content-Type response header anyway, so this saves a couple of lines of code but also makes sure that the content negotiation between the Cryostat server and the user's browser properly determines the response format and header value. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This same simplification should be applied elsewhere too, unless there is a particular reason to wrap the result in a Response, but I think most of the time there won't be. |
||
@RestPath String connectUrl, @RestForm String username, @RestForm String password) | ||
throws URISyntaxException { | ||
Target target = Target.getTargetByConnectUrl(new URI(connectUrl)); | ||
|
@@ -74,8 +72,7 @@ public Uni<V2Response> checkCredentialForTarget( | |
|| connectionManager.isAgentAuthFailure( | ||
t)) | ||
.recoverWithItem(t -> CredentialTestResult.FAILURE); | ||
}) | ||
.map(r -> V2Response.json(Status.OK, r)); | ||
}); | ||
} | ||
|
||
static enum CredentialTestResult { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,70 +15,92 @@ | |
*/ | ||
package io.cryostat.credentials; | ||
|
||
import java.net.URI; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
import io.cryostat.V2Response; | ||
import io.cryostat.expressions.MatchExpression; | ||
import io.cryostat.expressions.MatchExpression.TargetMatcher; | ||
|
||
import io.smallrye.common.annotation.Blocking; | ||
import jakarta.annotation.security.RolesAllowed; | ||
import jakarta.inject.Inject; | ||
import jakarta.persistence.NoResultException; | ||
import jakarta.transaction.Transactional; | ||
import jakarta.ws.rs.DELETE; | ||
import jakarta.ws.rs.GET; | ||
import jakarta.ws.rs.POST; | ||
import jakarta.ws.rs.Path; | ||
import jakarta.ws.rs.core.Context; | ||
import jakarta.ws.rs.core.MediaType; | ||
import jakarta.ws.rs.core.Response; | ||
import jakarta.ws.rs.core.UriInfo; | ||
import org.jboss.logging.Logger; | ||
import org.jboss.resteasy.reactive.RestForm; | ||
import org.jboss.resteasy.reactive.RestPath; | ||
import org.jboss.resteasy.reactive.RestResponse; | ||
import org.jboss.resteasy.reactive.RestResponse.ResponseBuilder; | ||
import org.projectnessie.cel.tools.ScriptException; | ||
|
||
@Path("/api/v2.2/credentials") | ||
@Path("/api/v4/credentials") | ||
public class Credentials { | ||
|
||
@Inject TargetMatcher targetMatcher; | ||
@Inject Logger logger; | ||
|
||
@Blocking | ||
@GET | ||
@RolesAllowed("read") | ||
public V2Response list() { | ||
List<Credential> credentials = Credential.listAll(); | ||
return V2Response.json( | ||
Response.Status.OK, | ||
credentials.stream() | ||
.map( | ||
c -> { | ||
try { | ||
return Credentials.safeResult(c, targetMatcher); | ||
} catch (ScriptException e) { | ||
logger.warn(e); | ||
return null; | ||
} | ||
}) | ||
.filter(Objects::nonNull) | ||
.toList()); | ||
public Response list() { | ||
try { | ||
List<Credential> credentials = Credential.listAll(); | ||
List<Map<String, Object>> results = | ||
credentials.stream() | ||
.map( | ||
c -> { | ||
try { | ||
return safeResult(c, targetMatcher); | ||
} catch (ScriptException e) { | ||
logger.warn(e); | ||
return null; | ||
} | ||
}) | ||
.filter(Objects::nonNull) | ||
.toList(); | ||
|
||
return Response.ok(results).type(MediaType.APPLICATION_JSON).build(); | ||
} catch (Exception e) { | ||
logger.error("Error listing credentials", e); | ||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); | ||
} | ||
} | ||
|
||
@Blocking | ||
@GET | ||
@RolesAllowed("read") | ||
@Path("/{id}") | ||
public V2Response get(@RestPath long id) throws ScriptException { | ||
Credential credential = Credential.find("id", id).singleResult(); | ||
return V2Response.json(Response.Status.OK, safeMatchedResult(credential, targetMatcher)); | ||
public Response get(@RestPath long id) throws ScriptException { | ||
try { | ||
Credential credential = Credential.find("id", id).singleResult(); | ||
Map<String, Object> result = safeResult(credential, targetMatcher); | ||
return Response.ok(result).type(MediaType.APPLICATION_JSON).build(); | ||
} catch (ScriptException e) { | ||
logger.error("Error retrieving credential", e); | ||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); | ||
} catch (NoResultException e) { | ||
throw e; | ||
} catch (Exception e) { | ||
logger.error("Unexpected error occurred", e); | ||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); | ||
} | ||
} | ||
|
||
@Transactional | ||
@POST | ||
@RolesAllowed("write") | ||
public RestResponse<Void> create( | ||
public RestResponse<Credential> create( | ||
@Context UriInfo uriInfo, | ||
@RestForm String matchExpression, | ||
@RestForm String username, | ||
@RestForm String password) { | ||
|
@@ -89,7 +111,9 @@ public RestResponse<Void> create( | |
credential.username = username; | ||
credential.password = password; | ||
credential.persist(); | ||
return ResponseBuilder.<Void>created(URI.create("/api/v2.2/credentials/" + credential.id)) | ||
return ResponseBuilder.<Credential>created( | ||
uriInfo.getAbsolutePathBuilder().path(Long.toString(credential.id)).build()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @aali309 see this as well - I found this nice way to set the Location header in responses relative to the current request path. This pattern will apply most of the time to |
||
.entity(credential) | ||
.build(); | ||
} | ||
|
||
|
@@ -113,23 +137,15 @@ static Map<String, Object> notificationResult(Credential credential) throws Scri | |
return result; | ||
} | ||
|
||
@Blocking | ||
static Map<String, Object> safeResult(Credential credential, TargetMatcher matcher) | ||
throws ScriptException { | ||
Map<String, Object> result = new HashMap<>(); | ||
result.put("id", credential.id); | ||
result.put("matchExpression", credential.matchExpression); | ||
result.put( | ||
"numMatchingTargets", matcher.match(credential.matchExpression).targets().size()); | ||
return result; | ||
} | ||
|
||
@Blocking | ||
static Map<String, Object> safeMatchedResult(Credential credential, TargetMatcher matcher) | ||
throws ScriptException { | ||
Map<String, Object> result = new HashMap<>(); | ||
result.put("matchExpression", credential.matchExpression); | ||
result.put("targets", matcher.match(credential.matchExpression).targets()); | ||
// TODO remove numMatchingTargets, clients can just use targets.length | ||
var matchedTargets = matcher.match(credential.matchExpression).targets(); | ||
result.put("numMatchingTargets", matchedTargets.size()); | ||
result.put("targets", matchedTargets); | ||
return result; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
v2/graphql
can be removed now, right?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
v1 path should also be v4? @andrewazores
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please, everything should become v4 in this release.