Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jlahtinen committed Nov 22, 2023
1 parent 626f4a6 commit fa6c165
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 24 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.eficode</groupId>
<artifactId>devstack</artifactId>
<version>2.3.12-SNAPSHOT</version>
<version>2.3.13-SNAPSHOT</version>
<packaging>jar</packaging>

<name>DevStack</name>
Expand Down Expand Up @@ -228,4 +228,4 @@
</plugins>
</build>

</project>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -974,4 +974,4 @@ trait Container {
return callBack.output
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,25 +60,23 @@ class JsmContainer implements Container {

@Override
ContainerCreateRequest setupContainerCreateRequest() {

String image = containerImage + ":" + containerImageTag

log.debug("Setting up container create request for JSM container")
if (dockerClient.engineArch != "x86_64") {
log.debug("\tDocker engine is not x86, building custom JSM docker image")

ImageBuilder imageBuilder = new ImageBuilder(dockerClient.host, dockerClient.certPath)
String jsmVersion = containerImageTag
if (jsmVersion == "latest") {
log.debug("\tCurrent image tag is set to \"latest\", need to resolve latest version number from Atlassian Marketplace in order to build custom image")
jsmVersion = getLatestJsmVersion()
}
log.debug("\tStarting building of Docker Image for JSM verion $jsmVersion")
ImageSummary newImage = imageBuilder.buildJsm(jsmVersion)
log.debug("\tFinished building custom image:" + newImage.repoTags.join(","))

image = newImage.repoTags.first()
new ImageBuilder(dockerClient.host, dockerClient.certPath)
String jsmVersion = containerImageTag
if (jsmVersion == "latest") {
log.debug("\tCurrent image tag is set to \"latest\", need to resolve latest version number from Atlassian Marketplace in order to build custom image")
jsmVersion = getLatestJsmVersion()
}
log.debug("\tStarting building of Docker Image for JSM verion $jsmVersion")
ImageSummary jsmImage = new ImageBuilder(dockerClient.host, dockerClient.certPath).buildJsm(jsmVersion)
log.debug("\tFinished building custom image:" + jsmImage.repoTags.join(","))

log.debug("\tStarting building of Docker Image for faketime JSM verion $jsmVersion")
ImageSummary faketimeJsmImage = new ImageBuilder(dockerClient.host, dockerClient.certPath).buildFaketimeJsm(jsmVersion)
log.debug("\tFinished building custom image:" + faketimeJsmImage.repoTags.join(","))

String image = faketimeJsmImage.repoTags.first()

ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest().tap { c ->

Expand All @@ -94,7 +92,7 @@ class JsmContainer implements Container {
if (debugPort) {
h.portBindings.put((debugPort + "/tcp"), [new PortBinding("0.0.0.0", (debugPort))])
c.exposedPorts.put((debugPort + "/tcp"), [:])
c.env.add("JVM_SUPPORT_RECOMMENDED_ARGS=-Xdebug -Xrunjdwp:transport=dt_socket,address=*:${debugPort},server=y,suspend=n".toString())
c.env.add("JVM_SUPPORT_RECOMMENDED_ARGS=-XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_currentTimeMillis -XX:CompileCommand=dontinline,java.lang.System::currentTimeMillis -agentpath:/libfaketime.so=+2592000000 -Xdebug -Xrunjdwp:transport=dt_socket,address=*:${debugPort},server=y,suspend=n".toString())
}


Expand Down
52 changes: 48 additions & 4 deletions src/main/groovy/com/eficode/devstack/util/ImageBuilder.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import com.eficode.devstack.container.impl.DoodContainer
import de.gesellix.docker.remote.api.ImageSummary
import java.util.concurrent.TimeoutException


/**
* A utility class intended to build docker images so that they match the docker engines CPU architecture
*
Expand All @@ -16,7 +15,6 @@ class ImageBuilder extends DoodContainer {
Map<String, ArrayList<String>>builderOut = [:]
long cmdTimeoutS = 800 //Will timeout individual container commands after this many seconds


ImageBuilder(String dockerHost, String dockerCertPath) {
assert setupSecureRemoteConnection(dockerHost, dockerCertPath): "Error setting up secure remote docker connection"
prepareBindMount("/var/run/docker.sock", "/var/run/docker.sock")
Expand Down Expand Up @@ -48,7 +46,6 @@ class ImageBuilder extends DoodContainer {
* @return
*/
ImageSummary buildJsm(String jsmVersion, boolean force = false){

String imageName = "atlassian/jira-servicemanagement"
String artifactName = "atlassian-servicedesk"
String archType = dockerClient.engineArch
Expand Down Expand Up @@ -76,7 +73,55 @@ class ImageBuilder extends DoodContainer {
ImageSummary newImage = images.find {it.repoTags == [imageTag]}
log.debug("\tFinished building image:" + imageTag + ", ID:" + newImage.id[7..17])
return newImage
}

ImageSummary buildFaketimeJsm(String jsmVersion, boolean force = false){
String imageName = "atlassian/jira-servicemanagement"
String artifactName = "atlassian-servicedesk"
String archType = dockerClient.engineArch
String imageTag = "$imageName:$jsmVersion-$archType"
String faketimeRoot = "/faketimebuild"
String faketimeDockerFilePath = "$faketimeRoot/Dockerfile"
String faketimeAgentFilePath = "$faketimeRoot/faketime.cpp"
String faketimeImageTag = "$imageName-faketime:$jsmVersion-$archType"
String faketimecpp = getClass().getResourceAsStream("/faketime.cpp").text
containerName = faketimeImageTag.replaceAll(/[^a-zA-Z0-9_.-]/, "-").take(128-"-IB".length())
containerName += "-IB"

log.info("my name is now $containerName")

//Check first if an image with the expected tag already exists
if (!force) {
ArrayList<ImageSummary> existingImages = dockerClient.images().content
ImageSummary existingImage = existingImages.find {it.repoTags == [faketimeImageTag]}
if (existingImage) {
return existingImage
}
}

String faketimeDockerFile = """
FROM $imageTag
WORKDIR /
RUN apt-get update && apt-get install -y wget g++ make
# RUN wget https://github.com/odnoklassniki/jvmti-tools/raw/master/faketime/faketime.cpp
COPY faketime.cpp .
RUN g++ -O2 -fPIC -shared -I \$JAVA_HOME/include -I \$JAVA_HOME/include/linux -olibfaketime.so faketime.cpp
ENV JVM_SUPPORT_RECOMMENDED_ARGS="-agentpath:/libfaketime.so=+2592000000"
"""


putBuilderCommand("mkdir -p $faketimeRoot", "")
putBuilderCommand("cat > $faketimeDockerFilePath <<- 'EOF'\n" + faketimeDockerFile + "\nEOF", "")
putBuilderCommand("cat > $faketimeAgentFilePath <<- 'EOF'\n" + faketimecpp + "\nEOF", "")
putBuilderCommand("cd $faketimeRoot && docker build --tag $faketimeImageTag --build-arg JIRA_VERSION=$jsmVersion --build-arg ARTEFACT_NAME=$artifactName . && echo status:\$?", "status:0")
putBuilderCommand("pkill tail", "")

assert build() : "Error building the image."

ArrayList<ImageSummary> images = dockerClient.images().content
ImageSummary newImage = images.find {it.repoTags == [faketimeImageTag]}
return newImage
}


Expand Down Expand Up @@ -140,7 +185,6 @@ class ImageBuilder extends DoodContainer {
@Override
boolean runAfterDockerSetup(){


builderCommands.each {cmd, expectedLastOut ->
log.info("Running container command:" + cmd)
log.info("\tExpecting last output from command:" + expectedLastOut)
Expand Down
92 changes: 92 additions & 0 deletions src/main/resources/faketime.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright 2020 Odnoklassniki Ltd, Mail.Ru Group
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <jvmti.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static jlong (*real_time_millis)(JNIEnv *, jclass) = NULL;
static jlong (*real_nano_time_adjustment)(JNIEnv *, jclass, jlong) = NULL;

jlong JNICALL fake_time_millis(JNIEnv* env, jclass cls)
{
jclass systemClass = env->FindClass("java/lang/System");
jmethodID getPropertyMethodId = env->GetStaticMethodID(systemClass, "getProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
jstring offsetPropertyName = env->NewStringUTF("faketime.offset.seconds");
jstring offsetPropertyDefault = env->NewStringUTF("0");
jstring offsetValue = (jstring)env->CallStaticObjectMethod(systemClass, getPropertyMethodId, offsetPropertyName, offsetPropertyDefault);
const char *offset = env->GetStringUTFChars(offsetValue, NULL);
jlong result = real_time_millis(env, cls) + atoll(offset);
env->ReleaseStringUTFChars(offsetValue, offset);
return result;
}

jlong JNICALL fake_nano_time_adjustment(JNIEnv *env, jclass cls, jlong offset_seconds)
{
jclass systemClass = env->FindClass("java/lang/System");
jmethodID getPropertyMethodId = env->GetStaticMethodID(systemClass, "getProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
jstring offsetPropertyName = env->NewStringUTF("faketime.offset.seconds");
jstring offsetPropertyDefault = env->NewStringUTF("0");
jstring offsetValue = (jstring)env->CallStaticObjectMethod(systemClass, getPropertyMethodId, offsetPropertyName, offsetPropertyDefault);
const char *offset = env->GetStringUTFChars(offsetValue, NULL);
jlong result = real_nano_time_adjustment(env, cls, offset_seconds) + atoll(offset) * 1000000;
env->ReleaseStringUTFChars(offsetValue, offset);
return result;
}

void JNICALL NativeMethodBind(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jmethodID method,
void *address, void **new_address_ptr)
{
char *name;
if (jvmti->GetMethodName(method, &name, NULL, NULL) == 0)
{
if (real_time_millis == NULL && strcmp(name, "currentTimeMillis") == 0)
{
real_time_millis = (jlong(*)(JNIEnv *, jclass))address;
*new_address_ptr = (void *)fake_time_millis;
}
else if (real_nano_time_adjustment == NULL && strcmp(name, "getNanoTimeAdjustment") == 0)
{
real_nano_time_adjustment = (jlong(*)(JNIEnv *, jclass, jlong))address;
*new_address_ptr = (void *)fake_nano_time_adjustment;
}
jvmti->Deallocate((unsigned char *)name);
}
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
{
jvmtiEnv *jvmti;
vm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_0);

jvmtiCapabilities capabilities = {0};
capabilities.can_generate_native_method_bind_events = 1;
#if JNI_VERSION_9
jvmtiCapabilities potential_capabilities;
jvmti->GetPotentialCapabilities(&potential_capabilities);
capabilities.can_generate_early_vmstart = potential_capabilities.can_generate_early_vmstart;
#endif
jvmti->AddCapabilities(&capabilities);

jvmtiEventCallbacks callbacks = {0};
callbacks.NativeMethodBind = NativeMethodBind;
jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));

jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_NATIVE_METHOD_BIND, NULL);

return 0;
}

0 comments on commit fa6c165

Please sign in to comment.