Skip to content

Commit cb2591e

Browse files
authored
Refactor HCD Agents (#609)
* Update CC 4 version in HCD Agent. * Refactor HCD Agent modules
1 parent 903f024 commit cb2591e

32 files changed

+222
-70
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Changelog for Management API, new PRs should update the `main / unreleased` sect
1111

1212
## unreleased
1313
* [CHANGE] Remove Cassandra 4.0.16 from the build matrix due to a regression (https://issues.apache.org/jira/browse/CASSANDRA-20090)
14+
* [CHANGE] [#608](https://github.com/k8ssandra/management-api-for-apache-cassandra/issues/608) Refactor HCD Agents (cc4 vs cc5)
1415
* [FEATURE] [#601](https://github.com/k8ssandra/management-api-for-apache-cassandra/issues/602) Add Cassandra 4.0.17 to the build matrix
1516
* [FEATURE] [#603](https://github.com/k8ssandra/management-api-for-apache-cassandra/issues/603) Add DSE 6.8.54 to the build matrix
1617
* [FEATURE] [#604](https://github.com/k8ssandra/management-api-for-apache-cassandra/issues/604) Add DSE 6.9.7 to the build matrix

README.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -196,29 +196,29 @@ Example for DSE 6.9.0
196196

197197
** NOTE: The docker repo is not a typo, it really is `datastax/dse-mgmtapi-6_8` for 6.9 images
198198

199-
### Docker coordinates for HCD 1.0.x/1.2.x images
199+
### Docker coordinates for HCD 1.1.x/1.2.x images
200200

201-
#### Ubuntu based images (HCD 1.0/1.2)
201+
#### Ubuntu based images (HCD 1.1/1.2)
202202

203-
For all JDK 11 Ubuntu based HCD 1.0.x/1.2.x images, the Docker coordinates are as follows:
203+
For all JDK 11 Ubuntu based HCD 1.1.x/1.2.x images, the Docker coordinates are as follows:
204204

205205
datastax/hcd:<version>
206206

207-
Example for HCD 1.0.0
207+
Example for HCD 1.1.0
208208

209-
datastax/hcd:1.0.0
209+
datastax/hcd:1.1.0
210210

211211
Example for HCD 1.2.0
212212

213213
datastax/hcd:1.2.0
214214

215-
#### RedHat UBI images (HCD 1.0/1.2)
215+
#### RedHat UBI images (HCD 1.1/1.2)
216216

217-
For all RedHat UBI based HCD 1.0.x/1.2.x images, the Docker coordinates are as follows:
217+
For all RedHat UBI based HCD 1.1.x/1.2.x images, the Docker coordinates are as follows:
218218

219219
datastax/hcd:<version>-ubi
220220

221-
Example for HCD 1.0.0
221+
Example for HCD 1.1.0
222222

223223
datastax/hcd:1.0.0-ubi
224224

management-api-agent-hcd/README.md management-api-agent-hcd-cc4/README.md

+9-14
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
It is important to note that all HCD dependencies should only be specified in the HCD agent modules. No HCD dependencies
44
can be added to any other projects/modules, as users without access to HCD artifacts won't be able to build the OSS Management API.
55

6-
## HCD versions
6+
## HCD versions (hcd-cc4 vs hcd-cc5)
77

8-
As of this document edit, there are 2 versions of HCD in development. Version 1.0.x is currently maintained on the `hcd-1.0` branch
9-
of the HCD repository. Version 1.2.x is maintained on the `main` branch of the repository. The major difference between the two
10-
versions is the Converged Cassandra Core that is used. HCD 1.0.x uses Converged Core 4, while HCD 1.2.x uses Converged Core 5. As
11-
with Cassandra versions, the HCD agent has to be broken into 2 sub-modules for compiling compatibility. The version in this
12-
sub-module is for HCD 1.0.x. For HCD 1.2.x, use the agent in sub-module `management-api-agent-hcd-1.2.x`.
8+
As of this document edit, there are 2 versions of HCD in development. Version 1.1.x is currently maintained on the `hcd-1.1` branch
9+
of the HCD repository. Version 1.2.x is maintained on the `main` branch of the repository. Until recently, HCD 1.2 was based on
10+
Converged Cassandra (Converged Core/CC) 5, while HCD 1.1 is based on CC 4. Soon, HCD 1.2 will switch to CC 4, meaning a future release
11+
of HCD 2.x will be based on CC 5. To make things a little easier to follow from this project's view, as of v0.1.97, the Management
12+
API Agent for HCD will be CC based. This Readme is in the `hcd-cc4` Agent. There is an equivalent one in the `hcd-cc5` Agent. You
13+
must pick the one that your HCD code is based on for it to work properly.
1314

1415
## Maven Settings
1516

@@ -37,18 +38,12 @@ OUT OF SCOPE: At the moment, no HCD images are being built as part of this proje
3738

3839
OUT OF SCOPE: At the moment, no HCD images are being built as part of this project. They are built from the HCD repo currently.
3940

40-
If you have access to the HCD repository, you can build an image from the `hcd-1.0` branch. Use the following from the HCD repository root:
41+
If you have access to the HCD repository, you can build an image from the `hcd-1.1` branch. Use the following from the HCD repository root:
4142

4243
```sh
43-
./mvnw clean verify
44+
./mvnw clean package
4445
```
4546

46-
### Building a specific version of HCD
47-
48-
HCD versions are maintained in branch names with the format `hcd-<major>.<minor>` (for example `hcd-1.1`). The latest/current version
49-
pf HCD will be in the `main` branch (version 1.2.x as of this edit). Building a specific versions of HCD simply requires you to checkout
50-
the version bracnh (or `main` if you wanto build the latest version) and build as above.
51-
5247
## Running a locally built image
5348

5449
To run an image you built locally with Management API enabled, run the following:

management-api-agent-hcd/pom.xml management-api-agent-hcd-cc4/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<version>${revision}</version>
1515
</parent>
1616
<version>${revision}</version>
17-
<artifactId>datastax-mgmtapi-agent-hcd</artifactId>
17+
<artifactId>datastax-mgmtapi-agent-hcd-cc4</artifactId>
1818
<repositories>
1919
<repository>
2020
<id>artifactory</id>
@@ -79,7 +79,7 @@
7979
<dependency>
8080
<groupId>com.datastax.dse</groupId>
8181
<artifactId>dse-db-all</artifactId>
82-
<version>4.0.11-3b5d38811943</version>
82+
<version>4.0.11-21b99d7386fd</version>
8383
<exclusions>
8484
<exclusion>
8585
<groupId>commons-codec</groupId>

management-api-agent-hcd/src/main/java/org/apache/cassandra/transport/UnixSocketServerHcd.java management-api-agent-hcd-cc4/src/main/java/org/apache/cassandra/transport/UnixSocketServerHcd.java

+109-22
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
import io.netty.channel.VoidChannelPromise;
1818
import io.netty.handler.codec.ByteToMessageDecoder;
1919
import io.netty.util.Attribute;
20+
import java.lang.reflect.Method;
2021
import java.util.ArrayList;
2122
import java.util.HashMap;
2223
import java.util.List;
2324
import java.util.Map;
25+
import java.util.concurrent.CompletableFuture;
2426
import org.apache.cassandra.auth.IAuthenticator;
2527
import org.apache.cassandra.cql3.QueryProcessor;
2628
import org.apache.cassandra.service.ClientState;
@@ -62,7 +64,7 @@ protected void initChannel(Channel channel) throws Exception {
6264
INITIAL_HANDLER,
6365
new PipelineChannelInitializer(
6466
new Envelope.Decoder(),
65-
(channel1, version) ->
67+
(Channel channel1, ProtocolVersion version) ->
6668
new UnixSocketConnection(channel1, version, connectionTracker)));
6769
/**
6870
* The exceptionHandler will take care of handling exceptionCaught(...) events while still
@@ -82,7 +84,6 @@ static class UnixSockMessage extends SimpleChannelInboundHandler<Message.Request
8284
@Override
8385
protected void channelRead0(ChannelHandlerContext ctx, Message.Request request)
8486
throws Exception {
85-
final Message.Response response;
8687
final UnixSocketConnection connection;
8788
long queryStartNanoTime = System.nanoTime();
8889

@@ -98,15 +99,35 @@ protected void channelRead0(ChannelHandlerContext ctx, Message.Request request)
9899
// logger.info("Executing {} {} {}", request, connection.getVersion(),
99100
// request.getStreamId());
100101

101-
Message.Response r = request.execute(qstate, queryStartNanoTime);
102-
103-
// UnixSocket has no auth
104-
response = r instanceof AuthenticateMessage ? new ReadyMessage() : r;
102+
// Converged Cassandra/Core 4 added Async processing as part of CNDB-10759. See if we have
103+
// the method that returns a CompletableFuture.
104+
try {
105+
Method requestExecute =
106+
Message.Request.class.getDeclaredMethod("execute", QueryState.class, long.class);
107+
// get CompletableFuture type
108+
if (CompletableFuture.class.equals(requestExecute.getReturnType())) {
109+
// newer Async processing
110+
CompletableFuture<Message.Response> future =
111+
(CompletableFuture<Message.Response>)
112+
requestExecute.invoke(request, qstate, queryStartNanoTime);
113+
future.whenComplete(
114+
(Message.Response response, Throwable ignore) -> {
115+
processMessageResponse(response, request, connection, ctx);
116+
});
117+
} else if (Message.Response.class.equals(requestExecute.getReturnType())) {
118+
// older non-async processing
119+
Message.Response response =
120+
(Message.Response) requestExecute.invoke(request, qstate, queryStartNanoTime);
105121

106-
response.setStreamId(request.getStreamId());
107-
response.setWarnings(ClientWarn.instance.getWarnings());
108-
response.attach(connection);
109-
connection.applyStateTransition(request.type, response.type);
122+
processMessageResponse(response, request, connection, ctx);
123+
}
124+
} catch (NoSuchMethodException ex) {
125+
// Unexepected missing method, throw an error and figure out what method signature we have
126+
logger.error(
127+
"Expected Cassandra Message.Request.execute() method signature not found. Management API agent will not be able to start Cassandra.",
128+
ex);
129+
throw ex;
130+
}
110131
} catch (Throwable t) {
111132
// logger.warn("Exception encountered", t);
112133
JVMStabilityInspector.inspectThrowable(t);
@@ -119,7 +140,21 @@ protected void channelRead0(ChannelHandlerContext ctx, Message.Request request)
119140
} finally {
120141
ClientWarn.instance.resetWarnings();
121142
}
143+
}
122144

145+
private void processMessageResponse(
146+
Message.Response response,
147+
Message.Request request,
148+
final UnixSocketConnection connection,
149+
ChannelHandlerContext ctx) {
150+
if (response instanceof AuthenticateMessage) {
151+
// UnixSocket has no auth
152+
response = new ReadyMessage();
153+
}
154+
response.setStreamId(request.getStreamId());
155+
response.setWarnings(ClientWarn.instance.getWarnings());
156+
response.attach(connection);
157+
connection.applyStateTransition(request.type, response.type);
123158
ctx.writeAndFlush(response);
124159
request.getSource().release();
125160
}
@@ -284,18 +319,56 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> ou
284319

285320
promise = new VoidChannelPromise(ctx.channel(), false);
286321

287-
Message.Response response =
288-
Dispatcher.processRequest(
289-
(ServerConnection) connection, startup, ClientResourceLimits.Overload.NONE);
290-
291-
if (response.type.equals(Message.Type.AUTHENTICATE))
292-
// bypass authentication
293-
response = new ReadyMessage();
294-
295-
outbound = response.encode(inbound.header.version);
296-
ctx.writeAndFlush(outbound, promise);
297-
logger.debug("Configured pipeline: {}", ctx.pipeline());
298-
break;
322+
// More Converged Cassandra/Core 4 changes for Async processing. This is generally a
323+
// copy of upstream's InitConnectionHandler.
324+
325+
// Try to get the newer processInit static method
326+
try {
327+
Method processInit =
328+
Dispatcher.class.getDeclaredMethod(
329+
"processInit", ServerConnection.class, StartupMessage.class);
330+
((CompletableFuture<Message.Response>)
331+
processInit.invoke(null, (ServerConnection) connection, startup))
332+
.whenComplete(
333+
(Message.Response response, Throwable error) -> {
334+
if (error == null) {
335+
processStartupResponse(response, inbound, ctx, promise);
336+
} else {
337+
ErrorMessage message =
338+
ErrorMessage.fromException(
339+
new ProtocolException(
340+
String.format("Unexpected error %s", error.getMessage())));
341+
Envelope encoded = message.encode(inbound.header.version);
342+
ctx.writeAndFlush(encoded);
343+
}
344+
});
345+
break;
346+
} catch (NoSuchMethodException nsme) {
347+
// try the older processRequest method
348+
try {
349+
Method processRequest =
350+
Dispatcher.class.getDeclaredMethod(
351+
"processRequest",
352+
ServerConnection.class,
353+
StartupMessage.class,
354+
ClientResourceLimits.Overload.class);
355+
Message.Response response =
356+
(Message.Response)
357+
processRequest.invoke(
358+
null,
359+
(ServerConnection) connection,
360+
startup,
361+
ClientResourceLimits.Overload.NONE);
362+
processStartupResponse(response, inbound, ctx, promise);
363+
break;
364+
} catch (NoSuchMethodException nsme2) {
365+
// Expected method not found. Log an error and figure out what signature we need
366+
logger.error(
367+
"Expected Cassandra Dispatcher.processRequest() method signature not found. Management API agent will not be able to start Cassandra.",
368+
nsme2);
369+
throw nsme2;
370+
}
371+
}
299372

300373
default:
301374
ErrorMessage error =
@@ -311,5 +384,19 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> ou
311384
inbound.release();
312385
}
313386
}
387+
388+
private void processStartupResponse(
389+
Message.Response response,
390+
Envelope inbound,
391+
ChannelHandlerContext ctx,
392+
ChannelPromise promise) {
393+
if (response.type.equals(Message.Type.AUTHENTICATE)) {
394+
// bypass authentication
395+
response = new ReadyMessage();
396+
}
397+
Envelope encoded = response.encode(inbound.header.version);
398+
ctx.writeAndFlush(encoded, promise);
399+
logger.debug("Configured pipeline: {}", ctx.pipeline());
400+
}
314401
}
315402
}
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Management API with HCD (Hyper-Converged Database)
2+
3+
It is important to note that all HCD dependencies should only be specified in the HCD agent modules. No HCD dependencies
4+
can be added to any other projects/modules, as users without access to HCD artifacts won't be able to build the OSS Management API.
5+
6+
## HCD versions (hcd-cc4 vs hcd-cc5)
7+
8+
As of this document edit, there are 2 versions of HCD in development. Version 1.1.x is currently maintained on the `hcd-1.1` branch
9+
of the HCD repository. Version 1.2.x is maintained on the `main` branch of the repository. Until recently, HCD 1.2 was based on
10+
Converged Cassandra (Converged Core/CC) 5, while HCD 1.1 is based on CC 4. Soon, HCD 1.2 will switch to CC 4, meaning a future release
11+
of HCD 2.x will be based on CC 5. To make things a little easier to follow from this project's view, as of v0.1.97, the Management
12+
API Agent for HCD will be CC based. This Readme is in the `hcd-cc5` Agent. There is an equivalent one in the `hcd-cc4` Agent. You
13+
must pick the one that your HCD code is based on for it to work properly.
14+
15+
## Maven Settings
16+
17+
In order to build Management API artifacts for HCD (jarfiles and/or Docker images), you will need to have access to the DSE Maven
18+
Artifactory. This will require credentials that should be stored in your `${HOME}/.m2/settings.xml` file.
19+
20+
## Building the Management API with HCD
21+
22+
A special `hcd` profile was created when building the Management API with HCD dependencies. The required maven command is as following:
23+
24+
```sh
25+
mvn package -P hcd
26+
```
27+
28+
## Running tests for the HCD Agent
29+
30+
TODO: The tests have not yet been adapted to run against HCD as this would require copying the HCD Docker image build from DSE repos,
31+
which is an ongoing effort.
32+
33+
## Docker image builds
34+
35+
OUT OF SCOPE: At the moment, no HCD images are being built as part of this project. They are built from the HCD repo currently.
36+
37+
### Building HCD images locally
38+
39+
OUT OF SCOPE: At the moment, no HCD images are being built as part of this project. They are built from the HCD repo currently.
40+
41+
If you have access to the HCD repository, you can build an image from the `main` branch. Use the following from the HCD repository root:
42+
43+
```sh
44+
./mvnw clean package
45+
```
46+
47+
## Running a locally built image
48+
49+
To run an image you built locally with Management API enabled, run the following:
50+
51+
```sh
52+
docker run -e DS_LICENSE=accept -e USE_MGMT_API=true -p 8080:8080 --name hcd my-hcd
53+
```
54+
55+
where `my-hcd` is the tag of the image you built (you must have access to the BDP repo to build an image).

management-api-agent-hcd-1.2.x/pom.xml management-api-agent-hcd-cc5/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<version>${revision}</version>
1515
</parent>
1616
<version>${revision}</version>
17-
<artifactId>datastax-mgmtapi-agent-hcd-1.2.x</artifactId>
17+
<artifactId>datastax-mgmtapi-agent-hcd-cc5</artifactId>
1818
<repositories>
1919
<repository>
2020
<id>artifactory</id>

0 commit comments

Comments
 (0)