I want to get the status code of my command executed in a container with Fabric8 Java Kubernetes client.
Here is the script located in my container:
echo Bye Bye
exit 1
When I run the script with CLI or NodeJS Client I am able to get the output status code
Here is an example taken from fabric8 repository:
package org.package;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.dsl.ExecListener;
import io.fabric8.kubernetes.client.dsl.ExecWatch;
import okhttp3.Response;
public class OtherMain {
public static void main(String[] args) throws InterruptedException {
String podName = "my-pod";
String namespace = "my-namespace";
try (
KubernetesClient client = new DefaultKubernetesClient();
ExecWatch watch = newExecWatch(client, namespace, podName)) {
Thread.sleep(10 * 1000L);
}
}
private static ExecWatch newExecWatch(KubernetesClient client, String namespace, String podName) {
return client.pods()
.inNamespace(namespace)
.withName(podName)
.readingInput(System.in)
.writingOutput(System.out)
.writingError(System.err)
.withTTY()
.usingListener(new SimpleListener())
.exec("sh", "test.sh");
}
private static class SimpleListener implements ExecListener {
#Override
public void onOpen(Response response) {
System.out.println("The shell will remain open for 10 seconds.");
}
#Override
public void onFailure(Throwable t, Response response) {
System.err.println("shell barfed");
}
#Override
public void onClose(int code, String reason) {
System.out.println("The shell will now close.");
}
}
}
However when looking at the output it seems that everything went ok. Is there a way to get the output status code ?
It is possible by using the wri method:
Can use the .writingErrorChannel and parse the response:
{
"metadata": {},
"status": "Failure",
"message": "command terminated with non-zero exit code: exit status 1",
"reason": "NonZeroExitCode",
"details": {
"causes": [
{
"reason": "ExitCode",
"message": "1"
}
]
}
}
Type is: io.fabric8.kubernetes.api.model.Status
Since 6.x versions of Fabric8 Kubernetes Client, a new exitCode() method has been added to ExecWatch interface which returns a CompletableFuture<Integer>, so now you should be able to get exit code like this:
ExecWatch execWatch = client.pods().inNamespace("default").withName("example-pod")
.writingOutput(System.out)
.writingError(System.out)
.exec("/bin/ping", "goo");
// ...
int exitCode = execWatch.exitCode().get();
Related
I have a service that is making use of the Quarkus Event bus. Quarkus version in use is 2.9.0.CR1
When I run my tests through intellij, all tests pass and i do not get issues. However, when I try to run with mvn clean install from command line, I am getting this excpetion:
(RECIPIENT_FAILURE,8185) java.nio.BufferOverflowException
at io.vertx.core.eventbus.Message.fail(Message.java:141)
at io.quarkus.vertx.runtime.VertxRecorder$3$1$1.handle(VertxRecorder.java:117)
at io.quarkus.vertx.runtime.VertxRecorder$3$1$1.handle(VertxRecorder.java:107)
at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:548)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
The object I am trying to send over the event bus is this:
public record TransportSendMessage(MimeMessage message, String from, String to) {
}
(For the record, the MimeMessage in that is the jakarta one to send mail with. It also contains an image as an attachment in it, so it is posisble that there isa bit of heft to the message in terms of bytes)
The Codec for this is:
public class TransportSendMessageCodec implements MessageCodec<TransportSendMessage, TransportSendMessage> {
#Override
public void encodeToWire(Buffer buffer, TransportSendMessage scheduledPubsubMessage) {
// NO-OP
}
#Override
public TransportSendMessage decodeFromWire(int pos, Buffer buffer) {
// NO-OP
return null;
}
#Override
public TransportSendMessage transform(TransportSendMessage transportSendMessage) {
// we pass the object by reference over the eventbus.
return transportSendMessage;
}
#Override
public String name() {
return getClass().getName();
}
#Override
public byte systemCodecID() {
return -1;
}
}
My handler class:
#Slf4j
#Startup
#ApplicationScoped
public class TransportSendHandler {
public static final String TRANSPORT_HANDLER_EVENT_BUS_ADDRESS = "emailTransportSendEventBus";
#Inject
EventBus eventBus;
#PostConstruct
public void init() {
eventBus.registerCodec(new TransportSendMessageCodec());
}
/**
* We consume a message from the event bus. The message received will then be emailed
*
* #param message The message to email
*/
#ConsumeEvent(value = TRANSPORT_HANDLER_EVENT_BUS_ADDRESS)
#Blocking
public Uni<Void> consumeMessage(TransportSendMessage message) {
try {
log.debug("Attempting to send email: from {}, to {}", message.from(), message.to());
Transport.send(message.message());
log.debug("Email has been sent: from {}, to {} ", message.from(), message.to());
return Uni.createFrom().voidItem();
} catch (MessagingException e) {
log.warn("Failed sending email: from {}, to {}", message.from(), message.to());
return Uni.createFrom().failure(e);
}
}
}
And the code sending the message:
eventBus.request(TransportSendHandler.TRANSPORT_HANDLER_EVENT_BUS_ADDRESS,
new TransportSendMessage(myMimeMessage, fromADdress, toAddress)))
I'm a bit lost really as to why this is happening just when run from command line.
I want to group exception with Sentry, the exception comes from different servers, but I want all exception by type together, for example, all NPE be grouped. I know you can extend EventBuilderHelper and this is how sentry group things, but sentry java doesn't provide features to send an event with fingerprints of the method, error type, etc, as others SDK like this example in docs.sentry.io
function makeRequest(method, path, options) {
return fetch(method, path, options).catch(err => {
Sentry.withScope(scope => {
// group errors together based on their request and response
scope.setFingerprint([method, path, err.statusCode]);
Sentry.captureException(err);
});
});
}
this is what I try to do, but in this scope, don't have knowledge about method, error, etc.
package com.test;
import io.sentry.SentryClient;
import io.sentry.event.EventBuilder;
import io.sentry.event.helper.ContextBuilderHelper;
public class FingerprintEventBuilderHelper extends ContextBuilderHelper {
private static final String EXCEPTION_TYPE = "exception_type";
public FingerprintEventBuilderHelper(SentryClient sentryClient) {
super(sentryClient);
}
#Override
public void helpBuildingEvent(EventBuilder eventBuilder) {
super.helpBuildingEvent(eventBuilder);
//Get the exception type
String exceptionType =
if (exceptionType != null) {
eventBuilder.withTag(EXCEPTION_TYPE, exceptionType);
}
//Get method information and params
if (paramX != null) {
eventBuilder.withTag("PARAM", paramX);
}
}
}
the json send to the server has some information about the exception, but I dont know hoy to get it
...
"release": null,
"dist": null,
"platform": "java",
"culprit": "com.sun.ejb.containers.BaseContainer in checkExceptionClientTx",
"message": "Task execution failed",
"datetime": "2019-06-26T14:13:29.000000Z",
"time_spent": null,
"tags": [
["logger", "com.test.TestService"],
["server_name", "localhost"],
["level", "error"]
],
"errors": [],
"extra": {
"Sentry-Threadname": "MainThread",
"rid": "5ff37e943-f4b4-4hc9-870b-4f8c4d18cf84"
},
"fingerprint": ["{{ default }}"],
"key_id": 3,
"metadata": {
"type": "NullPointerException",
"value": ""
},
...
You can get the type of exception that was raised, but I have my doubts about getting the parameters related to functions in the trace
EventBuilderHelper myEventBuilderHelper = new EventBuilderHelper() {
public void helpBuildingEvent(EventBuilder eventBuilder) {
eventBuilder.withMessage("Overwritten by myEventBuilderHelper!");
Map<String, SentryInterface> ifs = eventBuilder.getEvent().getSentryInterfaces();
if (ifs.containsKey("sentry.interfaces.Exception"))
{
ExceptionInterface exI = (ExceptionInterface) ifs.get("sentry.interfaces.Exception");
for (SentryException ex: exI.getExceptions()){
String exceptionType = ex.getExceptionClassName();
}
}
}
};
If you look at the sendException method of the client, it initiates the ExceptionInterface with the actual Exception
public void sendException(Throwable throwable) {
EventBuilder eventBuilder = (new EventBuilder()).withMessage(throwable.getMessage()).withLevel(Level.ERROR).withSentryInterface(new ExceptionInterface(throwable));
this.sendEvent(eventBuilder);
}
And the constructor for the same is like
public ExceptionInterface(Throwable throwable) {
this(SentryException.extractExceptionQueue(throwable));
}
public ExceptionInterface(Deque<SentryException> exceptions) {
this.exceptions = exceptions;
}
So each exception get converted to a SentryException, but the original exception is not stored. So if you need params also, you will need to throw a custom exception with those parameter and also override the sendException method, not a straightforward way
I am trying to add a restful api to a java microservice. For this, I am using spark:
http://sparkjava.com/documentation.html
I've created a very simple class which stands up an api. That class is here:
public class Routes {
public void establishRoutes(){
get("/test", (req, res) -> "Hello World");
after((req, res) -> {
res.type("application/json");
});
exception(IllegalArgumentException.class, (e, req, res) -> {
res.status(400);
});
}
Now, running Routes.establishRoutes() should stand up an api which would show "Hello World" in the event someone decides to visit http://localhost:4567/test. This does actually work. Hurray!
The next step is unit testing the code. My unit test, unfortunately, does not succeed. The spark documentation does not detail a sound way for doing testing so what I have is pieced together from examples I found around the net. Here is my Junit test:
public class TestRoutes {
#Before
public void setUp() throws Exception {
Routes newRoutes = new Routes();
newRoutes.establishRoutes();
}
#After
public void tearDown() throws Exception {
stop();
}
#Test
public void testModelObjectsPOST(){
String testUrl = "/test";
ApiTestUtils.TestResponse res = ApiTestUtils.request("GET", testUrl, null);
Map<String, String> json = res.json();
assertEquals(201, res.status);
}
Here is the code behind ApiTestUtils.request():
public class ApiTestUtils {
public static TestResponse request(String method, String path, String requestBody) {
try {
URL url = new URL("http://localhost:4567" + path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(method);
connection.setDoOutput(true);
connection.connect();
String body = IOUtils.toString(connection.getInputStream());
return new TestResponse(connection.getResponseCode(), body);
} catch (IOException e) {
e.printStackTrace();
fail("Sending request failed: " + e.getMessage());
return null;
}
}
public static class TestResponse {
public final String body;
public final int status;
public TestResponse(int status, String body) {
this.status = status;
this.body = body;
}
public Map<String,String> json() {
return new Gson().fromJson(body, HashMap.class);
}
}
}
I am failing on connection.connect() inside ApiTestUtils.request(). Specifically, I get the error: java.lang.AssertionError: Sending request failed: Connection refused
I believe this is happening because the application isn't listening when my test tries to make the request. However, I don't understand why that would be the case. I borrowed the test code from the demo project found here:
https://github.com/mscharhag/blog-examples/blob/master/sparkdemo/src/test/java/com/mscharhag/sparkdemo/UserControllerIntegrationTest.java
UPDATE:
I tried running the example linked above. Turns out, it doesn't work either. Looks like spinning up a spark instance in this context is more difficult than I thought? I'm not trying to figure out how to do so.
In your test case is missing the code used for waiting the initialization of the embedded server.
I've tried your code and stumbled on the same issue as you did, but after debugging it I've noticed that the embedded spark server is initialized in a newly created thread. ( see the method spark.Service#init()).
All you need to do in your test is to await for the initialization by calling the method spark.Spark#awaitInitialization()
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static junit.framework.TestCase.assertEquals;
import static spark.Spark.awaitInitialization;
import static spark.Spark.stop;
public class TestRoutes {
#Before
public void setUp() throws Exception {
Routes newRoutes = new Routes();
newRoutes.establishRoutes();
awaitInitialization();
}
#After
public void tearDown() throws Exception {
stop();
}
#Test
public void testModelObjectsPOST() {
String testUrl = "/test";
ApiTestUtils.TestResponse res = ApiTestUtils.request("GET", testUrl, null);
assertEquals(200, res.status);
}
}
I can't help you with Spark, but if you're open to trying an alternative lightweight Java library for writing micro services, have a look at Molecule.
You'll find documentation and examples for writing unit tests and integration tests. If I understand what you're trying to test correctly, the test would look like:
HttpRequest request = new HttpRequest(4567);
HttpResponse response = request.get("/test");
assertThat(response).hasStatusCode(201)
.hasContentType("application/json")
.hasBodyText("Hello World");
We have a SignalR hub. The following jQuery code connects and properly processes SignalR client "call" events successfully on cordova.
var connectionURL = "https://SOMEURL.azurewebsites.net/message";
connection = $.connection(connectionURL);
connection.start().done(function () {
console.log("Connected to hub again");
});
connection.disconnected(function () {
setTimeout(function () {
connection.start().done(function () {
console.log("Disconnected and Connected to hub again");
});
}, 5000);
});
connection.stateChanged(function (change) {
if (change.newState == $.signalR.connectionState.reconnecting) {
}
else if (change.newState == $.signalR.connectionState.connected) {
}
else if (change.newState == $.signalR.connectionState.disconnected) {
}// else if
});
connection.received(function (data) {
connectId = connection.id + "";
console.log("onDeviceReady run");
// call the function to parse the data
if (data.PayloadType == "Dispatch") {
dataDispatch(data);
}
if (data.PayloadType == "ConnectionAcknowledge") {
sendConnectionAcknowledge(data);
}
});
However when I try to emulate this code in java android using the SignalR Java Client, I get a lot of log output (tonnes), and no connection ever finishes. it gets as far as the debug at line awaitConnection.get(); and never prints the second line of debug, instead it prints endless (thousands) of lines of semi gibberish (it's not piping, it's like it's some sort of "SSL handshake" but it's not doing anything but logging the same thing repeatedly, very odd) anyway it never runs the 2nd line of "my" debug
package com.some.thing;
import android.util.Log;
import java.util.concurrent.ExecutionException;
import microsoft.aspnet.signalr.client.Platform;
import microsoft.aspnet.signalr.client.SignalRFuture;
import microsoft.aspnet.signalr.client.http.android.AndroidPlatformComponent;
import microsoft.aspnet.signalr.client.hubs.HubConnection;
import microsoft.aspnet.signalr.client.hubs.HubProxy;
import microsoft.aspnet.signalr.client.hubs.SubscriptionHandler1;
public class SignalRClient {
public static void startConnection() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
String host = "https://SOMEURL.azurewebsites.net/message";
HubConnection connection = new HubConnection(host);
HubProxy hub = connection.createHubProxy( "IDoNoHaveThisNorKnowIt" );
SignalRFuture<Void> awaitConnection = connection.start();
try {
Log.v("CONANSignalR :=", "CONNECTING");
awaitConnection.get();
Log.v("CONANSignalR :=", "CONNECTED");
} catch (InterruptedException e) {
// Handle ...
} catch (ExecutionException e) {
// Handle ...
}
hub.on("IDoNotKnowThisEither", new SubscriptionHandler1<String>(){
#Override
public void run( String status ){
Log.v("CONANDispatch :=", status);
}
}, String.class);
}
}
Can anyone help me translate the working, jQuery SignalR client code into usable java client code? I don't have any information on the hub so I cannot know the proxy or the function names, I'd like to see everything (like the jQuery).
EDIT
To test things, I have altered my original jquery code it use to say
console.log("onDeviceReady run");
now it says
console.log("SignalR Raw Data:" + JSON.stringify(data));
when I do this this is what the jquery returns
SignalR Raw Data:{"ConnectionId":"9c4b4ba5-cb6e-4dcb-8df9-069cbf749873","OrderId":null,"SenderId":null,"PayloadType":"ConnectionAck","Message":"Welcome, you are connected to the Hub!","Payload":null,"Initiator":"HUB","Version":null}
however none of this appears inside the java equivalent
connection.received(new MessageReceivedHandler() {
#Override
public void onMessageReceived(JsonElement json) {
System.out.println("RAW received message: " + json.toString());
// ADD HANDLING OF RECEIVED IN HERE
}
});
i.e. the text "RAW received message:" doesn't appear at all
Since you don't know hub name, you have to use handle events on connection object directly (like you do in js client).
Here is sample code which could get you started (note, this is not tested, written just from top of my head):
public static void startConnection() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
String host = "https://SOMEURL.azurewebsites.net/message";
HubConnection connection = new HubConnection(host);
// subscribe to received - equal to `connection.received(function (data)` from javascript
connection.received(new MessageReceivedHandler() {
#Override
public void onMessageReceived(JsonElement json) {
System.out.println("RAW received message: " + json.toString());
// ADD HANDLING OF RECEIVED IN HERE
}
});
// equal to `connection.disconnected(function ()` from javascript
connection.closed(new Runnable() {
#Override
public void run() {
// ADD CODE TO HANDLE DISCONNECTED EVENT
}
});
// equal to `connection.stateChanged(function (change)`
connection.stateChanged(new StateChangedCallback() {
#Override
public void stateChanged(ConnectionState oldState, ConnectionState newState) {
// ADD CODE TO HANDLE STATE CHANGES
}
});
// start the connection
connection.start()
.done(new Action<Void>() {
#Override
public void run(Void obj) throws Exception {
System.out.println("Connected");
}
});
}
Also, I recommend you to check sample chat client for java which can be found here: https://github.com/SignalR/java-samples/blob/master/signalr-sample-chat/src/microsoft/aspnet/signalr/samples/chat/Program.java
Most of code I posted is based on that one.
I'm playing around with my new toy, JCC 2.21, and am having trouble implementing callbacks in a python script. I have wrapped the following simple Java thread API and am calling it from python 2.7 (CPython), but when I call the JccTest.addJccTestListener(JccTestListener) method, the JVM reports a null argument.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class JccTest implements Runnable {
private final Object listenersLock = new Object();
private final List<JccTestListener> listeners = new ArrayList<JccTestListener>();
private final AtomicBoolean running = new AtomicBoolean(false);
private final AtomicBoolean finished = new AtomicBoolean(false);
public void start() {
if (running.compareAndSet(false, true)) {
new Thread(this).start();
}
}
public void stop() {
finished.set(true);
}
public void addJccTestListener(JccTestListener l) {
if (l == null) {
throw new IllegalArgumentException("argument must be non-null");
}
synchronized (listenersLock) {
listeners.add(l);
}
}
public void removeJccTestListener(JccTestListener l) {
synchronized (listenersLock) {
listeners.remove(l);
}
}
#Override
public void run() {
System.out.println("Start");
while (!finished.get()) {
System.out.println("Notifiying listeners");
synchronized (listenersLock) {
for (JccTestListener l : listeners) {
System.out.println("Notifiying " + String.valueOf(l));
l.message("I'm giving you a message!");
}
}
System.out.println("Sleeping");
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
continue;
}
}
running.set(false);
System.out.println("Stop");
}
public static void main(String[] args) throws InterruptedException {
JccTest test = new JccTest();
test.addJccTestListener(new JccTestListener() {
#Override
public void message(String msg) {
// called from another thread
System.out.println(msg);
}
});
test.start();
Thread.sleep(10000);
test.stop();
}
}
public interface JccTestListener {
public void message(String msg);
}
Generated wrapper with:
python -m jcc --jar jcc-test.jar --python jcc_test --build --install
And then executed this script (equivalent to the main method of JccTest):
import jcc_test
import time, sys
jcc_test.initVM(jcc_test.CLASSPATH)
test = jcc_test.JccTest()
class MyListener(jcc_test.JccTestListener):
def __init__(self):
pass
def message(self, msg):
print msg
test.addJccTestListener(MyListener())
test.start()
time.sleep(10)
test.stop()
sys.exit(0)
Which results in:
"python.exe" jcc_test_test.py
Traceback (most recent call last):
File "jcc_test_test.py", line 16, in <module>
test.addJccTestListener(MyListener())
jcc_test.JavaError: java.lang.IllegalArgumentException: argument must be non-null
Java stacktrace:
java.lang.IllegalArgumentException: argument must be non-null
at com.example.jcc.JccTest.addJccTestListener(JccTest.java:32)
Besides the null listener instance, is doing something like this even possible with CPython? I've read that in its implementation only one thread may execute the python script at a time, which might (?) be a problem for me. Doing something like this with Jython was trivial.
I'm rather new to python so please be gentle.
Figured it out. You need to define a pythonic extension for a java class to make this work. The detailed procedure is described in JCC documentation (Writing Java class extensions in Python) and is rather simple.
First, code a class that implements your interface and add some magic markers that are recognized by JCC and affect what the wrapper generator will generate.
public class JccTestListenerImpl implements JccTestListener {
// jcc specific
private long pythonObject;
public JccTestListenerImpl() {}
#Override
public void message(String msg) {
messageImpl(msg);
}
// jcc specific
public void pythonExtension(long pythonObject) {
this.pythonObject = pythonObject;
}
// jcc specific
public long pythonExtension() {
return this.pythonObject;
}
// jcc specific
#Override
public void finalize() throws Throwable {
pythonDecRef();
}
// jcc specific
public native void pythonDecRef();
public native void messageImpl(String msg);
}
The markers are denoted by my comments and must appear verbatim in any class that is to be extended in python. My implementation delegates the interface method to a native implementation method, which will be extended in python.
Then generate the wrapper as usual:
python -m jcc --jar jcc-test.jar --python jcc_test --build --install
And finally make a python extension for the new class:
import jcc_test
import time, sys
jvm = jcc_test.initVM(jcc_test.CLASSPATH)
test = jcc_test.JccTest()
class MyListener(jcc_test.JccTestListenerImpl):
## if you define a constructor here make sure to invoke super constructor
#def __init__(self):
# super(MyListener, self).__init__()
# pass
def messageImpl(self, msg):
print msg
listener = MyListener()
test.addJccTestListener(listener)
test.start()
time.sleep(10)
test.stop()
sys.exit(0)
This now works as expected with callbacks coming in.
"python.exe" jcc_test_test.py
Start
Notifiying listeners
Notifiying com.example.jcc.JccTestListenerImpl#4b67cf4d
I'm giving you a message!
Sleeping
Notifiying listeners
Notifiying com.example.jcc.JccTestListenerImpl#4b67cf4d
I'm giving you a message!
Sleeping
Process finished with exit code 0