From 33624f15f01a592b69ec0f0e2cb0f96202753b37 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Thu, 16 Jan 2025 15:12:20 +0100 Subject: [PATCH 01/52] start migrating to kubernetes --- platform-controller/Makefile | 2 +- .../ContainerManagerKubernetesImpl.java | 134 ++++++++++++++++++ .../docker/FileBasedImageManagerTest.java | 3 +- .../docker/GitlabBasedImageManagerTest.java | 2 + .../controller/docker/LongImageNameTest.java | 5 +- .../docker/MetaDataFactoryTest.java | 4 + .../docker/VersionTagIdentificationTest.java | 5 + 7 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerKubernetesImpl.java diff --git a/platform-controller/Makefile b/platform-controller/Makefile index 486875fb..0c52512b 100644 --- a/platform-controller/Makefile +++ b/platform-controller/Makefile @@ -11,7 +11,7 @@ run: DOCKER_HOST=tcp://localhost:2375 \ HOBBIT_RABBIT_HOST=localhost \ java -cp \ - target/platform-controller-0.0.1-SNAPSHOT.jar \ + target/platform-controller.jar \ org.hobbit.core.run.ComponentStarter \ org.hobbit.controller.PlatformController diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerKubernetesImpl.java b/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerKubernetesImpl.java new file mode 100644 index 00000000..7db55a52 --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerKubernetesImpl.java @@ -0,0 +1,134 @@ +package org.hobbit.controller.docker; + +import com.spotify.docker.client.exceptions.DockerException; +import com.spotify.docker.client.messages.ContainerStats; +import com.spotify.docker.client.messages.swarm.Service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Created by Farshad Afshari on 13/01/2025 + * + * @author Farshad afshari (farshad.afshari@uni-paderborn.de) + */ + +public class ContainerManagerKubernetesImpl implements ContainerManager { + + private String experimentId = null; + + + @Deprecated + public String startContainer(String imageName) { + return ""; + } + + @Deprecated + public String startContainer(String imageName, String[] command) { + return ""; + } + + @Override + public String startContainer(String imageName, String type, String parent) { + return startContainer(imageName, type, parent, null); + } + + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] command) { + return startContainer(imageName, containerType, parentId, null, command); + } + + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] command) { + return startContainer(imageName, containerType, parentId, env, null, command); + } + + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command) { + return startContainer(imageName, containerType, parentId, env, netAliases, command, true, + Collections.emptyMap()); + } + + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] command, boolean pullImage) { + return startContainer(imageName, containerType, parentId, env, null, command, true, Collections.emptyMap()); + } + + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command, boolean pullImage, Map constraints) { +//todo + return null; + } + + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command, String experimentId, Map constraints) { + this.experimentId = experimentId; + return startContainer(imageName, containerType, parentId, env, netAliases, command, true, constraints); + } + + @Override + public void stopContainer(String containerId) { + + } + + @Override + public void removeContainer(String serviceName) { + + } + + @Override + public void stopParentAndChildren(String parentId) { + + } + + @Override + public void removeParentAndChildren(String parent) { + + } + + @Override + public Long getContainerExitCode(String serviceName) throws DockerException, InterruptedException { + return 0L; + } + + @Override + public Service getContainerInfo(String serviceName) throws InterruptedException, DockerException { + return null; + } + + @Override + public List getContainers(Service.Criteria criteria) { + return null; + } + + @Override + public String getContainerId(String name) { + return ""; + } + + @Override + public String getContainerName(String containerId) { + return ""; + } + + @Override + public void addContainerObserver(ContainerStateObserver containerObserver) { + + } + + @Override + public void pullImage(String imageName) { + + } + + @Override + public ContainerStats getStats(String containerId) { + return null; + } + + @Override + public String getContainerType(String containerId) { + return ""; + } +} diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java index 37f3674f..853c78da 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java @@ -8,9 +8,10 @@ /** * A simple test which tests the ability of the {@link FileBasedImageManager} * class to load metadata from a file. - * + * * @author Michael Röder (michael.roeder@uni-paderborn.de) * + * TODO: maybe need to move */ public class FileBasedImageManagerTest { diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java index ee935ea9..b7bccc9d 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java @@ -41,6 +41,8 @@ /** * Created by Timofey Ermilov on 22/09/16. + * + * TODO: maybe need to move */ public class GitlabBasedImageManagerTest { private GitlabBasedImageManager imageManager; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/LongImageNameTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/LongImageNameTest.java index 35550252..be739fa6 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/LongImageNameTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/LongImageNameTest.java @@ -21,7 +21,10 @@ import org.hobbit.core.Constants; import org.junit.Test; - +/** + * + * TODO: maybe need to move + */ public class LongImageNameTest extends ContainerManagerBasedTest { private static final String imageName = "hobbitproject/nonexisting_image_name_thats_too_long"; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java index a67778cf..3d07663e 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java @@ -16,6 +16,10 @@ import org.junit.Assert; import org.junit.Test; +/** + * + * TODO: maybe need to move + */ public class MetaDataFactoryTest { @Test diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/VersionTagIdentificationTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/VersionTagIdentificationTest.java index 2a1a9a56..e483711a 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/VersionTagIdentificationTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/VersionTagIdentificationTest.java @@ -27,6 +27,11 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; + +/** + * + * TODO: maybe have a single class implementing the containsVersionTag method independently of Docker swarm or Kubernetes + */ @RunWith(Parameterized.class) public class VersionTagIdentificationTest { From bdb8e4898c9f405f816b0f30417ee2f9106fe9fa Mon Sep 17 00:00:00 2001 From: farshad68 Date: Fri, 24 Jan 2025 10:57:12 +0100 Subject: [PATCH 02/52] first class migrated --- platform-controller/pom.xml | 19 + .../hobbit/controller/ExperimentManager.java | 10 +- .../hobbit/controller/PlatformController.java | 10 +- .../controller/docker/ClusterManagerImpl.java | 1 + .../docker/ContainerManagerImpl.java | 18 +- .../ContainerManagerKubernetesImpl.java | 134 ----- .../docker/ContainerStateObserverImpl.java | 6 +- .../ResourceInformationCollectorImpl.java | 1 + .../ClusterManager.java | 2 +- .../ContainerManager.java | 40 +- .../kubernetes/ClusterManagerImpl.java | 42 ++ .../kubernetes/ContainerManagerImpl.java | 536 ++++++++++++++++++ .../controller/PlatformControllerTest.java | 4 +- .../docker/ContainerManagerImplTest.java | 12 +- .../ContainerStateObserverImplTest.java | 1 + .../mocks/DummyContainerManager.java | 16 +- 16 files changed, 663 insertions(+), 189 deletions(-) delete mode 100644 platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerKubernetesImpl.java rename platform-controller/src/main/java/org/hobbit/controller/{docker => interfaces}/ClusterManager.java (97%) rename platform-controller/src/main/java/org/hobbit/controller/{docker => interfaces}/ContainerManager.java (93%) create mode 100644 platform-controller/src/main/java/org/hobbit/controller/kubernetes/ClusterManagerImpl.java create mode 100644 platform-controller/src/main/java/org/hobbit/controller/kubernetes/ContainerManagerImpl.java diff --git a/platform-controller/pom.xml b/platform-controller/pom.xml index f3ee6fbd..91c86ead 100644 --- a/platform-controller/pom.xml +++ b/platform-controller/pom.xml @@ -28,6 +28,9 @@ platform-controller jar + + 18.0.0 + @@ -105,6 +108,22 @@ 2.8.8 + + + + io.kubernetes + client-java-api + ${kubernetes-client.version} + + + + io.kubernetes + client-java + ${kubernetes-client.version} + + + + javax.activation activation diff --git a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java index d6adfe52..e80c9458 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java @@ -44,8 +44,8 @@ import org.hobbit.controller.data.ExperimentStatus; import org.hobbit.controller.data.ExperimentStatus.States; import org.hobbit.controller.data.SetupHardwareInformation; -import org.hobbit.controller.docker.ClusterManager; -import org.hobbit.controller.docker.ContainerManager; +import org.hobbit.controller.interfaces.ClusterManager; +import org.hobbit.controller.interfaces.ContainerManager; import org.hobbit.controller.docker.MetaDataFactory; import org.hobbit.controller.execute.ExperimentAbortTimerTask; import org.hobbit.controller.utils.RabbitMQConnector; @@ -599,7 +599,7 @@ public void notifyTermination(String containerId, long exitCode) { // send a message using sendToCmdQueue(command, // data) comprising a command that indicates that a // container terminated and the container name - String containerName = controller.containerManager.getContainerName(containerId); + String containerName = controller.containerManager.getContainerPodName(containerId); if (containerName != null) { try { controller.sendToCmdQueue(Constants.HOBBIT_SESSION_ID_FOR_BROADCASTS, @@ -663,7 +663,7 @@ public void systemOrBenchmarkReady(boolean systemReportedReady, String sessionId * daemon */ private void startBenchmark_unsecured() throws IOException { - String containerName = controller.containerManager.getContainerName(experimentStatus.getSystemContainer()); + String containerName = controller.containerManager.getContainerPodName(experimentStatus.getSystemContainer()); if (containerName == null) { throw new IOException( "Couldn't derive container name of the system container for sending start message to the benchmark."); @@ -799,7 +799,7 @@ public void setController(PlatformController controller) { /** * Add reported error to the experiment result model if the experiment with the * given session is still running. - * + * * @param sessionId the session ID of the container that reported the * error * @param errorData the data of the reported error diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 419dbb1b..2cc136a2 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -49,9 +49,9 @@ import org.apache.jena.vocabulary.RDF; import org.hobbit.controller.analyze.ExperimentAnalyzer; import org.hobbit.controller.data.ExperimentConfiguration; -import org.hobbit.controller.docker.ClusterManager; +import org.hobbit.controller.interfaces.ClusterManager; import org.hobbit.controller.docker.ClusterManagerImpl; -import org.hobbit.controller.docker.ContainerManager; +import org.hobbit.controller.interfaces.ContainerManager; import org.hobbit.controller.docker.ContainerManagerImpl; import org.hobbit.controller.docker.ContainerStateObserver; import org.hobbit.controller.docker.ContainerStateObserverImpl; @@ -498,7 +498,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas * @return the name of the created container */ private String createContainer(StartCommandData data) { - String parentId = containerManager.getContainerId(data.parent); + String parentId = containerManager.getContainerPodId(data.parent); if ((parentId == null) && (CONTAINER_PARENT_CHECK)) { LOGGER.error("Couldn't create container because the parent \"{}\" is not known.", data.parent); return null; @@ -515,7 +515,7 @@ private String createContainer(StartCommandData data) { if (containerId == null) { return null; } else { - return containerManager.getContainerName(containerId); + return containerManager.getContainerPodName(containerId); } } @@ -525,7 +525,7 @@ private String createContainer(StartCommandData data) { * @param containerName name of the container that should be stopped */ public void stopContainer(String containerName) { - String containerId = containerManager.getContainerId(containerName); + String containerId = containerManager.getContainerPodId(containerName); if (containerId != null) { containerManager.removeContainer(containerId); } diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ClusterManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/docker/ClusterManagerImpl.java index d628800a..b7f15e53 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ClusterManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/docker/ClusterManagerImpl.java @@ -2,6 +2,7 @@ import java.util.stream.Stream; +import org.hobbit.controller.interfaces.ClusterManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerImpl.java index 0d109e6c..9d382531 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerImpl.java @@ -30,6 +30,8 @@ import java.util.stream.Collectors; import org.hobbit.controller.gitlab.GitlabControllerImpl; +import org.hobbit.controller.interfaces.ClusterManager; +import org.hobbit.controller.interfaces.ContainerManager; import org.hobbit.controller.utils.Waiting; import org.hobbit.core.Constants; import org.slf4j.Logger; @@ -561,8 +563,8 @@ public String startContainer(String imageName, String[] command) { return startContainer(imageName, null, "", command); } - public String startContainer(String imageName, String type, String parent) { - return startContainer(imageName, type, parent, null); + public String startContainer(String imageName, String type, String parentId) { + return startContainer(imageName, type, parentId, null); } @Override @@ -618,7 +620,7 @@ public String startContainer(String imageName, String containerType, String pare @Override public void removeContainer(String serviceName) { try { - Long exitCode = getContainerExitCode(serviceName); + Long exitCode = getContainerPodExitCode(serviceName); if (DEPLOY_ENV.equals(DEPLOY_ENV_DEVELOP)) { LOGGER.info("Will not remove container {}. " + "Development mode is enabled.", serviceName); } else if (DEPLOY_ENV.equals(DEPLOY_ENV_TESTING) && (exitCode != null && exitCode != 0)) { @@ -681,7 +683,7 @@ public void removeParentAndChildren(String parent) { } } - @Override + //@Override public Service getContainerInfo(String serviceName) throws InterruptedException, DockerException { if (serviceName == null) { return null; @@ -705,7 +707,7 @@ public List getContainers(Service.Criteria criteria) { } @Override - public Long getContainerExitCode(String serviceName) throws DockerException, InterruptedException { + public Long getContainerPodExitCode(String serviceName) throws DockerException, InterruptedException { if (getContainerInfo(serviceName) == null) { LOGGER.warn( "Couldn't get the exit code for container {}. Service doesn't exist. Assuming it was stopped by the platform.", @@ -740,13 +742,13 @@ public Long getContainerExitCode(String serviceName) throws DockerException, Int @Deprecated @Override - public String getContainerId(String name) { + public String getContainerPodId(String name) { return name; } @Deprecated @Override - public String getContainerName(String containerId) { + public String getContainerPodName(String containerId) { return containerId; } @@ -778,7 +780,7 @@ public ContainerStats getStats(String containerId) { return stats; } - @Override + //@Override public String getContainerType(String containerId) { Service container = null; try { diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerKubernetesImpl.java b/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerKubernetesImpl.java deleted file mode 100644 index 7db55a52..00000000 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerKubernetesImpl.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.hobbit.controller.docker; - -import com.spotify.docker.client.exceptions.DockerException; -import com.spotify.docker.client.messages.ContainerStats; -import com.spotify.docker.client.messages.swarm.Service; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * Created by Farshad Afshari on 13/01/2025 - * - * @author Farshad afshari (farshad.afshari@uni-paderborn.de) - */ - -public class ContainerManagerKubernetesImpl implements ContainerManager { - - private String experimentId = null; - - - @Deprecated - public String startContainer(String imageName) { - return ""; - } - - @Deprecated - public String startContainer(String imageName, String[] command) { - return ""; - } - - @Override - public String startContainer(String imageName, String type, String parent) { - return startContainer(imageName, type, parent, null); - } - - @Override - public String startContainer(String imageName, String containerType, String parentId, String[] command) { - return startContainer(imageName, containerType, parentId, null, command); - } - - @Override - public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] command) { - return startContainer(imageName, containerType, parentId, env, null, command); - } - - @Override - public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command) { - return startContainer(imageName, containerType, parentId, env, netAliases, command, true, - Collections.emptyMap()); - } - - @Override - public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] command, boolean pullImage) { - return startContainer(imageName, containerType, parentId, env, null, command, true, Collections.emptyMap()); - } - - @Override - public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command, boolean pullImage, Map constraints) { -//todo - return null; - } - - @Override - public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command, String experimentId, Map constraints) { - this.experimentId = experimentId; - return startContainer(imageName, containerType, parentId, env, netAliases, command, true, constraints); - } - - @Override - public void stopContainer(String containerId) { - - } - - @Override - public void removeContainer(String serviceName) { - - } - - @Override - public void stopParentAndChildren(String parentId) { - - } - - @Override - public void removeParentAndChildren(String parent) { - - } - - @Override - public Long getContainerExitCode(String serviceName) throws DockerException, InterruptedException { - return 0L; - } - - @Override - public Service getContainerInfo(String serviceName) throws InterruptedException, DockerException { - return null; - } - - @Override - public List getContainers(Service.Criteria criteria) { - return null; - } - - @Override - public String getContainerId(String name) { - return ""; - } - - @Override - public String getContainerName(String containerId) { - return ""; - } - - @Override - public void addContainerObserver(ContainerStateObserver containerObserver) { - - } - - @Override - public void pullImage(String imageName) { - - } - - @Override - public ContainerStats getStats(String containerId) { - return null; - } - - @Override - public String getContainerType(String containerId) { - return ""; - } -} diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerStateObserverImpl.java b/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerStateObserverImpl.java index e181609f..21549082 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerStateObserverImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerStateObserverImpl.java @@ -21,6 +21,8 @@ import java.util.Timer; import java.util.TimerTask; +import io.kubernetes.client.openapi.ApiException; +import org.hobbit.controller.interfaces.ContainerManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -94,7 +96,7 @@ public void run() { } for (String id : containerIds) { try { - Long exitStatus = manager.getContainerExitCode(id); + Long exitStatus = manager.getContainerPodExitCode(id); if (exitStatus != null) { // notify all callbacks @@ -106,7 +108,7 @@ public void run() { } } } - } catch (DockerException | InterruptedException e) { + } catch (DockerException | ApiException | InterruptedException e ) { LOGGER.error("Couldn't get the status of container " + id + ". It will be ignored during this run but will be checked again during the next run."); } diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ResourceInformationCollectorImpl.java b/platform-controller/src/main/java/org/hobbit/controller/docker/ResourceInformationCollectorImpl.java index a4384067..2836024c 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ResourceInformationCollectorImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/docker/ResourceInformationCollectorImpl.java @@ -13,6 +13,7 @@ import javax.ws.rs.core.UriBuilder; import org.apache.commons.io.IOUtils; +import org.hobbit.controller.interfaces.ContainerManager; import org.hobbit.core.Constants; import org.hobbit.core.data.usage.CpuStats; import org.hobbit.core.data.usage.DiskStats; diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ClusterManager.java b/platform-controller/src/main/java/org/hobbit/controller/interfaces/ClusterManager.java similarity index 97% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ClusterManager.java rename to platform-controller/src/main/java/org/hobbit/controller/interfaces/ClusterManager.java index 9f8b93dc..d784e968 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ClusterManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/interfaces/ClusterManager.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.interfaces; import com.spotify.docker.client.exceptions.DockerException; import com.spotify.docker.client.messages.Info; diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManager.java b/platform-controller/src/main/java/org/hobbit/controller/interfaces/ContainerManager.java similarity index 93% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManager.java rename to platform-controller/src/main/java/org/hobbit/controller/interfaces/ContainerManager.java index 3daf465e..c6c93403 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/interfaces/ContainerManager.java @@ -14,11 +14,13 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.interfaces; import java.util.List; import java.util.Map; +import io.kubernetes.client.openapi.ApiException; +import org.hobbit.controller.docker.ContainerStateObserver; import org.hobbit.core.Constants; import com.spotify.docker.client.exceptions.DockerException; @@ -26,7 +28,7 @@ import com.spotify.docker.client.messages.swarm.Service; /** - * This interface is implemented by classes that can be used to manage Docker + * This interface is implemented by classes that can be used to manage Docker or Kubernetes * containers. * * @author Michael Röder (roeder@informatik.uni-leipzig.de) @@ -85,12 +87,12 @@ public interface ContainerManager { * * @param imageName name of the image to start * @param type container type - * @param parent parent id + * @param parentId parent id * * * @return container id */ - public String startContainer(String imageName, String type, String parent); + public String startContainer(String imageName, String type, String parentId); /** * Starts the container with the given image name. @@ -216,16 +218,18 @@ public String startContainer(String imageName, String containerType, String pare /** * Returns container's exit code or null if container is still running. * - * @param container + * @param serviceName */ - public Long getContainerExitCode(String serviceName) throws DockerException, InterruptedException; + public Long getContainerPodExitCode(String serviceName) throws DockerException, InterruptedException, ApiException; - /** - * Returns container info - * - * @param containerId - */ - public Service getContainerInfo(String serviceName) throws InterruptedException, DockerException; + + //TODO maybe remove this method from interface just keeo the usage in implementation for dokcer +// /** +// * Returns container info +// * +// * @param serviceName +// */ +// public Service getContainerInfo(String serviceName) throws InterruptedException, DockerException; /** * Get a list of services @@ -248,24 +252,24 @@ public default List getContainers() { * be found. */ @Deprecated - public String getContainerId(String name); + public String getContainerPodId(String name); /** * @deprecated Platform uses names as IDs. Returns the name of the container * with the given Id or {@code null} if such a container can not be * found - * + * * @param containerId the Id of the container for which the name should be * retrieved * @return the name of the container with the given Id or {@code null} if such a * container can not be found */ @Deprecated - public String getContainerName(String containerId); + public String getContainerPodName(String containerId); /** * Adds the given observer to the list of internal observers. - * + * * @param containerObserver the observer that should be added to the internal * list */ @@ -281,7 +285,7 @@ public default List getContainers() { /** * Returns statistics of the container with the given Id or {@code null} if the * container can not be found or an error occurs. - * + * * @param containerId the Id of the container for which statistics should be * requested * @return statistics of the container with the given Id or {@code null} if the @@ -294,7 +298,7 @@ public default List getContainers() { * {@link Constants#CONTAINER_TYPE_BENCHMARK}, * {@link Constants#CONTAINER_TYPE_DATABASE} or * {@link Constants#CONTAINER_TYPE_SYSTEM}. - * + * * @param containerId * @return */ diff --git a/platform-controller/src/main/java/org/hobbit/controller/kubernetes/ClusterManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/kubernetes/ClusterManagerImpl.java new file mode 100644 index 00000000..5e5900da --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/kubernetes/ClusterManagerImpl.java @@ -0,0 +1,42 @@ +package org.hobbit.controller.kubernetes; + +import com.spotify.docker.client.exceptions.DockerException; +import com.spotify.docker.client.messages.Info; +import org.hobbit.controller.interfaces.ClusterManager; + +public class ClusterManagerImpl implements ClusterManager { + @Override + public Info getClusterInfo() throws DockerException, InterruptedException { + return null; + } + + @Override + public long getNumberOfNodes() throws DockerException, InterruptedException { + return 0; + } + + @Override + public long getNumberOfNodes(String label) throws DockerException, InterruptedException { + return 0; + } + + @Override + public boolean isClusterHealthy() throws DockerException, InterruptedException { + return false; + } + + @Override + public long getExpectedNumberOfNodes() { + return 0; + } + + @Override + public void setTaskHistoryLimit(Integer taskHistoryLimit) throws DockerException, InterruptedException { + + } + + @Override + public int getTaskHistoryLimit() throws DockerException, InterruptedException { + return 0; + } +} diff --git a/platform-controller/src/main/java/org/hobbit/controller/kubernetes/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/kubernetes/ContainerManagerImpl.java new file mode 100644 index 00000000..8b3c2ed3 --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/kubernetes/ContainerManagerImpl.java @@ -0,0 +1,536 @@ +package org.hobbit.controller.kubernetes; + +import com.spotify.docker.client.exceptions.DockerException; +import com.spotify.docker.client.messages.ContainerStats; +import com.spotify.docker.client.messages.swarm.Placement; +import com.spotify.docker.client.messages.swarm.Resources; +import com.spotify.docker.client.messages.swarm.Service; +import org.hobbit.controller.interfaces.ContainerManager; +import org.hobbit.controller.docker.ContainerStateObserver; +import org.hobbit.controller.utils.Waiting; +import org.hobbit.core.Constants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.Configuration; +import io.kubernetes.client.util.Config; +import io.kubernetes.client.util.generic.GenericKubernetesApi; +import io.kubernetes.client.custom.Quantity; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.models.*; + +import java.io.IOException; +import java.util.*; + +public class ContainerManagerImpl implements ContainerManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(org.hobbit.controller.kubernetes.ContainerManagerImpl.class); + private ApiClient client; + //TODO make configable + private int TIMEOUT_MILLISECONDS = 60000; + private String nameSpace = "default"; + private static final long KUBERNETES_POLL_INTERVAL = 5000; // Poll interval in ms + private static final long KUBERNETES_EXITCODE_SIGKILL = 137L; // Equivalent to SIGKILL exit code + /** + * Logging separator for type/experiment id. + */ + private static final String LOGGING_SEPARATOR = "_sep_"; + public static final String LOGGING_TAG = "{{.ImageName}}/{{.Name}}/{{.ID}}"; + public static final String DEPLOY_ENV_KEY = "DEPLOY_ENV"; + private static final String DEPLOY_ENV_DEVELOP = "develop"; + private static final String DEPLOY_ENV_TESTING = "testing"; + private static final String DEPLOY_ENV = System.getenv().containsKey(DEPLOY_ENV_KEY) + ? System.getenv().get(DEPLOY_ENV_KEY) + : "production"; + + /** + * Observers that should be notified if a container terminates. + */ + private final List containerObservers = new ArrayList<>(); + + + public ContainerManagerImpl() { + try { + if (client == null) { + client = initiateClient(); + } + } catch (Exception ex) { + LOGGER.error("Error initializing Kubernetes client: ", ex); + } + } + + + + @Deprecated + public String startContainer(String imageName) { + return null; + } + + @Deprecated + public String startContainer(String imageName, String[] command){ + return null; + } + + @Override + public String startContainer(String imageName, String type, String parentId) { + return startContainer(imageName, type, parentId, null); + } + + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] command) { + return startContainer(imageName, containerType, parentId, null, command); + } + + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] command) { + return startContainer(imageName, containerType, parentId, env, null, command); + } + + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command) { + return startContainer(imageName, containerType, parentId, env, null, command, true, + Collections.emptyMap()); + } + + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] command, boolean pullImage) { + return startContainer(imageName, containerType, parentId, env, null, command, true, Collections.emptyMap()); + } + + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command, boolean pullImage, Map constraints) { + // we dont need this in kubernetes +// if (pullImage) { +// pullImage(imageName); +// } + //todo why in Interface there is no experimentID ? + return startContainer(imageName, containerType, parentId, env, null, command, "", constraints); + } + + // we do not use netAliases + @Override + public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command, String experimentId, Map constraints) { + String podName = LOGGING_TAG; + if (experimentId != null) { + podName = containerType + LOGGING_SEPARATOR + experimentId + LOGGING_SEPARATOR + LOGGING_TAG; + } + return createContainerKub(imageName, podName,containerType,parentId, env,command,constraints); + } + + /** + * Creates environment variables from the provided list of key-value pairs. + */ +// private List createEnvVariables(List> variables) { +// List env = new ArrayList<>(); +// if (variables != null) { +// for (Map.Entry entry : variables) { +// V1EnvVar v1env = new V1EnvVar(); +// v1env.setName(entry.getKey()); +// v1env.setValue(entry.getValue()); +// env.add(v1env); +// } +// } +// return env; +// } + + /** + * Initializes and configures a Kubernetes API client with custom timeout settings. + * + * This method: + * - Creates a default Kubernetes API client using the default configuration. + * - Sets custom connection, read, and write timeouts. + * - Sets the configured client as the default client in the global Configuration class. + * + * @return ApiClient configured with specified timeouts. + * @throws IOException if an error occurs during client initialization. + */ + protected ApiClient initiateClient() throws IOException { + try{ + LOGGER.info("initiating Kubernetes client"); + ApiClient client = Config.defaultClient(); + client.setConnectTimeout(TIMEOUT_MILLISECONDS); + client.setReadTimeout(TIMEOUT_MILLISECONDS); + client.setWriteTimeout(TIMEOUT_MILLISECONDS); + Configuration.setDefaultApiClient(client); + LOGGER.info("Kubernetes API client initiated with default configuration."); + return client; + } + catch (Exception ex){ + LOGGER.error("Failed to initiate Kubernetes API client", ex); + throw ex; + } + } + + private String createContainerKub(String imageName, String podName, String containerType, String parentPodName, + String[] env, String[] command, Map constraints) { + LOGGER.info("Creating container: Image = {}, Pod Name = {}, Container Type = {}, Parent ID = {}", + imageName, podName, containerType, parentPodName); + + // Prepare environment variable + List environmentVariables = new ArrayList<>(); + if (env != null) { + for (String envVar : env) { + String[] parts = envVar.split("=", 2); + if (parts.length == 2) { + environmentVariables.add(new V1EnvVar().name(parts[0]).value(parts[1])); + } + } + } + + String parentType = getContainerType(parentPodName); + // if there is no container type then try to use the type of the parent + if(containerType == null || containerType.isEmpty()) { + if (parentType == null) { + // If it can not resolve then return, because we don't want to make a pod with no type + return null; + }else{ + containerType = parentType; + } + } + + // Create resource requirements if constraints are provided + V1ResourceRequirements resourceRequirements = createResourceRequirementsFromConstraints(constraints); + + // Prepare the container specification + V1Container container = new V1Container() + .name(podName) + .image(imageName) + .env(environmentVariables) + .command(command != null ? Arrays.asList(command) : null) + .resources(resourceRequirements); + + // Create a volume and volume mount for shared directories +// V1Volume volume = createVolumeForSharedDirectory(); +// V1VolumeMount volumeMount = new V1VolumeMount() +// .name("shared-dir") +// .mountPath("/shared"); + +// container.setVolumeMounts(Collections.singletonList(volumeMount)); + + // Create the pod specification + V1PodSpec podSpec = new V1PodSpec() + .restartPolicy("Never") + .containers(Collections.singletonList(container)); + //.volumes(Collections.singletonList(volume)); + + if ((((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType)) + && Constants.CONTAINER_TYPE_SYSTEM.equals(containerType)) + || Constants.CONTAINER_TYPE_SYSTEM.equals(parentType)) { + podSpec.nodeSelector(Collections.singletonMap("node-group", "system-nodes")); + // todo : why we set the container type here ? + containerType = Constants.CONTAINER_TYPE_SYSTEM; + } else if (Constants.CONTAINER_TYPE_DATABASE.equals(containerType) + && ((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType) + || Constants.CONTAINER_TYPE_DATABASE.equals(parentType))) { + + podSpec.nodeSelector(Collections.singletonMap("node-group", "benchmark-nodes")); + + } else if (Constants.CONTAINER_TYPE_BENCHMARK.equals(containerType) + && ((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType))) { + + podSpec.nodeSelector(Collections.singletonMap("node-group", "benchmark-nodes")); + + } else { + LOGGER.error("Got a request to create a container with type={} and parentType={}. " + + "Got no rule to determine its type. Returning null.", containerType, parentType); + return null; + } + + + Map labels = new HashMap<>(); + labels.put(LABEL_TYPE, containerType); + labels.put(LABEL_PARENT, parentPodName); + + + // Build the pod metadata + V1ObjectMeta metadata = new V1ObjectMeta() + .name(podName) + .namespace(nameSpace) + .labels(labels); + + + // Build the pod object + V1Pod pod = new V1Pod() + .metadata(metadata) + .spec(podSpec); + + // Deploy the pod + try { + GenericKubernetesApi podClient = new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); + V1Pod createdPod = podClient.create(pod).throwsApiException().getObject(); + String podUid = createdPod.getMetadata().getUid(); + LOGGER.info("Successfully created container with Pod UID: {}", podUid); + // if the creation was successful + if (podUid != null) { + for (ContainerStateObserver observer : containerObservers) { + observer.addObservedContainer(podUid); + } + } + return podUid; + } catch (ApiException e) { + LOGGER.error("Failed to create container for image: {}. Returning null.", imageName, e); + return null; + } + } + + + private V1Pod getPod(String podName) { + CoreV1Api coreV1Api = new CoreV1Api(client); + + try { + // Inspect the pod by name + V1Pod pod = coreV1Api.readNamespacedPod(podName, this.nameSpace, null); + return pod; + }catch (ApiException exc){ + LOGGER.error("Failed to get container for image: {} in namespace {}. Returning null.", podName, this.nameSpace, exc); + return null; + } + } + +// /** +// * +// * @param parentId +// * @return String of type based on the label of the parent +// */ +// private String resolveContainerType(String parentId) { +// // Logic to resolve container type based on the parentId +// // return null if resolution fails +// V1Pod parent = getPod(parentId); +// return (parent == null) ? null : parent.getMetadata().getLabels().get(LABEL_TYPE); +// } + + private V1ResourceRequirements createResourceRequirementsFromConstraints(Map constraints) { + V1ResourceRequirements resourceRequirements = new V1ResourceRequirements(); + Map limits = new HashMap<>(); + + if (constraints != null && (constraints.containsKey(MEMORY_LIMIT_CONSTRAINT) + || constraints.containsKey(NANO_CPU_LIMIT_CONSTRAINT))) { + Resources.Builder rBuilder = Resources.builder(); + // if there is a memory limitation + if (constraints.containsKey(MEMORY_LIMIT_CONSTRAINT)) { + long memory = (Long) constraints.get(MEMORY_LIMIT_CONSTRAINT); + limits.put("memory", new Quantity(String.valueOf(memory))); + } + // if there is a CPU limitation + if (constraints.containsKey(NANO_CPU_LIMIT_CONSTRAINT)) { + // CPU quota in units of 10^-9 CPUs. + long nanoCPUs = (Long) constraints.get(NANO_CPU_LIMIT_CONSTRAINT); + limits.put("cpu", new Quantity(String.valueOf(nanoCPUs))); + } + } + + resourceRequirements.setLimits(limits); + return resourceRequirements; + } + + private V1Volume createVolumeForSharedDirectory() { + return new V1Volume().name("shared-dir") + .hostPath(new V1HostPathVolumeSource().path("/shared").type("Directory")); + } + + @Deprecated + @Override + public void stopContainer(String containerId) { + LOGGER.error("ContainerManager.stopContainer() is deprecated! Will remove container instead"); + removeContainer(containerId); + } + + + @Override + public void removeContainer(String podName) { + try { + Long exitCode = getContainerPodExitCode(podName); + + if (DEPLOY_ENV.equals(DEPLOY_ENV_DEVELOP)) { + LOGGER.info("Will not remove pod {}. Development mode is enabled.", podName); + } else if (DEPLOY_ENV.equals(DEPLOY_ENV_TESTING) && (exitCode != null && exitCode != 0)) { + LOGGER.info("Will not remove pod {}. ExitCode: {} != 0 and testing mode is enabled.", podName, exitCode); + } else { + LOGGER.info("Removing pod {}.", podName); + + // Initialize the API client + CoreV1Api api = new CoreV1Api(client); + + // Delete the pod + V1DeleteOptions deleteOptions = new V1DeleteOptions(); + api.deleteNamespacedPod(podName, nameSpace, null, null, null, null, null, deleteOptions); + + // Wait for the pod to be deleted + Waiting.waitFor(() -> { + try { + api.readNamespacedPod(podName, nameSpace, null); + return false; + } catch (ApiException e) { + if (e.getCode() == 404) { + return true; // Pod not found + } + throw e; // Other errors should not be ignored + } + }, KUBERNETES_POLL_INTERVAL); + } + } catch (ApiException e) { + if (e.getCode() == 404) { + LOGGER.error("Couldn't remove pod {} because it doesn't exist", podName); + } else { + LOGGER.error("Couldn't remove pod {}.", podName, e); + } + } catch (Exception e) { + LOGGER.error("Unexpected error while removing pod {}.", podName, e); + } + } + + @Deprecated + @Override + public void stopParentAndChildren(String parentId) { + LOGGER.error("ContainerManager.stopParentAndChildren() is deprecated! Will remove them instead"); + removeParentAndChildren(parentId); + } + + @Override + public void removeParentAndChildren(String parentPodName) { + // Remove the parent pod + removeContainer(parentPodName); + + // Find child pods + try { + CoreV1Api api = new CoreV1Api(client); + + // Search for pods with the label "parent=" + String labelSelector = String.format(LABEL_PARENT+"=%s", parentPodName); + V1PodList childPods = api.listNamespacedPod( + nameSpace, null, null, null, null, labelSelector, null, null, null, null, false); + + for (V1Pod childPod : childPods.getItems()) { + if (childPod != null && childPod.getMetadata() != null) { + String childPodName = childPod.getMetadata().getName(); + if (childPodName != null) { + // Recursively remove the child pod and its children + removeParentAndChildren(childPodName); + } + } + } + } catch (ApiException e) { + LOGGER.error("Error while finding child pods: " + e.getResponseBody(), e); + } catch (Exception e) { + LOGGER.error("Unexpected error while removing pods: " + e.toString(), e); + } + } + + + @Override + public Long getContainerPodExitCode(String podName) throws DockerException, InterruptedException, ApiException { + try { + // Initialize the API client + CoreV1Api api = new CoreV1Api(client); + + // Fetch the pod details + V1Pod pod = api.readNamespacedPod(podName, nameSpace, null); + + // Check if the pod has a terminated container + if (pod.getStatus() == null || pod.getStatus().getContainerStatuses() == null) { + LOGGER.warn("Couldn't get the exit code for pod {}. Pod has no container statuses.", podName); + return null; + } + + for (V1ContainerStatus containerStatus : pod.getStatus().getContainerStatuses()) { + V1ContainerStateTerminated terminatedState = containerStatus.getState().getTerminated(); + if (terminatedState != null) { + return terminatedState.getExitCode().longValue(); + } + } + + // Pod is still running + LOGGER.warn("Couldn't get the exit code for pod {}. Pod is not terminated.", podName); + return null; + } catch (ApiException e) { + if (e.getCode() == 404) { + LOGGER.warn("Couldn't get the exit code for pod {}. Pod doesn't exist. Assuming it was stopped by the platform.", podName); + return KUBERNETES_EXITCODE_SIGKILL; + } + throw e; + } + } + + // we do not use this here + // todo change in interface and define another class as return value which is Service and V1Pod + // maybe for kubernetes we dont need this method ! we cover usage of this method in docker version in in the method in diffrent way here + +// @Override +// public Service getContainerInfo(String serviceName) throws InterruptedException, DockerException { +// return null; +// } + + + // used in ResourceInformationCollectorImpl + @Override + public List getContainers(Service.Criteria criteria) { + return null; + } + + @Override + public String getContainerPodId(String podName) { + try { + // Fetch the pod information using its name and namespace + CoreV1Api api = new CoreV1Api(client); + V1Pod pod = api.readNamespacedPod(podName, nameSpace, null); + + // Return the Pod's UID (unique identifier) + return pod.getMetadata().getUid(); + } catch (Exception e) { + LOGGER.error("Failed to fetch Pod ID for Pod name: {} in namespace: {}. Error: {}", podName, nameSpace, e); + return null; + } + } + + @Override + public String getContainerPodName(String podId) { + try { + // Fetch the list of all pods in the namespace + CoreV1Api api = new CoreV1Api(client); + V1PodList podList = api.listNamespacedPod(nameSpace, null, null, null, null, null, null, null, null, null, false); + + // Search for the pod with the given UID + for (V1Pod pod : podList.getItems()) { + if (pod.getMetadata().getUid().equals(podId)) { + // Return the Pod's name + return pod.getMetadata().getName(); + } + } + + // If no matching pod is found, return null + LOGGER.warn("No Pod found with ID: {} in namespace: {}", podId, nameSpace); + return null; + } catch (Exception e) { + LOGGER.error("Failed to fetch Pod name for Pod ID: {} in namespace: {}. Error: {}", podId, nameSpace, e); + return null; + } + } + + + @Override + public void addContainerObserver(ContainerStateObserver containerObserver) { + containerObservers.add(containerObserver); + } + + @Override + public void pullImage(String imageName) { + // we dont need this in kubernetes + } + + //TODO: do we need this for kubernetes? no usage in docker version + @Override + public ContainerStats getStats(String containerId) { + return null; + } + + + @Override + public String getContainerType(String podName) { + // Logic to resolve container type based on the parentId + // return null if resolution fails + V1Pod parent = getPod(podName); + return (parent == null) ? null : parent.getMetadata().getLabels().get(LABEL_TYPE); + } +} diff --git a/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java b/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java index 5d8a287e..0e09111e 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java @@ -93,7 +93,7 @@ public void close() throws Exception { * container creation is checked by the test. The second command has an invalid * (because unknown) session id and the test checks whether the second command * creates an additional container. - * + * * @throws Exception */ @Test @@ -103,7 +103,7 @@ public void receiveCreateContainerCommand() throws Exception { // create and execute parent container final String parentId = manager.startContainer("busybox", Constants.CONTAINER_TYPE_SYSTEM, null, new String[] { "sh", "-c", "while :; do sleep 1; done" }); - final String parentName = manager.getContainerName(parentId); + final String parentName = manager.getContainerPodName(parentId); services.add(parentId); // create and execute test container diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerImplTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerImplTest.java index 2fc27180..4ad24b36 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerImplTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerImplTest.java @@ -235,8 +235,8 @@ public void getContainerIdAndName() throws Exception { services.add(containerId); // compare containerId and retrieved id - String containerName = manager.getContainerName(containerId); - assertEquals(containerId, manager.getContainerId(containerName)); + String containerName = manager.getContainerPodName(containerId); + assertEquals(containerId, manager.getContainerPodId(containerName)); } private void removeImage(String imageName) throws Exception { @@ -341,7 +341,7 @@ public void pullUpdatedImage() throws Exception { Long exitCode = null; while (exitCode == null) { Thread.sleep(500); - exitCode = manager.getContainerExitCode(testTask); + exitCode = manager.getContainerPodExitCode(testTask); } assertEquals("Service is using first image version", Long.valueOf(1), exitCode); @@ -361,7 +361,7 @@ public void pullUpdatedImage() throws Exception { exitCode = null; while (exitCode == null) { Thread.sleep(500); - exitCode = manager.getContainerExitCode(testTask); + exitCode = manager.getContainerPodExitCode(testTask); } assertEquals("Service is using second image version", Long.valueOf(2), exitCode); @@ -431,13 +431,13 @@ public void testNetworkAliases() throws Exception { assertNotNull(pingContainer); services.add(pingContainer); Thread.sleep(10000); - assertEquals("Result of pinging the container's network alias", Long.valueOf(0), manager.getContainerExitCode(pingContainer)); + assertEquals("Result of pinging the container's network alias", Long.valueOf(0), manager.getContainerPodExitCode(pingContainer)); pingContainer = manager.startContainer(busyboxImageName, Constants.CONTAINER_TYPE_BENCHMARK, null, null, null, new String[]{"ping", "-c", "1", "-W", "2", "nonexistant"}); assertNotNull(pingContainer); services.add(pingContainer); Thread.sleep(10000); - assertEquals("Result of pinging the nonexisting host", Long.valueOf(1), manager.getContainerExitCode(pingContainer)); + assertEquals("Result of pinging the nonexisting host", Long.valueOf(1), manager.getContainerPodExitCode(pingContainer)); } } diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerStateObserverImplTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerStateObserverImplTest.java index d13ae82f..f49452f3 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerStateObserverImplTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerStateObserverImplTest.java @@ -16,6 +16,7 @@ */ package org.hobbit.controller.docker; +import org.hobbit.controller.interfaces.ContainerManager; import org.junit.Assert; import org.junit.Before; import org.junit.Test; diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java index 24e8ffe5..04c31a87 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java @@ -5,7 +5,7 @@ import java.util.Map; import java.util.concurrent.Semaphore; -import org.hobbit.controller.docker.ContainerManager; +import org.hobbit.controller.interfaces.ContainerManager; import org.hobbit.controller.docker.ContainerStateObserver; import org.hobbit.controller.docker.ContainerTerminationCallback; @@ -107,10 +107,10 @@ public void removeParentAndChildren(String parent) { stopContainer(parent); } - @Override - public Service getContainerInfo(String serviceName) { - return null; - } +// @Override +// public Service getContainerInfo(String serviceName) { +// return null; +// } @Override public List getContainers(Criteria criteria) { @@ -118,17 +118,17 @@ public List getContainers(Criteria criteria) { } @Override - public Long getContainerExitCode(String serviceName) { + public Long getContainerPodExitCode(String serviceName) { return null; } @Override - public String getContainerId(String name) { + public String getContainerPodId(String name) { return name; } @Override - public String getContainerName(String containerId) { + public String getContainerPodName(String containerId) { return containerId; } From b55c430f4475c778f59605fb64ef14a25c44348c Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 27 Jan 2025 11:12:33 +0100 Subject: [PATCH 03/52] add ClusterManagerImpl for Kub --- .../hobbit/controller/ExperimentManager.java | 6 +- .../hobbit/controller/PlatformController.java | 26 +++--- .../ClusterManager.java | 5 +- .../ContainerManager.java | 4 +- .../docker/AbstactImageManager.java | 16 ++-- .../docker/ClusterManagerImpl.java | 4 +- .../docker/ContainerManagerImpl.java | 6 +- .../docker/ContainerStateObserver.java | 4 +- .../docker/ContainerStateObserverImpl.java | 4 +- .../docker/ContainerTerminationCallback.java | 2 +- .../ContainerTerminationCallbackImpl.java | 2 +- .../docker/DockerUtility.java | 2 +- .../docker/FileBasedImageManager.java | 2 +- .../docker/GitlabBasedImageManager.java | 6 +- .../{ => containers}/docker/ImageManager.java | 2 +- .../docker/ImageManagerFacade.java | 4 +- .../docker/MetaDataFactory.java | 6 +- .../docker/ResourceInformationCollector.java | 2 +- .../ResourceInformationCollectorImpl.java | 4 +- .../kubernetes/ClusterManagerImpl.java | 86 +++++++++++++++++++ .../kubernetes/ContainerManagerImpl.java | 9 +- .../controller/data/ExperimentStatus.java | 6 +- .../kubernetes/ClusterManagerImpl.java | 42 --------- .../ExperimentHardwareInformationTest.java | 2 +- .../controller/PlatformControllerTest.java | 2 +- .../docker/ClusterManagerImplTest.java | 13 +-- .../docker/ContainerAccessByHostnameTest.java | 1 + .../docker/ContainerManagerBasedTest.java | 1 + .../docker/ContainerManagerImplTest.java | 1 + .../ContainerStateObserverImplTest.java | 4 +- .../ContainerTerminationCallbackImplTest.java | 1 + .../docker/FileBasedImageManagerTest.java | 1 + .../docker/GitlabBasedImageManagerTest.java | 1 + .../docker/MetaDataFactoryTest.java | 1 + .../ResourceInformationCollectorTest.java | 2 + .../docker/VersionTagIdentificationTest.java | 1 + .../mocks/DummyContainerManager.java | 6 +- .../controller/mocks/DummyImageManager.java | 2 +- .../mocks/DummyPlatformController.java | 2 +- .../DummyResourceInformationCollector.java | 2 +- 40 files changed, 175 insertions(+), 118 deletions(-) rename platform-controller/src/main/java/org/hobbit/controller/{interfaces => containers}/ClusterManager.java (91%) rename platform-controller/src/main/java/org/hobbit/controller/{interfaces => containers}/ContainerManager.java (99%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/AbstactImageManager.java (98%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/ClusterManagerImpl.java (97%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/ContainerManagerImpl.java (99%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/ContainerStateObserver.java (97%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/ContainerStateObserverImpl.java (98%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/ContainerTerminationCallback.java (96%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/ContainerTerminationCallbackImpl.java (95%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/DockerUtility.java (94%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/FileBasedImageManager.java (99%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/GitlabBasedImageManager.java (98%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/ImageManager.java (99%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/ImageManagerFacade.java (96%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/MetaDataFactory.java (98%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/ResourceInformationCollector.java (92%) rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/docker/ResourceInformationCollectorImpl.java (99%) create mode 100644 platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java rename platform-controller/src/main/java/org/hobbit/controller/{ => containers}/kubernetes/ContainerManagerImpl.java (98%) delete mode 100644 platform-controller/src/main/java/org/hobbit/controller/kubernetes/ClusterManagerImpl.java diff --git a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java index e80c9458..5f962a54 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java @@ -44,9 +44,9 @@ import org.hobbit.controller.data.ExperimentStatus; import org.hobbit.controller.data.ExperimentStatus.States; import org.hobbit.controller.data.SetupHardwareInformation; -import org.hobbit.controller.interfaces.ClusterManager; -import org.hobbit.controller.interfaces.ContainerManager; -import org.hobbit.controller.docker.MetaDataFactory; +import org.hobbit.controller.containers.ClusterManager; +import org.hobbit.controller.containers.ContainerManager; +import org.hobbit.controller.containers.docker.MetaDataFactory; import org.hobbit.controller.execute.ExperimentAbortTimerTask; import org.hobbit.controller.utils.RabbitMQConnector; import org.hobbit.core.Commands; diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 2cc136a2..7c1be569 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -49,19 +49,19 @@ import org.apache.jena.vocabulary.RDF; import org.hobbit.controller.analyze.ExperimentAnalyzer; import org.hobbit.controller.data.ExperimentConfiguration; -import org.hobbit.controller.interfaces.ClusterManager; -import org.hobbit.controller.docker.ClusterManagerImpl; -import org.hobbit.controller.interfaces.ContainerManager; -import org.hobbit.controller.docker.ContainerManagerImpl; -import org.hobbit.controller.docker.ContainerStateObserver; -import org.hobbit.controller.docker.ContainerStateObserverImpl; -import org.hobbit.controller.docker.ContainerTerminationCallback; -import org.hobbit.controller.docker.FileBasedImageManager; -import org.hobbit.controller.docker.GitlabBasedImageManager; -import org.hobbit.controller.docker.ImageManager; -import org.hobbit.controller.docker.ImageManagerFacade; -import org.hobbit.controller.docker.ResourceInformationCollector; -import org.hobbit.controller.docker.ResourceInformationCollectorImpl; +import org.hobbit.controller.containers.ClusterManager; +import org.hobbit.controller.containers.docker.ClusterManagerImpl; +import org.hobbit.controller.containers.ContainerManager; +import org.hobbit.controller.containers.docker.ContainerManagerImpl; +import org.hobbit.controller.containers.docker.ContainerStateObserver; +import org.hobbit.controller.containers.docker.ContainerStateObserverImpl; +import org.hobbit.controller.containers.docker.ContainerTerminationCallback; +import org.hobbit.controller.containers.docker.FileBasedImageManager; +import org.hobbit.controller.containers.docker.GitlabBasedImageManager; +import org.hobbit.controller.containers.docker.ImageManager; +import org.hobbit.controller.containers.docker.ImageManagerFacade; +import org.hobbit.controller.containers.docker.ResourceInformationCollector; +import org.hobbit.controller.containers.docker.ResourceInformationCollectorImpl; import org.hobbit.controller.front.FrontEndApiHandler; import org.hobbit.controller.queue.ExperimentQueue; import org.hobbit.controller.queue.ExperimentQueueImpl; diff --git a/platform-controller/src/main/java/org/hobbit/controller/interfaces/ClusterManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ClusterManager.java similarity index 91% rename from platform-controller/src/main/java/org/hobbit/controller/interfaces/ClusterManager.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/ClusterManager.java index d784e968..a1f29e36 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/interfaces/ClusterManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ClusterManager.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.interfaces; +package org.hobbit.controller.containers; import com.spotify.docker.client.exceptions.DockerException; import com.spotify.docker.client.messages.Info; @@ -16,7 +16,8 @@ public interface ClusterManager { * * @return com.spotify.docker.client.messages.Info */ - public Info getClusterInfo() throws DockerException, InterruptedException; + // it just used in one test then commented + //public Info getClusterInfo() throws DockerException, InterruptedException; /** * Get number of nodes in the cluster diff --git a/platform-controller/src/main/java/org/hobbit/controller/interfaces/ContainerManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java similarity index 99% rename from platform-controller/src/main/java/org/hobbit/controller/interfaces/ContainerManager.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java index c6c93403..9de53e64 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/interfaces/ContainerManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java @@ -14,13 +14,13 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.interfaces; +package org.hobbit.controller.containers; import java.util.List; import java.util.Map; import io.kubernetes.client.openapi.ApiException; -import org.hobbit.controller.docker.ContainerStateObserver; +import org.hobbit.controller.containers.docker.ContainerStateObserver; import org.hobbit.core.Constants; import com.spotify.docker.client.exceptions.DockerException; diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/AbstactImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/AbstactImageManager.java similarity index 98% rename from platform-controller/src/main/java/org/hobbit/controller/docker/AbstactImageManager.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/AbstactImageManager.java index f83907a8..82b5c702 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/AbstactImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/AbstactImageManager.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.util.Collections; import java.util.Comparator; @@ -14,7 +14,7 @@ /** * An abstract implementation of the {@link ImageManager} interface which takes * care of systems or benchmarks which have the same URI. - * + * * @author Michael Röder (michael.roeder@uni-paderborn.de) * */ @@ -30,7 +30,7 @@ public List getBenchmarks() { /** * A method that returns a list of unchecked benchmarks (they may have * overlapping URIs). - * + * * @return a list of known benchmarks */ protected abstract List getUncheckedBenchmarks(); @@ -43,7 +43,7 @@ public List getSystems() { /** * A method that returns a list of unchecked systems (they may have overlapping * URIs). - * + * * @return a list of known systems */ protected abstract List getUncheckedSystems(); @@ -85,7 +85,7 @@ public SystemMetaData getSystem(String systemUri) { /** * Identifies duplicates and marks them using the * {@link #addErrorToDuplicates(List)} method. - * + * * @param images * a list of images that may contain duplicates * @return the same list @@ -98,7 +98,7 @@ protected List markDuplicates(List images) { /** * Sets the {@link ImageMetaData#defError} attribute of all meta data elements * that are identified as duplicates. - * + * * @param images * the list of image meta data objects that have the same URI */ @@ -127,7 +127,7 @@ protected void addErrorToDuplicates(List images) { /** * Creates a stream of lists each containing all image meta data instances that * are sharing the same URI. - * + * * @param images * a list of image meta data instances * @return a stream of lists grouped by the image meta data URI @@ -143,7 +143,7 @@ protected static Stream> createListPerUri(List * makes sure that the correct {@link #getSystems()} method is used (i.e., the * method that adds additional information to the systems which can not be added * later on, after the filtering). - * + * * @param filter * the filter that is used. Should be thread safe. * @return the filtered list diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ClusterManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ClusterManagerImpl.java similarity index 97% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ClusterManagerImpl.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/ClusterManagerImpl.java index b7f15e53..84bb78d2 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ClusterManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ClusterManagerImpl.java @@ -1,8 +1,8 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.util.stream.Stream; -import org.hobbit.controller.interfaces.ClusterManager; +import org.hobbit.controller.containers.ClusterManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java similarity index 99% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerImpl.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java index 9d382531..3071e7fa 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.util.ArrayList; import java.util.Arrays; @@ -30,8 +30,8 @@ import java.util.stream.Collectors; import org.hobbit.controller.gitlab.GitlabControllerImpl; -import org.hobbit.controller.interfaces.ClusterManager; -import org.hobbit.controller.interfaces.ContainerManager; +import org.hobbit.controller.containers.ClusterManager; +import org.hobbit.controller.containers.ContainerManager; import org.hobbit.controller.utils.Waiting; import org.hobbit.core.Constants; import org.slf4j.Logger; diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerStateObserver.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserver.java similarity index 97% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ContainerStateObserver.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserver.java index 727a7d06..fa99b64f 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerStateObserver.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserver.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.util.List; @@ -73,7 +73,7 @@ public interface ContainerStateObserver { /** * Returns the list of observed containers. - * + * * @return the list of containers that should be observer */ public List getObservedContainers(); diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerStateObserverImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserverImpl.java similarity index 98% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ContainerStateObserverImpl.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserverImpl.java index 21549082..d10979a8 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerStateObserverImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserverImpl.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.util.ArrayList; import java.util.List; @@ -22,7 +22,7 @@ import java.util.TimerTask; import io.kubernetes.client.openapi.ApiException; -import org.hobbit.controller.interfaces.ContainerManager; +import org.hobbit.controller.containers.ContainerManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerTerminationCallback.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallback.java similarity index 96% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ContainerTerminationCallback.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallback.java index e28937e7..5a1a51b2 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerTerminationCallback.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallback.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; /** * These methods have to be implemented by a class that should be called if a diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerTerminationCallbackImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallbackImpl.java similarity index 95% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ContainerTerminationCallbackImpl.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallbackImpl.java index 175ec4f5..cdbc02ee 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ContainerTerminationCallbackImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallbackImpl.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; /** * Created by Timofey Ermilov on 01/09/16. diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/DockerUtility.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/DockerUtility.java similarity index 94% rename from platform-controller/src/main/java/org/hobbit/controller/docker/DockerUtility.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/DockerUtility.java index 2b3ba85c..6ccc0c52 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/DockerUtility.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/DockerUtility.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import com.spotify.docker.client.DefaultDockerClient; import com.spotify.docker.client.DockerClient; diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/FileBasedImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/FileBasedImageManager.java similarity index 99% rename from platform-controller/src/main/java/org/hobbit/controller/docker/FileBasedImageManager.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/FileBasedImageManager.java index e96a6faf..b935bfe1 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/FileBasedImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/FileBasedImageManager.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.io.File; import java.io.IOException; diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/GitlabBasedImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/GitlabBasedImageManager.java similarity index 98% rename from platform-controller/src/main/java/org/hobbit/controller/docker/GitlabBasedImageManager.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/GitlabBasedImageManager.java index 76af0876..7343af08 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/GitlabBasedImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/GitlabBasedImageManager.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.util.List; import java.util.Set; @@ -29,9 +29,9 @@ /** * An {@link ImageManager} implementation relying on the usage of a * {@link GitlabController}. - * + * * Created by Timofey Ermilov on 22/09/16. - * + * */ public class GitlabBasedImageManager extends AbstactImageManager implements ImageManager { diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManager.java similarity index 99% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ImageManager.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManager.java index e9edef50..de088142 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManager.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.util.Collections; import java.util.List; diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ImageManagerFacade.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManagerFacade.java similarity index 96% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ImageManagerFacade.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManagerFacade.java index 8fe487d9..82df1100 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ImageManagerFacade.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManagerFacade.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.util.ArrayList; import java.util.Arrays; @@ -12,7 +12,7 @@ * This Facade is able to manage one or more {@link ImageManager} instances and * handles the problem of benchmarks or systems sharing the same URI (see * https://github.com/hobbit-project/platform/issues/136). - * + * * @author Michael Röder (michael.roeder@uni-paderborn.de) * */ diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/MetaDataFactory.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/MetaDataFactory.java similarity index 98% rename from platform-controller/src/main/java/org/hobbit/controller/docker/MetaDataFactory.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/MetaDataFactory.java index 5731c4b1..68191112 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/MetaDataFactory.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/MetaDataFactory.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.io.ByteArrayInputStream; import java.io.StringReader; @@ -93,7 +93,7 @@ public static Model byteArrayToModel(byte data[], String lang) { * Creates a new model that contains all triples of the old model except the * definitions of other hobbit:Benchmark elements than the benchmark with the * given URI. - * + * * @param model the model from which all triples will be copied * @param benchmarkUri the URI of the only benchmark which is not removed from * the copied model @@ -110,7 +110,7 @@ public static Model getModelWithUniqueBenchmark(Model model, String benchmarkUri * have a system URI as subject. A system URI is a URI of a resource {@code s} * for which a triple {@code s rdf:type hobbit:SystemInstance} can be found in * the given model. - * + * * @param model the model from which all triples will be copied * @param systemUri the URI of the only system which is not removed from the * copied model diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ResourceInformationCollector.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollector.java similarity index 92% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ResourceInformationCollector.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollector.java index 6969542c..344f0d3d 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ResourceInformationCollector.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollector.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import org.hobbit.controller.data.SetupHardwareInformation; import org.hobbit.core.data.usage.ResourceUsageInformation; diff --git a/platform-controller/src/main/java/org/hobbit/controller/docker/ResourceInformationCollectorImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorImpl.java similarity index 99% rename from platform-controller/src/main/java/org/hobbit/controller/docker/ResourceInformationCollectorImpl.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorImpl.java index 2836024c..204176e8 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/docker/ResourceInformationCollectorImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorImpl.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.io.IOException; import java.net.MalformedURLException; @@ -13,7 +13,7 @@ import javax.ws.rs.core.UriBuilder; import org.apache.commons.io.IOUtils; -import org.hobbit.controller.interfaces.ContainerManager; +import org.hobbit.controller.containers.ContainerManager; import org.hobbit.core.Constants; import org.hobbit.core.data.usage.CpuStats; import org.hobbit.core.data.usage.DiskStats; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java new file mode 100644 index 00000000..d9d54ae8 --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java @@ -0,0 +1,86 @@ +package org.hobbit.controller.containers.kubernetes; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.models.V1Node; +import io.kubernetes.client.openapi.models.V1NodeList; +import org.hobbit.controller.containers.ClusterManager; + +import java.util.List; + +public class ClusterManagerImpl implements ClusterManager { + + private final CoreV1Api coreV1Api; + private Integer taskHistoryLimit = 0; // Default task history limit + + public ClusterManagerImpl(ApiClient apiClient) { + this.coreV1Api = new CoreV1Api(apiClient); + } + + + @Override + public long getNumberOfNodes() throws InterruptedException { + try { + V1NodeList nodeList = coreV1Api.listNode(null, null, null, null, null, null, null, null, null, false); + return nodeList.getItems().size(); + } catch (ApiException e) { + throw new RuntimeException("Failed to get the number of nodes", e); + } + } + + @Override + public long getNumberOfNodes(String label) throws InterruptedException { + try { + String labelSelector = label; + V1NodeList nodeList = coreV1Api.listNode(null, null, null, labelSelector, null, null, null, null, null, false); + return nodeList.getItems().size(); + } catch (ApiException e) { + throw new RuntimeException("Failed to get the number of nodes with label: " + label, e); + } + } + + @Override + public boolean isClusterHealthy() throws InterruptedException { + try { + V1NodeList nodeList = coreV1Api.listNode(null, null, null, null, null, null, null, null, null, false); + List nodes = nodeList.getItems(); + for (V1Node node : nodes) { + String status = node.getStatus().getConditions() + .stream() + .filter(condition -> "Ready".equals(condition.getType())) + .findFirst() + .map(condition -> condition.getStatus()) + .orElse("Unknown"); + + if (!"True".equalsIgnoreCase(status)) { + return false; + } + } + return true; + } catch (ApiException e) { + throw new RuntimeException("Failed to check cluster health", e); + } + } + + // TODO do we need this and should the environment variable be one or define another for kubernetes like KUB_NODE_NUMBER + @Override + public long getExpectedNumberOfNodes() { + String expectedNodesEnv = System.getenv("SWARM_NODE_NUMBER"); + return expectedNodesEnv != null ? Long.parseLong(expectedNodesEnv) : 0; + } + + @Override + public void setTaskHistoryLimit(Integer taskHistoryLimit) throws InterruptedException { + if (taskHistoryLimit == null || taskHistoryLimit < 0) { + throw new IllegalArgumentException("Task history limit must be non-negative"); + } + this.taskHistoryLimit = taskHistoryLimit; + // TODO define this for kubernetes because as default I could not find usage ! + } + + @Override + public int getTaskHistoryLimit() throws InterruptedException { + return this.taskHistoryLimit; + } +} diff --git a/platform-controller/src/main/java/org/hobbit/controller/kubernetes/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java similarity index 98% rename from platform-controller/src/main/java/org/hobbit/controller/kubernetes/ContainerManagerImpl.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java index 8b3c2ed3..cde28b6a 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/kubernetes/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java @@ -1,12 +1,11 @@ -package org.hobbit.controller.kubernetes; +package org.hobbit.controller.containers.kubernetes; import com.spotify.docker.client.exceptions.DockerException; import com.spotify.docker.client.messages.ContainerStats; -import com.spotify.docker.client.messages.swarm.Placement; import com.spotify.docker.client.messages.swarm.Resources; import com.spotify.docker.client.messages.swarm.Service; -import org.hobbit.controller.interfaces.ContainerManager; -import org.hobbit.controller.docker.ContainerStateObserver; +import org.hobbit.controller.containers.ContainerManager; +import org.hobbit.controller.containers.docker.ContainerStateObserver; import org.hobbit.controller.utils.Waiting; import org.hobbit.core.Constants; import org.slf4j.Logger; @@ -26,7 +25,7 @@ public class ContainerManagerImpl implements ContainerManager { - private static final Logger LOGGER = LoggerFactory.getLogger(org.hobbit.controller.kubernetes.ContainerManagerImpl.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ContainerManagerImpl.class); private ApiClient client; //TODO make configable private int TIMEOUT_MILLISECONDS = 60000; diff --git a/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java b/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java index 6ee359fb..b68ecd53 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java +++ b/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java @@ -35,8 +35,8 @@ import org.apache.jena.vocabulary.RDF; import org.hobbit.controller.ExperimentManager; import org.hobbit.controller.PlatformController; -import org.hobbit.controller.docker.ImageManager; -import org.hobbit.controller.docker.MetaDataFactory; +import org.hobbit.controller.containers.docker.ImageManager; +import org.hobbit.controller.containers.docker.MetaDataFactory; import org.hobbit.controller.execute.ExperimentAbortTimerTask; import org.hobbit.core.rabbit.RabbitMQUtils; import org.hobbit.vocab.HOBBIT; @@ -598,7 +598,7 @@ public void addMetaDataToResult(ImageManager imageManager, long endTimeStamp, /** * Returns the next error report ID for this experiment. Note that each call of * this method increases the error ID counter internally. - * + * * @return the next error report ID for this experiment */ public int getNextErrorReportId() { diff --git a/platform-controller/src/main/java/org/hobbit/controller/kubernetes/ClusterManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/kubernetes/ClusterManagerImpl.java deleted file mode 100644 index 5e5900da..00000000 --- a/platform-controller/src/main/java/org/hobbit/controller/kubernetes/ClusterManagerImpl.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.hobbit.controller.kubernetes; - -import com.spotify.docker.client.exceptions.DockerException; -import com.spotify.docker.client.messages.Info; -import org.hobbit.controller.interfaces.ClusterManager; - -public class ClusterManagerImpl implements ClusterManager { - @Override - public Info getClusterInfo() throws DockerException, InterruptedException { - return null; - } - - @Override - public long getNumberOfNodes() throws DockerException, InterruptedException { - return 0; - } - - @Override - public long getNumberOfNodes(String label) throws DockerException, InterruptedException { - return 0; - } - - @Override - public boolean isClusterHealthy() throws DockerException, InterruptedException { - return false; - } - - @Override - public long getExpectedNumberOfNodes() { - return 0; - } - - @Override - public void setTaskHistoryLimit(Integer taskHistoryLimit) throws DockerException, InterruptedException { - - } - - @Override - public int getTaskHistoryLimit() throws DockerException, InterruptedException { - return 0; - } -} diff --git a/platform-controller/src/test/java/org/hobbit/controller/ExperimentHardwareInformationTest.java b/platform-controller/src/test/java/org/hobbit/controller/ExperimentHardwareInformationTest.java index 04c69df2..2ff27347 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/ExperimentHardwareInformationTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/ExperimentHardwareInformationTest.java @@ -10,7 +10,7 @@ import org.apache.jena.vocabulary.RDF; import org.apache.jena.vocabulary.RDFS; import org.hobbit.controller.data.ExperimentConfiguration; -import org.hobbit.controller.docker.ResourceInformationCollectorImpl; +import org.hobbit.controller.containers.docker.ResourceInformationCollectorImpl; import org.hobbit.controller.mocks.DummyImageManager; import org.hobbit.controller.mocks.DummyPlatformController; import org.hobbit.controller.mocks.DummyStorageServiceClient; diff --git a/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java b/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java index 0e09111e..bba71039 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java @@ -33,7 +33,7 @@ import org.hobbit.controller.data.ExperimentStatus; import org.hobbit.controller.data.ExperimentStatus.States; import org.hobbit.controller.docker.ContainerManagerBasedTest; -import org.hobbit.controller.docker.ContainerManagerImpl; +import org.hobbit.controller.containers.docker.ContainerManagerImpl; import org.hobbit.core.Commands; import org.hobbit.core.Constants; import org.hobbit.utils.config.HobbitConfiguration; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ClusterManagerImplTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/ClusterManagerImplTest.java index c3060c51..a14a4acf 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ClusterManagerImplTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/ClusterManagerImplTest.java @@ -1,6 +1,7 @@ package org.hobbit.controller.docker; import com.spotify.docker.client.messages.Info; +import org.hobbit.controller.containers.docker.ClusterManagerImpl; import org.junit.Before; import org.junit.Test; @@ -15,11 +16,11 @@ public void setUp() throws Exception { clusterManager = new ClusterManagerImpl(); } - @Test - public void getClusterInfo() throws Exception { - final Info info = clusterManager.getClusterInfo(); - assertNotNull(info); - } +// @Test +// public void getClusterInfo() throws Exception { +// final Info info = clusterManager.getClusterInfo(); +// assertNotNull(info); +// } @Test public void getNumberOfNodes() throws Exception { @@ -55,4 +56,4 @@ public void setTaskHistoryLimit() throws Exception { } -} \ No newline at end of file +} diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerAccessByHostnameTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerAccessByHostnameTest.java index f70bed93..cf69db41 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerAccessByHostnameTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerAccessByHostnameTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertNotNull; import com.spotify.docker.client.messages.ContainerConfig; +import org.hobbit.controller.containers.docker.ContainerManagerImpl; import org.hobbit.core.Constants; import org.junit.Test; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerBasedTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerBasedTest.java index dfa3512b..9b5d14ad 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerBasedTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerBasedTest.java @@ -20,6 +20,7 @@ import java.util.List; import org.hobbit.controller.DockerBasedTest; +import org.hobbit.controller.containers.docker.ContainerManagerImpl; import org.junit.After; import org.junit.Before; import org.slf4j.Logger; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerImplTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerImplTest.java index 4ad24b36..8cffa1c4 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerImplTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerImplTest.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.stream.Collectors; +import org.hobbit.controller.containers.docker.ContainerManagerImpl; import org.hobbit.core.Constants; import org.junit.Assert; import org.junit.Assume; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerStateObserverImplTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerStateObserverImplTest.java index f49452f3..1e600cb8 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerStateObserverImplTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerStateObserverImplTest.java @@ -16,7 +16,9 @@ */ package org.hobbit.controller.docker; -import org.hobbit.controller.interfaces.ContainerManager; +import org.hobbit.controller.containers.docker.ContainerStateObserverImpl; +import org.hobbit.controller.containers.docker.ContainerTerminationCallbackImpl; +import org.hobbit.controller.containers.ContainerManager; import org.junit.Assert; import org.junit.Before; import org.junit.Test; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerTerminationCallbackImplTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerTerminationCallbackImplTest.java index 6f08ead8..87cfc5b8 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerTerminationCallbackImplTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerTerminationCallbackImplTest.java @@ -16,6 +16,7 @@ */ package org.hobbit.controller.docker; +import org.hobbit.controller.containers.docker.ContainerTerminationCallbackImpl; import org.junit.Test; import static org.junit.Assert.*; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java index 853c78da..243526ea 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java @@ -1,5 +1,6 @@ package org.hobbit.controller.docker; +import org.hobbit.controller.containers.docker.FileBasedImageManager; import org.hobbit.core.data.BenchmarkMetaData; import org.hobbit.core.data.SystemMetaData; import org.junit.Assert; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java index b7bccc9d..6df7fc64 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java @@ -26,6 +26,7 @@ import org.apache.jena.rdf.model.Model; import org.apache.jena.vocabulary.RDF; import org.hobbit.controller.ConnectivityAssumptionUtils; +import org.hobbit.controller.containers.docker.GitlabBasedImageManager; import org.hobbit.controller.gitlab.GitlabControllerImplTest; import org.hobbit.core.data.BenchmarkMetaData; import org.hobbit.core.data.SystemMetaData; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java index 3d07663e..aac7eca1 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java @@ -10,6 +10,7 @@ import org.apache.commons.compress.utils.IOUtils; import org.apache.log4j.lf5.util.StreamUtils; import org.hobbit.controller.ParameterForwardingTest; +import org.hobbit.controller.containers.docker.MetaDataFactory; import org.hobbit.core.data.BenchmarkMetaData; import org.hobbit.core.data.ImageMetaData; import org.hobbit.core.data.SystemMetaData; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ResourceInformationCollectorTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/ResourceInformationCollectorTest.java index 0fa2b317..d71e9e3b 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ResourceInformationCollectorTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/ResourceInformationCollectorTest.java @@ -7,6 +7,8 @@ import org.apache.jena.sparql.vocabulary.DOAP; import org.apache.jena.vocabulary.RDF; import org.apache.jena.vocabulary.RDFS; +import org.hobbit.controller.containers.docker.ResourceInformationCollector; +import org.hobbit.controller.containers.docker.ResourceInformationCollectorImpl; import org.hobbit.controller.data.SetupHardwareInformation; import org.hobbit.core.Constants; import org.hobbit.core.data.usage.ResourceUsageInformation; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/VersionTagIdentificationTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/VersionTagIdentificationTest.java index e483711a..8449960a 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/VersionTagIdentificationTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/VersionTagIdentificationTest.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.List; +import org.hobbit.controller.containers.docker.ContainerManagerImpl; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java index 04c31a87..fcd9969d 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java @@ -5,9 +5,9 @@ import java.util.Map; import java.util.concurrent.Semaphore; -import org.hobbit.controller.interfaces.ContainerManager; -import org.hobbit.controller.docker.ContainerStateObserver; -import org.hobbit.controller.docker.ContainerTerminationCallback; +import org.hobbit.controller.containers.ContainerManager; +import org.hobbit.controller.containers.docker.ContainerStateObserver; +import org.hobbit.controller.containers.docker.ContainerTerminationCallback; import com.spotify.docker.client.messages.ContainerStats; import com.spotify.docker.client.messages.swarm.Service; diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyImageManager.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyImageManager.java index ce815c2e..884b1c5c 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyImageManager.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyImageManager.java @@ -4,7 +4,7 @@ import java.util.HashSet; import java.util.List; import org.apache.jena.rdf.model.ModelFactory; -import org.hobbit.controller.docker.ImageManager; +import org.hobbit.controller.containers.docker.ImageManager; import org.hobbit.core.data.BenchmarkMetaData; import org.hobbit.core.data.SystemMetaData; diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyPlatformController.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyPlatformController.java index 2ef8c689..62db965e 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyPlatformController.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyPlatformController.java @@ -4,7 +4,7 @@ import com.spotify.docker.client.exceptions.DockerCertificateException; import java.io.IOException; import java.util.concurrent.Semaphore; -import org.hobbit.controller.docker.ClusterManagerImpl; +import org.hobbit.controller.containers.docker.ClusterManagerImpl; import org.hobbit.controller.PlatformController; import org.hobbit.controller.queue.InMemoryQueue; diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java index 06bcb903..aaa40a9d 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java @@ -2,7 +2,7 @@ import com.spotify.docker.client.messages.swarm.Service; import org.hobbit.controller.data.SetupHardwareInformation; -import org.hobbit.controller.docker.ResourceInformationCollector; +import org.hobbit.controller.containers.docker.ResourceInformationCollector; import org.hobbit.core.data.usage.ResourceUsageInformation; public class DummyResourceInformationCollector implements ResourceInformationCollector { From 5d317b347b1375932a725c726e5ea877e051127d Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 28 Jan 2025 11:05:14 +0100 Subject: [PATCH 04/52] move to kub directory --- platform-controller/pom.xml | 8 ++ .../hobbit/controller/PlatformController.java | 10 +- .../{docker => }/AbstactImageManager.java | 3 +- .../containers/ContainerManager.java | 1 - .../{docker => }/ContainerStateObserver.java | 2 +- .../ContainerTerminationCallback.java | 4 +- .../containers/{docker => }/ImageManager.java | 2 +- .../{docker => }/ImageManagerFacade.java | 2 +- .../ResourceInformationCollector.java | 2 +- .../docker/ContainerManagerImpl.java | 1 + .../docker/ContainerStateObserverImpl.java | 2 + .../ContainerTerminationCallbackImpl.java | 2 + .../docker/FileBasedImageManager.java | 1 + .../docker/GitlabBasedImageManager.java | 2 + .../ResourceInformationCollectorImpl.java | 1 + .../kubernetes/ContainerManagerImpl.java | 7 +- .../ContainerStateObserverImpl.java | 135 ++++++++++++++++++ .../ContainerTerminationCallbackImpl.java | 22 +++ .../ResourceInformationCollectorImpl.java | 122 ++++++++++++++++ .../controller/data/ExperimentStatus.java | 2 +- .../ResourceInformationCollectorTest.java | 2 +- .../mocks/DummyContainerManager.java | 4 +- .../controller/mocks/DummyImageManager.java | 2 +- .../DummyResourceInformationCollector.java | 2 +- 24 files changed, 317 insertions(+), 24 deletions(-) rename platform-controller/src/main/java/org/hobbit/controller/containers/{docker => }/AbstactImageManager.java (98%) rename platform-controller/src/main/java/org/hobbit/controller/containers/{docker => }/ContainerStateObserver.java (98%) rename platform-controller/src/main/java/org/hobbit/controller/containers/{docker => }/ContainerTerminationCallback.java (92%) rename platform-controller/src/main/java/org/hobbit/controller/containers/{docker => }/ImageManager.java (99%) rename platform-controller/src/main/java/org/hobbit/controller/containers/{docker => }/ImageManagerFacade.java (97%) rename platform-controller/src/main/java/org/hobbit/controller/containers/{docker => }/ResourceInformationCollector.java (92%) create mode 100644 platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java create mode 100644 platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerTerminationCallbackImpl.java create mode 100644 platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java diff --git a/platform-controller/pom.xml b/platform-controller/pom.xml index 91c86ead..a6443ed7 100644 --- a/platform-controller/pom.xml +++ b/platform-controller/pom.xml @@ -30,6 +30,7 @@ 18.0.0 + @@ -121,6 +122,13 @@ client-java ${kubernetes-client.version} + + + + + + + diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 7c1be569..6597effc 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -53,14 +53,14 @@ import org.hobbit.controller.containers.docker.ClusterManagerImpl; import org.hobbit.controller.containers.ContainerManager; import org.hobbit.controller.containers.docker.ContainerManagerImpl; -import org.hobbit.controller.containers.docker.ContainerStateObserver; +import org.hobbit.controller.containers.ContainerStateObserver; import org.hobbit.controller.containers.docker.ContainerStateObserverImpl; -import org.hobbit.controller.containers.docker.ContainerTerminationCallback; +import org.hobbit.controller.containers.ContainerTerminationCallback; import org.hobbit.controller.containers.docker.FileBasedImageManager; import org.hobbit.controller.containers.docker.GitlabBasedImageManager; -import org.hobbit.controller.containers.docker.ImageManager; -import org.hobbit.controller.containers.docker.ImageManagerFacade; -import org.hobbit.controller.containers.docker.ResourceInformationCollector; +import org.hobbit.controller.containers.ImageManager; +import org.hobbit.controller.containers.ImageManagerFacade; +import org.hobbit.controller.containers.ResourceInformationCollector; import org.hobbit.controller.containers.docker.ResourceInformationCollectorImpl; import org.hobbit.controller.front.FrontEndApiHandler; import org.hobbit.controller.queue.ExperimentQueue; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/AbstactImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/AbstactImageManager.java similarity index 98% rename from platform-controller/src/main/java/org/hobbit/controller/containers/docker/AbstactImageManager.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/AbstactImageManager.java index 82b5c702..795307cf 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/AbstactImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/AbstactImageManager.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.containers.docker; +package org.hobbit.controller.containers; import java.util.Collections; import java.util.Comparator; @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.hobbit.controller.containers.ImageManager; import org.hobbit.core.data.BenchmarkMetaData; import org.hobbit.core.data.ImageMetaData; import org.hobbit.core.data.SystemMetaData; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java index 9de53e64..3fe9a1a6 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java @@ -20,7 +20,6 @@ import java.util.Map; import io.kubernetes.client.openapi.ApiException; -import org.hobbit.controller.containers.docker.ContainerStateObserver; import org.hobbit.core.Constants; import com.spotify.docker.client.exceptions.DockerException; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserver.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerStateObserver.java similarity index 98% rename from platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserver.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/ContainerStateObserver.java index fa99b64f..2c9da86b 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserver.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerStateObserver.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.containers.docker; +package org.hobbit.controller.containers; import java.util.List; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallback.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerTerminationCallback.java similarity index 92% rename from platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallback.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/ContainerTerminationCallback.java index 5a1a51b2..7322a9fd 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallback.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerTerminationCallback.java @@ -14,7 +14,9 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.containers.docker; +package org.hobbit.controller.containers; + +import org.hobbit.controller.containers.ContainerStateObserver; /** * These methods have to be implemented by a class that should be called if a diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ImageManager.java similarity index 99% rename from platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManager.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/ImageManager.java index de088142..7e67834f 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ImageManager.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.containers.docker; +package org.hobbit.controller.containers; import java.util.Collections; import java.util.List; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManagerFacade.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ImageManagerFacade.java similarity index 97% rename from platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManagerFacade.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/ImageManagerFacade.java index 82df1100..2f0df8d2 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ImageManagerFacade.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ImageManagerFacade.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.containers.docker; +package org.hobbit.controller.containers; import java.util.ArrayList; import java.util.Arrays; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollector.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ResourceInformationCollector.java similarity index 92% rename from platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollector.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/ResourceInformationCollector.java index 344f0d3d..e8994fdb 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollector.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ResourceInformationCollector.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.containers.docker; +package org.hobbit.controller.containers; import org.hobbit.controller.data.SetupHardwareInformation; import org.hobbit.core.data.usage.ResourceUsageInformation; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java index 3071e7fa..fdd5854f 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java @@ -29,6 +29,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.hobbit.controller.containers.ContainerStateObserver; import org.hobbit.controller.gitlab.GitlabControllerImpl; import org.hobbit.controller.containers.ClusterManager; import org.hobbit.controller.containers.ContainerManager; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserverImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserverImpl.java index d10979a8..3cd6f202 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserverImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserverImpl.java @@ -23,6 +23,8 @@ import io.kubernetes.client.openapi.ApiException; import org.hobbit.controller.containers.ContainerManager; +import org.hobbit.controller.containers.ContainerStateObserver; +import org.hobbit.controller.containers.ContainerTerminationCallback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallbackImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallbackImpl.java index cdbc02ee..148f1c6b 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallbackImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerTerminationCallbackImpl.java @@ -16,6 +16,8 @@ */ package org.hobbit.controller.containers.docker; +import org.hobbit.controller.containers.ContainerTerminationCallback; + /** * Created by Timofey Ermilov on 01/09/16. */ diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/FileBasedImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/FileBasedImageManager.java index b935bfe1..adf755ea 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/FileBasedImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/FileBasedImageManager.java @@ -28,6 +28,7 @@ import org.apache.commons.io.FileUtils; import org.apache.jena.rdf.model.Model; +import org.hobbit.controller.containers.AbstactImageManager; import org.hobbit.core.data.BenchmarkMetaData; import org.hobbit.core.data.SystemMetaData; import org.slf4j.Logger; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/GitlabBasedImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/GitlabBasedImageManager.java index 7343af08..648f4484 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/GitlabBasedImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/GitlabBasedImageManager.java @@ -20,6 +20,8 @@ import java.util.Set; import java.util.stream.Collectors; +import org.hobbit.controller.containers.AbstactImageManager; +import org.hobbit.controller.containers.ImageManager; import org.hobbit.controller.gitlab.GitlabController; import org.hobbit.controller.gitlab.GitlabControllerImpl; import org.hobbit.controller.gitlab.Project; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorImpl.java index 204176e8..3f385641 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorImpl.java @@ -14,6 +14,7 @@ import org.apache.commons.io.IOUtils; import org.hobbit.controller.containers.ContainerManager; +import org.hobbit.controller.containers.ResourceInformationCollector; import org.hobbit.core.Constants; import org.hobbit.core.data.usage.CpuStats; import org.hobbit.core.data.usage.DiskStats; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java index cde28b6a..23d691bf 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java @@ -1,11 +1,7 @@ package org.hobbit.controller.containers.kubernetes; -import com.spotify.docker.client.exceptions.DockerException; -import com.spotify.docker.client.messages.ContainerStats; -import com.spotify.docker.client.messages.swarm.Resources; -import com.spotify.docker.client.messages.swarm.Service; import org.hobbit.controller.containers.ContainerManager; -import org.hobbit.controller.containers.docker.ContainerStateObserver; +import org.hobbit.controller.containers.ContainerStateObserver; import org.hobbit.controller.utils.Waiting; import org.hobbit.core.Constants; import org.slf4j.Logger; @@ -462,7 +458,6 @@ public Long getContainerPodExitCode(String podName) throws DockerException, Inte // } - // used in ResourceInformationCollectorImpl @Override public List getContainers(Service.Criteria criteria) { return null; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java new file mode 100644 index 00000000..f813e02e --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java @@ -0,0 +1,135 @@ +package org.hobbit.controller.containers.kubernetes; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.models.V1Pod; +import io.kubernetes.client.openapi.models.V1PodList; +import org.hobbit.controller.containers.ContainerStateObserver; +import org.hobbit.controller.containers.ContainerTerminationCallback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +public class ContainerStateObserverImpl implements ContainerStateObserver { + + private static final Logger LOGGER = LoggerFactory.getLogger(ContainerStateObserverImpl.class); + + private final ApiClient apiClient; + private final CoreV1Api coreV1Api; + private final List monitoredContainers; + private final List terminationCallbacks; + private final Timer timer; + private final int repeatInterval; + + public ContainerStateObserverImpl(ApiClient apiClient, int repeatInterval) { + this.apiClient = apiClient; + this.coreV1Api = new CoreV1Api(apiClient); + this.monitoredContainers = new ArrayList<>(); + this.terminationCallbacks = new ArrayList<>(); + this.timer = new Timer(); + this.repeatInterval = repeatInterval; + } + + @Override + public void startObserving() { + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + List containerNames; + synchronized (monitoredContainers) { + containerNames = new ArrayList<>(monitoredContainers); + } + + for (String containerName : containerNames) { + try { + V1Pod pod = getPodByContainerName(containerName); + if (pod != null && isPodTerminated(pod)) { + int exitCode = getPodExitCode(pod); + + for (ContainerTerminationCallback callback : terminationCallbacks) { + try { + callback.notifyTermination(containerName, exitCode); + } catch (Exception e) { + LOGGER.error("Error while calling container termination callback.", e); + } + } + } + } catch (ApiException e) { + LOGGER.error("Couldn't get the status of container " + containerName + ". It will be ignored during this run but will be checked again during the next run.", e); + } + } + } + }, repeatInterval, repeatInterval); + } + + @Override + public void stopObserving() { + timer.cancel(); + timer.purge(); + } + + @Override + public void addTerminationCallback(ContainerTerminationCallback callback) { + terminationCallbacks.add(callback); + } + + @Override + public void removeTerminationCallback(ContainerTerminationCallback callback) { + terminationCallbacks.remove(callback); + } + + @Override + public void addObservedContainer(String containerName) { + synchronized (monitoredContainers) { + if (!monitoredContainers.contains(containerName)) { + monitoredContainers.add(containerName); + } + } + } + + @Override + public void removedObservedContainer(String containerName) { + synchronized (monitoredContainers) { + monitoredContainers.remove(containerName); + } + } + + @Override + public List getObservedContainers() { + synchronized (monitoredContainers) { + return new ArrayList<>(monitoredContainers); + } + } + + private V1Pod getPodByContainerName(String containerName) throws ApiException { + V1PodList podList = coreV1Api.listPodForAllNamespaces(null, null, null, "", null, null, null, null, null, false); + for (V1Pod pod : podList.getItems()) { + if (pod.getStatus() != null && pod.getStatus().getContainerStatuses() != null) { + if (pod.getStatus().getContainerStatuses().stream().anyMatch(status -> containerName.equals(status.getName()))) { + return pod; + } + } + } + return null; + } + + private boolean isPodTerminated(V1Pod pod) { + return pod.getStatus() != null && "Succeeded".equals(pod.getStatus().getPhase()) || "Failed".equals(pod.getStatus().getPhase()); + } + + private int getPodExitCode(V1Pod pod) { + if (pod.getStatus() != null && pod.getStatus().getContainerStatuses() != null) { + return pod.getStatus().getContainerStatuses().stream() + .filter(status -> status.getState() != null && status.getState().getTerminated() != null) + .findFirst() + .map(status -> status.getState().getTerminated().getExitCode().intValue()) + .orElse(0); + } + return 0; + } +} diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerTerminationCallbackImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerTerminationCallbackImpl.java new file mode 100644 index 00000000..131203b8 --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerTerminationCallbackImpl.java @@ -0,0 +1,22 @@ +package org.hobbit.controller.containers.kubernetes; + +import org.hobbit.controller.containers.ContainerTerminationCallback; + +public class ContainerTerminationCallbackImpl implements ContainerTerminationCallback { + private String containerId; + private long exitCode; + + @Override + public void notifyTermination(String containerId, long exitCode) { + this.containerId = containerId; + this.exitCode = exitCode; + } + + public String getContainerId() { + return containerId; + } + + public long getExitCode() { + return exitCode; + } +} diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java new file mode 100644 index 00000000..1c4535b5 --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java @@ -0,0 +1,122 @@ +package org.hobbit.controller.containers.kubernetes; +import com.spotify.docker.client.messages.swarm.Service; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.apis.MetricsApi; +import io.kubernetes.client.openapi.models.V1Node; +import io.kubernetes.client.openapi.models.V1NodeList; +import io.kubernetes.client.openapi.models.V1PodMetrics; +import io.kubernetes.client.openapi.models.V1PodMetricsList; +import io.kubernetes.client.util.Config; +import org.hobbit.controller.containers.ResourceInformationCollector; +import org.hobbit.core.data.usage.ResourceUsageInformation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; +public class ResourceInformationCollectorImpl implements ResourceInformationCollector { + + private static final Logger LOGGER = LoggerFactory.getLogger(ResourceInformationCollectorImpl.class); + + private final ApiClient apiClient; + private final MetricsApi metricsApi; + + public ResourceInformationCollectorImpl() throws IOException { + this.apiClient = Config.defaultClient(); + this.metricsApi = new MetricsApi(apiClient); + } + + @Override + public ResourceUsageInformation getSystemUsageInformation() { + return getUsageInformation(null); + } + + @Override + public ResourceUsageInformation getUsageInformation(Service.Criteria criteria) { + return null; + } + + @Override + public ResourceUsageInformation getUsageInformation( criteria) { + try { + V1PodMetricsList podMetricsList = metricsApi.listPodMetricsForAllNamespaces( + null, null, null, null, null, null, null, null, null); + + List filteredMetrics = podMetricsList.getItems(); + + // If criteria exist, filter pods accordingly (example: by namespace or labels) + if (criteria != null) { + filteredMetrics = filteredMetrics.stream() + .filter(metrics -> matchesCriteria(metrics, criteria)) + .collect(Collectors.toList()); + } + + return aggregatePodMetrics(filteredMetrics); + + } catch (ApiException e) { + LOGGER.error("Error retrieving pod metrics from Kubernetes", e); + return null; + } + } + + @Override + public SetupHardwareInformation getHardwareInformation() { + SetupHardwareInformation hardwareInfo = new SetupHardwareInformation(); + try { + V1NodeList nodeList = new MetricsApi(apiClient).listNode(null, null, null, null, null, null, null, null, null); + + for (V1Node node : nodeList.getItems()) { + NodeHardwareInformation nodeInfo = new NodeHardwareInformation(); + nodeInfo.setInstance(node.getMetadata().getName()); + nodeInfo.setCpu( + Long.parseLong(node.getStatus().getCapacity().get("cpu").toString()), + Collections.singletonList(Long.parseLong(node.getStatus().getCapacity().get("cpu").toString())) + ); + nodeInfo.setMemory( + Long.parseLong(node.getStatus().getCapacity().get("memory").toString().replaceAll("[^\\d]", "")), + null + ); + nodeInfo.setOs(node.getStatus().getNodeInfo().getOsImage()); + hardwareInfo.addNode(nodeInfo); + } + + } catch (ApiException e) { + LOGGER.error("Error retrieving hardware information from Kubernetes nodes", e); + } + + return hardwareInfo; + } + + private boolean matchesCriteria(V1PodMetrics metrics, Criteria criteria) { + // Example implementation: filter by namespace + if (criteria.getNamespace() != null && !criteria.getNamespace().equals(metrics.getMetadata().getNamespace())) { + return false; + } + // Add additional criteria filtering logic if necessary + return true; + } + + private ResourceUsageInformation aggregatePodMetrics(List podMetrics) { + ResourceUsageInformation resourceInfo = new ResourceUsageInformation(); + podMetrics.forEach(metrics -> { + metrics.getContainers().forEach(container -> { + try { + long memoryUsage = Long.parseLong( + container.getUsage().get("memory").replaceAll("[^\\d]", "")); + long cpuUsage = Long.parseLong( + container.getUsage().get("cpu").replaceAll("[^\\d]", "")); + + resourceInfo.addMemoryUsage(memoryUsage); + resourceInfo.addCpuUsage(cpuUsage); + + } catch (NumberFormatException e) { + LOGGER.warn("Error parsing resource usage for container: {}", container.getName(), e); + } + }); + }); + + return resourceInfo; + } +} diff --git a/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java b/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java index b68ecd53..d58f1cf6 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java +++ b/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java @@ -35,7 +35,7 @@ import org.apache.jena.vocabulary.RDF; import org.hobbit.controller.ExperimentManager; import org.hobbit.controller.PlatformController; -import org.hobbit.controller.containers.docker.ImageManager; +import org.hobbit.controller.containers.ImageManager; import org.hobbit.controller.containers.docker.MetaDataFactory; import org.hobbit.controller.execute.ExperimentAbortTimerTask; import org.hobbit.core.rabbit.RabbitMQUtils; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ResourceInformationCollectorTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/ResourceInformationCollectorTest.java index d71e9e3b..d252a955 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ResourceInformationCollectorTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/ResourceInformationCollectorTest.java @@ -7,7 +7,7 @@ import org.apache.jena.sparql.vocabulary.DOAP; import org.apache.jena.vocabulary.RDF; import org.apache.jena.vocabulary.RDFS; -import org.hobbit.controller.containers.docker.ResourceInformationCollector; +import org.hobbit.controller.containers.ResourceInformationCollector; import org.hobbit.controller.containers.docker.ResourceInformationCollectorImpl; import org.hobbit.controller.data.SetupHardwareInformation; import org.hobbit.core.Constants; diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java index fcd9969d..cdd3560c 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java @@ -6,8 +6,8 @@ import java.util.concurrent.Semaphore; import org.hobbit.controller.containers.ContainerManager; -import org.hobbit.controller.containers.docker.ContainerStateObserver; -import org.hobbit.controller.containers.docker.ContainerTerminationCallback; +import org.hobbit.controller.containers.ContainerStateObserver; +import org.hobbit.controller.containers.ContainerTerminationCallback; import com.spotify.docker.client.messages.ContainerStats; import com.spotify.docker.client.messages.swarm.Service; diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyImageManager.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyImageManager.java index 884b1c5c..92cbc8ab 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyImageManager.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyImageManager.java @@ -4,7 +4,7 @@ import java.util.HashSet; import java.util.List; import org.apache.jena.rdf.model.ModelFactory; -import org.hobbit.controller.containers.docker.ImageManager; +import org.hobbit.controller.containers.ImageManager; import org.hobbit.core.data.BenchmarkMetaData; import org.hobbit.core.data.SystemMetaData; diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java index aaa40a9d..b2415cf3 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java @@ -2,7 +2,7 @@ import com.spotify.docker.client.messages.swarm.Service; import org.hobbit.controller.data.SetupHardwareInformation; -import org.hobbit.controller.containers.docker.ResourceInformationCollector; +import org.hobbit.controller.containers.ResourceInformationCollector; import org.hobbit.core.data.usage.ResourceUsageInformation; public class DummyResourceInformationCollector implements ResourceInformationCollector { From 3db7479f3fe99825337d246cea6753e44acd0b62 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 3 Feb 2025 14:40:08 +0100 Subject: [PATCH 05/52] add yaml files --- kubernetes-yaml-files/00-rabbitmq-pvc.yaml | 10 +++ .../01-rabbitmq-deployment.yaml | 77 +++++++++++++++++++ .../02-rabbitmq-service.yaml | 17 ++++ .../03-storage-deployment.yaml | 46 +++++++++++ kubernetes-yaml-files/04-storage-service.yaml | 14 ++++ kubernetes-yaml-files/05-storage-pvc.yaml | 10 +++ kubernetes-yaml-files/06-virtuoso-pvc.yaml | 12 +++ .../07-virtuoso-deployment.yaml | 36 +++++++++ .../08-virtuoso-service.yaml | 19 +++++ .../{docker => }/FileBasedImageManager.java | 2 +- .../{docker => }/GitlabBasedImageManager.java | 2 +- .../{docker => }/MetaDataFactory.java | 2 +- 12 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 kubernetes-yaml-files/00-rabbitmq-pvc.yaml create mode 100644 kubernetes-yaml-files/01-rabbitmq-deployment.yaml create mode 100644 kubernetes-yaml-files/02-rabbitmq-service.yaml create mode 100644 kubernetes-yaml-files/03-storage-deployment.yaml create mode 100644 kubernetes-yaml-files/04-storage-service.yaml create mode 100644 kubernetes-yaml-files/05-storage-pvc.yaml create mode 100644 kubernetes-yaml-files/06-virtuoso-pvc.yaml create mode 100644 kubernetes-yaml-files/07-virtuoso-deployment.yaml create mode 100644 kubernetes-yaml-files/08-virtuoso-service.yaml rename platform-controller/src/main/java/org/hobbit/controller/containers/{docker => }/FileBasedImageManager.java (99%) rename platform-controller/src/main/java/org/hobbit/controller/containers/{docker => }/GitlabBasedImageManager.java (98%) rename platform-controller/src/main/java/org/hobbit/controller/containers/{docker => }/MetaDataFactory.java (99%) diff --git a/kubernetes-yaml-files/00-rabbitmq-pvc.yaml b/kubernetes-yaml-files/00-rabbitmq-pvc.yaml new file mode 100644 index 00000000..44b71796 --- /dev/null +++ b/kubernetes-yaml-files/00-rabbitmq-pvc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: rabbitmq-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/kubernetes-yaml-files/01-rabbitmq-deployment.yaml b/kubernetes-yaml-files/01-rabbitmq-deployment.yaml new file mode 100644 index 00000000..265ed9e2 --- /dev/null +++ b/kubernetes-yaml-files/01-rabbitmq-deployment.yaml @@ -0,0 +1,77 @@ +#apiVersion: apps/v1 +#kind: Deployment +#metadata: +# name: rabbitmq +# labels: +# app: rabbitmq +#spec: +# replicas: 1 +# selector: +# matchLabels: +# app: rabbitmq +# template: +# metadata: +# labels: +# app: rabbitmq +# spec: +# containers: +# - name: rabbitmq +# image: rabbitmq:3-management +# ports: +# - containerPort: 5672 # AMQP protocol (for applications) +# - containerPort: 15672 # Management UI (for admins) +# env: +# - name: RABBITMQ_DEFAULT_USER +# value: "guest" +# - name: RABBITMQ_DEFAULT_PASS +# value: "guest" +# volumeMounts: +# - mountPath: /var/lib/rabbitmq +# name: rabbitmq-storage +# volumes: +# - name: rabbitmq-storage +# persistentVolumeClaim: +# claimName: rabbitmq-pvc +apiVersion: apps/v1 +kind: Deployment +metadata: + name: rabbitmq + labels: + app: rabbitmq +spec: + replicas: 1 + selector: + matchLabels: + app: rabbitmq + template: + metadata: + labels: + app: rabbitmq + spec: + containers: + - name: rabbitmq + image: rabbitmq:3-management + ports: + - containerPort: 5672 # AMQP protocol (for applications) + - containerPort: 15672 # Management UI (for admins) + env: + - name: RABBITMQ_DEFAULT_USER + value: "guest" + - name: RABBITMQ_DEFAULT_PASS + value: "guest" + volumeMounts: + - mountPath: /var/lib/rabbitmq + name: rabbitmq-storage + initContainers: + - name: configure-rabbitmq + image: busybox + command: ['sh', '-c', 'echo "loopback_users.guest = false" > /etc/rabbitmq/rabbitmq.conf'] + volumeMounts: + - mountPath: /etc/rabbitmq + name: rabbitmq-config + volumes: + - name: rabbitmq-storage + persistentVolumeClaim: + claimName: rabbitmq-pvc + - name: rabbitmq-config + emptyDir: {} diff --git a/kubernetes-yaml-files/02-rabbitmq-service.yaml b/kubernetes-yaml-files/02-rabbitmq-service.yaml new file mode 100644 index 00000000..0420a296 --- /dev/null +++ b/kubernetes-yaml-files/02-rabbitmq-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: rabbitmq + labels: + app: rabbitmq +spec: + selector: + app: rabbitmq + ports: + - name: amqp + port: 5672 # Exposes AMQP port inside the cluster + targetPort: 5672 + - name: management + port: 15672 # Exposes the Management UI inside the cluster + targetPort: 15672 + type: ClusterIP # Internal access only diff --git a/kubernetes-yaml-files/03-storage-deployment.yaml b/kubernetes-yaml-files/03-storage-deployment.yaml new file mode 100644 index 00000000..f47f3468 --- /dev/null +++ b/kubernetes-yaml-files/03-storage-deployment.yaml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hobbit-storage-service-deployment + labels: + app: hobbit-storage-service +spec: + replicas: 1 + selector: + matchLabels: + app: hobbit-storage-service + template: + metadata: + labels: + app: hobbit-storage-service + spec: + containers: + - name: storage-service + image: hobbit/storage_service:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + env: + - name: JAVA_OPTS + value: "-Xmx256m -Xms128m" + - name: HOBBIT_RABBIT_HOST + value: rabbitmq # The name of the RabbitMQ service (02-rabbitmq-service.yaml) + volumeMounts: + - mountPath: /path/to/mount + name: storage-volume + livenessProbe: + httpGet: + path: /actuator/health + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /actuator/health + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + volumes: + - name: storage-volume + persistentVolumeClaim: + claimName: hobbit-storage-pvc diff --git a/kubernetes-yaml-files/04-storage-service.yaml b/kubernetes-yaml-files/04-storage-service.yaml new file mode 100644 index 00000000..a92a987f --- /dev/null +++ b/kubernetes-yaml-files/04-storage-service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: hobbit-storage-service + labels: + app: hobbit-storage-service +spec: + selector: + app: hobbit-storage-service + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 + type: NodePort # change for deployment ( for test keep it) diff --git a/kubernetes-yaml-files/05-storage-pvc.yaml b/kubernetes-yaml-files/05-storage-pvc.yaml new file mode 100644 index 00000000..ec610886 --- /dev/null +++ b/kubernetes-yaml-files/05-storage-pvc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: hobbit-storage-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/kubernetes-yaml-files/06-virtuoso-pvc.yaml b/kubernetes-yaml-files/06-virtuoso-pvc.yaml new file mode 100644 index 00000000..7f6503bd --- /dev/null +++ b/kubernetes-yaml-files/06-virtuoso-pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: virtuoso-pvc + labels: + app: virtuoso +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/kubernetes-yaml-files/07-virtuoso-deployment.yaml b/kubernetes-yaml-files/07-virtuoso-deployment.yaml new file mode 100644 index 00000000..d80530e6 --- /dev/null +++ b/kubernetes-yaml-files/07-virtuoso-deployment.yaml @@ -0,0 +1,36 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: virtuoso + labels: + app: virtuoso +spec: + replicas: 1 + selector: + matchLabels: + app: virtuoso + template: + metadata: + labels: + app: virtuoso + spec: + containers: + - name: virtuoso + image: openlink/virtuoso-opensource-7:latest + ports: + - containerPort: 8890 # HTTP (SPARQL endpoint) + - containerPort: 1111 # ISQL (command-line interface) + env: + - name: VIRTUOSO_DBNAME + value: "virtuoso" + - name: VIRTUOSO_USER + value: "dba" + - name: VIRTUOSO_PASSWORD + value: "dba" + volumeMounts: + - mountPath: /data + name: virtuoso-storage + volumes: + - name: virtuoso-storage + persistentVolumeClaim: + claimName: virtuoso-pvc diff --git a/kubernetes-yaml-files/08-virtuoso-service.yaml b/kubernetes-yaml-files/08-virtuoso-service.yaml new file mode 100644 index 00000000..1d27c400 --- /dev/null +++ b/kubernetes-yaml-files/08-virtuoso-service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: virtuoso-service + labels: + app: virtuoso +spec: + selector: + app: virtuoso + ports: + - protocol: TCP + port: 8890 + targetPort: 8890 + name: sparql + - protocol: TCP + port: 1111 + targetPort: 1111 + name: isql + type: LoadBalancer diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/FileBasedImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java similarity index 99% rename from platform-controller/src/main/java/org/hobbit/controller/containers/docker/FileBasedImageManager.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java index adf755ea..917b2cf8 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/FileBasedImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.containers.docker; +package org.hobbit.controller.containers; import java.io.File; import java.io.IOException; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/GitlabBasedImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/GitlabBasedImageManager.java similarity index 98% rename from platform-controller/src/main/java/org/hobbit/controller/containers/docker/GitlabBasedImageManager.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/GitlabBasedImageManager.java index 648f4484..4cf6da48 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/GitlabBasedImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/GitlabBasedImageManager.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.containers.docker; +package org.hobbit.controller.containers; import java.util.List; import java.util.Set; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/MetaDataFactory.java b/platform-controller/src/main/java/org/hobbit/controller/containers/MetaDataFactory.java similarity index 99% rename from platform-controller/src/main/java/org/hobbit/controller/containers/docker/MetaDataFactory.java rename to platform-controller/src/main/java/org/hobbit/controller/containers/MetaDataFactory.java index 68191112..50516ae6 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/MetaDataFactory.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/MetaDataFactory.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.containers.docker; +package org.hobbit.controller.containers; import java.io.ByteArrayInputStream; import java.io.StringReader; From 006e5ab57db59ab233a5f6f4b8ff49157093a498 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 3 Feb 2025 14:48:57 +0100 Subject: [PATCH 06/52] add yaml files, storage service running --- .../{06-virtuoso-pvc.yaml => 03-virtuoso-pvc.yaml} | 0 ...rtuoso-deployment.yaml => 04-virtuoso-deployment.yaml} | 0 ...{08-virtuoso-service.yaml => 05-virtuoso-service.yaml} | 0 ...storage-deployment.yaml => 06-storage-deployment.yaml} | 8 ++++++++ .../{04-storage-service.yaml => 07-storage-service.yaml} | 0 .../{05-storage-pvc.yaml => 08-storage-pvc.yaml} | 0 6 files changed, 8 insertions(+) rename kubernetes-yaml-files/{06-virtuoso-pvc.yaml => 03-virtuoso-pvc.yaml} (100%) rename kubernetes-yaml-files/{07-virtuoso-deployment.yaml => 04-virtuoso-deployment.yaml} (100%) rename kubernetes-yaml-files/{08-virtuoso-service.yaml => 05-virtuoso-service.yaml} (100%) rename kubernetes-yaml-files/{03-storage-deployment.yaml => 06-storage-deployment.yaml} (81%) rename kubernetes-yaml-files/{04-storage-service.yaml => 07-storage-service.yaml} (100%) rename kubernetes-yaml-files/{05-storage-pvc.yaml => 08-storage-pvc.yaml} (100%) diff --git a/kubernetes-yaml-files/06-virtuoso-pvc.yaml b/kubernetes-yaml-files/03-virtuoso-pvc.yaml similarity index 100% rename from kubernetes-yaml-files/06-virtuoso-pvc.yaml rename to kubernetes-yaml-files/03-virtuoso-pvc.yaml diff --git a/kubernetes-yaml-files/07-virtuoso-deployment.yaml b/kubernetes-yaml-files/04-virtuoso-deployment.yaml similarity index 100% rename from kubernetes-yaml-files/07-virtuoso-deployment.yaml rename to kubernetes-yaml-files/04-virtuoso-deployment.yaml diff --git a/kubernetes-yaml-files/08-virtuoso-service.yaml b/kubernetes-yaml-files/05-virtuoso-service.yaml similarity index 100% rename from kubernetes-yaml-files/08-virtuoso-service.yaml rename to kubernetes-yaml-files/05-virtuoso-service.yaml diff --git a/kubernetes-yaml-files/03-storage-deployment.yaml b/kubernetes-yaml-files/06-storage-deployment.yaml similarity index 81% rename from kubernetes-yaml-files/03-storage-deployment.yaml rename to kubernetes-yaml-files/06-storage-deployment.yaml index f47f3468..4b53e4bc 100644 --- a/kubernetes-yaml-files/03-storage-deployment.yaml +++ b/kubernetes-yaml-files/06-storage-deployment.yaml @@ -25,6 +25,14 @@ spec: value: "-Xmx256m -Xms128m" - name: HOBBIT_RABBIT_HOST value: rabbitmq # The name of the RabbitMQ service (02-rabbitmq-service.yaml) + - name: SPARQL_ENDPOINT_URL + value: virtuoso + - name: SPARQL_ENDPOINT_USERNAME + value: "dba" + - name: SPARQL_ENDPOINT_PASSWORD + value: "dba" + - name: SPARQL_ENDPOINT_DATABASE + value: "virtuoso" volumeMounts: - mountPath: /path/to/mount name: storage-volume diff --git a/kubernetes-yaml-files/04-storage-service.yaml b/kubernetes-yaml-files/07-storage-service.yaml similarity index 100% rename from kubernetes-yaml-files/04-storage-service.yaml rename to kubernetes-yaml-files/07-storage-service.yaml diff --git a/kubernetes-yaml-files/05-storage-pvc.yaml b/kubernetes-yaml-files/08-storage-pvc.yaml similarity index 100% rename from kubernetes-yaml-files/05-storage-pvc.yaml rename to kubernetes-yaml-files/08-storage-pvc.yaml From 53c68251644595bfd0ba7f380ef1520a461d8ae3 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 4 Feb 2025 15:12:33 +0100 Subject: [PATCH 07/52] add yaml files , redis and role --- kubernetes-yaml-files/09-redis-pvc.yaml | 12 +++++ .../10-redis-deployment.yaml | 28 ++++++++++ kubernetes-yaml-files/11-redis-service.yaml | 14 +++++ kubernetes-yaml-files/12-controller-pvc.yaml | 12 +++++ .../13-controller-deployment.yaml | 51 +++++++++++++++++++ .../14-controller-service.yaml | 15 ++++++ kubernetes-yaml-files/15-controller-role.yaml | 30 +++++++++++ 7 files changed, 162 insertions(+) create mode 100644 kubernetes-yaml-files/09-redis-pvc.yaml create mode 100644 kubernetes-yaml-files/10-redis-deployment.yaml create mode 100644 kubernetes-yaml-files/11-redis-service.yaml create mode 100644 kubernetes-yaml-files/12-controller-pvc.yaml create mode 100644 kubernetes-yaml-files/13-controller-deployment.yaml create mode 100644 kubernetes-yaml-files/14-controller-service.yaml create mode 100644 kubernetes-yaml-files/15-controller-role.yaml diff --git a/kubernetes-yaml-files/09-redis-pvc.yaml b/kubernetes-yaml-files/09-redis-pvc.yaml new file mode 100644 index 00000000..e258a3a1 --- /dev/null +++ b/kubernetes-yaml-files/09-redis-pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: redis-pvc + labels: + app: redis +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/kubernetes-yaml-files/10-redis-deployment.yaml b/kubernetes-yaml-files/10-redis-deployment.yaml new file mode 100644 index 00000000..3e0b3e41 --- /dev/null +++ b/kubernetes-yaml-files/10-redis-deployment.yaml @@ -0,0 +1,28 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redis + labels: + app: redis +spec: + replicas: 1 + selector: + matchLabels: + app: redis + template: + metadata: + labels: + app: redis + spec: + containers: + - name: redis + image: redis:6.2.6 + ports: + - containerPort: 6379 + volumeMounts: + - mountPath: /data + name: redis-storage + volumes: + - name: redis-storage + persistentVolumeClaim: + claimName: redis-pvc diff --git a/kubernetes-yaml-files/11-redis-service.yaml b/kubernetes-yaml-files/11-redis-service.yaml new file mode 100644 index 00000000..a5df6ec2 --- /dev/null +++ b/kubernetes-yaml-files/11-redis-service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: redis-service + labels: + app: redis +spec: + selector: + app: redis + ports: + - protocol: TCP + port: 6379 + targetPort: 6379 + type: ClusterIP # Change to LoadBalancer or NodePort if needed for external access diff --git a/kubernetes-yaml-files/12-controller-pvc.yaml b/kubernetes-yaml-files/12-controller-pvc.yaml new file mode 100644 index 00000000..f4a11fd5 --- /dev/null +++ b/kubernetes-yaml-files/12-controller-pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: controller-pvc + labels: + app: controller +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi diff --git a/kubernetes-yaml-files/13-controller-deployment.yaml b/kubernetes-yaml-files/13-controller-deployment.yaml new file mode 100644 index 00000000..0648bcce --- /dev/null +++ b/kubernetes-yaml-files/13-controller-deployment.yaml @@ -0,0 +1,51 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller + labels: + app: controller +spec: + replicas: 1 + selector: + matchLabels: + app: controller + template: + metadata: + labels: + app: controller + spec: + containers: + - name: controller + image: hobbit/platform_controller:dev0.0.4 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + env: + - name: HOBBIT_RABBIT_HOST + value: rabbitmq # The name of the RabbitMQ service (02-rabbitmq-service.yaml) + - name: SPARQL_ENDPOINT_URL + value: virtuoso + - name: SPARQL_ENDPOINT_USERNAME + value: "dba" + - name: SPARQL_ENDPOINT_PASSWORD + value: "dba" + - name: SPARQL_ENDPOINT_DATABASE + value: "virtuoso" + - name: HOBBIT_REDIS_HOST + value: "redis-service" + - name: GITLAB_TOKEN + valueFrom: + secretKeyRef: + name: gitlab-secret + key: GITLAB_TOKEN + - name: GITLAB_USER + value: "gitadmin" + - name: GITLAB_EMAIL + value: "gitadmin@project-hobbit.eu" + volumeMounts: + - mountPath: /data + name: controller-storage # Only if you are using a PVC + volumes: + - name: controller-storage + persistentVolumeClaim: + claimName: controller-pvc # Only if you are using a PVC diff --git a/kubernetes-yaml-files/14-controller-service.yaml b/kubernetes-yaml-files/14-controller-service.yaml new file mode 100644 index 00000000..a4790c8d --- /dev/null +++ b/kubernetes-yaml-files/14-controller-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: controller-service + labels: + app: controller +spec: + selector: + app: controller + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 + name: http + type: ClusterIP # Change to LoadBalancer or NodePort if needed diff --git a/kubernetes-yaml-files/15-controller-role.yaml b/kubernetes-yaml-files/15-controller-role.yaml new file mode 100644 index 00000000..f4ec0669 --- /dev/null +++ b/kubernetes-yaml-files/15-controller-role.yaml @@ -0,0 +1,30 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: node-pod-service-reader + namespace: default +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["services"] + verbs: ["create", "get", "update", "delete", "list", "watch"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["create", "get", "update", "delete", "list", "watch"] + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: my-service-account-binding + namespace: default +subjects: + - kind: ServiceAccount + name: controller-service + namespace: default +roleRef: + kind: Role + name: node-pod-service-reader + apiGroup: rbac.authorization.k8s.io From 0af737eb007affae98c8d8b1bb7c8be7104401e4 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 10 Feb 2025 13:53:13 +0100 Subject: [PATCH 08/52] update yaml files --- .../06-storage-deployment.yaml | 4 +-- kubernetes-yaml-files/12-controller-pvc.yaml | 2 +- .../13-controller-deployment.yaml | 26 ++++++++++++++++++- kubernetes-yaml-files/15-controller-role.yaml | 12 +++------ .../16-controller-service-account.yaml | 5 ++++ 5 files changed, 36 insertions(+), 13 deletions(-) create mode 100644 kubernetes-yaml-files/16-controller-service-account.yaml diff --git a/kubernetes-yaml-files/06-storage-deployment.yaml b/kubernetes-yaml-files/06-storage-deployment.yaml index 4b53e4bc..942b892e 100644 --- a/kubernetes-yaml-files/06-storage-deployment.yaml +++ b/kubernetes-yaml-files/06-storage-deployment.yaml @@ -16,7 +16,7 @@ spec: spec: containers: - name: storage-service - image: hobbit/storage_service:latest + image: hub.cs.upb.de/dice-research/images/hobbit-storage_service:dev0.0.1 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 @@ -26,7 +26,7 @@ spec: - name: HOBBIT_RABBIT_HOST value: rabbitmq # The name of the RabbitMQ service (02-rabbitmq-service.yaml) - name: SPARQL_ENDPOINT_URL - value: virtuoso + value: virtuoso-service - name: SPARQL_ENDPOINT_USERNAME value: "dba" - name: SPARQL_ENDPOINT_PASSWORD diff --git a/kubernetes-yaml-files/12-controller-pvc.yaml b/kubernetes-yaml-files/12-controller-pvc.yaml index f4a11fd5..304f57f7 100644 --- a/kubernetes-yaml-files/12-controller-pvc.yaml +++ b/kubernetes-yaml-files/12-controller-pvc.yaml @@ -9,4 +9,4 @@ spec: - ReadWriteOnce resources: requests: - storage: 10Gi + storage: 2Gi diff --git a/kubernetes-yaml-files/13-controller-deployment.yaml b/kubernetes-yaml-files/13-controller-deployment.yaml index 0648bcce..00b58b7c 100644 --- a/kubernetes-yaml-files/13-controller-deployment.yaml +++ b/kubernetes-yaml-files/13-controller-deployment.yaml @@ -14,9 +14,10 @@ spec: labels: app: controller spec: + serviceAccountName: controller-service-sa containers: - name: controller - image: hobbit/platform_controller:dev0.0.4 + image: hub.cs.upb.de/dice-research/images/hobbit-platform_controller:dev0.0.9 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 @@ -42,10 +43,33 @@ spec: value: "gitadmin" - name: GITLAB_EMAIL value: "gitadmin@project-hobbit.eu" + - name: DEPLOY_ENV + value: "develop" + - name: MAX_EXECUTION_TIME + value: "1200000" volumeMounts: - mountPath: /data name: controller-storage # Only if you are using a PVC + - mountPath: /var/run/secrets/kubernetes.io/serviceaccount + name: kube-api-access + readOnly: true volumes: - name: controller-storage persistentVolumeClaim: claimName: controller-pvc # Only if you are using a PVC + - name: kube-api-access + projected: + sources: + - serviceAccountToken: + expirationSeconds: 3607 + path: token + - configMap: + name: kube-root-ca.crt + items: + - key: ca.crt + path: ca.crt + - downwardAPI: + items: + - path: namespace + fieldRef: + fieldPath: metadata.namespace diff --git a/kubernetes-yaml-files/15-controller-role.yaml b/kubernetes-yaml-files/15-controller-role.yaml index f4ec0669..32ddcca4 100644 --- a/kubernetes-yaml-files/15-controller-role.yaml +++ b/kubernetes-yaml-files/15-controller-role.yaml @@ -5,24 +5,18 @@ metadata: namespace: default rules: - apiGroups: [""] - resources: ["nodes"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["services"] - verbs: ["create", "get", "update", "delete", "list", "watch"] - - apiGroups: [""] - resources: ["pods"] + resources: ["nodes", "pods", "services", "namespaces"] verbs: ["create", "get", "update", "delete", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: my-service-account-binding + name: controller-service-account-binding namespace: default subjects: - kind: ServiceAccount - name: controller-service + name: controller-service-sa namespace: default roleRef: kind: Role diff --git a/kubernetes-yaml-files/16-controller-service-account.yaml b/kubernetes-yaml-files/16-controller-service-account.yaml new file mode 100644 index 00000000..3d60e783 --- /dev/null +++ b/kubernetes-yaml-files/16-controller-service-account.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: controller-service-sa + namespace: default From e4eba4e0280179a86cc888d5038dd9ccfd187c40 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 10 Feb 2025 15:42:04 +0100 Subject: [PATCH 09/52] add pv --- kubernetes-yaml-files/00-1-rabbitmq-pv.yaml | 14 ++++++++++++++ kubernetes-yaml-files/03-01-virtuoso-pv.yaml | 14 ++++++++++++++ kubernetes-yaml-files/08-01-storage-pv.yaml | 14 ++++++++++++++ kubernetes-yaml-files/09-01-redis-pv.yaml | 14 ++++++++++++++ kubernetes-yaml-files/12-01-controller-pv.yaml | 14 ++++++++++++++ 5 files changed, 70 insertions(+) create mode 100644 kubernetes-yaml-files/00-1-rabbitmq-pv.yaml create mode 100644 kubernetes-yaml-files/03-01-virtuoso-pv.yaml create mode 100644 kubernetes-yaml-files/08-01-storage-pv.yaml create mode 100644 kubernetes-yaml-files/09-01-redis-pv.yaml create mode 100644 kubernetes-yaml-files/12-01-controller-pv.yaml diff --git a/kubernetes-yaml-files/00-1-rabbitmq-pv.yaml b/kubernetes-yaml-files/00-1-rabbitmq-pv.yaml new file mode 100644 index 00000000..4f975356 --- /dev/null +++ b/kubernetes-yaml-files/00-1-rabbitmq-pv.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: rabbitmq-pv +spec: + capacity: + storage: 1Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain # or Delete, depending on your needs + storageClassName: "" # Important: Leave this empty if not using Storage Classes + nfs: + server: 131.234.29.64 + path: /data/nfs/kubedata/rabbitmq diff --git a/kubernetes-yaml-files/03-01-virtuoso-pv.yaml b/kubernetes-yaml-files/03-01-virtuoso-pv.yaml new file mode 100644 index 00000000..93fab5a2 --- /dev/null +++ b/kubernetes-yaml-files/03-01-virtuoso-pv.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: virtuoso-pv +spec: + capacity: + storage: 1Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain # or Delete, as needed + storageClassName: "" # Important: Leave empty if not using Storage Classes + nfs: + server: 131.234.29.64 # Your NFS server IP + path: /data/nfs/kubedata/virtuoso # The path to your exported NFS share diff --git a/kubernetes-yaml-files/08-01-storage-pv.yaml b/kubernetes-yaml-files/08-01-storage-pv.yaml new file mode 100644 index 00000000..472f1f36 --- /dev/null +++ b/kubernetes-yaml-files/08-01-storage-pv.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: hobbit-storage-pv +spec: + capacity: + storage: 1Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain # Or Delete, as needed + storageClassName: "" # Important: Leave empty if not using Storage Classes + nfs: + server: 131.234.29.64 + path: /data/nfs/kubedata/hobbit diff --git a/kubernetes-yaml-files/09-01-redis-pv.yaml b/kubernetes-yaml-files/09-01-redis-pv.yaml new file mode 100644 index 00000000..09e2e403 --- /dev/null +++ b/kubernetes-yaml-files/09-01-redis-pv.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: redis-pv +spec: + capacity: + storage: 1Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain # Or Delete, as needed + storageClassName: "" # Important: Leave empty if not using Storage Classes + nfs: + server: 131.234.29.64 + path: /data/nfs/kubedata/redis diff --git a/kubernetes-yaml-files/12-01-controller-pv.yaml b/kubernetes-yaml-files/12-01-controller-pv.yaml new file mode 100644 index 00000000..68f7f2c5 --- /dev/null +++ b/kubernetes-yaml-files/12-01-controller-pv.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: controller-pv +spec: + capacity: + storage: 2Gi # Increased to 2Gi to match the PVC request + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain # Or Delete, as needed + storageClassName: "" # Important: Leave empty if not using Storage Classes + nfs: + server: 131.234.29.64 # Your NFS server IP + path: /data/nfs/kubedata/controller From 47265c7af202f6f97f58fd660e99f23a74dde3dd Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 10 Feb 2025 16:12:59 +0100 Subject: [PATCH 10/52] add user ID to use NFS --- kubernetes-yaml-files/01-rabbitmq-deployment.yaml | 3 +++ kubernetes-yaml-files/04-virtuoso-deployment.yaml | 3 +++ kubernetes-yaml-files/06-storage-deployment.yaml | 3 +++ kubernetes-yaml-files/10-redis-deployment.yaml | 3 +++ kubernetes-yaml-files/13-controller-deployment.yaml | 3 +++ 5 files changed, 15 insertions(+) diff --git a/kubernetes-yaml-files/01-rabbitmq-deployment.yaml b/kubernetes-yaml-files/01-rabbitmq-deployment.yaml index 265ed9e2..46eb362e 100644 --- a/kubernetes-yaml-files/01-rabbitmq-deployment.yaml +++ b/kubernetes-yaml-files/01-rabbitmq-deployment.yaml @@ -51,6 +51,9 @@ spec: containers: - name: rabbitmq image: rabbitmq:3-management + securityContext: + runAsUser: 79184 # Replace with the actual numeric user ID + runAsGroup: 10000 ports: - containerPort: 5672 # AMQP protocol (for applications) - containerPort: 15672 # Management UI (for admins) diff --git a/kubernetes-yaml-files/04-virtuoso-deployment.yaml b/kubernetes-yaml-files/04-virtuoso-deployment.yaml index d80530e6..ec23ee88 100644 --- a/kubernetes-yaml-files/04-virtuoso-deployment.yaml +++ b/kubernetes-yaml-files/04-virtuoso-deployment.yaml @@ -17,6 +17,9 @@ spec: containers: - name: virtuoso image: openlink/virtuoso-opensource-7:latest + securityContext: + runAsUser: 79184 # Replace with the actual numeric user ID + runAsGroup: 10000 ports: - containerPort: 8890 # HTTP (SPARQL endpoint) - containerPort: 1111 # ISQL (command-line interface) diff --git a/kubernetes-yaml-files/06-storage-deployment.yaml b/kubernetes-yaml-files/06-storage-deployment.yaml index 942b892e..68eb9c2d 100644 --- a/kubernetes-yaml-files/06-storage-deployment.yaml +++ b/kubernetes-yaml-files/06-storage-deployment.yaml @@ -17,6 +17,9 @@ spec: containers: - name: storage-service image: hub.cs.upb.de/dice-research/images/hobbit-storage_service:dev0.0.1 + securityContext: + runAsUser: 79184 # Replace with the actual numeric user ID + runAsGroup: 10000 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 diff --git a/kubernetes-yaml-files/10-redis-deployment.yaml b/kubernetes-yaml-files/10-redis-deployment.yaml index 3e0b3e41..3ffe994b 100644 --- a/kubernetes-yaml-files/10-redis-deployment.yaml +++ b/kubernetes-yaml-files/10-redis-deployment.yaml @@ -17,6 +17,9 @@ spec: containers: - name: redis image: redis:6.2.6 + securityContext: + runAsUser: 79184 # Replace with the actual numeric user ID + runAsGroup: 10000 ports: - containerPort: 6379 volumeMounts: diff --git a/kubernetes-yaml-files/13-controller-deployment.yaml b/kubernetes-yaml-files/13-controller-deployment.yaml index 00b58b7c..750ec265 100644 --- a/kubernetes-yaml-files/13-controller-deployment.yaml +++ b/kubernetes-yaml-files/13-controller-deployment.yaml @@ -19,6 +19,9 @@ spec: - name: controller image: hub.cs.upb.de/dice-research/images/hobbit-platform_controller:dev0.0.9 imagePullPolicy: IfNotPresent + securityContext: + runAsUser: 79184 # Replace with the actual numeric user ID + runAsGroup: 10000 ports: - containerPort: 8080 env: From bc962903a9c184c73f677282e7fc3455108eb433 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 11 Feb 2025 14:30:59 +0100 Subject: [PATCH 11/52] update security Context --- kubernetes-yaml-files/04-virtuoso-deployment.yaml | 2 ++ kubernetes-yaml-files/06-storage-deployment.yaml | 5 ++--- kubernetes-yaml-files/10-redis-deployment.yaml | 6 +++--- kubernetes-yaml-files/13-controller-deployment.yaml | 5 ++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/kubernetes-yaml-files/04-virtuoso-deployment.yaml b/kubernetes-yaml-files/04-virtuoso-deployment.yaml index ec23ee88..1450d3b9 100644 --- a/kubernetes-yaml-files/04-virtuoso-deployment.yaml +++ b/kubernetes-yaml-files/04-virtuoso-deployment.yaml @@ -14,6 +14,8 @@ spec: labels: app: virtuoso spec: + securityContext: + fsGroup: 1000 containers: - name: virtuoso image: openlink/virtuoso-opensource-7:latest diff --git a/kubernetes-yaml-files/06-storage-deployment.yaml b/kubernetes-yaml-files/06-storage-deployment.yaml index 68eb9c2d..0bc412ff 100644 --- a/kubernetes-yaml-files/06-storage-deployment.yaml +++ b/kubernetes-yaml-files/06-storage-deployment.yaml @@ -14,12 +14,11 @@ spec: labels: app: hobbit-storage-service spec: + securityContext: + fsGroup: 1000 containers: - name: storage-service image: hub.cs.upb.de/dice-research/images/hobbit-storage_service:dev0.0.1 - securityContext: - runAsUser: 79184 # Replace with the actual numeric user ID - runAsGroup: 10000 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 diff --git a/kubernetes-yaml-files/10-redis-deployment.yaml b/kubernetes-yaml-files/10-redis-deployment.yaml index 3ffe994b..b544345a 100644 --- a/kubernetes-yaml-files/10-redis-deployment.yaml +++ b/kubernetes-yaml-files/10-redis-deployment.yaml @@ -14,12 +14,12 @@ spec: labels: app: redis spec: + securityContext: + fsGroup: 1000 + runAsUser: 79184 #because it need to run chown if user is different containers: - name: redis image: redis:6.2.6 - securityContext: - runAsUser: 79184 # Replace with the actual numeric user ID - runAsGroup: 10000 ports: - containerPort: 6379 volumeMounts: diff --git a/kubernetes-yaml-files/13-controller-deployment.yaml b/kubernetes-yaml-files/13-controller-deployment.yaml index 750ec265..4f8d1db7 100644 --- a/kubernetes-yaml-files/13-controller-deployment.yaml +++ b/kubernetes-yaml-files/13-controller-deployment.yaml @@ -15,13 +15,12 @@ spec: app: controller spec: serviceAccountName: controller-service-sa + securityContext: + fsGroup: 1000 containers: - name: controller image: hub.cs.upb.de/dice-research/images/hobbit-platform_controller:dev0.0.9 imagePullPolicy: IfNotPresent - securityContext: - runAsUser: 79184 # Replace with the actual numeric user ID - runAsGroup: 10000 ports: - containerPort: 8080 env: From a70a6fd873ff8d15a7713bc6be582f0ec9c026ab Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 11 Feb 2025 14:54:55 +0100 Subject: [PATCH 12/52] Cluster role --- kubernetes-yaml-files/17-cluster-role.yaml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 kubernetes-yaml-files/17-cluster-role.yaml diff --git a/kubernetes-yaml-files/17-cluster-role.yaml b/kubernetes-yaml-files/17-cluster-role.yaml new file mode 100644 index 00000000..c4c428b5 --- /dev/null +++ b/kubernetes-yaml-files/17-cluster-role.yaml @@ -0,0 +1,22 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: node-reader +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] # Minimum permissions needed + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: controller-service-account-binding +subjects: + - kind: ServiceAccount + name: controller-service-sa + namespace: default +roleRef: + kind: ClusterRole + name: node-reader + apiGroup: rbac.authorization.k8s.io From 258f2466d51e4f459c9c109e71c881b9e162b8c4 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Thu, 13 Feb 2025 16:18:50 +0100 Subject: [PATCH 13/52] add a lot of logs --- .../hobbit/controller/ExperimentManager.java | 4 +- .../hobbit/controller/PlatformController.java | 50 +++- .../containers/ContainerManager.java | 37 ++- .../containers/ContainerPodException.java | 7 + .../containers/FileBasedImageManager.java | 2 +- .../ResourceInformationCollector.java | 3 +- .../docker/ContainerManagerImpl.java | 87 +++--- .../docker/ContainerStateObserverImpl.java | 3 +- .../ResourceInformationCollectorImpl.java | 37 ++- .../kubernetes/ClusterManagerImpl.java | 18 +- .../kubernetes/ContainerManagerImpl.java | 264 +++++++++++++---- .../ContainerStateObserverImpl.java | 54 +++- .../ResourceInformationCollectorImpl.java | 274 ++++++++++++------ .../controller/data/ContainerCriteria.java | 73 +++++ ...tainerCriteriaToServiceCriteriaMapper.java | 70 +++++ .../controller/data/ExperimentStatus.java | 2 +- .../docker/FileBasedImageManagerTest.java | 2 +- .../docker/GitlabBasedImageManagerTest.java | 2 +- .../docker/MetaDataFactoryTest.java | 2 +- .../mocks/DummyContainerManager.java | 3 +- .../DummyResourceInformationCollector.java | 3 +- 21 files changed, 762 insertions(+), 235 deletions(-) create mode 100644 platform-controller/src/main/java/org/hobbit/controller/containers/ContainerPodException.java create mode 100644 platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java create mode 100644 platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java diff --git a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java index 5f962a54..a058ed31 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java @@ -46,7 +46,7 @@ import org.hobbit.controller.data.SetupHardwareInformation; import org.hobbit.controller.containers.ClusterManager; import org.hobbit.controller.containers.ContainerManager; -import org.hobbit.controller.containers.docker.MetaDataFactory; +import org.hobbit.controller.containers.MetaDataFactory; import org.hobbit.controller.execute.ExperimentAbortTimerTask; import org.hobbit.controller.utils.RabbitMQConnector; import org.hobbit.core.Commands; @@ -168,6 +168,7 @@ public void run() { * experiment waiting in the queue. */ public void createNextExperiment() { + LOGGER.info("create experiment"); synchronized (experimentMutex) { try { // if there is no benchmark running, the queue has been @@ -324,6 +325,7 @@ protected static Map getHardwareConstraints(String serializedBen protected void createRabbitMQ(ExperimentConfiguration config) throws Exception { String rabbitMQAddress = hobbitConfig.getString(RABBIT_MQ_EXPERIMENTS_HOST_NAME_KEY, (String) null); + LOGGER.info("Using the newly started RabbitMQ for the experiment: {}", rabbitMQAddress); if (rabbitMQAddress == null) { LOGGER.info("Starting new RabbitMQ for the experiment..."); rabbitMQAddress = controller.containerManager.startContainer(hobbitConfig.getString(RABBIT_IMAGE_ENV_KEY), diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 6597effc..675588f2 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -35,6 +35,11 @@ import java.util.TimerTask; import java.util.concurrent.Semaphore; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.Configuration; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.util.ClientBuilder; +import io.kubernetes.client.util.Config; import org.apache.commons.configuration2.EnvironmentConfiguration; import org.apache.commons.io.IOUtils; import org.apache.jena.query.Dataset; @@ -50,18 +55,22 @@ import org.hobbit.controller.analyze.ExperimentAnalyzer; import org.hobbit.controller.data.ExperimentConfiguration; import org.hobbit.controller.containers.ClusterManager; -import org.hobbit.controller.containers.docker.ClusterManagerImpl; +//import org.hobbit.controller.containers.docker.ClusterManagerImpl; +import org.hobbit.controller.containers.kubernetes.ClusterManagerImpl; import org.hobbit.controller.containers.ContainerManager; -import org.hobbit.controller.containers.docker.ContainerManagerImpl; +//import org.hobbit.controller.containers.docker.ContainerManagerImpl; +import org.hobbit.controller.containers.kubernetes.ContainerManagerImpl; import org.hobbit.controller.containers.ContainerStateObserver; -import org.hobbit.controller.containers.docker.ContainerStateObserverImpl; +//import org.hobbit.controller.containers.docker.ContainerStateObserverImpl; +import org.hobbit.controller.containers.kubernetes.ContainerStateObserverImpl; import org.hobbit.controller.containers.ContainerTerminationCallback; -import org.hobbit.controller.containers.docker.FileBasedImageManager; -import org.hobbit.controller.containers.docker.GitlabBasedImageManager; +import org.hobbit.controller.containers.FileBasedImageManager; +import org.hobbit.controller.containers.GitlabBasedImageManager; import org.hobbit.controller.containers.ImageManager; import org.hobbit.controller.containers.ImageManagerFacade; import org.hobbit.controller.containers.ResourceInformationCollector; -import org.hobbit.controller.containers.docker.ResourceInformationCollectorImpl; +//import org.hobbit.controller.containers.docker.ResourceInformationCollectorImpl; +import org.hobbit.controller.containers.kubernetes.ResourceInformationCollectorImpl; import org.hobbit.controller.front.FrontEndApiHandler; import org.hobbit.controller.queue.ExperimentQueue; import org.hobbit.controller.queue.ExperimentQueueImpl; @@ -220,6 +229,9 @@ public class PlatformController extends AbstractComponent implements ContainerTe protected Timer challengeCheckTimer; protected HobbitConfiguration hobbitConfig; + //@Value("${container.manager.timeoutMilliSeconds:60000}") + private int TIMEOUT_MILLISECONDS = 60000; + /** * Default constructor. */ @@ -240,7 +252,7 @@ public PlatformController(ExperimentManager expManager) { public void init() throws Exception { // First initialize the super class super.init(); - LOGGER.debug("Platform controller initialization started."); + LOGGER.info("Platform controller initialization started."); hobbitConfig = new HobbitConfiguration(); hobbitConfig.addConfiguration(new EnvironmentConfiguration()); @@ -248,7 +260,21 @@ public void init() throws Exception { // Set task history limit for swarm cluster to 0 (will remove all terminated // containers) // Only for prod mode - clusterManager = new ClusterManagerImpl(); + + LOGGER.info("configuration initialized."); + + // Config.fromConfig("/var/run/secrets/kubernetes.io/serviceaccount/token"); + //ApiClient client = Configuration.get(); + ApiClient client = Config.defaultClient(); + client.setConnectTimeout(TIMEOUT_MILLISECONDS); + client.setReadTimeout(TIMEOUT_MILLISECONDS); + client.setWriteTimeout(TIMEOUT_MILLISECONDS); + Configuration.setDefaultApiClient(client); + + LOGGER.info("kub client initialized."); + + + clusterManager = new ClusterManagerImpl(client); if (DEPLOY_ENV.equals(DEPLOY_ENV_TESTING) || DEPLOY_ENV.equals(DEPLOY_ENV_DEVELOP)) { LOGGER.debug("Ignoring task history limit parameter. Will remain default (run 'docker info' for details)."); } else { @@ -258,14 +284,14 @@ public void init() throws Exception { } // create container manager - containerManager = new ContainerManagerImpl(); - LOGGER.debug("Container manager initialized."); + containerManager = new ContainerManagerImpl(client); + LOGGER.info("Container manager initialized."); // Create container observer (polls status every 5s) - containerObserver = new ContainerStateObserverImpl(containerManager, 5 * 1000); + containerObserver = new ContainerStateObserverImpl(containerManager, 5 * 1000, client); containerObserver.addTerminationCallback(this); // Tell the manager to add container to the observer containerManager.addContainerObserver(containerObserver); - resInfoCollector = new ResourceInformationCollectorImpl(containerManager); + resInfoCollector = new ResourceInformationCollectorImpl(containerManager,client,new CoreV1Api(client)); containerObserver.startObserving(); LOGGER.debug("Container observer initialized."); diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java index 3fe9a1a6..85b96b39 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java @@ -19,12 +19,9 @@ import java.util.List; import java.util.Map; -import io.kubernetes.client.openapi.ApiException; +import org.hobbit.controller.data.ContainerCriteria; import org.hobbit.core.Constants; -import com.spotify.docker.client.exceptions.DockerException; -import com.spotify.docker.client.messages.ContainerStats; -import com.spotify.docker.client.messages.swarm.Service; /** * This interface is implemented by classes that can be used to manage Docker or Kubernetes @@ -182,6 +179,8 @@ public String startContainer(String imageName, String containerType, String pare public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command, String experimentId, Map constraints); + + /** * Stops the container with the given container Id. * @@ -219,7 +218,7 @@ public String startContainer(String imageName, String containerType, String pare * * @param serviceName */ - public Long getContainerPodExitCode(String serviceName) throws DockerException, InterruptedException, ApiException; + public Long getContainerPodExitCode(String serviceName) throws ContainerPodException ,InterruptedException; //TODO maybe remove this method from interface just keeo the usage in implementation for dokcer @@ -231,10 +230,10 @@ public String startContainer(String imageName, String containerType, String pare // public Service getContainerInfo(String serviceName) throws InterruptedException, DockerException; /** - * Get a list of services + * Get a list of services names */ - public default List getContainers() { - return getContainers(Service.Criteria.builder().build()); + public default List getContainers() { + return getContainers(ContainerCriteria.builder().build()); } /** @@ -243,7 +242,7 @@ public default List getContainers() { * @Service.Criteria criteria service criteria for filtering the list of * services */ - public List getContainers(Service.Criteria criteria); + public List getContainers(ContainerCriteria criteria); /** * @deprecated Platform uses names as IDs. Retrieves the container Id for the @@ -281,16 +280,16 @@ public default List getContainers() { */ public void pullImage(String imageName); - /** - * Returns statistics of the container with the given Id or {@code null} if the - * container can not be found or an error occurs. - * - * @param containerId the Id of the container for which statistics should be - * requested - * @return statistics of the container with the given Id or {@code null} if the - * container can not be found or an error occurs. - */ - public ContainerStats getStats(String containerId); +// /** +// * Returns statistics of the container with the given Id or {@code null} if the +// * container can not be found or an error occurs. +// * +// * @param containerId the Id of the container for which statistics should be +// * requested +// * @return statistics of the container with the given Id or {@code null} if the +// * container can not be found or an error occurs. +// */ +// public ContainerStats getStats(String containerId); /** * Returns the type of the container as string. The type is typically one of diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerPodException.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerPodException.java new file mode 100644 index 00000000..6f9a1d4a --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerPodException.java @@ -0,0 +1,7 @@ +package org.hobbit.controller.containers; + +public class ContainerPodException extends Exception { + public ContainerPodException(String message, Throwable cause) { + super(message, cause); + } + } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java index 917b2cf8..5622788a 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java @@ -38,7 +38,7 @@ public class FileBasedImageManager extends AbstactImageManager { private static final Logger LOGGER = LoggerFactory.getLogger(FileBasedImageManager.class); - private static final String DEFAULT_DEF_FOLDER = "metadata"; + private static final String DEFAULT_DEF_FOLDER = "/data/metadata"; private static final Date DEFAULT_DATE = new Date(0); private final String inputFolder; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/ResourceInformationCollector.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ResourceInformationCollector.java index e8994fdb..66f938f9 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/ResourceInformationCollector.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ResourceInformationCollector.java @@ -1,5 +1,6 @@ package org.hobbit.controller.containers; +import org.hobbit.controller.data.ContainerCriteria; import org.hobbit.controller.data.SetupHardwareInformation; import org.hobbit.core.data.usage.ResourceUsageInformation; import com.spotify.docker.client.messages.swarm.Service.Criteria; @@ -14,7 +15,7 @@ public interface ResourceInformationCollector { public ResourceUsageInformation getSystemUsageInformation(); - public ResourceUsageInformation getUsageInformation(Criteria criteria); + public ResourceUsageInformation getUsageInformation(ContainerCriteria criteria); public SetupHardwareInformation getHardwareInformation(); diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java index fdd5854f..419fcc2c 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java @@ -29,7 +29,10 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.hobbit.controller.containers.ContainerPodException; import org.hobbit.controller.containers.ContainerStateObserver; +import org.hobbit.controller.data.ContainerCriteria; +import org.hobbit.controller.data.ContainerCriteriaToServiceCriteriaMapper; import org.hobbit.controller.gitlab.GitlabControllerImpl; import org.hobbit.controller.containers.ClusterManager; import org.hobbit.controller.containers.ContainerManager; @@ -685,7 +688,7 @@ public void removeParentAndChildren(String parent) { } //@Override - public Service getContainerInfo(String serviceName) throws InterruptedException, DockerException { + public Service getContainerInfo(String serviceName) throws InterruptedException, ContainerPodException { if (serviceName == null) { return null; } @@ -694,51 +697,63 @@ public Service getContainerInfo(String serviceName) throws InterruptedException, info = dockerClient.inspectService(serviceName); } catch (ServiceNotFoundException e) { // return null + } catch (DockerException e) { + throw new ContainerPodException("Error getting container pod exit code: " , e); } return info; } @Override - public List getContainers(Service.Criteria criteria) { + public List getContainers(ContainerCriteria criteria) { try { - return dockerClient.listServices(criteria); + Service.Criteria serviceCriteria = ContainerCriteriaToServiceCriteriaMapper.map(criteria); + List services = dockerClient.listServices(serviceCriteria); + List serviceNames = new ArrayList<>(); + for (Service c : services) { + serviceNames.add(c.spec().name()); + } + return serviceNames; } catch (Exception e) { return new ArrayList<>(); } } @Override - public Long getContainerPodExitCode(String serviceName) throws DockerException, InterruptedException { - if (getContainerInfo(serviceName) == null) { - LOGGER.warn( + public Long getContainerPodExitCode(String serviceName) throws ContainerPodException, InterruptedException { + try { + if (getContainerInfo(serviceName) == null) { + LOGGER.warn( "Couldn't get the exit code for container {}. Service doesn't exist. Assuming it was stopped by the platform.", serviceName); - return DOCKER_EXITCODE_SIGKILL; - } + return DOCKER_EXITCODE_SIGKILL; + } - // Service exists, but no tasks are observed. - List tasks = dockerClient.listTasks(Task.Criteria.builder().serviceName(serviceName).build()); - if (tasks.size() == 0) { - LOGGER.warn("Couldn't get the exit code for container {}. Service has no tasks. Returning null.", + // Service exists, but no tasks are observed. + List tasks = dockerClient.listTasks(Task.Criteria.builder().serviceName(serviceName).build()); + if (tasks.size() == 0) { + LOGGER.warn("Couldn't get the exit code for container {}. Service has no tasks. Returning null.", serviceName); - return null; - } + return null; + } - for (Task task : tasks) { - if (!UNFINISHED_TASK_STATES.contains(task.status().state())) { - // Task is finished. - Long exitCode = task.status().containerStatus().exitCode(); - if (exitCode == null) { - LOGGER.warn("Couldn't get the exit code for container {}. Task is finished. Returning 0.", + for (Task task : tasks) { + if (!UNFINISHED_TASK_STATES.contains(task.status().state())) { + // Task is finished. + Long exitCode = task.status().containerStatus().exitCode(); + if (exitCode == null) { + LOGGER.warn("Couldn't get the exit code for container {}. Task is finished. Returning 0.", serviceName); - return 0l; + return 0l; + } + return exitCode; } - return exitCode; } - } - // Task is not finished. - return null; + // Task is not finished. + return null; + }catch (DockerException e) { + throw new ContainerPodException("Error getting container pod exit code: " , e); + } } @Deprecated @@ -769,17 +784,17 @@ public static boolean containsVersionTag(String imageName) { return imageName.indexOf(':', pos) >= 0; } - @Override - public ContainerStats getStats(String containerId) { - ContainerStats stats = null; - try { - stats = dockerClient.stats(containerId); - } catch (Exception e) { - LOGGER.warn("Error while requesting usage stats for {}. Returning null. Error: {}", containerId, - e.getLocalizedMessage()); - } - return stats; - } +// @Override +// public ContainerStats getStats(String containerId) { +// ContainerStats stats = null; +// try { +// stats = dockerClient.stats(containerId); +// } catch (Exception e) { +// LOGGER.warn("Error while requesting usage stats for {}. Returning null. Error: {}", containerId, +// e.getLocalizedMessage()); +// } +// return stats; +// } //@Override public String getContainerType(String containerId) { diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserverImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserverImpl.java index 3cd6f202..133c35f5 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserverImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerStateObserverImpl.java @@ -23,6 +23,7 @@ import io.kubernetes.client.openapi.ApiException; import org.hobbit.controller.containers.ContainerManager; +import org.hobbit.controller.containers.ContainerPodException; import org.hobbit.controller.containers.ContainerStateObserver; import org.hobbit.controller.containers.ContainerTerminationCallback; import org.slf4j.Logger; @@ -110,7 +111,7 @@ public void run() { } } } - } catch (DockerException | ApiException | InterruptedException e ) { + } catch (ContainerPodException | InterruptedException e ) { LOGGER.error("Couldn't get the status of container " + id + ". It will be ignored during this run but will be checked again during the next run."); } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorImpl.java index 3f385641..2ae3b4da 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorImpl.java @@ -15,6 +15,7 @@ import org.apache.commons.io.IOUtils; import org.hobbit.controller.containers.ContainerManager; import org.hobbit.controller.containers.ResourceInformationCollector; +import org.hobbit.controller.data.ContainerCriteria; import org.hobbit.core.Constants; import org.hobbit.core.data.usage.CpuStats; import org.hobbit.core.data.usage.DiskStats; @@ -98,8 +99,8 @@ public ResourceInformationCollectorImpl(ContainerManager manager, String prometh @Override public ResourceUsageInformation getSystemUsageInformation() { - return getUsageInformation(Service.Criteria.builder() - .labels(ImmutableMap.of(ContainerManager.LABEL_TYPE, Constants.CONTAINER_TYPE_SYSTEM)) + return getUsageInformation(ContainerCriteria.builder() + .withLabels(ImmutableMap.of(ContainerManager.LABEL_TYPE, Constants.CONTAINER_TYPE_SYSTEM)) .build()); } @@ -116,21 +117,27 @@ private long countRunningTasks(String serviceName) { } } + private boolean isServiceRunning(String serviceName) { + try { + return dockerClient.listTasks( + Task.Criteria.builder().serviceName(serviceName).build() + ).stream() + .anyMatch(t -> TaskStatus.TASK_STATE_RUNNING.equals(t.status().state())); + } catch (DockerException | InterruptedException e) { + LOGGER.error("Error checking if service {} is running: {}", serviceName, e.getMessage(), e); + return false; // Or throw an exception if you prefer + } + } + @Override - public ResourceUsageInformation getUsageInformation(Service.Criteria criteria) { - List services = manager.getContainers(criteria); + public ResourceUsageInformation getUsageInformation(ContainerCriteria criteria) { + List servicesName = manager.getContainers(criteria); + + ResourceUsageInformation resourceInfo = servicesName.parallelStream() + .filter(this::isServiceRunning) // Use a method to check if the service is running + .map(this::requestCpuAndMemoryStats) + .collect(Collectors.reducing(ResourceUsageInformation::staticMerge)).orElse(null); - Map containerMapping = new HashMap<>(); - for (Service c : services) { - containerMapping.put(c.spec().name(), c); - } - ResourceUsageInformation resourceInfo = containerMapping.keySet().parallelStream() - // filter all containers that are not running - .filter(s -> countRunningTasks(s) != 0) - // get the stats for the single - .map(id -> requestCpuAndMemoryStats(id)) - // sum up the stats - .collect(Collectors.reducing(ResourceUsageInformation::staticMerge)).orElse(null); return resourceInfo; } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java index d9d54ae8..680e7ee3 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java @@ -6,16 +6,28 @@ import io.kubernetes.client.openapi.models.V1Node; import io.kubernetes.client.openapi.models.V1NodeList; import org.hobbit.controller.containers.ClusterManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.List; public class ClusterManagerImpl implements ClusterManager { - + private static final Logger LOGGER = LoggerFactory.getLogger(ClusterManagerImpl.class); private final CoreV1Api coreV1Api; private Integer taskHistoryLimit = 0; // Default task history limit public ClusterManagerImpl(ApiClient apiClient) { + LOGGER.info("Creating a new cluster manager "); this.coreV1Api = new CoreV1Api(apiClient); + LOGGER.info("coreV1Api created, lets test it"); + try{ + + V1NodeList nodeList = coreV1Api.listNode(null, null, null, null, null, null, null, null, null, false); + List nodes = nodeList.getItems(); + LOGGER.info(nodes.size() + " nodes found"); + }catch(Exception e){ + LOGGER.error("Failed to create cluster manager coreV1Api is the root of the problem", e); + } } @@ -42,9 +54,11 @@ public long getNumberOfNodes(String label) throws InterruptedException { @Override public boolean isClusterHealthy() throws InterruptedException { + LOGGER.info("Checking cluster health"); try { V1NodeList nodeList = coreV1Api.listNode(null, null, null, null, null, null, null, null, null, false); List nodes = nodeList.getItems(); + LOGGER.info(nodes.size() + " nodes found"); for (V1Node node : nodes) { String status = node.getStatus().getConditions() .stream() @@ -59,6 +73,8 @@ public boolean isClusterHealthy() throws InterruptedException { } return true; } catch (ApiException e) { + LOGGER.error(e.getMessage()); + e.printStackTrace(); throw new RuntimeException("Failed to check cluster health", e); } } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java index 23d691bf..5bfd6f09 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java @@ -1,7 +1,9 @@ package org.hobbit.controller.containers.kubernetes; import org.hobbit.controller.containers.ContainerManager; +import org.hobbit.controller.containers.ContainerPodException; import org.hobbit.controller.containers.ContainerStateObserver; +import org.hobbit.controller.data.ContainerCriteria; import org.hobbit.controller.utils.Waiting; import org.hobbit.core.Constants; import org.slf4j.Logger; @@ -18,6 +20,8 @@ import java.io.IOException; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class ContainerManagerImpl implements ContainerManager { @@ -32,7 +36,7 @@ public class ContainerManagerImpl implements ContainerManager { * Logging separator for type/experiment id. */ private static final String LOGGING_SEPARATOR = "_sep_"; - public static final String LOGGING_TAG = "{{.ImageName}}/{{.Name}}/{{.ID}}"; + //public static final String LOGGING_TAG = "{{.ImageName}}/{{.Name}}/{{.ID}}"; public static final String DEPLOY_ENV_KEY = "DEPLOY_ENV"; private static final String DEPLOY_ENV_DEVELOP = "develop"; private static final String DEPLOY_ENV_TESTING = "testing"; @@ -40,20 +44,19 @@ public class ContainerManagerImpl implements ContainerManager { ? System.getenv().get(DEPLOY_ENV_KEY) : "production"; + private static final int MAX_POD_NAME_LENGTH = 63; + private static final Pattern VALID_POD_NAME_REGEX = Pattern.compile("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"); + + /** * Observers that should be notified if a container terminates. */ private final List containerObservers = new ArrayList<>(); - public ContainerManagerImpl() { - try { - if (client == null) { - client = initiateClient(); - } - } catch (Exception ex) { - LOGGER.error("Error initializing Kubernetes client: ", ex); - } + public ContainerManagerImpl(ApiClient client) { + LOGGER.info("Initializing Kubernetes client"); + this.client = client; } @@ -104,14 +107,112 @@ public String startContainer(String imageName, String containerType, String pare return startContainer(imageName, containerType, parentId, env, null, command, "", constraints); } + public String generatePodName(String moduleIri,String containerType) { + /* + * MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); + * messageDigest.update(moduleIri.getBytes()); String stringHash = new + * String(messageDigest.digest()); + */ + if(containerType==null){ + return "notype" + (moduleIri.hashCode() * 31 + (int) (System.currentTimeMillis())); + } + return containerType + (moduleIri.hashCode() * 31 + (int) (System.currentTimeMillis())); + + } + + public static String shortenAndValidatePodName(String podName) { + if (podName == null || podName.isEmpty()) { + throw new IllegalArgumentException("Pod name cannot be null or empty."); + } + + String shortenedName = podName; + + if (podName.length() > MAX_POD_NAME_LENGTH) { + // Shorten the name, prioritizing the end (more unique). + int excessLength = podName.length() - MAX_POD_NAME_LENGTH; + int charsToKeep = podName.length() - excessLength; + shortenedName = podName.substring(0, charsToKeep); + + //Ensure it ends with alphanumeric + while (shortenedName.length() > 0 && !Character.isLetterOrDigit(shortenedName.charAt(shortenedName.length()-1))) { + shortenedName = shortenedName.substring(0, shortenedName.length()-1); + } + } + + //Validate the shortened name + Matcher matcher = VALID_POD_NAME_REGEX.matcher(shortenedName); + if (!matcher.matches()) { + //Handle invalid characters (replace with hyphens or remove) + shortenedName = shortenedName.replaceAll("[^a-z0-9-]", "-"); + // Ensure starts and ends with alphanumeric after sanitization + while (shortenedName.length() > 0 && !Character.isLetterOrDigit(shortenedName.charAt(0))) { + shortenedName = shortenedName.substring(1); + } + while (shortenedName.length() > 0 && !Character.isLetterOrDigit(shortenedName.charAt(shortenedName.length()-1))) { + shortenedName = shortenedName.substring(0, shortenedName.length()-1); + } + //Re-check length after sanitization + if (shortenedName.length() > MAX_POD_NAME_LENGTH) { + shortenedName = shortenedName.substring(0, MAX_POD_NAME_LENGTH); + } + matcher = VALID_POD_NAME_REGEX.matcher(shortenedName); + if (!matcher.matches()) { + throw new IllegalArgumentException("Pod name could not be sanitized to comply with naming conventions."); + } + } + + return shortenedName; + } + // we do not use netAliases @Override public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command, String experimentId, Map constraints) { - String podName = LOGGING_TAG; + String podName = generatePodName(imageName,containerType); if (experimentId != null) { - podName = containerType + LOGGING_SEPARATOR + experimentId + LOGGING_SEPARATOR + LOGGING_TAG; + podName = experimentId + LOGGING_SEPARATOR + generatePodName(imageName,containerType); + } + + podName = shortenAndValidatePodName(podName); + + LOGGER.info("start Container podname is {}", podName); + + if (imageName != null) { + LOGGER.info("image name is {}", imageName); + } else { + LOGGER.info("image name is null"); + } + + if (containerType != null) { + LOGGER.info("container type is {}", containerType); + } else { + LOGGER.info("container type is null"); + } + + if (parentId != null) { + LOGGER.info("Parent ID is {}", parentId); + } else { + LOGGER.info("Parent ID is null"); } - return createContainerKub(imageName, podName,containerType,parentId, env,command,constraints); + + if (env != null && env.length > 0) { + LOGGER.info("env is {}", String.join(",", env)); + } else { + LOGGER.info("env is null or empty"); + } + + if (command != null && command.length > 0) { + LOGGER.info("command is {}", String.join(",", command)); + } else { + LOGGER.info("command is null or empty"); + } + + if (experimentId != null) { + LOGGER.info("experimentID is {}", experimentId); + } else { + LOGGER.info("experimentID is null"); + } + + return createContainerKub(imageName, podName, containerType, parentId, env, command, constraints); } /** @@ -166,29 +267,49 @@ private String createContainerKub(String imageName, String podName, String conta // Prepare environment variable List environmentVariables = new ArrayList<>(); if (env != null) { + LOGGER.info("Processing environment variables, total count: {}", env.length); + for (String envVar : env) { + LOGGER.info("Parsing environment variable: {}", envVar); String[] parts = envVar.split("=", 2); + if (parts.length == 2) { + LOGGER.info("Adding environment variable - Name: {}, Value: {}", parts[0], parts[1]); environmentVariables.add(new V1EnvVar().name(parts[0]).value(parts[1])); + } else { + LOGGER.warn("Skipping invalid environment variable: {}", envVar); } } + } else { + LOGGER.warn("No environment variables provided."); } - String parentType = getContainerType(parentPodName); - // if there is no container type then try to use the type of the parent - if(containerType == null || containerType.isEmpty()) { + LOGGER.info("Determining container type for parent pod: {}", parentPodName); + String parentType = null; + if(parentPodName != null) { + parentType = getContainerType(parentPodName); + } + + + if (containerType == null || containerType.isEmpty()) { + LOGGER.info("No container type provided, attempting to use parent pod's type."); + if (parentType == null) { - // If it can not resolve then return, because we don't want to make a pod with no type + LOGGER.error("Unable to resolve parent container type. Returning null to avoid creating pod with no type."); return null; - }else{ + } else { + LOGGER.info("Using parent container type: {}", parentType); containerType = parentType; } } + // Create resource requirements if constraints are provided + LOGGER.info("Creating resource requirements from constraints."); V1ResourceRequirements resourceRequirements = createResourceRequirementsFromConstraints(constraints); // Prepare the container specification + LOGGER.info("Preparing container specification with name: {}, image: {}", podName, imageName); V1Container container = new V1Container() .name(podName) .image(imageName) @@ -196,6 +317,9 @@ private String createContainerKub(String imageName, String podName, String conta .command(command != null ? Arrays.asList(command) : null) .resources(resourceRequirements); + LOGGER.info("Container specification created successfully."); + + // Create a volume and volume mount for shared directories // V1Volume volume = createVolumeForSharedDirectory(); // V1VolumeMount volumeMount = new V1VolumeMount() @@ -205,85 +329,114 @@ private String createContainerKub(String imageName, String podName, String conta // container.setVolumeMounts(Collections.singletonList(volumeMount)); // Create the pod specification + LOGGER.info("Creating pod specification for container: {}", podName); V1PodSpec podSpec = new V1PodSpec() .restartPolicy("Never") .containers(Collections.singletonList(container)); //.volumes(Collections.singletonList(volume)); + LOGGER.info("Determining node selector based on container type: {} and parent type: {}", containerType, parentType); if ((((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType)) && Constants.CONTAINER_TYPE_SYSTEM.equals(containerType)) || Constants.CONTAINER_TYPE_SYSTEM.equals(parentType)) { + + LOGGER.info("Setting node selector to 'system-nodes' for container type: {}", containerType); podSpec.nodeSelector(Collections.singletonMap("node-group", "system-nodes")); - // todo : why we set the container type here ? + + LOGGER.debug("Assigning container type to SYSTEM."); containerType = Constants.CONTAINER_TYPE_SYSTEM; + } else if (Constants.CONTAINER_TYPE_DATABASE.equals(containerType) && ((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType) || Constants.CONTAINER_TYPE_DATABASE.equals(parentType))) { + LOGGER.info("Setting node selector to 'benchmark-nodes' for DATABASE container type."); podSpec.nodeSelector(Collections.singletonMap("node-group", "benchmark-nodes")); } else if (Constants.CONTAINER_TYPE_BENCHMARK.equals(containerType) && ((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType))) { + LOGGER.info("Setting node selector to 'benchmark-nodes' for BENCHMARK container type."); podSpec.nodeSelector(Collections.singletonMap("node-group", "benchmark-nodes")); } else { LOGGER.error("Got a request to create a container with type={} and parentType={}. " - + "Got no rule to determine its type. Returning null.", containerType, parentType); + + "No rule found to determine its type. Returning null.", containerType, parentType); return null; } + LOGGER.info("Pod specification created successfully."); + - Map labels = new HashMap<>(); + LOGGER.info("Creating labels for pod: {}", podName); + + Map labels = new HashMap<>(); labels.put(LABEL_TYPE, containerType); labels.put(LABEL_PARENT, parentPodName); + LOGGER.info("Labels set - Type: {}, Parent: {}", containerType, parentPodName); - // Build the pod metadata +// Build the pod metadata + LOGGER.info("Building pod metadata for pod: {} in namespace: {}", podName, nameSpace); V1ObjectMeta metadata = new V1ObjectMeta() .name(podName) .namespace(nameSpace) .labels(labels); - - // Build the pod object +// Build the pod object + LOGGER.info("Constructing the pod object."); V1Pod pod = new V1Pod() .metadata(metadata) .spec(podSpec); + LOGGER.info("Pod object created successfully: {}", podName); + + // Deploy the pod try { - GenericKubernetesApi podClient = new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); + GenericKubernetesApi podClient = + new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); + + LOGGER.info("Sending request to create pod with name: {}", podName); + V1Pod createdPod = podClient.create(pod).throwsApiException().getObject(); - String podUid = createdPod.getMetadata().getUid(); - LOGGER.info("Successfully created container with Pod UID: {}", podUid); - // if the creation was successful - if (podUid != null) { + String createdPodName = createdPod.getMetadata().getName(); + + // If the creation was successful + if (createdPodName != null) { + LOGGER.info("Successfully created pod with name: {}", createdPodName); for (ContainerStateObserver observer : containerObservers) { - observer.addObservedContainer(podUid); + LOGGER.info("Notifying observer about created pod with name: {}", createdPodName); + observer.addObservedContainer(createdPodName); } } - return podUid; + + return createdPodName; } catch (ApiException e) { - LOGGER.error("Failed to create container for image: {}. Returning null.", imageName, e); + LOGGER.error("Failed to create pod for image: {}. Returning null.", imageName, e); return null; } + } private V1Pod getPod(String podName) { + LOGGER.info("Attempting to retrieve pod: {} in namespace: {}", podName, this.nameSpace); + CoreV1Api coreV1Api = new CoreV1Api(client); try { // Inspect the pod by name V1Pod pod = coreV1Api.readNamespacedPod(podName, this.nameSpace, null); + LOGGER.info("Successfully retrieved pod: {} in namespace: {}", podName, this.nameSpace); return pod; - }catch (ApiException exc){ - LOGGER.error("Failed to get container for image: {} in namespace {}. Returning null.", podName, this.nameSpace, exc); - return null; + } catch (ApiException exc) { + LOGGER.error("Failed to get pod: {} in namespace: {}. Error: {}", podName, this.nameSpace, exc.getMessage(), exc); + return null; } } + // /** // * // * @param parentId @@ -302,7 +455,7 @@ private V1ResourceRequirements createResourceRequirementsFromConstraints(Map getContainers(Service.Criteria criteria) { + public List getContainers(ContainerCriteria criteria) { return null; } @@ -513,18 +662,33 @@ public void pullImage(String imageName) { // we dont need this in kubernetes } - //TODO: do we need this for kubernetes? no usage in docker version - @Override - public ContainerStats getStats(String containerId) { - return null; - } +// //TODO: do we need this for kubernetes? no usage in docker version +// @Override +// public ContainerStats getStats(String containerId) { +// return null; +// } @Override public String getContainerType(String podName) { - // Logic to resolve container type based on the parentId - // return null if resolution fails + LOGGER.info("Resolving container type for pod: {}", podName); + + // Logic to retrieve the parent pod based on the podName V1Pod parent = getPod(podName); - return (parent == null) ? null : parent.getMetadata().getLabels().get(LABEL_TYPE); + + if (parent == null) { + LOGGER.warn("Parent pod not found for pod name: {}", podName); + return null; + } + + String containerType = parent.getMetadata().getLabels().get(LABEL_TYPE); + + if (containerType == null) { + LOGGER.warn("Container type not found in labels for pod: {}", podName); + } else { + LOGGER.info("Resolved container type for pod {}: {}", podName, containerType); + } + + return containerType; } } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java index f813e02e..2cd888e1 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java @@ -5,6 +5,7 @@ import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.models.V1Pod; import io.kubernetes.client.openapi.models.V1PodList; +import org.hobbit.controller.containers.ContainerManager; import org.hobbit.controller.containers.ContainerStateObserver; import org.hobbit.controller.containers.ContainerTerminationCallback; import org.slf4j.Logger; @@ -19,16 +20,17 @@ public class ContainerStateObserverImpl implements ContainerStateObserver { private static final Logger LOGGER = LoggerFactory.getLogger(ContainerStateObserverImpl.class); - private final ApiClient apiClient; + ContainerManager manager; + private String nameSpace = "default"; private final CoreV1Api coreV1Api; private final List monitoredContainers; private final List terminationCallbacks; private final Timer timer; private final int repeatInterval; - public ContainerStateObserverImpl(ApiClient apiClient, int repeatInterval) { - this.apiClient = apiClient; - this.coreV1Api = new CoreV1Api(apiClient); + public ContainerStateObserverImpl(ContainerManager manager, int repeatInterval,ApiClient client) { + this.manager = manager; + this.coreV1Api = new CoreV1Api(client); this.monitoredContainers = new ArrayList<>(); this.terminationCallbacks = new ArrayList<>(); this.timer = new Timer(); @@ -59,7 +61,7 @@ public void run() { } } } - } catch (ApiException e) { + } catch (Exception e) { LOGGER.error("Couldn't get the status of container " + containerName + ". It will be ignored during this run but will be checked again during the next run.", e); } } @@ -106,18 +108,48 @@ public List getObservedContainers() { } } - private V1Pod getPodByContainerName(String containerName) throws ApiException { - V1PodList podList = coreV1Api.listPodForAllNamespaces(null, null, null, "", null, null, null, null, null, false); - for (V1Pod pod : podList.getItems()) { - if (pod.getStatus() != null && pod.getStatus().getContainerStatuses() != null) { - if (pod.getStatus().getContainerStatuses().stream().anyMatch(status -> containerName.equals(status.getName()))) { + private V1Pod getPodByContainerName(String containerName) { + //LOGGER.info("Attempting to find pod by container name: {} in namespace {}", containerName, nameSpace); + + try { + V1PodList podList = coreV1Api.listNamespacedPod(nameSpace,null, null, null, "", null, null, null, null, null, false); + //LOGGER.info("Found pods: {}", podList.getItems().size()); + // Search for pod by container name + for (V1Pod pod : podList.getItems()) { + if (pod.getStatus() != null && pod.getStatus().getContainerStatuses() != null) { + //LOGGER.info("Checking pod: {}", pod.getMetadata().getName()); + + if (pod.getStatus().getContainerStatuses().stream().anyMatch(status -> containerName.equals(status.getName()))) { + //LOGGER.info("Found pod: {} matching container name: {}", pod.getMetadata().getName(), containerName); + return pod; + } + } + } + + //LOGGER.warn("No pod found by container name: {}. Attempting to search by UID.", containerName); + + // If no pod was found by container name, search by UID + for (V1Pod pod : podList.getItems()) { + if (pod.getMetadata() != null && containerName.equals(pod.getMetadata().getUid())) { + //LOGGER.info("Found pod: {} matching UID: {}", pod.getMetadata().getName(), containerName); return pod; } } + + LOGGER.warn("No pod found with container name or UID: {}", containerName); + return null; + + } catch (ApiException e) { + LOGGER.error("ApiException occurred while trying to list pods. Error message: {}. Stack trace: {}", e.getMessage(), e); + // You can rethrow the exception if needed or return null as fallback + return null; + } catch (Exception e) { + LOGGER.error("Unexpected error occurred while trying to list pods. Error message: {}. Stack trace: {}", e.getMessage(), e); + return null; } - return null; } + private boolean isPodTerminated(V1Pod pod) { return pod.getStatus() != null && "Succeeded".equals(pod.getStatus().getPhase()) || "Failed".equals(pod.getStatus().getPhase()); } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java index 1c4535b5..8fe97e6e 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java @@ -1,122 +1,234 @@ package org.hobbit.controller.containers.kubernetes; -import com.spotify.docker.client.messages.swarm.Service; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.ApiException; -import io.kubernetes.client.openapi.apis.MetricsApi; + + +import com.google.common.collect.ImmutableMap; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.kubernetes.client.custom.Quantity; +import io.kubernetes.client.openapi.Configuration; import io.kubernetes.client.openapi.models.V1Node; -import io.kubernetes.client.openapi.models.V1NodeList; -import io.kubernetes.client.openapi.models.V1PodMetrics; -import io.kubernetes.client.openapi.models.V1PodMetricsList; -import io.kubernetes.client.util.Config; +import io.kubernetes.client.openapi.models.V1NodeSystemInfo; +import io.kubernetes.client.openapi.models.V1Pod; +import org.hobbit.controller.containers.ContainerManager; import org.hobbit.controller.containers.ResourceInformationCollector; +import org.hobbit.controller.data.ContainerCriteria; +import org.hobbit.controller.data.NodeHardwareInformation; +import org.hobbit.controller.data.SetupHardwareInformation; +import org.hobbit.core.Constants; +import org.hobbit.core.data.usage.CpuStats; +import org.hobbit.core.data.usage.DiskStats; +import org.hobbit.core.data.usage.MemoryStats; import org.hobbit.core.data.usage.ResourceUsageInformation; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.apis.CoreV1Api; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.util.*; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; + public class ResourceInformationCollectorImpl implements ResourceInformationCollector { private static final Logger LOGGER = LoggerFactory.getLogger(ResourceInformationCollectorImpl.class); - private final ApiClient apiClient; - private final MetricsApi metricsApi; - - public ResourceInformationCollectorImpl() throws IOException { - this.apiClient = Config.defaultClient(); - this.metricsApi = new MetricsApi(apiClient); + //TODO make configable + private int TIMEOUT_MILLISECONDS = 60000; + private final String namespace = "default"; + private static final long KUBERNETES_POLL_INTERVAL = 5000; // Poll interval in ms + private static final long KUBERNETES_EXITCODE_SIGKILL = 137L; // Equivalent to SIGKILL exit code + + private ApiClient apiClient; + private CoreV1Api coreV1Api; + private ContainerManager manager; + + public ResourceInformationCollectorImpl(ContainerManager manager,ApiClient apiClient, CoreV1Api coreV1Api) { + this.manager = manager; + this.apiClient = apiClient; + this.apiClient.setConnectTimeout(TIMEOUT_MILLISECONDS); + this.apiClient.setReadTimeout(TIMEOUT_MILLISECONDS); + this.apiClient.setWriteTimeout(TIMEOUT_MILLISECONDS); + Configuration.setDefaultApiClient(this.apiClient); + + // Create a CoreV1Api instance + this.coreV1Api = new CoreV1Api(this.apiClient); } @Override public ResourceUsageInformation getSystemUsageInformation() { - return getUsageInformation(null); + return getUsageInformation(ContainerCriteria.builder() + .withLabels(ImmutableMap.of(ContainerManager.LABEL_TYPE, Constants.CONTAINER_TYPE_SYSTEM)) + .build()); } @Override - public ResourceUsageInformation getUsageInformation(Service.Criteria criteria) { - return null; - } + public ResourceUsageInformation getUsageInformation(ContainerCriteria criteria) { + List servicesName = manager.getContainers(criteria); - @Override - public ResourceUsageInformation getUsageInformation( criteria) { - try { - V1PodMetricsList podMetricsList = metricsApi.listPodMetricsForAllNamespaces( - null, null, null, null, null, null, null, null, null); + LOGGER.info("number of services which has thecriteri {} is: {}", criteria.toString(),servicesName.size()); + ResourceUsageInformation resourceInfo = servicesName.parallelStream() + .filter(this::isPodRunning) // Use a method to check if the service is running + .map(this::requestCpuAndMemoryStats) + .collect(Collectors.reducing(ResourceUsageInformation::staticMerge)).orElse(null); - List filteredMetrics = podMetricsList.getItems(); + return resourceInfo; + } - // If criteria exist, filter pods accordingly (example: by namespace or labels) - if (criteria != null) { - filteredMetrics = filteredMetrics.stream() - .filter(metrics -> matchesCriteria(metrics, criteria)) - .collect(Collectors.toList()); - } + protected ResourceUsageInformation requestCpuAndMemoryStats(String podName) { + ResourceUsageInformation resourceUsage = fetchPodMetrics(this.apiClient, this.namespace, podName); - return aggregatePodMetrics(filteredMetrics); + return resourceUsage; + } - } catch (ApiException e) { - LOGGER.error("Error retrieving pod metrics from Kubernetes", e); - return null; + private boolean isPodRunning(String podName) { + try { + // Fetch the pod details by name + V1Pod pod = this.coreV1Api.readNamespacedPod(podName, this.namespace, null); + + // Check the pod's status + String status = pod.getStatus().getPhase(); + return "Running".equalsIgnoreCase(status); + } catch (Exception e) { + System.err.println("Error checking status for Pod " + podName + ": " + e.getMessage()); + e.printStackTrace(); } + return false; } @Override public SetupHardwareInformation getHardwareInformation() { - SetupHardwareInformation hardwareInfo = new SetupHardwareInformation(); - try { - V1NodeList nodeList = new MetricsApi(apiClient).listNode(null, null, null, null, null, null, null, null, null); + SetupHardwareInformation information = new SetupHardwareInformation(); + try{ + List nodes = coreV1Api.listNode( + null, // pretty + true, // allowWatchBookmarks + null, // continue + null, // fieldSelector + null, // labelSelector (not setting any label filter) + null, // limit (no limit set, returns all results) + null, // resourceVersion + null, // resourceVersionMatch + null, // timeoutSeconds + false // watch + ).getItems(); + + // Iterate through each node + for (V1Node node : nodes) { + V1NodeSystemInfo systemInfo = node.getStatus().getNodeInfo(); + + LOGGER.info("Kernel Version: " + systemInfo.getKernelVersion()); + LOGGER.info("Machine ID: " + systemInfo.getMachineID()); + LOGGER.info("Container Runtime Version: " + systemInfo.getContainerRuntimeVersion()); + LOGGER.info("Kubelet Version: " + systemInfo.getKubeletVersion()); + LOGGER.info("KubeProxy Version: " + systemInfo.getKubeProxyVersion()); + + + //TODO test + + String nodeName = node.getMetadata().getName(); + LOGGER.info("nodeName: " + nodeName); + Map capacity = node.getStatus().getCapacity(); +// Map allocatable = node.getStatus().getAllocatable(); + + String cpu = capacity.get("cpu").toSuffixedString(); // e.g., "8" + String memory = capacity.get("memory").toSuffixedString(); // e.g., "32Gi" + - for (V1Node node : nodeList.getItems()) { NodeHardwareInformation nodeInfo = new NodeHardwareInformation(); - nodeInfo.setInstance(node.getMetadata().getName()); - nodeInfo.setCpu( - Long.parseLong(node.getStatus().getCapacity().get("cpu").toString()), - Collections.singletonList(Long.parseLong(node.getStatus().getCapacity().get("cpu").toString())) - ); - nodeInfo.setMemory( - Long.parseLong(node.getStatus().getCapacity().get("memory").toString().replaceAll("[^\\d]", "")), - null - ); - nodeInfo.setOs(node.getStatus().getNodeInfo().getOsImage()); - hardwareInfo.addNode(nodeInfo); + nodeInfo.setOs(systemInfo.getOsImage()); + nodeInfo.setCpu(Long.valueOf(cpu),new LinkedList<>()); + nodeInfo.setMemory(parseMemoryUsage(memory),0L); + information.addNode(nodeInfo); } - - } catch (ApiException e) { - LOGGER.error("Error retrieving hardware information from Kubernetes nodes", e); + } catch (Exception e) { + LOGGER.error("Error getting hardware information", e); } - - return hardwareInfo; + return information; } - private boolean matchesCriteria(V1PodMetrics metrics, Criteria criteria) { - // Example implementation: filter by namespace - if (criteria.getNamespace() != null && !criteria.getNamespace().equals(metrics.getMetadata().getNamespace())) { - return false; + private static ResourceUsageInformation fetchPodMetrics(ApiClient client, String namespace, String podName) { + try { + // Metrics server endpoint for the pod + String metricsUrl = "/apis/metrics.k8s.io/v1beta1/namespaces/" + namespace + "/pods/" + podName; + + // Send a request to the metrics API + okhttp3.Request request = new okhttp3.Request.Builder() + .url(client.getBasePath() + metricsUrl) + .get() + .build(); + + okhttp3.Response response = client.getHttpClient().newCall(request).execute(); + + if (response.isSuccessful() && response.body() != null) { + String responseBody = response.body().string(); + + // Parse the JSON response + ObjectMapper mapper = new ObjectMapper(); + JsonNode root = mapper.readTree(responseBody); + + // Extract metrics for the pod + ResourceUsageInformation resourceUsage = new ResourceUsageInformation(); + + long cpuTotalUsage = 0; + long memoryTotalUsage = 0; + + // Iterate over containers in the pod + JsonNode containers = root.path("containers"); + for (JsonNode container : containers) { + String cpuUsageStr = container.path("usage").path("cpu").asText(); + String memoryUsageStr = container.path("usage").path("memory").asText(); + + cpuTotalUsage += parseCpuUsage(cpuUsageStr); + memoryTotalUsage += parseMemoryUsage(memoryUsageStr); + } + + // Set resource usage data + CpuStats cpuStats = new CpuStats(); + cpuStats.setTotalUsage(cpuTotalUsage); + + MemoryStats memoryStats = new MemoryStats(); + memoryStats.setUsageSum(memoryTotalUsage); + + DiskStats diskStats = new DiskStats(); // Metrics Server does not provide disk usage + diskStats.setFsSizeSum(0); // Set to 0 or implement a disk usage fetcher + + resourceUsage.setCpuStats(cpuStats); + resourceUsage.setMemoryStats(memoryStats); + resourceUsage.setDiskStats(diskStats); + + return resourceUsage; + } else { + System.err.println("Failed to fetch metrics for Pod " + podName + ": " + response.message()); + } + + } catch (Exception e) { + System.err.println("Error fetching metrics for Pod " + podName + ": " + e.getMessage()); + e.printStackTrace(); } - // Add additional criteria filtering logic if necessary - return true; + return null; } - private ResourceUsageInformation aggregatePodMetrics(List podMetrics) { - ResourceUsageInformation resourceInfo = new ResourceUsageInformation(); - podMetrics.forEach(metrics -> { - metrics.getContainers().forEach(container -> { - try { - long memoryUsage = Long.parseLong( - container.getUsage().get("memory").replaceAll("[^\\d]", "")); - long cpuUsage = Long.parseLong( - container.getUsage().get("cpu").replaceAll("[^\\d]", "")); - - resourceInfo.addMemoryUsage(memoryUsage); - resourceInfo.addCpuUsage(cpuUsage); - - } catch (NumberFormatException e) { - LOGGER.warn("Error parsing resource usage for container: {}", container.getName(), e); - } - }); - }); + private static long parseCpuUsage(String cpuUsageStr) { + // Convert CPU usage string (e.g., "12345n" for nanoseconds) to long + if (cpuUsageStr.endsWith("n")) { + return Long.parseLong(cpuUsageStr.replace("n", "")); + } + return 0; + } - return resourceInfo; + private static long parseMemoryUsage(String memoryUsageStr) { + // Convert memory usage string (e.g., "128Mi", "512Ki") to bytes + if (memoryUsageStr.endsWith("Mi")) { + return Long.parseLong(memoryUsageStr.replace("Mi", "")) * 1024 * 1024; + } else if (memoryUsageStr.endsWith("Ki")) { + return Long.parseLong(memoryUsageStr.replace("Ki", "")) * 1024; + } else if (memoryUsageStr.endsWith("Gi")) { + return Long.parseLong(memoryUsageStr.replace("Gi", "")) * 1024 * 1024 * 1024; + } + return 0; } + } diff --git a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java new file mode 100644 index 00000000..7337a1e4 --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java @@ -0,0 +1,73 @@ +package org.hobbit.controller.data; + +import java.util.Map; +import java.util.HashMap; + +public class ContainerCriteria { + protected String containerId; + protected String containerName; + protected Map labels; + + public static class Builder { + private String containerId; + private String containerName; + private Map labels = new HashMap<>(); + + public Builder withContainerId(String containerId) { + this.containerId = containerId; + return this; + } + + public Builder withContainerName(String containerName) { + this.containerName = containerName; + return this; + } + + public Builder withLabels(Map labels) { + this.labels.putAll(labels); + return this; + } + + public Builder withLabel(String key, String value) { + this.labels.put(key, value); + return this; + } + + + public ContainerCriteria build() { + ContainerCriteria criteria = new ContainerCriteria(); + criteria.containerId = this.containerId; + criteria.containerName = this.containerName; + criteria.labels = new HashMap<>(this.labels); // Create a copy to prevent external modification + return criteria; + } + } + + + public String getContainerId() { + return containerId; + } + + public String getContainerName() { + return containerName; + } + + public Map getLabels() { + return labels; + } + + public static Builder builder() { + return new Builder(); + } + + + @Override + public String toString() { + return "ContainerCriteria{" + + "containerId='" + containerId + '\'' + + ", containerName='" + containerName + '\'' + + ", labels=" + labels + + '}'; + } +} + diff --git a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java new file mode 100644 index 00000000..500ccaea --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java @@ -0,0 +1,70 @@ +package org.hobbit.controller.data; + +import com.spotify.docker.client.messages.swarm.Service; +import org.hobbit.controller.data.ContainerCriteria; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +//TODO check the whole mapping concept +public class ContainerCriteriaToServiceCriteriaMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(ContainerCriteriaToServiceCriteriaMapper.class); + public static Service.Criteria map(ContainerCriteria containerCriteria) { + if (containerCriteria == null) { + LOGGER.error("containerCriteria is null can not map it to ServiceCriteria"); + return null; + } + + Service.Criteria.Builder builder = Service.Criteria.builder(); + + if (containerCriteria.getContainerId() != null) { + // map container ID to service + builder.serviceId(containerCriteria.getContainerId()); + // also is possible to use labels like bellow + //builder.labels(Collections.singletonMap("container_id", containerCriteria.getContainerId())); + } + + if (containerCriteria.getContainerName() != null) { + //map container ID to service ID + builder.serviceName(containerCriteria.getContainerName()); + //same as ID we can use label if need + //builder.labels(Collections.singletonMap("container_name", containerCriteria.getContainerName())); + } + + if (containerCriteria.getLabels() != null && !containerCriteria.getLabels().isEmpty()) { + builder.labels(containerCriteria.getLabels()); + } + + return builder.build(); + } + + + public static void main(String[] args) { + // Example Usage + ContainerCriteria criteria = ContainerCriteria.builder() + .withContainerId("12345") + .withContainerName("my-service") + .withLabel("app", "my-app") + .build(); + + Service.Criteria serviceCriteria = map(criteria); + + if (serviceCriteria != null) { + System.out.println(serviceCriteria.labels()); // Print the labels for verification + } + + ContainerCriteria criteria2 = ContainerCriteria.builder() + .withLabels(Collections.singletonMap("env", "prod")) + .build(); + + Service.Criteria serviceCriteria2 = map(criteria2); + + if (serviceCriteria2 != null) { + System.out.println(serviceCriteria2.labels()); // Print the labels for verification + } + + } +} diff --git a/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java b/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java index d58f1cf6..7a41efb3 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java +++ b/platform-controller/src/main/java/org/hobbit/controller/data/ExperimentStatus.java @@ -36,7 +36,7 @@ import org.hobbit.controller.ExperimentManager; import org.hobbit.controller.PlatformController; import org.hobbit.controller.containers.ImageManager; -import org.hobbit.controller.containers.docker.MetaDataFactory; +import org.hobbit.controller.containers.MetaDataFactory; import org.hobbit.controller.execute.ExperimentAbortTimerTask; import org.hobbit.core.rabbit.RabbitMQUtils; import org.hobbit.vocab.HOBBIT; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java index 243526ea..278961ac 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java @@ -1,6 +1,6 @@ package org.hobbit.controller.docker; -import org.hobbit.controller.containers.docker.FileBasedImageManager; +import org.hobbit.controller.containers.FileBasedImageManager; import org.hobbit.core.data.BenchmarkMetaData; import org.hobbit.core.data.SystemMetaData; import org.junit.Assert; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java index 6df7fc64..e8565dc9 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java @@ -26,7 +26,7 @@ import org.apache.jena.rdf.model.Model; import org.apache.jena.vocabulary.RDF; import org.hobbit.controller.ConnectivityAssumptionUtils; -import org.hobbit.controller.containers.docker.GitlabBasedImageManager; +import org.hobbit.controller.containers.GitlabBasedImageManager; import org.hobbit.controller.gitlab.GitlabControllerImplTest; import org.hobbit.core.data.BenchmarkMetaData; import org.hobbit.core.data.SystemMetaData; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java index aac7eca1..b73b413f 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java @@ -10,7 +10,7 @@ import org.apache.commons.compress.utils.IOUtils; import org.apache.log4j.lf5.util.StreamUtils; import org.hobbit.controller.ParameterForwardingTest; -import org.hobbit.controller.containers.docker.MetaDataFactory; +import org.hobbit.controller.containers.MetaDataFactory; import org.hobbit.core.data.BenchmarkMetaData; import org.hobbit.core.data.ImageMetaData; import org.hobbit.core.data.SystemMetaData; diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java index cdd3560c..d1864096 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java @@ -12,6 +12,7 @@ import com.spotify.docker.client.messages.ContainerStats; import com.spotify.docker.client.messages.swarm.Service; import com.spotify.docker.client.messages.swarm.Service.Criteria; +import org.hobbit.controller.data.ContainerCriteria; public class DummyContainerManager implements ContainerManager { @@ -113,7 +114,7 @@ public void removeParentAndChildren(String parent) { // } @Override - public List getContainers(Criteria criteria) { + public List getContainers(ContainerCriteria criteria) { return new ArrayList<>(0); } diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java index b2415cf3..932420eb 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyResourceInformationCollector.java @@ -1,6 +1,7 @@ package org.hobbit.controller.mocks; import com.spotify.docker.client.messages.swarm.Service; +import org.hobbit.controller.data.ContainerCriteria; import org.hobbit.controller.data.SetupHardwareInformation; import org.hobbit.controller.containers.ResourceInformationCollector; import org.hobbit.core.data.usage.ResourceUsageInformation; @@ -13,7 +14,7 @@ public ResourceUsageInformation getSystemUsageInformation() { }; @Override - public ResourceUsageInformation getUsageInformation(Service.Criteria criteria) { + public ResourceUsageInformation getUsageInformation(ContainerCriteria criteria) { return null; }; From ec954e1fbcf36cdc5406314a5eb8d3d29693db5e Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 19 Feb 2025 15:43:05 +0100 Subject: [PATCH 14/52] add yaml files , keycloak db2 file --- kubernetes-yaml-files/17-cluster-role.yaml | 4 +- .../18-keycloak-deployment.yaml | 64 +++++++++++++++++++ kubernetes-yaml-files/19-keycloak.yaml | 14 ++++ kubernetes-yaml-files/20-keycloak-pv.yaml | 14 ++++ kubernetes-yaml-files/21-keycloak-pvc.yaml | 10 +++ kubernetes-yaml-files/99-test-job.yaml | 37 +++++++++++ 6 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 kubernetes-yaml-files/18-keycloak-deployment.yaml create mode 100644 kubernetes-yaml-files/19-keycloak.yaml create mode 100644 kubernetes-yaml-files/20-keycloak-pv.yaml create mode 100644 kubernetes-yaml-files/21-keycloak-pvc.yaml create mode 100644 kubernetes-yaml-files/99-test-job.yaml diff --git a/kubernetes-yaml-files/17-cluster-role.yaml b/kubernetes-yaml-files/17-cluster-role.yaml index c4c428b5..0058fa41 100644 --- a/kubernetes-yaml-files/17-cluster-role.yaml +++ b/kubernetes-yaml-files/17-cluster-role.yaml @@ -4,8 +4,8 @@ metadata: name: node-reader rules: - apiGroups: [""] - resources: ["nodes"] - verbs: ["get", "list", "watch"] # Minimum permissions needed + resources: ["nodes" , "pods", "services", "namespaces"] + verbs: ["create", "get", "update", "delete", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 diff --git a/kubernetes-yaml-files/18-keycloak-deployment.yaml b/kubernetes-yaml-files/18-keycloak-deployment.yaml new file mode 100644 index 00000000..99b8bed7 --- /dev/null +++ b/kubernetes-yaml-files/18-keycloak-deployment.yaml @@ -0,0 +1,64 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hobbit-keycloak + labels: + app: hobbit-keycloak +spec: + replicas: 1 + selector: + matchLabels: + app: hobbit-keycloak + template: + metadata: + labels: + app: hobbit-keycloak + spec: + volumes: + - name: nfs-volume + persistentVolumeClaim: + claimName: keycloack-pvc + - name: cfg-volume + emptyDir: { } + initContainers: + - name: init-copy-db + image: alpine:latest + command: + - /bin/sh + - -c + - | + mkdir -p /cfg-volume + cp /nfs/keycloak.h2.db /cfg-volume/keycloak.h2.db + chmod 777 /cfg-volume + chmod 666 /cfg-volume/keycloak.h2.db + volumeMounts: + - name: nfs-volume + mountPath: /nfs + - name: cfg-volume + mountPath: /cfg-volume + containers: + - name: hobbit-keycloak + image: hobbitproject/hobbit-keycloak:latest + ports: + - containerPort: 8080 + env: + - name: KEYCLOAK_USER + value: admin + - name: KEYCLOAK_PASSWORD + value: admin + - name: DB_VENDOR + value: h2 + volumeMounts: + - name: cfg-volume + mountPath: /cfg-volume + readinessProbe: + httpGet: + path: /auth/realms/master + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /auth/realms/master + port: 8080 + initialDelaySeconds: 30 diff --git a/kubernetes-yaml-files/19-keycloak.yaml b/kubernetes-yaml-files/19-keycloak.yaml new file mode 100644 index 00000000..4f50d7a9 --- /dev/null +++ b/kubernetes-yaml-files/19-keycloak.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: hobbit-keycloak + labels: + app: hobbit-keycloak +spec: + ports: + - port: 8080 + targetPort: 8080 + nodePort: 31000 + selector: + app: hobbit-keycloak + type: NodePort diff --git a/kubernetes-yaml-files/20-keycloak-pv.yaml b/kubernetes-yaml-files/20-keycloak-pv.yaml new file mode 100644 index 00000000..82093d21 --- /dev/null +++ b/kubernetes-yaml-files/20-keycloak-pv.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: keycloak-pv +spec: + capacity: + storage: 1Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain # or Delete, depending on your needs + storageClassName: "" # Important: Leave this empty if not using Storage Classes + nfs: + server: 131.234.29.64 + path: /data/nfs/kubedata/keycloak diff --git a/kubernetes-yaml-files/21-keycloak-pvc.yaml b/kubernetes-yaml-files/21-keycloak-pvc.yaml new file mode 100644 index 00000000..7ea0d9c6 --- /dev/null +++ b/kubernetes-yaml-files/21-keycloak-pvc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: keycloack-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/kubernetes-yaml-files/99-test-job.yaml b/kubernetes-yaml-files/99-test-job.yaml new file mode 100644 index 00000000..d2d46ac0 --- /dev/null +++ b/kubernetes-yaml-files/99-test-job.yaml @@ -0,0 +1,37 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: hobbit-benchmark +spec: + template: + spec: + securityContext: + fsGroup: 1000 + containers: + - name: hobbit-benchmark + image: maven + command: ["/bin/bash", "-c"] + args: + - | + java -cp target/platform-controller.jar org.hobbit.core.run.ComponentStarter org.hobbit.controller.test.StartBenchmarkRequest + env: + - name: HOBBIT_RABBIT_HOST + value: "rabbitmq" + - name: BENCHMARK + value: "http://example.org/GerbilBenchmark" + - name: SYSTEM + value: "http://example.org/DummySystemInstance1" + - name: BENCHMARK_PARAM_FILE + value: "src/test/resources/exampleExperiment.ttl" + - name: USERNAME + value: "testuser" + volumeMounts: + - name: app-volume + mountPath: /usr/src/app + restartPolicy: Never + volumes: + - name: app-volume + nfs: + server: 131.234.29.64 + path: /data/nfs/kubedata/test + readOnly: false From b9232930c59fdcbabe6d1ec0362fbbe0f8da6e96 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Fri, 7 Mar 2025 15:42:52 +0100 Subject: [PATCH 15/52] middle way of converting container name to IP --- .../hobbit/controller/ExperimentManager.java | 24 +- .../hobbit/controller/PlatformController.java | 12 + .../containers/ContainerManager.java | 8 + .../containers/FileBasedImageManager.java | 2 + .../containers/GitlabBasedImageManager.java | 23 +- .../docker/ContainerManagerImpl.java | 5 + .../kubernetes/ContainerManagerImpl.java | 267 +++++++++++++++++- .../data/NodeHardwareInformation.java | 36 ++- 8 files changed, 363 insertions(+), 14 deletions(-) diff --git a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java index a058ed31..af9c526d 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java @@ -196,6 +196,17 @@ public void createNextExperiment() { createRabbitMQ(config); BenchmarkMetaData benchmark = controller.imageManager().getBenchmark(config.benchmarkUri); + + if(benchmark==null){ + LOGGER.info("There is no benchmark found for {}",config.benchmarkUri); + }else{ + LOGGER.info("Benchmark found for {}",config.benchmarkUri); + LOGGER.info("Benchmark name is {}",benchmark.getName()); + LOGGER.info("Benchmark description is {}",benchmark.getDescription()); + LOGGER.info("Benchmark main image is {}",benchmark.getMainImage()); + LOGGER.info("Benchmark uri is {}",benchmark.getUri()); + } + if ((benchmark == null) || (benchmark.mainImage == null)) { // Think about reusing the existing object created above experimentStatus = new ExperimentStatus(config, HobbitExperiments.getExperimentURI(config.id), @@ -205,6 +216,11 @@ public void createNextExperiment() { } SystemMetaData system = controller.imageManager().getSystem(config.systemUri); + if(system==null){ + LOGGER.info("There is no system found for system " + config.systemUri); + }else{ + LOGGER.info("System found for benchmark " + config.systemUri); + } if ((system == null) || (system.mainImage == null)) { // Think about reusing the existing object created above experimentStatus = new ExperimentStatus(config, HobbitExperiments.getExperimentURI(config.id), @@ -328,9 +344,15 @@ protected void createRabbitMQ(ExperimentConfiguration config) throws Exception { LOGGER.info("Using the newly started RabbitMQ for the experiment: {}", rabbitMQAddress); if (rabbitMQAddress == null) { LOGGER.info("Starting new RabbitMQ for the experiment..."); - rabbitMQAddress = controller.containerManager.startContainer(hobbitConfig.getString(RABBIT_IMAGE_ENV_KEY), + String rabbitMQPOD = controller.containerManager.startContainer(hobbitConfig.getString(RABBIT_IMAGE_ENV_KEY), Constants.CONTAINER_TYPE_BENCHMARK, null, new String[] {}, null, null, config.id, Collections.emptyMap()); + //LOGGER.info("Starting service for RabbitMQ for the pod: {}", rabbitMQPOD); + //Map ports = new HashMap<>(); + //ports.put(5672,5672); + //rabbitMQAddress = controller.containerManager.startService(rabbitMQPOD,false,ports ); + rabbitMQAddress = rabbitMQPOD; + LOGGER.info("Service initialized for RabbitMQ with this name: {}", rabbitMQAddress); if (rabbitMQAddress == null) { experimentStatus.addError(HobbitErrors.UnexpectedError); // FIXME throw new Exception("Couldn't start new RabbitMQ for the experiment"); diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 675588f2..1aa5ead4 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -309,6 +309,7 @@ public void init() throws Exception { if (System.getenv().containsKey(USE_GITLAB_KEY)) { try { useGitlab = Boolean.parseBoolean(System.getenv().get(USE_GITLAB_KEY)); + LOGGER.info("Using git lab enabled"); } catch (Exception e) { LOGGER.error("Couldn't parse value of " + USE_GITLAB_KEY + ". It will be ignored."); } @@ -408,6 +409,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas // Determine the command switch (command) { case Commands.DOCKER_CONTAINER_START: { + LOGGER.info("Starting container with name: {}", sessionId); StartCommandData startParams = null; String containerName = ""; if (expManager.isExpRunning(sessionId)) { @@ -415,6 +417,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas startParams = GsonUtils.deserializeObjectWithGson(gson, data, StartCommandData.class, false); // trigger creation containerName = createContainer(startParams); + LOGGER.info("Starting container with name: {}", containerName); } else { LOGGER.error( "Got a request to start a container for experiment \"{}\" which is either not running or was already stopped. Returning null.", @@ -443,6 +446,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas break; } case Commands.DOCKER_CONTAINER_STOP: { + LOGGER.info("Stopping container with name: {}", sessionId); // get containerId from params StopCommandData stopParams = GsonUtils.deserializeObjectWithGson(gson, data, StopCommandData.class, false); // trigger stop @@ -450,14 +454,17 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas break; } case Commands.BENCHMARK_READY_SIGNAL: { + LOGGER.info("Ready signal: {}", sessionId); expManager.systemOrBenchmarkReady(false, sessionId); break; } case Commands.SYSTEM_READY_SIGNAL: { + LOGGER.info("System Ready signal: {}", sessionId); expManager.systemOrBenchmarkReady(true, sessionId); break; } case Commands.TASK_GENERATION_FINISHED: { + LOGGER.info("Task generator finish: {}", sessionId); expManager.taskGenFinished(sessionId); break; } @@ -536,6 +543,10 @@ private String createContainer(StartCommandData data) { pullImage = true; } + + //TODO here it is not container ID , it is container name + // search for this tag to find tha patch #klhadKA5468WDJnlawd + // in corerct version if possible every method should return pod name and convert String containerId = containerManager.startContainer(data.image, data.type, parentId, data.environmentVariables, data.networkAliases, null, pullImage, null); if (containerId == null) { @@ -551,6 +562,7 @@ private String createContainer(StartCommandData data) { * @param containerName name of the container that should be stopped */ public void stopContainer(String containerName) { + LOGGER.info("Stopping container with name: {}", containerName); String containerId = containerManager.getContainerPodId(containerName); if (containerId != null) { containerManager.removeContainer(containerId); diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java index 85b96b39..b1ac6420 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java @@ -180,6 +180,14 @@ public String startContainer(String imageName, String containerType, String pare String[] netAliases, String[] command, String experimentId, Map constraints); + /** + * + * @param containerIdentifier podname or container id + * @param toOutsideOfTheCluster if yes means outside the cluster should reachable + * @param ports map of all ports + * @return service name + */ + public String startService(String containerIdentifier, boolean toOutsideOfTheCluster, Map ports); /** * Stops the container with the given container Id. diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java index 5622788a..35fb06f0 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java @@ -131,11 +131,13 @@ protected void readFile(File f, List newBenchmarks, List getUncheckedBenchmarks() { + LOGGER.info("getUncheckedBenchmarks from File size {}", benchmarks.size()); return new ArrayList<>(benchmarks); } @Override protected List getUncheckedSystems() { + LOGGER.info("getUncheckedSystems from File size {}", systems.size()); return new ArrayList<>(systems); } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/GitlabBasedImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/GitlabBasedImageManager.java index 4cf6da48..848b7839 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/GitlabBasedImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/GitlabBasedImageManager.java @@ -27,6 +27,8 @@ import org.hobbit.controller.gitlab.Project; import org.hobbit.core.data.BenchmarkMetaData; import org.hobbit.core.data.SystemMetaData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * An {@link ImageManager} implementation relying on the usage of a @@ -37,6 +39,7 @@ */ public class GitlabBasedImageManager extends AbstactImageManager implements ImageManager { + private static final Logger LOGGER = LoggerFactory.getLogger(GitlabBasedImageManager.class); // gitlab access controller private GitlabControllerImpl gitlab; @@ -51,16 +54,28 @@ public void runWhenGitlabIsReady(Runnable r) { @Override protected List getUncheckedBenchmarks() { - return gitlab.getAllProjects().parallelStream().filter(p -> p.benchmarkModel != null) - .flatMap(p -> MetaDataFactory.modelToBenchmarkMetaData(p.benchmarkModel, p.name, p.createdAt).stream()) - .collect(Collectors.toList()); + LOGGER.info("Getting unchecked systems for benchmarks"); + List benchmarks = gitlab.getAllProjects().parallelStream().filter(p -> p.benchmarkModel != null) + .flatMap(p -> MetaDataFactory.modelToBenchmarkMetaData(p.benchmarkModel, p.name, p.createdAt).stream()) + .collect(Collectors.toList()); + LOGGER.info("Unchecked systems for benchmarks fetched size :{}", benchmarks.size()); +// for(BenchmarkMetaData benchmark : benchmarks) { +// LOGGER.info("Fetching benchmark {}:{}", benchmark.name,benchmark.uri); +// } + return benchmarks; } @Override protected List getUncheckedSystems() { - return gitlab.getAllProjects().parallelStream().filter(p -> p.systemModel != null) + LOGGER.info("Getting systems for benchmarks"); + List systems = gitlab.getAllProjects().parallelStream().filter(p -> p.systemModel != null) .flatMap(p -> MetaDataFactory.modelToSystemMetaData(p.systemModel, p.name, p.createdAt).stream()) .collect(Collectors.toList()); + LOGGER.info("Unchecked systems for benchmarks fetched size :{}", systems.size()); +// for(SystemMetaData system : systems) { +// LOGGER.info("Fetching system {} : {}", system.name,system.uri); +// } + return systems; } @Override diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java index 419fcc2c..9ac31d50 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java @@ -621,6 +621,11 @@ public String startContainer(String imageName, String containerType, String pare return startContainer(imageName, containerType, parentId, env, netAliases, command, true, constraints); } + @Override + public String startService(String containerIdentifier, boolean toOutsideOfTheCluster, Map ports) { + return containerIdentifier; + } + @Override public void removeContainer(String serviceName) { try { diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java index 5bfd6f09..a9d32868 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java @@ -1,5 +1,6 @@ package org.hobbit.controller.containers.kubernetes; +import io.kubernetes.client.custom.IntOrString; import org.hobbit.controller.containers.ContainerManager; import org.hobbit.controller.containers.ContainerPodException; import org.hobbit.controller.containers.ContainerStateObserver; @@ -19,9 +20,13 @@ import io.kubernetes.client.openapi.models.*; import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class ContainerManagerImpl implements ContainerManager { @@ -43,7 +48,7 @@ public class ContainerManagerImpl implements ContainerManager { private static final String DEPLOY_ENV = System.getenv().containsKey(DEPLOY_ENV_KEY) ? System.getenv().get(DEPLOY_ENV_KEY) : "production"; - + private static final long TIMEOUT_SECONDS = 60; // Adjust the timeout as needed private static final int MAX_POD_NAME_LENGTH = 63; private static final Pattern VALID_POD_NAME_REGEX = Pattern.compile("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"); @@ -215,6 +220,117 @@ public String startContainer(String imageName, String containerType, String pare return createContainerKub(imageName, podName, containerType, parentId, env, command, constraints); } + private boolean isPodRunning(String namespace, String podName) { + try { + GenericKubernetesApi podClient = + new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); + + V1Pod pod = podClient.get(namespace, podName).throwsApiException().getObject(); + if (pod != null && pod.getStatus() != null && "Running".equals(pod.getStatus().getPhase())) { + return true; + } + } catch (ApiException e) { + LOGGER.error("Error checking pod status in namespace {}: {}", namespace, podName, e); + } + return false; + } + + private boolean waitForPodToBeRunning(String namespace, String podName) { + final int maxAttempts = 10; + final int sleepMillis = 5000; + + LOGGER.info("Waiting for pod '{}' in namespace '{}' to reach 'Running' state (max {} attempts).", podName, namespace, maxAttempts); + + for (int attempt = 1; attempt <= maxAttempts; attempt++) { + if (isPodRunning(namespace, podName)) { + LOGGER.info("Pod '{}' is now running in namespace '{}' after {} attempts.", podName, namespace, attempt); + return true; + } + + LOGGER.warn("Attempt {}/{}: Pod '{}' is not running yet. Retrying in {} seconds...", attempt, maxAttempts, podName, sleepMillis / 1000); + + try { + Thread.sleep(sleepMillis); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.error("Thread interrupted while waiting for pod '{}' in namespace '{}'. Aborting wait.", podName, namespace, e); + return false; + } + } + + LOGGER.error("Pod '{}' in namespace '{}' did not reach 'Running' state after {} attempts.", podName, namespace, maxAttempts); + return false; + } + + + @Override + public String startService(String containerIdentifier, boolean toOutsideOfTheCluster, Map ports) { + LOGGER.info("Starting service for pod: {}", containerIdentifier); + + // Wait for pod to be in running state with a timeout + if (!waitForPodToBeRunning(nameSpace, containerIdentifier)) { + LOGGER.error("Pod {} did not reach running state within timeout. Cannot start service.", containerIdentifier); + return null; + } + + LOGGER.info("Pod {} is running. Proceeding to create service.", containerIdentifier); + + // Generate a unique service name + String serviceName = "service-"+containerIdentifier; + if (serviceName.length() > MAX_POD_NAME_LENGTH) { + serviceName = serviceName.substring(0, MAX_POD_NAME_LENGTH); + } + + // Define the service spec + V1ServiceSpec serviceSpec = new V1ServiceSpec() + .selector(Collections.singletonMap("app", containerIdentifier)) + .ports(ports.entrySet().stream() + .map(entry -> new V1ServicePort() + .name("port-" + entry.getKey()) + .protocol("TCP") + .port(entry.getKey()) + .targetPort(new IntOrString(entry.getValue())) + ).collect(Collectors.toList())) + .type("ClusterIP"); + + + if (toOutsideOfTheCluster) { + LOGGER.info("Exposing service {} outside of the cluster.", serviceName); + serviceSpec.setType("NodePort"); + } else { + LOGGER.info("Creating a ClusterIP service {}.", serviceName); + serviceSpec.setType("ClusterIP"); + } + + // Define the metadata + V1ObjectMeta metadata = new V1ObjectMeta() + .name(serviceName) + .namespace("default") // Adjust as needed + .labels(Collections.singletonMap("app", containerIdentifier)); + + // Build the service object + V1Service service = new V1Service() + .metadata(metadata) + .spec(serviceSpec); + + LOGGER.info("Constructed service object for {}.", serviceName); + + // Deploy the service + try { + GenericKubernetesApi serviceClient = + new GenericKubernetesApi<>(V1Service.class, V1ServiceList.class, "", "v1", "services", client); + + LOGGER.info("Sending request to create service: {}", serviceName); + + V1Service createdService = serviceClient.create(service).throwsApiException().getObject(); + LOGGER.info("Successfully created service: {}", createdService.getMetadata().getName()); + return createdService.getMetadata().getName(); + } catch (ApiException e) { + LOGGER.error("Failed to create service for pod: {}. Returning null.", containerIdentifier, e); + return null; + } + } + /** * Creates environment variables from the provided list of key-value pairs. */ @@ -259,11 +375,45 @@ protected ApiClient initiateClient() throws IOException { } } + public static String getPodName() { + String podName = System.getenv("HOSTNAME"); + if (podName == null || podName.isEmpty()) { + try { + podName = InetAddress.getLocalHost().getHostName(); // Fallback methoD + } catch (UnknownHostException e) { + podName = "Unknown-Pod"; + } + } + return podName; + } + + private String createContainerKub(String imageName, String podName, String containerType, String parentPodName, String[] env, String[] command, Map constraints) { LOGGER.info("Creating container: Image = {}, Pod Name = {}, Container Type = {}, Parent ID = {}", imageName, podName, containerType, parentPodName); + + + LOGGER.info("add environment variable HIBBIT DOCKER NAME"); + String thisPodName = Constants.CONTAINER_NAME_KEY + "=" +getPodName(); + + LOGGER.info("pod name is {}", thisPodName); + + if (env == null || env.length == 0) { + env= new String[]{thisPodName}; + }else { + String[] updatedEnv = Arrays.copyOf(env, env.length + 1); + updatedEnv[env.length] = thisPodName; + env = updatedEnv; + } + LOGGER.info("add environment variable HIBBIT ENV now it has {} environment variables.", env.length); + + for (String item : env) { + LOGGER.info(item); + } + + // Prepare environment variable List environmentVariables = new ArrayList<>(); if (env != null) { @@ -284,6 +434,23 @@ private String createContainerKub(String imageName, String podName, String conta LOGGER.warn("No environment variables provided."); } + LOGGER.info("Adding secret-based environment variable: GITLAB_TOKEN from gitlab-secret"); +// V1EnvVar gitlabTokenEnvVar = new V1EnvVar() +// .name("GITLAB_TOKEN") +// .valueFrom(new V1EnvVarSource() +// .secretKeyRef(new V1SecretKeySelector() +// .name("gitlab-secret") +// .key("GITLAB_TOKEN"))); + + //environmentVariables.add(gitlabTokenEnvVar); + environmentVariables.add(new V1EnvVar().name("GITLAB_USER").value("gitadmin")); + environmentVariables.add(new V1EnvVar().name("GITLAB_EMAIL").value("gitadmin@project-hobbit.eu")); + + for(V1EnvVar envVar : environmentVariables) { + LOGGER.info("Adding environment variable: {} = {}", envVar.getName(), envVar.getValue()); + } + + LOGGER.info("Determining container type for parent pod: {}", parentPodName); String parentType = null; if(parentPodName != null) { @@ -328,11 +495,17 @@ private String createContainerKub(String imageName, String podName, String conta // container.setVolumeMounts(Collections.singletonList(volumeMount)); + // Create the pod specification LOGGER.info("Creating pod specification for container: {}", podName); V1PodSpec podSpec = new V1PodSpec() .restartPolicy("Never") - .containers(Collections.singletonList(container)); + .addContainersItem(container) + .addImagePullSecretsItem( + new V1LocalObjectReference() + .name("gitlab-registry-secret") + //todo make this const + ); //.volumes(Collections.singletonList(volume)); LOGGER.info("Determining node selector based on container type: {} and parent type: {}", containerType, parentType); @@ -373,6 +546,7 @@ private String createContainerKub(String imageName, String podName, String conta Map labels = new HashMap<>(); labels.put(LABEL_TYPE, containerType); labels.put(LABEL_PARENT, parentPodName); + labels.put("app",podName); LOGGER.info("Labels set - Type: {}, Parent: {}", containerType, parentPodName); @@ -397,6 +571,8 @@ private String createContainerKub(String imageName, String podName, String conta GenericKubernetesApi podClient = new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); + + LOGGER.info("Sending request to create pod with name: {}", podName); V1Pod createdPod = podClient.create(pod).throwsApiException().getObject(); @@ -411,7 +587,56 @@ private String createContainerKub(String imageName, String podName, String conta } } - return createdPodName; + + if (createdPodName != null) { + LOGGER.info("Successfully created pod with name: {}", createdPodName); + + // Wait for the IP address to become available + long startTime = System.currentTimeMillis(); + V1PodList podList = podClient.list(nameSpace).getObject(); + while (System.currentTimeMillis() - startTime < TimeUnit.SECONDS.toMillis(TIMEOUT_SECONDS)) { + try { + LOGGER.info("Waiting for pod {} to start", createdPodName); + V1Pod targetPod = podList.getItems().stream() + .filter(podTocheck -> createdPodName.equals(pod.getMetadata().getName())) + .findFirst() + .orElse(null); + //todo remove this + if (targetPod == null) { + LOGGER.error("No pod found with name: {}", createdPod); + } + + LOGGER.info("Target pod found: {}", targetPod.getMetadata().getName()); + + String podPhase = targetPod.getStatus().getPhase(); + if ("Running".equals(podPhase)) { + String podIP = targetPod.getStatus().getPodIP(); + LOGGER.info("Pod IP: {}", podIP); + if (podIP != null && !podIP.isEmpty()) { + LOGGER.info("Obtained Pod IP: {}", podIP); + String convertedIP = podIP.replace(".", "-") + ".default.pod.cluster.local"; + LOGGER.info("Converted IP: {}", convertedIP); + return convertedIP; + } + } + LOGGER.info("pod phase is {}", podPhase); + podList = podClient.list(nameSpace).getObject(); + }catch (Exception ex){ + LOGGER.error(ex.getMessage()); + } + try { + Thread.sleep(2000); // Wait for 1 second before checking again + } catch (InterruptedException e) { + LOGGER.error("Thread interrupted while waiting for pod IP: " + e.getMessage()); + } + } + + LOGGER.warn("Timeout reached. Pod {} IP is still not available.", createdPodName); + } else { + LOGGER.error("Failed to create the pod."); + } + + return null; // Return null if the IP address is not available within the timeout } catch (ApiException e) { LOGGER.error("Failed to create pod for image: {}. Returning null.", imageName, e); return null; @@ -419,8 +644,27 @@ private String createContainerKub(String imageName, String podName, String conta } + private String mapIp2Name(String ip) { + String podIp = ip.replace("-",".").replace(".default.pod.cluster.local", ""); + LOGGER.info("Mapped IP: {}", podIp); + + GenericKubernetesApi podClient = + new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); + + V1PodList podList = podClient.list(nameSpace).getObject(); + V1Pod targetPod = podList.getItems().stream() + .filter(podTocheck -> podIp.equals(podTocheck.getStatus().getPodIP())) + .findFirst() + .orElse(null); + return targetPod.getMetadata().getName(); + } + + + private V1Pod getPod(String podIP) { + LOGGER.info("getPod"); + + String podName = mapIp2Name(podIP); - private V1Pod getPod(String podName) { LOGGER.info("Attempting to retrieve pod: {} in namespace: {}", podName, this.nameSpace); CoreV1Api coreV1Api = new CoreV1Api(client); @@ -431,7 +675,7 @@ private V1Pod getPod(String podName) { LOGGER.info("Successfully retrieved pod: {} in namespace: {}", podName, this.nameSpace); return pod; } catch (ApiException exc) { - LOGGER.error("Failed to get pod: {} in namespace: {}. Error: {}", podName, this.nameSpace, exc.getMessage(), exc); + LOGGER.error("Failed to get pod: {} in namespace: {}", podName, this.nameSpace); return null; } } @@ -488,6 +732,7 @@ public void stopContainer(String containerId) { @Override public void removeContainer(String podName) { + //String podName = mapIp2Name(podIp); try { Long exitCode = getContainerPodExitCode(podName); @@ -614,6 +859,8 @@ public List getContainers(ContainerCriteria criteria) { @Override public String getContainerPodId(String podName) { + LOGGER.info("getContainerPodId({})", podName); +// String podName = mapIp2Name(podIp); try { // Fetch the pod information using its name and namespace CoreV1Api api = new CoreV1Api(client); @@ -644,6 +891,16 @@ public String getContainerPodName(String podId) { // If no matching pod is found, return null LOGGER.warn("No Pod found with ID: {} in namespace: {}", podId, nameSpace); + LOGGER.warn("check if the input was the name of the pod"); + // todo this code should remove search for this to find the source of the error which head to this patch #klhadKA5468WDJnlawd + for (V1Pod pod : podList.getItems()) { + if (pod.getMetadata().getName().equals(podId)) { + // Return the Pod's name + LOGGER.warn("it is a pod name {}", pod.getMetadata().getName()); + return pod.getMetadata().getName(); + } + } + LOGGER.warn("nothing found return NULL !"); return null; } catch (Exception e) { LOGGER.error("Failed to fetch Pod name for Pod ID: {} in namespace: {}. Error: {}", podId, nameSpace, e); diff --git a/platform-controller/src/main/java/org/hobbit/controller/data/NodeHardwareInformation.java b/platform-controller/src/main/java/org/hobbit/controller/data/NodeHardwareInformation.java index 83ac5834..654a68d9 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/data/NodeHardwareInformation.java +++ b/platform-controller/src/main/java/org/hobbit/controller/data/NodeHardwareInformation.java @@ -32,6 +32,8 @@ import org.hobbit.utils.rdf.TripleHashCalculator; import org.hobbit.vocab.HobbitHardware; import org.hobbit.vocab.MEXCORE; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * This class is used to store information about hardware the experiment runs @@ -42,6 +44,9 @@ */ public class NodeHardwareInformation { + + private static final Logger LOGGER = LoggerFactory.getLogger(NodeHardwareInformation.class); + /** * Formatted hardware information. */ @@ -137,11 +142,34 @@ public Resource addToModel(Model model) { } private StmtIterator distinguishingProperties(Model model, Resource self) { + + // Check for nulls and provide default values + String instanceValue = (instance == null) ? "default-instance" : instance; + if (instance == null) { + LOGGER.warn("instance is null, using default value: {}", instanceValue); + } + + String cpuValue = (cpu == null) ? "default-cpu" : cpu; + if (cpu == null) { + LOGGER.warn("cpu is null, using default value: {}", cpuValue); + } + + String memoryValue = (memory == null) ? "default-memory" : memory; + if (memory == null) { + LOGGER.warn("memory is null, using default value: {}", memoryValue); + } + + String osValue = (os == null) ? "default-os" : os; + if (os == null) { + LOGGER.warn("os is null, using default value: {}", osValue); + } + + return new StmtIteratorImpl( - Stream.of((Statement) new StatementImpl(self, RDFS.label, model.createLiteral(instance)), - (Statement) new StatementImpl(self, MEXCORE.cpu, model.createLiteral(cpu)), - (Statement) new StatementImpl(self, MEXCORE.memory, model.createLiteral(memory)), - (Statement) new StatementImpl(self, DOAP.os, model.createLiteral(os))).iterator()); + Stream.of((Statement) new StatementImpl(self, RDFS.label, model.createLiteral(instanceValue)), + (Statement) new StatementImpl(self, MEXCORE.cpu, model.createLiteral(cpuValue)), + (Statement) new StatementImpl(self, MEXCORE.memory, model.createLiteral(memoryValue)), + (Statement) new StatementImpl(self, DOAP.os, model.createLiteral(osValue))).iterator()); } @Override From ea8e80ca4e67fba1d1118a6130e8612fb86cf400 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 17 Mar 2025 15:23:02 +0100 Subject: [PATCH 16/52] change yaml files --- .../04-virtuoso-deployment.yaml | 12 ++-- .../05-virtuoso-service.yaml | 3 +- .../06-storage-deployment.yaml | 45 +++++++------ kubernetes-yaml-files/09-01-redis-pv.yaml | 2 +- .../10-redis-deployment.yaml | 2 +- kubernetes-yaml-files/100-debug.yaml | 10 +++ .../13-controller-deployment.yaml | 11 +++- kubernetes-yaml-files/17-cluster-role.yaml | 3 +- kubernetes-yaml-files/18-ui-deployment.yaml | 36 ++++++++++ kubernetes-yaml-files/19-keycloak.yaml | 20 +++--- kubernetes-yaml-files/19-ui-service.yaml | 13 ++++ kubernetes-yaml-files/93-configmap.yaml | 26 ++++++++ kubernetes-yaml-files/94-riak-pv.yaml | 14 ++++ kubernetes-yaml-files/95-riak-pvc.yaml | 11 ++++ kubernetes-yaml-files/96-riaklatest.yaml | 48 ++++++++++++++ kubernetes-yaml-files/97-riaktest.yaml | 17 +++++ .../98-pod-sytem-benchmark-test.yaml | 66 +++++++++++++++++++ kubernetes-yaml-files/99-test-job.yaml | 66 +++++++++---------- .../KubExtendedContainerManager.java | 4 ++ 19 files changed, 331 insertions(+), 78 deletions(-) create mode 100644 kubernetes-yaml-files/100-debug.yaml create mode 100644 kubernetes-yaml-files/18-ui-deployment.yaml create mode 100644 kubernetes-yaml-files/19-ui-service.yaml create mode 100644 kubernetes-yaml-files/93-configmap.yaml create mode 100644 kubernetes-yaml-files/94-riak-pv.yaml create mode 100644 kubernetes-yaml-files/95-riak-pvc.yaml create mode 100644 kubernetes-yaml-files/96-riaklatest.yaml create mode 100644 kubernetes-yaml-files/97-riaktest.yaml create mode 100644 kubernetes-yaml-files/98-pod-sytem-benchmark-test.yaml create mode 100644 platform-controller/src/main/java/org/hobbit/controller/containers/KubExtendedContainerManager.java diff --git a/kubernetes-yaml-files/04-virtuoso-deployment.yaml b/kubernetes-yaml-files/04-virtuoso-deployment.yaml index 1450d3b9..8ea2f1c4 100644 --- a/kubernetes-yaml-files/04-virtuoso-deployment.yaml +++ b/kubernetes-yaml-files/04-virtuoso-deployment.yaml @@ -14,14 +14,14 @@ spec: labels: app: virtuoso spec: - securityContext: - fsGroup: 1000 + securityContext: # This is the correct place for fsGroup + fsGroup: 1000 containers: - name: virtuoso - image: openlink/virtuoso-opensource-7:latest + image: hobbitproject/virtuoso_opensource:v07.20.3217 securityContext: - runAsUser: 79184 # Replace with the actual numeric user ID - runAsGroup: 10000 + runAsUser: 79184 # Replace with the actual numeric user ID + runAsGroup: 10000 ports: - containerPort: 8890 # HTTP (SPARQL endpoint) - containerPort: 1111 # ISQL (command-line interface) @@ -33,7 +33,7 @@ spec: - name: VIRTUOSO_PASSWORD value: "dba" volumeMounts: - - mountPath: /data + - mountPath: /opt/virtuoso-opensource/database name: virtuoso-storage volumes: - name: virtuoso-storage diff --git a/kubernetes-yaml-files/05-virtuoso-service.yaml b/kubernetes-yaml-files/05-virtuoso-service.yaml index 1d27c400..e3571686 100644 --- a/kubernetes-yaml-files/05-virtuoso-service.yaml +++ b/kubernetes-yaml-files/05-virtuoso-service.yaml @@ -12,8 +12,9 @@ spec: port: 8890 targetPort: 8890 name: sparql + nodePort: 31001 - protocol: TCP port: 1111 targetPort: 1111 name: isql - type: LoadBalancer + type: NodePort diff --git a/kubernetes-yaml-files/06-storage-deployment.yaml b/kubernetes-yaml-files/06-storage-deployment.yaml index 0bc412ff..7270bcbc 100644 --- a/kubernetes-yaml-files/06-storage-deployment.yaml +++ b/kubernetes-yaml-files/06-storage-deployment.yaml @@ -15,41 +15,44 @@ spec: app: hobbit-storage-service spec: securityContext: - fsGroup: 1000 + fsGroup: 1000 containers: - name: storage-service - image: hub.cs.upb.de/dice-research/images/hobbit-storage_service:dev0.0.1 + #image: hub.cs.upb.de/dice-research/images/hobbit-storage_service:dev0.0.5 + image: hobbitproject/hobbit-storage-service:latest imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 +# ports: +# - containerPort: 8080 env: - name: JAVA_OPTS value: "-Xmx256m -Xms128m" - name: HOBBIT_RABBIT_HOST value: rabbitmq # The name of the RabbitMQ service (02-rabbitmq-service.yaml) - name: SPARQL_ENDPOINT_URL - value: virtuoso-service + value: "http://virtuoso-service:8890/sparql" - name: SPARQL_ENDPOINT_USERNAME - value: "dba" + value: "HobbitPlatform" - name: SPARQL_ENDPOINT_PASSWORD - value: "dba" - - name: SPARQL_ENDPOINT_DATABASE - value: "virtuoso" + value: "Password" + #- name: SPARQL_ENDPOINT_DATABASE + #value: "http://virtuoso-service:8890/sparql" + - name: hobbit.storage + value: rabbitmq volumeMounts: - mountPath: /path/to/mount name: storage-volume - livenessProbe: - httpGet: - path: /actuator/health - port: 8080 - initialDelaySeconds: 30 - periodSeconds: 10 - readinessProbe: - httpGet: - path: /actuator/health - port: 8080 - initialDelaySeconds: 30 - periodSeconds: 10 + # livenessProbe: + # httpGet: + # path: /actuator/health + # port: 8080 + # initialDelaySeconds: 30 + # periodSeconds: 10 + # readinessProbe: + # httpGet: + # path: /actuator/health + # port: 8080 + # initialDelaySeconds: 30 + # periodSeconds: 10 volumes: - name: storage-volume persistentVolumeClaim: diff --git a/kubernetes-yaml-files/09-01-redis-pv.yaml b/kubernetes-yaml-files/09-01-redis-pv.yaml index 09e2e403..7c4b751b 100644 --- a/kubernetes-yaml-files/09-01-redis-pv.yaml +++ b/kubernetes-yaml-files/09-01-redis-pv.yaml @@ -7,7 +7,7 @@ spec: storage: 1Gi accessModes: - ReadWriteOnce - persistentVolumeReclaimPolicy: Retain # Or Delete, as needed + persistentVolumeReclaimPolicy: Delete storageClassName: "" # Important: Leave empty if not using Storage Classes nfs: server: 131.234.29.64 diff --git a/kubernetes-yaml-files/10-redis-deployment.yaml b/kubernetes-yaml-files/10-redis-deployment.yaml index b544345a..fef02142 100644 --- a/kubernetes-yaml-files/10-redis-deployment.yaml +++ b/kubernetes-yaml-files/10-redis-deployment.yaml @@ -16,7 +16,7 @@ spec: spec: securityContext: fsGroup: 1000 - runAsUser: 79184 #because it need to run chown if user is different + runAsUser: 79184 containers: - name: redis image: redis:6.2.6 diff --git a/kubernetes-yaml-files/100-debug.yaml b/kubernetes-yaml-files/100-debug.yaml new file mode 100644 index 00000000..02dc2b65 --- /dev/null +++ b/kubernetes-yaml-files/100-debug.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: debug-pod +spec: + containers: + - name: debug-tools + image: nicolaka/netshoot + command: ["sh", "-c", "while true; do sleep 3600; done"] + diff --git a/kubernetes-yaml-files/13-controller-deployment.yaml b/kubernetes-yaml-files/13-controller-deployment.yaml index 4f8d1db7..d8ec1362 100644 --- a/kubernetes-yaml-files/13-controller-deployment.yaml +++ b/kubernetes-yaml-files/13-controller-deployment.yaml @@ -19,8 +19,11 @@ spec: fsGroup: 1000 containers: - name: controller - image: hub.cs.upb.de/dice-research/images/hobbit-platform_controller:dev0.0.9 + image: hub.cs.upb.de/dice-research/images/hobbit-platform_controller:dev0.0.83 imagePullPolicy: IfNotPresent + securityContext: + allowPrivilegeEscalation: false + runAsUser: 0 ports: - containerPort: 8080 env: @@ -28,12 +31,14 @@ spec: value: rabbitmq # The name of the RabbitMQ service (02-rabbitmq-service.yaml) - name: SPARQL_ENDPOINT_URL value: virtuoso + - name: HOBBIT_RABBIT_IMAGE + value: "rabbitmq:management" - name: SPARQL_ENDPOINT_USERNAME value: "dba" - name: SPARQL_ENDPOINT_PASSWORD value: "dba" - name: SPARQL_ENDPOINT_DATABASE - value: "virtuoso" + value: "virtuoso:8890" - name: HOBBIT_REDIS_HOST value: "redis-service" - name: GITLAB_TOKEN @@ -49,6 +54,8 @@ spec: value: "develop" - name: MAX_EXECUTION_TIME value: "1200000" + - name: CONTAINER_PARENT_CHECK + value: "0" volumeMounts: - mountPath: /data name: controller-storage # Only if you are using a PVC diff --git a/kubernetes-yaml-files/17-cluster-role.yaml b/kubernetes-yaml-files/17-cluster-role.yaml index 0058fa41..9ae872c7 100644 --- a/kubernetes-yaml-files/17-cluster-role.yaml +++ b/kubernetes-yaml-files/17-cluster-role.yaml @@ -5,7 +5,7 @@ metadata: rules: - apiGroups: [""] resources: ["nodes" , "pods", "services", "namespaces"] - verbs: ["create", "get", "update", "delete", "list", "watch"] + verbs: ["create", "get", "update", "delete", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 @@ -20,3 +20,4 @@ roleRef: kind: ClusterRole name: node-reader apiGroup: rbac.authorization.k8s.io + diff --git a/kubernetes-yaml-files/18-ui-deployment.yaml b/kubernetes-yaml-files/18-ui-deployment.yaml new file mode 100644 index 00000000..4e8093dc --- /dev/null +++ b/kubernetes-yaml-files/18-ui-deployment.yaml @@ -0,0 +1,36 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hobbit-gui + labels: + app: hobbit-gui +spec: + replicas: 1 + selector: + matchLabels: + app: hobbit-gui + template: + metadata: + labels: + app: hobbit-gui + spec: + containers: + - name: hobbit-gui + image: hobbitproject/hobbit-gui:latest + ports: + - containerPort: 8080 + env: + - name: HOBBIT_RABBIT_HOST + value: "rabbitmq" + - name: KEYCLOAK_AUTH_URL + value: "http://localhost:8181/auth" + - name: CHECK_REALM_URL + value: "false" + - name: KEYCLOAK_DIRECT_URL + value: "http://keycloak:8080/auth" + - name: ELASTICSEARCH_HOST + value: "elasticsearch" + - name: ELASTICSEARCH_HTTP_PORT + value: "9200" + - name: USE_UI_AUTH + value: "false" diff --git a/kubernetes-yaml-files/19-keycloak.yaml b/kubernetes-yaml-files/19-keycloak.yaml index 4f50d7a9..5e6cce4d 100644 --- a/kubernetes-yaml-files/19-keycloak.yaml +++ b/kubernetes-yaml-files/19-keycloak.yaml @@ -1,14 +1,14 @@ apiVersion: v1 kind: Service metadata: - name: hobbit-keycloak - labels: - app: hobbit-keycloak + name: hobbit-keycloak + labels: + app: hobbit-keycloak spec: - ports: - - port: 8080 - targetPort: 8080 - nodePort: 31000 - selector: - app: hobbit-keycloak - type: NodePort + ports: + - port: 8080 + targetPort: 8080 + nodePort: 31000 + selector: + app: hobbit-keycloak + type: NodePort diff --git a/kubernetes-yaml-files/19-ui-service.yaml b/kubernetes-yaml-files/19-ui-service.yaml new file mode 100644 index 00000000..e4e025c9 --- /dev/null +++ b/kubernetes-yaml-files/19-ui-service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: hobbit-gui +spec: + selector: + app: hobbit-gui + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 + nodePort: 31000 + type: NodePort diff --git a/kubernetes-yaml-files/93-configmap.yaml b/kubernetes-yaml-files/93-configmap.yaml new file mode 100644 index 00000000..80840f7e --- /dev/null +++ b/kubernetes-yaml-files/93-configmap.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: riak-config +data: + 00-autoconfig.sh: | + #!/bin/bash + CONFIG=/etc/riak/riak.conf + if [ -z "$RIAK_NODE_NAME" ]; then + RIAK_NODE_NAME=riak + fi + if [ -z "$RIAK_DISTRIBUTED_COOKIE" ]; then + RIAK_DISTRIBUTED_COOKIE=riak + fi + LOCAL_HOSTNAME_FQDN=$(hostname -f) + LOCAL_HOSTNAME_IP=$(hostname -I | awk '{ print $1; }') + if echo "$LOCAL_HOSTNAME_FQDN" | grep -iq '\.'; then + RIAK_NODE_HOSTNAME="$LOCAL_HOSTNAME_FQDN" + else + RIAK_NODE_HOSTNAME="$LOCAL_HOSTNAME_IP" + fi + echo "# Autogenerated configuration from '/etc/riak/prestart.d/00-autoconfig.sh' via '$0'" >> $CONFIG + echo "nodename = $RIAK_NODE_NAME@$RIAK_NODE_HOSTNAME" >> $CONFIG + echo "distributed_cookie = $RIAK_DISTRIBUTED_COOKIE" >> $CONFIG + echo "listener.protobuf.internal = 0.0.0.0:8087" >> $CONFIG + echo "listener.http.internal = 0.0.0.0:8098" >> $CONFIG diff --git a/kubernetes-yaml-files/94-riak-pv.yaml b/kubernetes-yaml-files/94-riak-pv.yaml new file mode 100644 index 00000000..85f5b577 --- /dev/null +++ b/kubernetes-yaml-files/94-riak-pv.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: riaktest-pv +spec: + capacity: + storage: 2Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Delete #, depending on your needs + storageClassName: "" # Important: Leave this empty if not using Storage Classes + nfs: + server: 131.234.29.64 + path: /data/nfs/kubedata/riaktest diff --git a/kubernetes-yaml-files/95-riak-pvc.yaml b/kubernetes-yaml-files/95-riak-pvc.yaml new file mode 100644 index 00000000..a36d21e2 --- /dev/null +++ b/kubernetes-yaml-files/95-riak-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: riak-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + diff --git a/kubernetes-yaml-files/96-riaklatest.yaml b/kubernetes-yaml-files/96-riaklatest.yaml new file mode 100644 index 00000000..2cb2bd9b --- /dev/null +++ b/kubernetes-yaml-files/96-riaklatest.yaml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: riak-deployment +spec: + replicas: 1 + selector: + matchLabels: + app: riak + template: + metadata: + labels: + app: riak + spec: + initContainers: + - name: riak-init + image: bash:latest + command: ["/bin/bash", "-c", "/scripts/00-autoconfig.sh"] + volumeMounts: + - name: script-volume + mountPath: /scripts + - name: riak-config + mountPath: /etc/riak/riak.conf + subPath: riak.conf + containers: + - name: riak + image: stojan/riak-kv + ports: + - containerPort: 8087 + env: + - name: RICK_START_ARGS + value: "--enable-search --enable-crypto" + volumeMounts: + - name: riak-data + mountPath: /var/lib/riak + - name: riak-config + mountPath: /etc/riak/riak.conf + subPath: riak.conf + volumes: + - name: riak-data + persistentVolumeClaim: + claimName: riak-pvc + - name: script-volume + configMap: + name: riak-config + defaultMode: 0755 + - name: riak-config + emptyDir: {} diff --git a/kubernetes-yaml-files/97-riaktest.yaml b/kubernetes-yaml-files/97-riaktest.yaml new file mode 100644 index 00000000..6c8221eb --- /dev/null +++ b/kubernetes-yaml-files/97-riaktest.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + name: riak-debug-pod +spec: + securityContext: + runAsUser: 0 + fsGroup: 0 + containers: + - name: debug-container + image: git.project-hobbit.eu:4567/gitadmin/basho-riak-kv:1.0.1 + stdin: true + tty: true + securityContext: + allowPrivilegeEscalation: true + runAsUser: 0 + runAsGroup: 0 diff --git a/kubernetes-yaml-files/98-pod-sytem-benchmark-test.yaml b/kubernetes-yaml-files/98-pod-sytem-benchmark-test.yaml new file mode 100644 index 00000000..8df24743 --- /dev/null +++ b/kubernetes-yaml-files/98-pod-sytem-benchmark-test.yaml @@ -0,0 +1,66 @@ +apiVersion: v1 +kind: Pod +metadata: + name: hobbit-pod-system-benchmark-test +spec: + imagePullSecrets: + - name: gitlab-registry + containers: + - name: hobbit-container-test + image: git.project-hobbit.eu:4567/gitadmin/platform-benchmark + env: + - name: HOBBIT_RABBIT_HOST + value: "service-1740670758851-sep-benchmark-328399376" + - name: HOBBIT_SESSION_ID + value: "1740670758851" + - name: HOBBIT_EXPERIMENT_URI + value: "http://w3id.org/hobbit/experiments#1740670758851" + - name: BENCHMARK_PARAMETERS_MODEL + value: | + { + "@id" : "http://w3id.org/hobbit/experiments#New", + "@type" : "hobbit:Experiment", + "hasExperimentType" : "gerbil:A2KB", + "hasNumberOfDocuments" : "200", + "involvesBenchmark" : "gerbil2:GerbilBenchmark", + "involvesSystem" : "ex:DummySystemInstance1", + "@context" : { + "involvesSystem" : { + "@id" : "http://w3id.org/hobbit/vocab#involvesSystem", + "@type" : "@id" + }, + "involvesBenchmark" : { + "@id" : "http://w3id.org/hobbit/vocab#involvesBenchmark", + "@type" : "@id" + }, + "hasExperimentType" : { + "@id" : "http://w3id.org/gerbil/hobbit/vocab#hasExperimentType", + "@type" : "@id" + }, + "hasNumberOfDocuments" : { + "@id" : "http://w3id.org/gerbil/hobbit/vocab#hasNumberOfDocuments", + "@type" : "http://www.w3.org/2001/XMLSchema#unsignedInt" + }, + "hobbit" : "http://w3id.org/hobbit/vocab#", + "ex" : "http://example.org/", + "rdf" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + "owl" : "http://www.w3.org/2002/07/owl#", + "gerbil" : "http://w3id.org/gerbil/vocab#", + "xsd" : "http://www.w3.org/2001/XMLSchema#", + "rdfs" : "http://www.w3.org/2000/01/rdf-schema#", + "gerbil2" : "http://w3id.org/gerbil/hobbit/vocab#" + } + } + - name: HOBBIT_SYSTEM_URI + value: "http://w3id.org/hobbit/platform-benchmark/vocab#PlatformBenchSystem_1" + - name: HOBBIT_CONTAINER_NAME + value: "controller-754749f957-lh4kq" + - name: GITLAB_USER + value: "gitadmin" + - name: GITLAB_EMAIL + value: "gitadmin@project-hobbit.eu" + - name: GITLAB_TOKEN + valueFrom: + secretKeyRef: + name: gitlab-secret + key: GITLAB_TOKEN diff --git a/kubernetes-yaml-files/99-test-job.yaml b/kubernetes-yaml-files/99-test-job.yaml index d2d46ac0..6de5d29d 100644 --- a/kubernetes-yaml-files/99-test-job.yaml +++ b/kubernetes-yaml-files/99-test-job.yaml @@ -1,37 +1,33 @@ -apiVersion: batch/v1 -kind: Job +apiVersion: v1 +kind: Pod metadata: - name: hobbit-benchmark + name: test-hobbit-pod + labels: + app: hobbit-app spec: - template: - spec: - securityContext: - fsGroup: 1000 - containers: - - name: hobbit-benchmark - image: maven - command: ["/bin/bash", "-c"] - args: - - | - java -cp target/platform-controller.jar org.hobbit.core.run.ComponentStarter org.hobbit.controller.test.StartBenchmarkRequest - env: - - name: HOBBIT_RABBIT_HOST - value: "rabbitmq" - - name: BENCHMARK - value: "http://example.org/GerbilBenchmark" - - name: SYSTEM - value: "http://example.org/DummySystemInstance1" - - name: BENCHMARK_PARAM_FILE - value: "src/test/resources/exampleExperiment.ttl" - - name: USERNAME - value: "testuser" - volumeMounts: - - name: app-volume - mountPath: /usr/src/app - restartPolicy: Never - volumes: - - name: app-volume - nfs: - server: 131.234.29.64 - path: /data/nfs/kubedata/test - readOnly: false + restartPolicy: Never + containers: + - name: hobbit-container + image: maven + command: ["sh", "-c"] + args: ["tail -f /dev/null"] # Keeps the container running indefinitely + env: + - name: HOBBIT_RABBIT_HOST + value: rabbitmq + - name: BENCHMARK + value: http://w3id.org/hobbit/platform-benchmark/vocab#PlatformBenchmark + - name: SYSTEM + value: http://w3id.org/hobbit/platform-benchmark/vocab#PlatformBenchSystem_1 + - name: BENCHMARK_PARAM_FILE + value: /usr/src/app/src/test/resources/org/hobbit/controller/exampleExperiment.ttl + - name: USERNAME + value: testuser + volumeMounts: + - mountPath: /usr/src/app + name: app-volume + volumes: + - name: app-volume + nfs: + server: 131.234.29.64 + path: /data/nfs/kubedata/test + readOnly: false diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/KubExtendedContainerManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/KubExtendedContainerManager.java new file mode 100644 index 00000000..4a823961 --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/KubExtendedContainerManager.java @@ -0,0 +1,4 @@ +package org.hobbit.controller.containers; + +public interface KubExtendedContainerManager { +} From 6a3c10576707d7ee4698bc082f849bf4d1dd4b13 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 17 Mar 2025 15:28:59 +0100 Subject: [PATCH 17/52] all changes until now , error with hostname in modules --- .../hobbit/controller/ExperimentManager.java | 5 +- .../hobbit/controller/PlatformController.java | 19 +- .../containers/ContainerManager.java | 17 +- .../containers/FileBasedImageManager.java | 4 +- .../KubExtendedContainerManager.java | 5 +- .../docker/ContainerManagerImpl.java | 8 +- .../kubernetes/ClusterManagerImpl.java | 4 +- .../kubernetes/ContainerManagerImpl.java | 679 +++++++++++------- .../ContainerStateObserverImpl.java | 77 +- .../mocks/DummyContainerManager.java | 8 +- platform-storage/storage-service/Dockerfile | 37 +- .../storage/service/StorageService.java | 66 +- test.yml | 13 + 13 files changed, 562 insertions(+), 380 deletions(-) create mode 100644 test.yml diff --git a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java index af9c526d..36cdcad5 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java @@ -168,7 +168,7 @@ public void run() { * experiment waiting in the queue. */ public void createNextExperiment() { - LOGGER.info("create experiment"); + //LOGGER.info("create next experiment"); synchronized (experimentMutex) { try { // if there is no benchmark running, the queue has been @@ -277,6 +277,7 @@ public void createNextExperiment() { Constants.BENCHMARK_PARAMETERS_MODEL_KEY + "=" + config.serializedBenchParams, Constants.SYSTEM_URI_KEY + "=" + config.systemUri }, null, null, config.id, Collections.emptyMap()); + LOGGER.info("^^> containerID is {}" , containerId); if (containerId == null) { experimentStatus.addError(HobbitErrors.BenchmarkCreationError); throw new Exception("Couldn't create benchmark controller " + config.benchmarkUri); @@ -296,6 +297,7 @@ public void createNextExperiment() { Constants.HOBBIT_SESSION_ID_KEY + "=" + config.id, Constants.SYSTEM_PARAMETERS_MODEL_KEY + "=" + serializedSystemParams }, null, null, config.id, getHardwareConstraints(config.serializedBenchParams)); + LOGGER.info("^^^> containerID is {}" , containerId); if (containerId == null) { LOGGER.error("Couldn't start the system. Trying to cancel the benchmark."); forceBenchmarkTerminate_unsecured(HobbitErrors.SystemCreationError); @@ -340,6 +342,7 @@ protected static Map getHardwareConstraints(String serializedBen } protected void createRabbitMQ(ExperimentConfiguration config) throws Exception { + LOGGER.info("create RabbitMQ"); String rabbitMQAddress = hobbitConfig.getString(RABBIT_MQ_EXPERIMENTS_HOST_NAME_KEY, (String) null); LOGGER.info("Using the newly started RabbitMQ for the experiment: {}", rabbitMQAddress); if (rabbitMQAddress == null) { diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 1aa5ead4..eeeb3731 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -53,22 +53,14 @@ import org.apache.jena.rdf.model.Resource; import org.apache.jena.vocabulary.RDF; import org.hobbit.controller.analyze.ExperimentAnalyzer; +import org.hobbit.controller.containers.*; import org.hobbit.controller.data.ExperimentConfiguration; -import org.hobbit.controller.containers.ClusterManager; //import org.hobbit.controller.containers.docker.ClusterManagerImpl; import org.hobbit.controller.containers.kubernetes.ClusterManagerImpl; -import org.hobbit.controller.containers.ContainerManager; //import org.hobbit.controller.containers.docker.ContainerManagerImpl; import org.hobbit.controller.containers.kubernetes.ContainerManagerImpl; -import org.hobbit.controller.containers.ContainerStateObserver; //import org.hobbit.controller.containers.docker.ContainerStateObserverImpl; import org.hobbit.controller.containers.kubernetes.ContainerStateObserverImpl; -import org.hobbit.controller.containers.ContainerTerminationCallback; -import org.hobbit.controller.containers.FileBasedImageManager; -import org.hobbit.controller.containers.GitlabBasedImageManager; -import org.hobbit.controller.containers.ImageManager; -import org.hobbit.controller.containers.ImageManagerFacade; -import org.hobbit.controller.containers.ResourceInformationCollector; //import org.hobbit.controller.containers.docker.ResourceInformationCollectorImpl; import org.hobbit.controller.containers.kubernetes.ResourceInformationCollectorImpl; import org.hobbit.controller.front.FrontEndApiHandler; @@ -179,7 +171,7 @@ public class PlatformController extends AbstractComponent implements ContainerTe /** * A manager for Docker containers. */ - protected ContainerManager containerManager; + protected KubExtendedContainerManager containerManager; /** * The observer of docker containers. */ @@ -287,7 +279,7 @@ public void init() throws Exception { containerManager = new ContainerManagerImpl(client); LOGGER.info("Container manager initialized."); // Create container observer (polls status every 5s) - containerObserver = new ContainerStateObserverImpl(containerManager, 5 * 1000, client); + containerObserver = new ContainerStateObserverImpl(containerManager, 5 * 1000); containerObserver.addTerminationCallback(this); // Tell the manager to add container to the observer containerManager.addContainerObserver(containerObserver); @@ -400,7 +392,8 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas replyTo = props.getReplyTo(); } - if (LOGGER.isDebugEnabled()) { + //if (LOGGER.isDebugEnabled()) { + if (true) { LOGGER.info("received command: session={}, command={}, data={}", sessionId, Commands.toString(command), data != null ? RabbitMQUtils.readString(data) : "null"); } else { @@ -531,6 +524,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas * @return the name of the created container */ private String createContainer(StartCommandData data) { + LOGGER.info("create Container in platform controller {}",data.toString()); String parentId = containerManager.getContainerPodId(data.parent); if ((parentId == null) && (CONTAINER_PARENT_CHECK)) { LOGGER.error("Couldn't create container because the parent \"{}\" is not known.", data.parent); @@ -844,6 +838,7 @@ private void handleErrorReport(String sessionId, ErrorData errorData) { LOGGER.error("Got an error report without container ID. It will be ignored."); return; } + LOGGER.info("handle error report for session \"{}\" and container Id {}", sessionId,errorData.getContainerId()); String containerType = containerManager.getContainerType(errorData.getContainerId()); boolean isBenchmarkContainer = Constants.CONTAINER_TYPE_BENCHMARK.equals(containerType); if (!isBenchmarkContainer && (!Constants.CONTAINER_TYPE_SYSTEM.equals(containerType))) { diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java index b1ac6420..3436ab21 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; +import io.kubernetes.client.openapi.models.V1Pod; import org.hobbit.controller.data.ContainerCriteria; import org.hobbit.core.Constants; @@ -180,14 +181,14 @@ public String startContainer(String imageName, String containerType, String pare String[] netAliases, String[] command, String experimentId, Map constraints); - /** - * - * @param containerIdentifier podname or container id - * @param toOutsideOfTheCluster if yes means outside the cluster should reachable - * @param ports map of all ports - * @return service name - */ - public String startService(String containerIdentifier, boolean toOutsideOfTheCluster, Map ports); +// /** +// * +// * @param containerIdentifier podname or container id +// * @param toOutsideOfTheCluster if yes means outside the cluster should reachable +// * @param ports map of all ports +// * @return service name +// */ +// public String startService(String containerIdentifier, boolean toOutsideOfTheCluster, Map ports); /** * Stops the container with the given container Id. diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java index 35fb06f0..c3880b62 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/FileBasedImageManager.java @@ -131,13 +131,13 @@ protected void readFile(File f, List newBenchmarks, List getUncheckedBenchmarks() { - LOGGER.info("getUncheckedBenchmarks from File size {}", benchmarks.size()); + //LOGGER.info("getUncheckedBenchmarks from File size {}", benchmarks.size()); return new ArrayList<>(benchmarks); } @Override protected List getUncheckedSystems() { - LOGGER.info("getUncheckedSystems from File size {}", systems.size()); + //LOGGER.info("getUncheckedSystems from File size {}", systems.size()); return new ArrayList<>(systems); } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/KubExtendedContainerManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/KubExtendedContainerManager.java index 4a823961..ae7e9cd0 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/KubExtendedContainerManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/KubExtendedContainerManager.java @@ -1,4 +1,7 @@ package org.hobbit.controller.containers; -public interface KubExtendedContainerManager { +import io.kubernetes.client.openapi.models.V1Pod; + +public interface KubExtendedContainerManager extends ContainerManager { + public V1Pod getPod(String podIP); } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java index 9ac31d50..cb503860 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/docker/ContainerManagerImpl.java @@ -621,10 +621,10 @@ public String startContainer(String imageName, String containerType, String pare return startContainer(imageName, containerType, parentId, env, netAliases, command, true, constraints); } - @Override - public String startService(String containerIdentifier, boolean toOutsideOfTheCluster, Map ports) { - return containerIdentifier; - } +// @Override +// public String startService(String containerIdentifier, boolean toOutsideOfTheCluster, Map ports) { +// return containerIdentifier; +// } @Override public void removeContainer(String serviceName) { diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java index 680e7ee3..abc83c81 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java @@ -54,11 +54,11 @@ public long getNumberOfNodes(String label) throws InterruptedException { @Override public boolean isClusterHealthy() throws InterruptedException { - LOGGER.info("Checking cluster health"); + //LOGGER.info("Checking cluster health"); try { V1NodeList nodeList = coreV1Api.listNode(null, null, null, null, null, null, null, null, null, false); List nodes = nodeList.getItems(); - LOGGER.info(nodes.size() + " nodes found"); + //LOGGER.info(nodes.size() + " nodes found"); for (V1Node node : nodes) { String status = node.getStatus().getConditions() .stream() diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java index a9d32868..89de0a7c 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java @@ -4,6 +4,7 @@ import org.hobbit.controller.containers.ContainerManager; import org.hobbit.controller.containers.ContainerPodException; import org.hobbit.controller.containers.ContainerStateObserver; +import org.hobbit.controller.containers.KubExtendedContainerManager; import org.hobbit.controller.data.ContainerCriteria; import org.hobbit.controller.utils.Waiting; import org.hobbit.core.Constants; @@ -20,15 +21,14 @@ import io.kubernetes.client.openapi.models.*; import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; +import java.net.*; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -public class ContainerManagerImpl implements ContainerManager { +public class ContainerManagerImpl implements ContainerManager, KubExtendedContainerManager { private static final Logger LOGGER = LoggerFactory.getLogger(ContainerManagerImpl.class); private ApiClient client; @@ -181,155 +181,164 @@ public String startContainer(String imageName, String containerType, String pare LOGGER.info("start Container podname is {}", podName); - if (imageName != null) { - LOGGER.info("image name is {}", imageName); - } else { - LOGGER.info("image name is null"); - } - - if (containerType != null) { - LOGGER.info("container type is {}", containerType); - } else { - LOGGER.info("container type is null"); - } +// if (imageName != null) { +// LOGGER.info("image name is {}", imageName); +// } else { +// LOGGER.info("image name is null"); +// } +// if (containerType != null) { +// LOGGER.info("container type is {}", containerType); +// } else { +// LOGGER.info("container type is null"); +// } if (parentId != null) { - LOGGER.info("Parent ID is {}", parentId); - } else { - LOGGER.info("Parent ID is null"); - } - - if (env != null && env.length > 0) { - LOGGER.info("env is {}", String.join(",", env)); - } else { - LOGGER.info("env is null or empty"); - } - - if (command != null && command.length > 0) { - LOGGER.info("command is {}", String.join(",", command)); - } else { - LOGGER.info("command is null or empty"); - } - - if (experimentId != null) { - LOGGER.info("experimentID is {}", experimentId); - } else { - LOGGER.info("experimentID is null"); - } - - return createContainerKub(imageName, podName, containerType, parentId, env, command, constraints); - } - - private boolean isPodRunning(String namespace, String podName) { - try { - GenericKubernetesApi podClient = - new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); - - V1Pod pod = podClient.get(namespace, podName).throwsApiException().getObject(); - if (pod != null && pod.getStatus() != null && "Running".equals(pod.getStatus().getPhase())) { - return true; + if (!parentId.contains(".pod.cluster.")) { +// LOGGER.info("##@@## wrong parent ID {}",parentId); + parentId = getContainerPodName(parentId); +// LOGGER.info("##@@## new parent ID is {}",parentId); } - } catch (ApiException e) { - LOGGER.error("Error checking pod status in namespace {}: {}", namespace, podName, e); } - return false; - } - - private boolean waitForPodToBeRunning(String namespace, String podName) { - final int maxAttempts = 10; - final int sleepMillis = 5000; - LOGGER.info("Waiting for pod '{}' in namespace '{}' to reach 'Running' state (max {} attempts).", podName, namespace, maxAttempts); - - for (int attempt = 1; attempt <= maxAttempts; attempt++) { - if (isPodRunning(namespace, podName)) { - LOGGER.info("Pod '{}' is now running in namespace '{}' after {} attempts.", podName, namespace, attempt); - return true; - } - - LOGGER.warn("Attempt {}/{}: Pod '{}' is not running yet. Retrying in {} seconds...", attempt, maxAttempts, podName, sleepMillis / 1000); +// if (parentId != null) { +// LOGGER.info("Parent ID is {}", parentId); +// //todo just as a patch, the parent id somewhere insert wrong and as container id +// +// } else { +// LOGGER.info("Parent ID is null"); +// } - try { - Thread.sleep(sleepMillis); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOGGER.error("Thread interrupted while waiting for pod '{}' in namespace '{}'. Aborting wait.", podName, namespace, e); - return false; - } - } +// if (env != null && env.length > 0) { +// LOGGER.info("env is {}", String.join(",", env)); +// } else { +// LOGGER.info("env is null or empty"); +// } +// +// if (command != null && command.length > 0) { +// LOGGER.info("command is {}", String.join(",", command)); +// } else { +// LOGGER.info("command is null or empty"); +// } +// +// if (experimentId != null) { +// LOGGER.info("experimentID is {}", experimentId); +// } else { +// LOGGER.info("experimentID is null"); +// } - LOGGER.error("Pod '{}' in namespace '{}' did not reach 'Running' state after {} attempts.", podName, namespace, maxAttempts); - return false; + return createContainerKub(imageName, podName, containerType, parentId, env, command, constraints); } +// private boolean isPodRunning(String namespace, String podName) { +// try { +// GenericKubernetesApi podClient = +// new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); +// +// V1Pod pod = podClient.get(namespace, podName).throwsApiException().getObject(); +// if (pod != null && pod.getStatus() != null && "Running".equals(pod.getStatus().getPhase())) { +// return true; +// } +// } catch (ApiException e) { +// LOGGER.error("Error checking pod status in namespace {}: {}", namespace, podName, e); +// } +// return false; +// } - @Override - public String startService(String containerIdentifier, boolean toOutsideOfTheCluster, Map ports) { - LOGGER.info("Starting service for pod: {}", containerIdentifier); - - // Wait for pod to be in running state with a timeout - if (!waitForPodToBeRunning(nameSpace, containerIdentifier)) { - LOGGER.error("Pod {} did not reach running state within timeout. Cannot start service.", containerIdentifier); - return null; - } - - LOGGER.info("Pod {} is running. Proceeding to create service.", containerIdentifier); - - // Generate a unique service name - String serviceName = "service-"+containerIdentifier; - if (serviceName.length() > MAX_POD_NAME_LENGTH) { - serviceName = serviceName.substring(0, MAX_POD_NAME_LENGTH); - } - - // Define the service spec - V1ServiceSpec serviceSpec = new V1ServiceSpec() - .selector(Collections.singletonMap("app", containerIdentifier)) - .ports(ports.entrySet().stream() - .map(entry -> new V1ServicePort() - .name("port-" + entry.getKey()) - .protocol("TCP") - .port(entry.getKey()) - .targetPort(new IntOrString(entry.getValue())) - ).collect(Collectors.toList())) - .type("ClusterIP"); - - - if (toOutsideOfTheCluster) { - LOGGER.info("Exposing service {} outside of the cluster.", serviceName); - serviceSpec.setType("NodePort"); - } else { - LOGGER.info("Creating a ClusterIP service {}.", serviceName); - serviceSpec.setType("ClusterIP"); - } - - // Define the metadata - V1ObjectMeta metadata = new V1ObjectMeta() - .name(serviceName) - .namespace("default") // Adjust as needed - .labels(Collections.singletonMap("app", containerIdentifier)); - - // Build the service object - V1Service service = new V1Service() - .metadata(metadata) - .spec(serviceSpec); - - LOGGER.info("Constructed service object for {}.", serviceName); - - // Deploy the service - try { - GenericKubernetesApi serviceClient = - new GenericKubernetesApi<>(V1Service.class, V1ServiceList.class, "", "v1", "services", client); +// private boolean waitForPodToBeRunning(String namespace, String podName) { +// final int maxAttempts = 10; +// final int sleepMillis = 5000; +// +// LOGGER.info("Waiting for pod '{}' in namespace '{}' to reach 'Running' state (max {} attempts).", podName, namespace, maxAttempts); +// +// for (int attempt = 1; attempt <= maxAttempts; attempt++) { +// if (isPodRunning(namespace, podName)) { +// LOGGER.info("Pod '{}' is now running in namespace '{}' after {} attempts.", podName, namespace, attempt); +// return true; +// } +// +// LOGGER.warn("Attempt {}/{}: Pod '{}' is not running yet. Retrying in {} seconds...", attempt, maxAttempts, podName, sleepMillis / 1000); +// +// try { +// Thread.sleep(sleepMillis); +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// LOGGER.error("Thread interrupted while waiting for pod '{}' in namespace '{}'. Aborting wait.", podName, namespace, e); +// return false; +// } +// } +// +// LOGGER.error("Pod '{}' in namespace '{}' did not reach 'Running' state after {} attempts.", podName, namespace, maxAttempts); +// return false; +// } - LOGGER.info("Sending request to create service: {}", serviceName); - V1Service createdService = serviceClient.create(service).throwsApiException().getObject(); - LOGGER.info("Successfully created service: {}", createdService.getMetadata().getName()); - return createdService.getMetadata().getName(); - } catch (ApiException e) { - LOGGER.error("Failed to create service for pod: {}. Returning null.", containerIdentifier, e); - return null; - } - } +// @Override +// public String startService(String containerIdentifier, boolean toOutsideOfTheCluster, Map ports) { +// LOGGER.info("Starting service for pod: {}", containerIdentifier); +// +// // Wait for pod to be in running state with a timeout +// if (!waitForPodToBeRunning(nameSpace, containerIdentifier)) { +// LOGGER.error("Pod {} did not reach running state within timeout. Cannot start service.", containerIdentifier); +// return null; +// } +// +// LOGGER.info("Pod {} is running. Proceeding to create service.", containerIdentifier); +// +// // Generate a unique service name +// String serviceName = "service-"+containerIdentifier; +// if (serviceName.length() > MAX_POD_NAME_LENGTH) { +// serviceName = serviceName.substring(0, MAX_POD_NAME_LENGTH); +// } +// +// // Define the service spec +// V1ServiceSpec serviceSpec = new V1ServiceSpec() +// .selector(Collections.singletonMap("app", containerIdentifier)) +// .ports(ports.entrySet().stream() +// .map(entry -> new V1ServicePort() +// .name("port-" + entry.getKey()) +// .protocol("TCP") +// .port(entry.getKey()) +// .targetPort(new IntOrString(entry.getValue())) +// ).collect(Collectors.toList())) +// .type("ClusterIP"); +// +// +// if (toOutsideOfTheCluster) { +// LOGGER.info("Exposing service {} outside of the cluster.", serviceName); +// serviceSpec.setType("NodePort"); +// } else { +// LOGGER.info("Creating a ClusterIP service {}.", serviceName); +// serviceSpec.setType("ClusterIP"); +// } +// +// // Define the metadata +// V1ObjectMeta metadata = new V1ObjectMeta() +// .name(serviceName) +// .namespace("default") // Adjust as needed +// .labels(Collections.singletonMap("app", containerIdentifier)); +// +// // Build the service object +// V1Service service = new V1Service() +// .metadata(metadata) +// .spec(serviceSpec); +// +// LOGGER.info("Constructed service object for {}.", serviceName); +// +// // Deploy the service +// try { +// GenericKubernetesApi serviceClient = +// new GenericKubernetesApi<>(V1Service.class, V1ServiceList.class, "", "v1", "services", client); +// +// LOGGER.info("Sending request to create service: {}", serviceName); +// +// V1Service createdService = serviceClient.create(service).throwsApiException().getObject(); +// LOGGER.info("Successfully created service: {}", createdService.getMetadata().getName()); +// return createdService.getMetadata().getName(); +// } catch (ApiException e) { +// LOGGER.error("Failed to create service for pod: {}. Returning null.", containerIdentifier, e); +// return null; +// } +// } /** * Creates environment variables from the provided list of key-value pairs. @@ -347,44 +356,75 @@ public String startService(String containerIdentifier, boolean toOutsideOfTheClu // return env; // } - /** - * Initializes and configures a Kubernetes API client with custom timeout settings. - * - * This method: - * - Creates a default Kubernetes API client using the default configuration. - * - Sets custom connection, read, and write timeouts. - * - Sets the configured client as the default client in the global Configuration class. - * - * @return ApiClient configured with specified timeouts. - * @throws IOException if an error occurs during client initialization. - */ - protected ApiClient initiateClient() throws IOException { - try{ - LOGGER.info("initiating Kubernetes client"); - ApiClient client = Config.defaultClient(); - client.setConnectTimeout(TIMEOUT_MILLISECONDS); - client.setReadTimeout(TIMEOUT_MILLISECONDS); - client.setWriteTimeout(TIMEOUT_MILLISECONDS); - Configuration.setDefaultApiClient(client); - LOGGER.info("Kubernetes API client initiated with default configuration."); - return client; - } - catch (Exception ex){ - LOGGER.error("Failed to initiate Kubernetes API client", ex); - throw ex; - } - } +// /** +// * Initializes and configures a Kubernetes API client with custom timeout settings. +// * +// * This method: +// * - Creates a default Kubernetes API client using the default configuration. +// * - Sets custom connection, read, and write timeouts. +// * - Sets the configured client as the default client in the global Configuration class. +// * +// * @return ApiClient configured with specified timeouts. +// * @throws IOException if an error occurs during client initialization. +// */ +// protected ApiClient initiateClient() throws IOException { +// try{ +// LOGGER.info("initiating Kubernetes client"); +// ApiClient client = Config.defaultClient(); +// client.setConnectTimeout(TIMEOUT_MILLISECONDS); +// client.setReadTimeout(TIMEOUT_MILLISECONDS); +// client.setWriteTimeout(TIMEOUT_MILLISECONDS); +// Configuration.setDefaultApiClient(client); +// LOGGER.info("Kubernetes API client initiated with default configuration."); +// return client; +// } +// catch (Exception ex){ +// LOGGER.error("Failed to initiate Kubernetes API client", ex); +// throw ex; +// } +// } - public static String getPodName() { - String podName = System.getenv("HOSTNAME"); - if (podName == null || podName.isEmpty()) { - try { - podName = InetAddress.getLocalHost().getHostName(); // Fallback methoD - } catch (UnknownHostException e) { - podName = "Unknown-Pod"; +// public static String getPodName() { +// String podName = System.getenv("HOSTNAME"); +// if (podName == null || podName.isEmpty()) { +// try { +// podName = InetAddress.getLocalHost().getHostName(); // Fallback methoD +// } catch (UnknownHostException e) { +// podName = "Unknown-Pod"; +// } +// } +// return podName; +// } + + public static String getPodIP() { + try { + // Get the local host's network interfaces + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + + while (networkInterfaces.hasMoreElements()) { + NetworkInterface networkInterface = networkInterfaces.nextElement(); + + // Ignore loopback and inactive interfaces + if (!networkInterface.isLoopback() && networkInterface.isUp()) { + Enumeration addresses = networkInterface.getInetAddresses(); + + while (addresses.hasMoreElements()) { + InetAddress address = addresses.nextElement(); + + // Ignore IPv6 addresses and return the first available IPv4 address found + if (address instanceof Inet4Address) { + return address.getHostAddress(); + } + } + } } + } catch (SocketException e) { + // Handle exception appropriately in your context + e.printStackTrace(); } - return podName; + + // Return a fallback value if no IP address was found + return "Unknown-IP"; } @@ -395,10 +435,10 @@ private String createContainerKub(String imageName, String podName, String conta - LOGGER.info("add environment variable HIBBIT DOCKER NAME"); - String thisPodName = Constants.CONTAINER_NAME_KEY + "=" +getPodName(); + //LOGGER.info("add environment variable HOBBIT DOCKER NAME"); + String thisPodName = Constants.CONTAINER_NAME_KEY + "=" +convertIP2dnsId(getPodIP()); - LOGGER.info("pod name is {}", thisPodName); + //LOGGER.info("this pod name which used for {} is {}",Constants.CONTAINER_NAME_KEY ,thisPodName); if (env == null || env.length == 0) { env= new String[]{thisPodName}; @@ -407,24 +447,31 @@ private String createContainerKub(String imageName, String podName, String conta updatedEnv[env.length] = thisPodName; env = updatedEnv; } - LOGGER.info("add environment variable HIBBIT ENV now it has {} environment variables.", env.length); + //LOGGER.info("add environment variable HOBBIT ENV now it has {} environment variables.", env.length); + + // environment variable also could be podname + // todo why the name set somewhere ? it measn we return pod name somewhere wrong or they read it directly + for (int i = 0; i < env.length; i++) { + env[i] = changeIfItIsContainerName(env[i]); + } + for (String item : env) { LOGGER.info(item); } - +LOGGER.info("######@@@@######"); // Prepare environment variable List environmentVariables = new ArrayList<>(); if (env != null) { - LOGGER.info("Processing environment variables, total count: {}", env.length); +// LOGGER.info("Processing environment variables, total count: {}", env.length); for (String envVar : env) { - LOGGER.info("Parsing environment variable: {}", envVar); +// LOGGER.info("Parsing environment variable: {}", envVar); String[] parts = envVar.split("=", 2); if (parts.length == 2) { - LOGGER.info("Adding environment variable - Name: {}, Value: {}", parts[0], parts[1]); +// LOGGER.info("Adding environment variable - Name: {}, Value: {}", parts[0], parts[1]); environmentVariables.add(new V1EnvVar().name(parts[0]).value(parts[1])); } else { LOGGER.warn("Skipping invalid environment variable: {}", envVar); @@ -434,7 +481,7 @@ private String createContainerKub(String imageName, String podName, String conta LOGGER.warn("No environment variables provided."); } - LOGGER.info("Adding secret-based environment variable: GITLAB_TOKEN from gitlab-secret"); +// LOGGER.info("Adding secret-based environment variable: GITLAB_TOKEN from gitlab-secret"); // V1EnvVar gitlabTokenEnvVar = new V1EnvVar() // .name("GITLAB_TOKEN") // .valueFrom(new V1EnvVarSource() @@ -446,12 +493,12 @@ private String createContainerKub(String imageName, String podName, String conta environmentVariables.add(new V1EnvVar().name("GITLAB_USER").value("gitadmin")); environmentVariables.add(new V1EnvVar().name("GITLAB_EMAIL").value("gitadmin@project-hobbit.eu")); - for(V1EnvVar envVar : environmentVariables) { - LOGGER.info("Adding environment variable: {} = {}", envVar.getName(), envVar.getValue()); - } +// for(V1EnvVar envVar : environmentVariables) { +// LOGGER.info("Adding environment variable: {} = {}", envVar.getName(), envVar.getValue()); +// } - LOGGER.info("Determining container type for parent pod: {}", parentPodName); +// LOGGER.info("Determining container type for parent pod: {}", parentPodName); String parentType = null; if(parentPodName != null) { parentType = getContainerType(parentPodName); @@ -472,11 +519,11 @@ private String createContainerKub(String imageName, String podName, String conta // Create resource requirements if constraints are provided - LOGGER.info("Creating resource requirements from constraints."); +// LOGGER.info("Creating resource requirements from constraints."); V1ResourceRequirements resourceRequirements = createResourceRequirementsFromConstraints(constraints); // Prepare the container specification - LOGGER.info("Preparing container specification with name: {}, image: {}", podName, imageName); +// LOGGER.info("Preparing container specification with name: {}, image: {}", podName, imageName); V1Container container = new V1Container() .name(podName) .image(imageName) @@ -484,7 +531,23 @@ private String createContainerKub(String imageName, String podName, String conta .command(command != null ? Arrays.asList(command) : null) .resources(resourceRequirements); - LOGGER.info("Container specification created successfully."); + // Add security context with NET_RAW capability + + V1SecurityContext securityContext = new V1SecurityContext(); + securityContext.setCapabilities(new V1Capabilities() + .addAddItem("NET_RAW").addAddItem("SYS_ADMIN")); + + //todo make them variable also for pod + securityContext.setRunAsUser(0L); // Replace with your actual user ID + securityContext.setRunAsGroup(0L); // Replace with your actual group ID + securityContext.allowPrivilegeEscalation(true); + + + + container.setSecurityContext(securityContext); + + +// LOGGER.info("Container specification created successfully."); // Create a volume and volume mount for shared directories @@ -497,7 +560,7 @@ private String createContainerKub(String imageName, String podName, String conta // Create the pod specification - LOGGER.info("Creating pod specification for container: {}", podName); +// LOGGER.info("Creating pod specification for container: {}", podName); V1PodSpec podSpec = new V1PodSpec() .restartPolicy("Never") .addContainersItem(container) @@ -508,28 +571,37 @@ private String createContainerKub(String imageName, String podName, String conta ); //.volumes(Collections.singletonList(volume)); - LOGGER.info("Determining node selector based on container type: {} and parent type: {}", containerType, parentType); + //todo make them variable also for container + + + V1PodSecurityContext podSecurityContext = new V1PodSecurityContext(); + podSecurityContext.setRunAsUser(0L); + podSecurityContext.setFsGroup(0L); + + podSpec.setSecurityContext(podSecurityContext); + +// LOGGER.info("Determining node selector based on container type: {} and parent type: {}", containerType, parentType); if ((((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType)) && Constants.CONTAINER_TYPE_SYSTEM.equals(containerType)) || Constants.CONTAINER_TYPE_SYSTEM.equals(parentType)) { - LOGGER.info("Setting node selector to 'system-nodes' for container type: {}", containerType); +// LOGGER.info("Setting node selector to 'system-nodes' for container type: {}", containerType); podSpec.nodeSelector(Collections.singletonMap("node-group", "system-nodes")); - LOGGER.debug("Assigning container type to SYSTEM."); +// LOGGER.debug("Assigning container type to SYSTEM."); containerType = Constants.CONTAINER_TYPE_SYSTEM; } else if (Constants.CONTAINER_TYPE_DATABASE.equals(containerType) && ((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType) || Constants.CONTAINER_TYPE_DATABASE.equals(parentType))) { - LOGGER.info("Setting node selector to 'benchmark-nodes' for DATABASE container type."); +// LOGGER.info("Setting node selector to 'benchmark-nodes' for DATABASE container type."); podSpec.nodeSelector(Collections.singletonMap("node-group", "benchmark-nodes")); } else if (Constants.CONTAINER_TYPE_BENCHMARK.equals(containerType) && ((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType))) { - LOGGER.info("Setting node selector to 'benchmark-nodes' for BENCHMARK container type."); +// LOGGER.info("Setting node selector to 'benchmark-nodes' for BENCHMARK container type."); podSpec.nodeSelector(Collections.singletonMap("node-group", "benchmark-nodes")); } else { @@ -538,32 +610,32 @@ private String createContainerKub(String imageName, String podName, String conta return null; } - LOGGER.info("Pod specification created successfully."); +// LOGGER.info("Pod specification created successfully."); - LOGGER.info("Creating labels for pod: {}", podName); +// LOGGER.info("Creating labels for pod: {}", podName); Map labels = new HashMap<>(); labels.put(LABEL_TYPE, containerType); labels.put(LABEL_PARENT, parentPodName); labels.put("app",podName); - LOGGER.info("Labels set - Type: {}, Parent: {}", containerType, parentPodName); +// LOGGER.info("Labels set - Type: {}, Parent: {}", containerType, parentPodName); // Build the pod metadata - LOGGER.info("Building pod metadata for pod: {} in namespace: {}", podName, nameSpace); +// LOGGER.info("Building pod metadata for pod: {} in namespace: {}", podName, nameSpace); V1ObjectMeta metadata = new V1ObjectMeta() .name(podName) .namespace(nameSpace) .labels(labels); // Build the pod object - LOGGER.info("Constructing the pod object."); +// LOGGER.info("Constructing the pod object."); V1Pod pod = new V1Pod() .metadata(metadata) .spec(podSpec); - LOGGER.info("Pod object created successfully: {}", podName); +// LOGGER.info("Pod object created successfully: {}", podName); // Deploy the pod @@ -573,21 +645,11 @@ private String createContainerKub(String imageName, String podName, String conta - LOGGER.info("Sending request to create pod with name: {}", podName); +// LOGGER.info("Sending request to create pod with name: {}", podName); V1Pod createdPod = podClient.create(pod).throwsApiException().getObject(); String createdPodName = createdPod.getMetadata().getName(); - // If the creation was successful - if (createdPodName != null) { - LOGGER.info("Successfully created pod with name: {}", createdPodName); - for (ContainerStateObserver observer : containerObservers) { - LOGGER.info("Notifying observer about created pod with name: {}", createdPodName); - observer.addObservedContainer(createdPodName); - } - } - - if (createdPodName != null) { LOGGER.info("Successfully created pod with name: {}", createdPodName); @@ -596,30 +658,36 @@ private String createContainerKub(String imageName, String podName, String conta V1PodList podList = podClient.list(nameSpace).getObject(); while (System.currentTimeMillis() - startTime < TimeUnit.SECONDS.toMillis(TIMEOUT_SECONDS)) { try { - LOGGER.info("Waiting for pod {} to start", createdPodName); +// LOGGER.info("Waiting for pod {} to start", createdPodName); V1Pod targetPod = podList.getItems().stream() - .filter(podTocheck -> createdPodName.equals(pod.getMetadata().getName())) + .filter(podTocheck -> createdPodName.equals(podTocheck.getMetadata().getName())) .findFirst() .orElse(null); //todo remove this - if (targetPod == null) { - LOGGER.error("No pod found with name: {}", createdPod); - } +// if (targetPod == null) { +// LOGGER.error("No pod found with name: {}", createdPod); + // } - LOGGER.info("Target pod found: {}", targetPod.getMetadata().getName()); +// LOGGER.info("Target pod found: {}", targetPod.getMetadata().getName()); String podPhase = targetPod.getStatus().getPhase(); if ("Running".equals(podPhase)) { String podIP = targetPod.getStatus().getPodIP(); - LOGGER.info("Pod IP: {}", podIP); +// LOGGER.info("Pod IP: {}", podIP); if (podIP != null && !podIP.isEmpty()) { - LOGGER.info("Obtained Pod IP: {}", podIP); - String convertedIP = podIP.replace(".", "-") + ".default.pod.cluster.local"; - LOGGER.info("Converted IP: {}", convertedIP); +// LOGGER.info("Obtained Pod IP: {}", podIP); + String convertedIP = convertIP2dnsId(podIP); +// LOGGER.info("Converted IP: {}", convertedIP); + + for (ContainerStateObserver observer : containerObservers) { +// LOGGER.info("Notifying observer about created pod with name: {}", convertedIP); + observer.addObservedContainer(convertedIP); + } + LOGGER.info("return this converted IP: {}", convertedIP); return convertedIP; } } - LOGGER.info("pod phase is {}", podPhase); +// LOGGER.info("pod phase is {}", podPhase); podList = podClient.list(nameSpace).getObject(); }catch (Exception ex){ LOGGER.error(ex.getMessage()); @@ -635,7 +703,7 @@ private String createContainerKub(String imageName, String podName, String conta } else { LOGGER.error("Failed to create the pod."); } - + LOGGER.warn("return null"); return null; // Return null if the IP address is not available within the timeout } catch (ApiException e) { LOGGER.error("Failed to create pod for image: {}. Returning null.", imageName, e); @@ -644,9 +712,23 @@ private String createContainerKub(String imageName, String podName, String conta } + private String changeIfItIsContainerName(String s) { + String[] parts = s.split("="); + if(isItContainerName(parts[1])){ + String newName = mapName2IP(parts[1]); + return parts[0]+"="+newName; + } + return s; + } + + private String convertIP2dnsId(String podIP) { + return podIP.replace(".", "-") + ".default.pod.cluster.local"; + } + private String mapIp2Name(String ip) { + String podIp = ip.replace("-",".").replace(".default.pod.cluster.local", ""); - LOGGER.info("Mapped IP: {}", podIp); + //LOGGER.info("map this IP: {} which extracted from this {}", podIp, ip); GenericKubernetesApi podClient = new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); @@ -659,20 +741,19 @@ private String mapIp2Name(String ip) { return targetPod.getMetadata().getName(); } - - private V1Pod getPod(String podIP) { - LOGGER.info("getPod"); - + @Override + public V1Pod getPod(String podIP) { + //LOGGER.info("getPod with {}",podIP); String podName = mapIp2Name(podIP); - - LOGGER.info("Attempting to retrieve pod: {} in namespace: {}", podName, this.nameSpace); - + //LOGGER.info("Attempting to retrieve pod: {} in namespace: {}", podName, this.nameSpace); + if(podName == null){ + LOGGER.error("No pod found with podIP: {}", podIP); + } CoreV1Api coreV1Api = new CoreV1Api(client); - try { // Inspect the pod by name V1Pod pod = coreV1Api.readNamespacedPod(podName, this.nameSpace, null); - LOGGER.info("Successfully retrieved pod: {} in namespace: {}", podName, this.nameSpace); + //LOGGER.info("Successfully retrieved pod: {} in namespace: {}", podName, this.nameSpace); return pod; } catch (ApiException exc) { LOGGER.error("Failed to get pod: {} in namespace: {}", podName, this.nameSpace); @@ -731,21 +812,25 @@ public void stopContainer(String containerId) { @Override - public void removeContainer(String podName) { + public void removeContainer(String podIp) { + + LOGGER.info("removing pod {}.", podIp); //String podName = mapIp2Name(podIp); try { - Long exitCode = getContainerPodExitCode(podName); + Long exitCode = getContainerPodExitCode(podIp); if (DEPLOY_ENV.equals(DEPLOY_ENV_DEVELOP)) { - LOGGER.info("Will not remove pod {}. Development mode is enabled.", podName); + LOGGER.info("Will not remove pod {}. Development mode is enabled.", podIp); } else if (DEPLOY_ENV.equals(DEPLOY_ENV_TESTING) && (exitCode != null && exitCode != 0)) { - LOGGER.info("Will not remove pod {}. ExitCode: {} != 0 and testing mode is enabled.", podName, exitCode); + LOGGER.info("Will not remove pod {}. ExitCode: {} != 0 and testing mode is enabled.", podIp, exitCode); } else { - LOGGER.info("Removing pod {}.", podName); + LOGGER.info("Removing pod {}.", podIp); // Initialize the API client CoreV1Api api = new CoreV1Api(client); + String podName = mapIp2Name(podIp); + // Delete the pod V1DeleteOptions deleteOptions = new V1DeleteOptions(); api.deleteNamespacedPod(podName, nameSpace, null, null, null, null, null, deleteOptions); @@ -765,12 +850,12 @@ public void removeContainer(String podName) { } } catch (ApiException e) { if (e.getCode() == 404) { - LOGGER.error("Couldn't remove pod {} because it doesn't exist", podName); + LOGGER.error("Couldn't remove pod {} because it doesn't exist", podIp); } else { - LOGGER.error("Couldn't remove pod {}.", podName, e); + LOGGER.error("Couldn't remove pod {}.", podIp, e); } } catch (Exception e) { - LOGGER.error("Unexpected error while removing pod {}.", podName, e); + LOGGER.error("Unexpected error while removing pod {}.", podIp, e); } } @@ -782,26 +867,29 @@ public void stopParentAndChildren(String parentId) { } @Override - public void removeParentAndChildren(String parentPodName) { + public void removeParentAndChildren(String parentPodIp) { + LOGGER.info("removing parent and child pod {}.", parentPodIp); // Remove the parent pod - removeContainer(parentPodName); + removeContainer(parentPodIp); // Find child pods try { CoreV1Api api = new CoreV1Api(client); // Search for pods with the label "parent=" - String labelSelector = String.format(LABEL_PARENT+"=%s", parentPodName); + String labelSelector = String.format(LABEL_PARENT+"=%s", parentPodIp); + LOGGER.info("Removing parent and child pod {}.", labelSelector); V1PodList childPods = api.listNamespacedPod( nameSpace, null, null, null, null, labelSelector, null, null, null, null, false); for (V1Pod childPod : childPods.getItems()) { if (childPod != null && childPod.getMetadata() != null) { - String childPodName = childPod.getMetadata().getName(); - if (childPodName != null) { - // Recursively remove the child pod and its children - removeParentAndChildren(childPodName); - } + String childPodIp = childPod.getStatus().getPodIP(); + LOGGER.info("Removing child pod with ip{}.", childPodIp); + String convertedChildIP =convertIP2dnsId(childPodIp); + LOGGER.info("Removing child pod with convertedip{}.", convertedChildIP); + // Recursively remove the child pod and its children + removeParentAndChildren(convertedChildIP); } } } catch (ApiException e) { @@ -813,7 +901,10 @@ public void removeParentAndChildren(String parentPodName) { @Override - public Long getContainerPodExitCode(String podName) throws ContainerPodException { + public Long getContainerPodExitCode(String podIp) throws ContainerPodException { + LOGGER.info("get exit code for pod {}.", podIp); + String podName = mapIp2Name(podIp); + LOGGER.info("get exit code for pod {}.", podName); try { // Initialize the API client CoreV1Api api = new CoreV1Api(client); @@ -858,8 +949,11 @@ public List getContainers(ContainerCriteria criteria) { } @Override - public String getContainerPodId(String podName) { - LOGGER.info("getContainerPodId({})", podName); + public String getContainerPodId(String podIp) { + + LOGGER.info("getContainerPodId({})", podIp); + String podName = mapIp2Name(podIp); + LOGGER.info(" Converted PodId to name ({})", podName); // String podName = mapIp2Name(podIp); try { // Fetch the pod information using its name and namespace @@ -885,7 +979,7 @@ public String getContainerPodName(String podId) { for (V1Pod pod : podList.getItems()) { if (pod.getMetadata().getUid().equals(podId)) { // Return the Pod's name - return pod.getMetadata().getName(); + return mapName2IP(pod.getMetadata().getName()); } } @@ -897,17 +991,71 @@ public String getContainerPodName(String podId) { if (pod.getMetadata().getName().equals(podId)) { // Return the Pod's name LOGGER.warn("it is a pod name {}", pod.getMetadata().getName()); - return pod.getMetadata().getName(); + return mapName2IP(pod.getMetadata().getName()); } } - LOGGER.warn("nothing found return NULL !"); - return null; + + LOGGER.warn("(^^) check if it is the converted IP of the pod : {}",podId); + + return mapIp2Name(podId); } catch (Exception e) { LOGGER.error("Failed to fetch Pod name for Pod ID: {} in namespace: {}. Error: {}", podId, nameSpace, e); return null; } } + private Boolean isItContainerName(String name) { + try { + CoreV1Api api = new CoreV1Api(client); + V1PodList podList = api.listNamespacedPod(nameSpace, null, null, null, null, null, null, null, null, null, false); + V1Pod targetPod = podList.getItems().stream() + .filter(podTocheck -> name.equals(podTocheck.getMetadata().getName())) + .findFirst() + .orElse(null); + //todo remove this + if (targetPod == null) { + return false; + } + return true; + }catch (ApiException e) { + LOGGER.error("Error while finding pods: " + e.getResponseBody(), e); + return false; + } + } + + private String mapName2IP(String name) { + try { + CoreV1Api api = new CoreV1Api(client); + V1PodList podList = api.listNamespacedPod(nameSpace, null, null, null, null, null, null, null, null, null, false); + V1Pod targetPod = podList.getItems().stream() + .filter(podTocheck -> name.equals(podTocheck.getMetadata().getName())) + .findFirst() + .orElse(null); + //todo remove this + if (targetPod == null) { + LOGGER.error("!No pod found with name: {}", name); + } + + LOGGER.info("Target pod found: {}", targetPod.getMetadata().getName()); + + String podPhase = targetPod.getStatus().getPhase(); + if ("Running".equals(podPhase)) { + String podIP = targetPod.getStatus().getPodIP(); + LOGGER.info("Pod IP: {}", podIP); + if (podIP != null && !podIP.isEmpty()) { + LOGGER.info("Obtained Pod IP: {}", podIP); + String convertedIP = convertIP2dnsId(podIP); + LOGGER.info("Converted IP: {}", convertedIP); + return convertedIP; + } + } + return null; + }catch (Exception ex){ + LOGGER.error(ex.getMessage()); + return null; + } + } + @Override public void addContainerObserver(ContainerStateObserver containerObserver) { @@ -927,23 +1075,22 @@ public void pullImage(String imageName) { @Override - public String getContainerType(String podName) { - LOGGER.info("Resolving container type for pod: {}", podName); - + public String getContainerType(String podIP) { + LOGGER.info("getContainerType({})", podIP); // Logic to retrieve the parent pod based on the podName - V1Pod parent = getPod(podName); + V1Pod parent = getPod(podIP); if (parent == null) { - LOGGER.warn("Parent pod not found for pod name: {}", podName); + LOGGER.warn("Parent pod not found for pod : {}", podIP); return null; } String containerType = parent.getMetadata().getLabels().get(LABEL_TYPE); if (containerType == null) { - LOGGER.warn("Container type not found in labels for pod: {}", podName); + LOGGER.warn("Container type not found in labels for pod: {}", podIP); } else { - LOGGER.info("Resolved container type for pod {}: {}", podName, containerType); + LOGGER.info("Resolved container type for pod {}: {}", podIP, containerType); } return containerType; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java index 2cd888e1..54694a65 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java @@ -1,13 +1,9 @@ package org.hobbit.controller.containers.kubernetes; -import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.openapi.ApiException; -import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.models.V1Pod; -import io.kubernetes.client.openapi.models.V1PodList; -import org.hobbit.controller.containers.ContainerManager; import org.hobbit.controller.containers.ContainerStateObserver; import org.hobbit.controller.containers.ContainerTerminationCallback; +import org.hobbit.controller.containers.KubExtendedContainerManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,17 +16,14 @@ public class ContainerStateObserverImpl implements ContainerStateObserver { private static final Logger LOGGER = LoggerFactory.getLogger(ContainerStateObserverImpl.class); - ContainerManager manager; - private String nameSpace = "default"; - private final CoreV1Api coreV1Api; + KubExtendedContainerManager manager; private final List monitoredContainers; private final List terminationCallbacks; private final Timer timer; private final int repeatInterval; - public ContainerStateObserverImpl(ContainerManager manager, int repeatInterval,ApiClient client) { + public ContainerStateObserverImpl(KubExtendedContainerManager manager, int repeatInterval) { this.manager = manager; - this.coreV1Api = new CoreV1Api(client); this.monitoredContainers = new ArrayList<>(); this.terminationCallbacks = new ArrayList<>(); this.timer = new Timer(); @@ -42,27 +35,27 @@ public void startObserving() { timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { - List containerNames; + List containerConvertedIPs; synchronized (monitoredContainers) { - containerNames = new ArrayList<>(monitoredContainers); + containerConvertedIPs = new ArrayList<>(monitoredContainers); } - for (String containerName : containerNames) { + for (String containerConvertedIP : containerConvertedIPs) { try { - V1Pod pod = getPodByContainerName(containerName); + V1Pod pod = manager.getPod(containerConvertedIP); if (pod != null && isPodTerminated(pod)) { int exitCode = getPodExitCode(pod); for (ContainerTerminationCallback callback : terminationCallbacks) { try { - callback.notifyTermination(containerName, exitCode); + callback.notifyTermination(containerConvertedIP, exitCode); } catch (Exception e) { LOGGER.error("Error while calling container termination callback.", e); } } } } catch (Exception e) { - LOGGER.error("Couldn't get the status of container " + containerName + ". It will be ignored during this run but will be checked again during the next run.", e); + LOGGER.error("Couldn't get the status of container " + containerConvertedIP + ". It will be ignored during this run but will be checked again during the next run.", e); } } } @@ -86,18 +79,18 @@ public void removeTerminationCallback(ContainerTerminationCallback callback) { } @Override - public void addObservedContainer(String containerName) { + public void addObservedContainer(String containerConvertedIP) { synchronized (monitoredContainers) { - if (!monitoredContainers.contains(containerName)) { - monitoredContainers.add(containerName); + if (!monitoredContainers.contains(containerConvertedIP)) { + monitoredContainers.add(containerConvertedIP); } } } @Override - public void removedObservedContainer(String containerName) { + public void removedObservedContainer(String containerConvertedIP) { synchronized (monitoredContainers) { - monitoredContainers.remove(containerName); + monitoredContainers.remove(containerConvertedIP); } } @@ -108,48 +101,6 @@ public List getObservedContainers() { } } - private V1Pod getPodByContainerName(String containerName) { - //LOGGER.info("Attempting to find pod by container name: {} in namespace {}", containerName, nameSpace); - - try { - V1PodList podList = coreV1Api.listNamespacedPod(nameSpace,null, null, null, "", null, null, null, null, null, false); - //LOGGER.info("Found pods: {}", podList.getItems().size()); - // Search for pod by container name - for (V1Pod pod : podList.getItems()) { - if (pod.getStatus() != null && pod.getStatus().getContainerStatuses() != null) { - //LOGGER.info("Checking pod: {}", pod.getMetadata().getName()); - - if (pod.getStatus().getContainerStatuses().stream().anyMatch(status -> containerName.equals(status.getName()))) { - //LOGGER.info("Found pod: {} matching container name: {}", pod.getMetadata().getName(), containerName); - return pod; - } - } - } - - //LOGGER.warn("No pod found by container name: {}. Attempting to search by UID.", containerName); - - // If no pod was found by container name, search by UID - for (V1Pod pod : podList.getItems()) { - if (pod.getMetadata() != null && containerName.equals(pod.getMetadata().getUid())) { - //LOGGER.info("Found pod: {} matching UID: {}", pod.getMetadata().getName(), containerName); - return pod; - } - } - - LOGGER.warn("No pod found with container name or UID: {}", containerName); - return null; - - } catch (ApiException e) { - LOGGER.error("ApiException occurred while trying to list pods. Error message: {}. Stack trace: {}", e.getMessage(), e); - // You can rethrow the exception if needed or return null as fallback - return null; - } catch (Exception e) { - LOGGER.error("Unexpected error occurred while trying to list pods. Error message: {}. Stack trace: {}", e.getMessage(), e); - return null; - } - } - - private boolean isPodTerminated(V1Pod pod) { return pod.getStatus() != null && "Succeeded".equals(pod.getStatus().getPhase()) || "Failed".equals(pod.getStatus().getPhase()); } diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java index d1864096..d867994e 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java @@ -5,6 +5,7 @@ import java.util.Map; import java.util.concurrent.Semaphore; +import io.kubernetes.client.openapi.models.V1Pod; import org.hobbit.controller.containers.ContainerManager; import org.hobbit.controller.containers.ContainerStateObserver; import org.hobbit.controller.containers.ContainerTerminationCallback; @@ -12,9 +13,10 @@ import com.spotify.docker.client.messages.ContainerStats; import com.spotify.docker.client.messages.swarm.Service; import com.spotify.docker.client.messages.swarm.Service.Criteria; +import org.hobbit.controller.containers.KubExtendedContainerManager; import org.hobbit.controller.data.ContainerCriteria; -public class DummyContainerManager implements ContainerManager { +public class DummyContainerManager implements ContainerManager, KubExtendedContainerManager { private Semaphore benchmarkControllerTerminated; private ContainerTerminationCallback terminationCallback; @@ -154,4 +156,8 @@ public String getContainerType(String containerId) { return null; } + @Override + public V1Pod getPod(String podIP) { + return null; + } } diff --git a/platform-storage/storage-service/Dockerfile b/platform-storage/storage-service/Dockerfile index 072e57ca..652a97a1 100644 --- a/platform-storage/storage-service/Dockerfile +++ b/platform-storage/storage-service/Dockerfile @@ -1,13 +1,40 @@ +#FROM maven:3-eclipse-temurin-11 AS build +#WORKDIR /usr/src/hobbit-platform +#COPY parent-pom/pom.xml parent-pom/ +#RUN mvn --file parent-pom -Dmaven.test.skip=true install +#ARG project=platform-storage/storage-service +#COPY ${project}/pom.xml ${project}/ +#RUN mvn --file ${project} dependency:go-offline +#COPY ${project}/src ${project}/src +#RUN mvn --file ${project} -Dmaven.test.skip=true package +# +#FROM eclipse-temurin:11 +#COPY --from=build /usr/src/hobbit-platform/platform-storage/storage-service/target/storage-service.jar . +#CMD ["java", "-cp", "storage-service.jar", "org.hobbit.core.run.ComponentStarter", "org.hobbit.storage.service.StorageService"] + + +# ---- Build Stage ---- FROM maven:3-eclipse-temurin-11 AS build + +# Set the working directory WORKDIR /usr/src/hobbit-platform + +# Copy parent POM COPY parent-pom/pom.xml parent-pom/ RUN mvn --file parent-pom -Dmaven.test.skip=true install -ARG project=platform-storage/storage-service -COPY ${project}/pom.xml ${project}/ -RUN mvn --file ${project} dependency:go-offline -COPY ${project}/src ${project}/src -RUN mvn --file ${project} -Dmaven.test.skip=true package +# Copy project files and build +WORKDIR /usr/src/hobbit-platform/platform-storage/storage-service +COPY platform-storage/storage-service/pom.xml . +RUN mvn dependency:go-offline + +COPY platform-storage/storage-service/src src +RUN mvn -Dmaven.test.skip=true package + +# ---- Runtime Stage ---- FROM eclipse-temurin:11 + +WORKDIR /app COPY --from=build /usr/src/hobbit-platform/platform-storage/storage-service/target/storage-service.jar . + CMD ["java", "-cp", "storage-service.jar", "org.hobbit.core.run.ComponentStarter", "org.hobbit.storage.service.StorageService"] diff --git a/platform-storage/storage-service/src/main/java/org/hobbit/storage/service/StorageService.java b/platform-storage/storage-service/src/main/java/org/hobbit/storage/service/StorageService.java index 66f50db0..922d343e 100644 --- a/platform-storage/storage-service/src/main/java/org/hobbit/storage/service/StorageService.java +++ b/platform-storage/storage-service/src/main/java/org/hobbit/storage/service/StorageService.java @@ -216,33 +216,67 @@ else if (query.isAskType()) @Override public void init() throws Exception { + LOGGER.info("Initializing storage service..."); + + // Call parent initialization + LOGGER.debug("Calling super.init()"); super.init(); - sparqlEndpointUrl = getEnvValue(SPARQL_ENDPOINT_URL_KEY, true) + "-auth"; - String username = getEnvValue(SPARQL_ENDPOINT_USERNAME_KEY, true); - String password = getEnvValue(SPARQL_ENDPOINT_PASSWORD_KEY, true); - credentials = new UsernamePasswordCredentials(username, password); + try { + LOGGER.debug("Fetching SPARQL endpoint URL from environment variables..."); + sparqlEndpointUrl = getEnvValue(SPARQL_ENDPOINT_URL_KEY, true) ;//+ "-auth"; + LOGGER.info("SPARQL Endpoint URL: {}", sparqlEndpointUrl); + + LOGGER.debug("Fetching SPARQL endpoint username..."); + String username = getEnvValue(SPARQL_ENDPOINT_USERNAME_KEY, true); + LOGGER.info("SPARQL Endpoint Username: {}", username); + + LOGGER.debug("Fetching SPARQL endpoint password..."); + String password = getEnvValue(SPARQL_ENDPOINT_PASSWORD_KEY, true); + LOGGER.info("SPARQL Endpoint Password: {}", password); // ⚠️ Consider removing in production + + LOGGER.debug("Creating credentials object..."); + credentials = new UsernamePasswordCredentials(username, password); + + LOGGER.debug("Building HTTP client with credentials..."); + HttpClientBuilder clientBuilder = HttpClientBuilder.create(); + clientBuilder.setDefaultCredentialsProvider(this); + client = clientBuilder.build(); + LOGGER.info("HTTP client successfully built."); - HttpClientBuilder clientBuilder = HttpClientBuilder.create(); - clientBuilder.setDefaultCredentialsProvider(this); - client = clientBuilder.build(); + LOGGER.debug("Initializing QueryExecutionFactory..."); + queryExecFactory = new QueryExecutionFactoryHttp(sparqlEndpointUrl, new DatasetDescription(), client); + queryExecFactory = new QueryExecutionFactoryPaginated(queryExecFactory, MAX_RESULT_SIZE); + LOGGER.info("QueryExecutionFactory initialized with pagination and max result size: {}", MAX_RESULT_SIZE); - queryExecFactory = new QueryExecutionFactoryHttp(sparqlEndpointUrl, new DatasetDescription(), client); - queryExecFactory = new QueryExecutionFactoryPaginated(queryExecFactory, MAX_RESULT_SIZE); + LOGGER.debug("Creating default RabbitMQ queue with name: {}", QUEUE_NAME); + queue = incomingDataQueueFactory.createDefaultRabbitQueue(QUEUE_NAME); - queue = incomingDataQueueFactory.createDefaultRabbitQueue(QUEUE_NAME); - queue.channel.basicQos(MAX_NUMBER_PARALLEL_REQUESTS); + LOGGER.debug("Setting channel QoS with max parallel requests: {}", MAX_NUMBER_PARALLEL_REQUESTS); + queue.channel.basicQos(MAX_NUMBER_PARALLEL_REQUESTS); - consumer = new QueueingConsumer(queue.channel); - queue.channel.basicConsume(QUEUE_NAME, false, consumer); + LOGGER.debug("Initializing QueueingConsumer for queue: {}", QUEUE_NAME); + consumer = new QueueingConsumer(queue.channel); + + LOGGER.info("Starting to consume messages from queue: {}", QUEUE_NAME); + queue.channel.basicConsume(QUEUE_NAME, false, consumer); + + LOGGER.info("Storage service initialization completed successfully."); + + } catch (Exception e) { + LOGGER.error("Error during initialization: ", e); + throw e; // Re-throw after logging + } } @Override public void run() throws Exception { - LOGGER.info("[Storage Service] Awaiting Storage Service requests"); + LOGGER.info("[Storage Service] Awaiting Storage Service requests "+MAX_NUMBER_PARALLEL_REQUESTS); ExecutorService executor = Executors.newFixedThreadPool(MAX_NUMBER_PARALLEL_REQUESTS); + LOGGER.info("executor is ready"+ MAX_NUMBER_PARALLEL_REQUESTS); Delivery delivery; while (true) { + LOGGER.info("Let's wait for a delivery for 60 seconds"); delivery = null; // Let's wait for a delivery for 60 seconds try { @@ -251,8 +285,10 @@ public void run() throws Exception { // interrupted; just continue } if (delivery != null) { + LOGGER.info("delivery is not null"); executor.execute(new DeliveryProcessing(this, delivery, queue)); } else { + LOGGER.info("delivery is null"); // This would be the place at which we could react to signals, e.g., terminate // the service if needed. } @@ -341,7 +377,7 @@ public void setCredentials(AuthScope arg0, Credentials arg1) { /** * Main method for debugging purposes. - * + * * @param args */ public static void main(String[] args) { diff --git a/test.yml b/test.yml new file mode 100644 index 00000000..22619ec6 --- /dev/null +++ b/test.yml @@ -0,0 +1,13 @@ +version: '3.3' +services: + redis: + image: redis:4.0.7 + volumes: + - ./config/redis-db:/data + command: ["redis-server", "/data/redis.conf"] + networks: + - test +networks: + test: + external: true + From 6f7197ddd16768ac5cffbaec0b90559003016d6c Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 1 Apr 2025 11:29:13 +0200 Subject: [PATCH 18/52] working version . need refactor and code cleaning --- .../hobbit/controller/PlatformController.java | 2 + .../kubernetes/ContainerManagerImpl.java | 53 ++++++++++++++----- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index eeeb3731..634aab12 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -543,9 +543,11 @@ private String createContainer(StartCommandData data) { // in corerct version if possible every method should return pod name and convert String containerId = containerManager.startContainer(data.image, data.type, parentId, data.environmentVariables, data.networkAliases, null, pullImage, null); + LOGGER.info("-->>--- container ID is {}", containerId); if (containerId == null) { return null; } else { + LOGGER.info("convert ID to PODNAME"); return containerManager.getContainerPodName(containerId); } } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java index 89de0a7c..153325c0 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java @@ -430,6 +430,11 @@ public static String getPodIP() { private String createContainerKub(String imageName, String podName, String containerType, String parentPodName, String[] env, String[] command, Map constraints) { + //todo complete the image name + if(imageName.equals("dicegroup/ckan-hobbit-db")){ + imageName = "docker.io/dicegroup/ckan-hobbit-db:latest"; + } + LOGGER.info("Creating container: Image = {}, Pod Name = {}, Container Type = {}, Parent ID = {}", imageName, podName, containerType, parentPodName); @@ -492,6 +497,7 @@ private String createContainerKub(String imageName, String podName, String conta //environmentVariables.add(gitlabTokenEnvVar); environmentVariables.add(new V1EnvVar().name("GITLAB_USER").value("gitadmin")); environmentVariables.add(new V1EnvVar().name("GITLAB_EMAIL").value("gitadmin@project-hobbit.eu")); + environmentVariables.add((new V1EnvVar().name("RUN_ON").value("kubernetes"))); // for(V1EnvVar envVar : environmentVariables) { // LOGGER.info("Adding environment variable: {} = {}", envVar.getName(), envVar.getValue()); @@ -534,13 +540,18 @@ private String createContainerKub(String imageName, String podName, String conta // Add security context with NET_RAW capability V1SecurityContext securityContext = new V1SecurityContext(); - securityContext.setCapabilities(new V1Capabilities() - .addAddItem("NET_RAW").addAddItem("SYS_ADMIN")); - //todo make them variable also for pod - securityContext.setRunAsUser(0L); // Replace with your actual user ID - securityContext.setRunAsGroup(0L); // Replace with your actual group ID - securityContext.allowPrivilegeEscalation(true); + // todo it is temporary + if(!imageName.contains("earthquakesan/ckan-solr:2.8.0")) { + securityContext.setCapabilities(new V1Capabilities() + .addAddItem("NET_RAW").addAddItem("SYS_ADMIN").addAddItem("AUDIT_WRITE")); + //todo make them variable also for pod + securityContext.setRunAsUser(0L); // Replace with your actual user ID + securityContext.setRunAsGroup(0L); // Replace with your actual group ID + securityContext.allowPrivilegeEscalation(true); + }else { + LOGGER.info("do not use as admin"); + } @@ -568,16 +579,22 @@ private String createContainerKub(String imageName, String podName, String conta new V1LocalObjectReference() .name("gitlab-registry-secret") //todo make this const - ); + ).addImagePullSecretsItem( + new V1LocalObjectReference() + .name("my-dockerhub-secret") + //todo make this const + );; //.volumes(Collections.singletonList(volume)); //todo make them variable also for container V1PodSecurityContext podSecurityContext = new V1PodSecurityContext(); + // todo it is temporary + if(!imageName.contains("earthquakesan/ckan-solr:2.8.0")) { podSecurityContext.setRunAsUser(0L); podSecurityContext.setFsGroup(0L); - + } podSpec.setSecurityContext(podSecurityContext); // LOGGER.info("Determining node selector based on container type: {} and parent type: {}", containerType, parentType); @@ -714,11 +731,16 @@ private String createContainerKub(String imageName, String podName, String conta private String changeIfItIsContainerName(String s) { String[] parts = s.split("="); - if(isItContainerName(parts[1])){ - String newName = mapName2IP(parts[1]); - return parts[0]+"="+newName; + if(parts.length !=2 ){ + LOGGER.error("Invalid container name. {}",s); + return s; + }else { + if (isItContainerName(parts[1])) { + String newName = mapName2IP(parts[1]); + return parts[0] + "=" + newName; + } + return s; } - return s; } private String convertIP2dnsId(String podIP) { @@ -997,7 +1019,12 @@ public String getContainerPodName(String podId) { LOGGER.warn("(^^) check if it is the converted IP of the pod : {}",podId); - return mapIp2Name(podId); + if(mapIp2Name(podId)!=null){ + LOGGER.info("it is the dns FriendlyPod IP "); + return podId; + } + LOGGER.error("can't get the name of the pod {}",podId); + return null; } catch (Exception e) { LOGGER.error("Failed to fetch Pod name for Pod ID: {} in namespace: {}. Error: {}", podId, nameSpace, e); return null; From 4b47533084d78d287684674f8be7a710568598b6 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 2 Apr 2025 15:55:09 +0200 Subject: [PATCH 19/52] make the code cleaner --- .../hobbit/controller/PlatformController.java | 14 +- .../kubernetes/ContainerManagerImpl.java | 853 ++++++++---------- 2 files changed, 390 insertions(+), 477 deletions(-) diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 634aab12..05f05784 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -439,7 +439,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas break; } case Commands.DOCKER_CONTAINER_STOP: { - LOGGER.info("Stopping container with name: {}", sessionId); + LOGGER.info("cmd-Stopping container, sessionId : {}", sessionId); // get containerId from params StopCommandData stopParams = GsonUtils.deserializeObjectWithGson(gson, data, StopCommandData.class, false); // trigger stop @@ -525,8 +525,8 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas */ private String createContainer(StartCommandData data) { LOGGER.info("create Container in platform controller {}",data.toString()); - String parentId = containerManager.getContainerPodId(data.parent); - if ((parentId == null) && (CONTAINER_PARENT_CHECK)) { + //String parentId = containerManager.getContainerPodId(data.parent); + if ((data.parent == null) && (CONTAINER_PARENT_CHECK)) { LOGGER.error("Couldn't create container because the parent \"{}\" is not known.", data.parent); return null; } @@ -541,7 +541,7 @@ private String createContainer(StartCommandData data) { //TODO here it is not container ID , it is container name // search for this tag to find tha patch #klhadKA5468WDJnlawd // in corerct version if possible every method should return pod name and convert - String containerId = containerManager.startContainer(data.image, data.type, parentId, data.environmentVariables, + String containerId = containerManager.startContainer(data.image, data.type, data.parent, data.environmentVariables, data.networkAliases, null, pullImage, null); LOGGER.info("-->>--- container ID is {}", containerId); if (containerId == null) { @@ -559,10 +559,8 @@ private String createContainer(StartCommandData data) { */ public void stopContainer(String containerName) { LOGGER.info("Stopping container with name: {}", containerName); - String containerId = containerManager.getContainerPodId(containerName); - if (containerId != null) { - containerManager.removeContainer(containerId); - } + //String containerId = containerManager.getContainerPodId(containerName); + containerManager.removeContainer(containerName); } @Override diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java index 153325c0..eab06c61 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java @@ -1,6 +1,5 @@ package org.hobbit.controller.containers.kubernetes; -import io.kubernetes.client.custom.IntOrString; import org.hobbit.controller.containers.ContainerManager; import org.hobbit.controller.containers.ContainerPodException; import org.hobbit.controller.containers.ContainerStateObserver; @@ -13,30 +12,28 @@ import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.ApiException; -import io.kubernetes.client.openapi.Configuration; -import io.kubernetes.client.util.Config; import io.kubernetes.client.util.generic.GenericKubernetesApi; import io.kubernetes.client.custom.Quantity; import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.models.*; -import java.io.IOException; import java.net.*; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; public class ContainerManagerImpl implements ContainerManager, KubExtendedContainerManager { private static final Logger LOGGER = LoggerFactory.getLogger(ContainerManagerImpl.class); + private static final String DEFAULT_GIT_USERNAME = "gitadmin"; + private static final String DEFAULT_GIT_EMAIL = "gitadmin@project-hobbit.eu"; + private static final String RUN_ON_KUBERNETES_FLAG = "kubernetes"; private ApiClient client; //TODO make configable - private int TIMEOUT_MILLISECONDS = 60000; private String nameSpace = "default"; private static final long KUBERNETES_POLL_INTERVAL = 5000; // Poll interval in ms - private static final long KUBERNETES_EXITCODE_SIGKILL = 137L; // Equivalent to SIGKILL exit code + /** * Logging separator for type/experiment id. */ @@ -50,6 +47,7 @@ public class ContainerManagerImpl implements ContainerManager, KubExtendedContai : "production"; private static final long TIMEOUT_SECONDS = 60; // Adjust the timeout as needed private static final int MAX_POD_NAME_LENGTH = 63; + private static final long POD_PHASE_CHECK_INTERVAL = 2000; // in ms private static final Pattern VALID_POD_NAME_REGEX = Pattern.compile("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"); @@ -104,11 +102,7 @@ public String startContainer(String imageName, String containerType, String pare @Override public String startContainer(String imageName, String containerType, String parentId, String[] env, String[] netAliases, String[] command, boolean pullImage, Map constraints) { - // we dont need this in kubernetes -// if (pullImage) { -// pullImage(imageName); -// } - //todo why in Interface there is no experimentID ? + //in Interface there is no experimentID , keep it for backward compatibility return startContainer(imageName, containerType, parentId, env, null, command, "", constraints); } @@ -125,6 +119,13 @@ public String generatePodName(String moduleIri,String containerType) { } + /** + * Shortens and validates a pod name to ensure it meets Kubernetes naming conventions. + * + * @param podName The original pod name. + * @return The shortened and validated pod name. + * @throws IllegalArgumentException If the pod name is null, empty, or cannot be sanitized. + */ public static String shortenAndValidatePodName(String podName) { if (podName == null || podName.isEmpty()) { throw new IllegalArgumentException("Pod name cannot be null or empty."); @@ -132,6 +133,7 @@ public static String shortenAndValidatePodName(String podName) { String shortenedName = podName; + // Shorten the name if it exceeds the maximum allowed length if (podName.length() > MAX_POD_NAME_LENGTH) { // Shorten the name, prioritizing the end (more unique). int excessLength = podName.length() - MAX_POD_NAME_LENGTH; @@ -179,223 +181,64 @@ public String startContainer(String imageName, String containerType, String pare podName = shortenAndValidatePodName(podName); - LOGGER.info("start Container podname is {}", podName); + LOGGER.debug("start Container podname is {}", podName); -// if (imageName != null) { -// LOGGER.info("image name is {}", imageName); -// } else { -// LOGGER.info("image name is null"); -// } + if (imageName != null) { + LOGGER.debug("image name is {}", imageName); + } else { + LOGGER.debug("image name is null"); + } -// if (containerType != null) { -// LOGGER.info("container type is {}", containerType); -// } else { -// LOGGER.info("container type is null"); -// } + if (containerType != null) { + LOGGER.debug("container type is {}", containerType); + } else { + LOGGER.debug("container type is null"); + } if (parentId != null) { if (!parentId.contains(".pod.cluster.")) { -// LOGGER.info("##@@## wrong parent ID {}",parentId); + LOGGER.debug("wrong parent ID {}",parentId); parentId = getContainerPodName(parentId); -// LOGGER.info("##@@## new parent ID is {}",parentId); + LOGGER.debug("new parent ID is {}",parentId); } } -// if (parentId != null) { -// LOGGER.info("Parent ID is {}", parentId); -// //todo just as a patch, the parent id somewhere insert wrong and as container id -// -// } else { -// LOGGER.info("Parent ID is null"); -// } - -// if (env != null && env.length > 0) { -// LOGGER.info("env is {}", String.join(",", env)); -// } else { -// LOGGER.info("env is null or empty"); -// } -// -// if (command != null && command.length > 0) { -// LOGGER.info("command is {}", String.join(",", command)); -// } else { -// LOGGER.info("command is null or empty"); -// } -// -// if (experimentId != null) { -// LOGGER.info("experimentID is {}", experimentId); -// } else { -// LOGGER.info("experimentID is null"); -// } - - return createContainerKub(imageName, podName, containerType, parentId, env, command, constraints); - } + if (parentId != null) { + LOGGER.debug("Parent ID is {}", parentId); + //todo just as a patch, the parent id somewhere insert wrong and as container id + } else { + LOGGER.debug("Parent ID is null"); + } -// private boolean isPodRunning(String namespace, String podName) { -// try { -// GenericKubernetesApi podClient = -// new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); -// -// V1Pod pod = podClient.get(namespace, podName).throwsApiException().getObject(); -// if (pod != null && pod.getStatus() != null && "Running".equals(pod.getStatus().getPhase())) { -// return true; -// } -// } catch (ApiException e) { -// LOGGER.error("Error checking pod status in namespace {}: {}", namespace, podName, e); -// } -// return false; -// } + if (env != null && env.length > 0) { + LOGGER.debug("env is {}", String.join(",", env)); + } else { + LOGGER.debug("env is null or empty"); + } -// private boolean waitForPodToBeRunning(String namespace, String podName) { -// final int maxAttempts = 10; -// final int sleepMillis = 5000; -// -// LOGGER.info("Waiting for pod '{}' in namespace '{}' to reach 'Running' state (max {} attempts).", podName, namespace, maxAttempts); -// -// for (int attempt = 1; attempt <= maxAttempts; attempt++) { -// if (isPodRunning(namespace, podName)) { -// LOGGER.info("Pod '{}' is now running in namespace '{}' after {} attempts.", podName, namespace, attempt); -// return true; -// } -// -// LOGGER.warn("Attempt {}/{}: Pod '{}' is not running yet. Retrying in {} seconds...", attempt, maxAttempts, podName, sleepMillis / 1000); -// -// try { -// Thread.sleep(sleepMillis); -// } catch (InterruptedException e) { -// Thread.currentThread().interrupt(); -// LOGGER.error("Thread interrupted while waiting for pod '{}' in namespace '{}'. Aborting wait.", podName, namespace, e); -// return false; -// } -// } -// -// LOGGER.error("Pod '{}' in namespace '{}' did not reach 'Running' state after {} attempts.", podName, namespace, maxAttempts); -// return false; -// } + if (command != null && command.length > 0) { + LOGGER.debug("command is {}", String.join(",", command)); + } else { + LOGGER.debug("command is null or empty"); + } + if (experimentId != null) { + LOGGER.debug("experimentID is {}", experimentId); + } else { + LOGGER.debug("experimentID is null"); + } -// @Override -// public String startService(String containerIdentifier, boolean toOutsideOfTheCluster, Map ports) { -// LOGGER.info("Starting service for pod: {}", containerIdentifier); -// -// // Wait for pod to be in running state with a timeout -// if (!waitForPodToBeRunning(nameSpace, containerIdentifier)) { -// LOGGER.error("Pod {} did not reach running state within timeout. Cannot start service.", containerIdentifier); -// return null; -// } -// -// LOGGER.info("Pod {} is running. Proceeding to create service.", containerIdentifier); -// -// // Generate a unique service name -// String serviceName = "service-"+containerIdentifier; -// if (serviceName.length() > MAX_POD_NAME_LENGTH) { -// serviceName = serviceName.substring(0, MAX_POD_NAME_LENGTH); -// } -// -// // Define the service spec -// V1ServiceSpec serviceSpec = new V1ServiceSpec() -// .selector(Collections.singletonMap("app", containerIdentifier)) -// .ports(ports.entrySet().stream() -// .map(entry -> new V1ServicePort() -// .name("port-" + entry.getKey()) -// .protocol("TCP") -// .port(entry.getKey()) -// .targetPort(new IntOrString(entry.getValue())) -// ).collect(Collectors.toList())) -// .type("ClusterIP"); -// -// -// if (toOutsideOfTheCluster) { -// LOGGER.info("Exposing service {} outside of the cluster.", serviceName); -// serviceSpec.setType("NodePort"); -// } else { -// LOGGER.info("Creating a ClusterIP service {}.", serviceName); -// serviceSpec.setType("ClusterIP"); -// } -// -// // Define the metadata -// V1ObjectMeta metadata = new V1ObjectMeta() -// .name(serviceName) -// .namespace("default") // Adjust as needed -// .labels(Collections.singletonMap("app", containerIdentifier)); -// -// // Build the service object -// V1Service service = new V1Service() -// .metadata(metadata) -// .spec(serviceSpec); -// -// LOGGER.info("Constructed service object for {}.", serviceName); -// -// // Deploy the service -// try { -// GenericKubernetesApi serviceClient = -// new GenericKubernetesApi<>(V1Service.class, V1ServiceList.class, "", "v1", "services", client); -// -// LOGGER.info("Sending request to create service: {}", serviceName); -// -// V1Service createdService = serviceClient.create(service).throwsApiException().getObject(); -// LOGGER.info("Successfully created service: {}", createdService.getMetadata().getName()); -// return createdService.getMetadata().getName(); -// } catch (ApiException e) { -// LOGGER.error("Failed to create service for pod: {}. Returning null.", containerIdentifier, e); -// return null; -// } -// } + return createContainerKub(imageName, podName, containerType, parentId, env, command, constraints); + } /** - * Creates environment variables from the provided list of key-value pairs. + * Retrieves the IPv4 address of the pod. + * + * This method iterates through the network interfaces to find an active, non-loopback interface + * and returns the first available IPv4 address it finds. + * + * @return The IPv4 address of the pod, or "Unknown-IP" if no valid IP is found. + * @throws RuntimeException if no valid IPv4 address is found. */ -// private List createEnvVariables(List> variables) { -// List env = new ArrayList<>(); -// if (variables != null) { -// for (Map.Entry entry : variables) { -// V1EnvVar v1env = new V1EnvVar(); -// v1env.setName(entry.getKey()); -// v1env.setValue(entry.getValue()); -// env.add(v1env); -// } -// } -// return env; -// } - -// /** -// * Initializes and configures a Kubernetes API client with custom timeout settings. -// * -// * This method: -// * - Creates a default Kubernetes API client using the default configuration. -// * - Sets custom connection, read, and write timeouts. -// * - Sets the configured client as the default client in the global Configuration class. -// * -// * @return ApiClient configured with specified timeouts. -// * @throws IOException if an error occurs during client initialization. -// */ -// protected ApiClient initiateClient() throws IOException { -// try{ -// LOGGER.info("initiating Kubernetes client"); -// ApiClient client = Config.defaultClient(); -// client.setConnectTimeout(TIMEOUT_MILLISECONDS); -// client.setReadTimeout(TIMEOUT_MILLISECONDS); -// client.setWriteTimeout(TIMEOUT_MILLISECONDS); -// Configuration.setDefaultApiClient(client); -// LOGGER.info("Kubernetes API client initiated with default configuration."); -// return client; -// } -// catch (Exception ex){ -// LOGGER.error("Failed to initiate Kubernetes API client", ex); -// throw ex; -// } -// } - -// public static String getPodName() { -// String podName = System.getenv("HOSTNAME"); -// if (podName == null || podName.isEmpty()) { -// try { -// podName = InetAddress.getLocalHost().getHostName(); // Fallback methoD -// } catch (UnknownHostException e) { -// podName = "Unknown-Pod"; -// } -// } -// return podName; -// } - public static String getPodIP() { try { // Get the local host's network interfaces @@ -419,316 +262,366 @@ public static String getPodIP() { } } } catch (SocketException e) { - // Handle exception appropriately in your context - e.printStackTrace(); + LOGGER.error("getPodIP failed", e); + throw new RuntimeException("Error retrieving pod IP address", e); } - // Return a fallback value if no IP address was found - return "Unknown-IP"; + // Log and throw an exception if no valid IP address is found + LOGGER.error("No valid IPv4 address found for the pod"); + throw new RuntimeException("No valid IPv4 address found for the pod"); } - - private String createContainerKub(String imageName, String podName, String containerType, String parentPodName, - String[] env, String[] command, Map constraints) { - //todo complete the image name - if(imageName.equals("dicegroup/ckan-hobbit-db")){ - imageName = "docker.io/dicegroup/ckan-hobbit-db:latest"; + // this is kind of the patch can remove after ckan image fetch without docker.io + private String completeImageName(String imageName) { + if ("dicegroup/ckan-hobbit-db".equals(imageName)) { + return "docker.io/dicegroup/ckan-hobbit-db:latest"; } + return imageName; + } - LOGGER.info("Creating container: Image = {}, Pod Name = {}, Container Type = {}, Parent ID = {}", - imageName, podName, containerType, parentPodName); - - - - //LOGGER.info("add environment variable HOBBIT DOCKER NAME"); - String thisPodName = Constants.CONTAINER_NAME_KEY + "=" +convertIP2dnsId(getPodIP()); - - //LOGGER.info("this pod name which used for {} is {}",Constants.CONTAINER_NAME_KEY ,thisPodName); - + /** + * Prepares and updates the environment variables array by adding a new variable representing the current pod's DNS ID. + * + * @param env The original array of environment variables. If {@code null} or empty, a new array will be created. + * @return A new array of environment variables with the additional variable for the current pod's DNS ID. + */ + private String[] prepareEnvironmentVariables(String[] env) { + String thisPodName = Constants.CONTAINER_NAME_KEY + "=" + convertIP2dnsId(getPodIP()); if (env == null || env.length == 0) { - env= new String[]{thisPodName}; - }else { - String[] updatedEnv = Arrays.copyOf(env, env.length + 1); - updatedEnv[env.length] = thisPodName; - env = updatedEnv; + return new String[]{thisPodName}; } - //LOGGER.info("add environment variable HOBBIT ENV now it has {} environment variables.", env.length); + String[] updatedEnv = Arrays.copyOf(env, env.length + 1); + updatedEnv[env.length] = thisPodName; + return updatedEnv; + } - // environment variable also could be podname - // todo why the name set somewhere ? it measn we return pod name somewhere wrong or they read it directly + /** + * Converts all container names in the environment variables array to their corresponding DNS IDs. + * + * @param env The array of environment variables to be converted. + * @return The updated array of environment variables with converted container names. + */ + private String[] convertAllNamesInENV(String[] env) { for (int i = 0; i < env.length; i++) { env[i] = changeIfItIsContainerName(env[i]); } + return env; + } - - for (String item : env) { - LOGGER.info(item); - } - -LOGGER.info("######@@@@######"); - // Prepare environment variable + /** + * Parses an array of environment variables in the format "key=value" into a list of {@code V1EnvVar} objects. + * + * @param env The array of environment variables to be parsed. + * @return A list of {@code V1EnvVar} objects representing the parsed environment variables. + */ + private List parseEnvironmentVariables(String[] env) { List environmentVariables = new ArrayList<>(); - if (env != null) { -// LOGGER.info("Processing environment variables, total count: {}", env.length); - - for (String envVar : env) { -// LOGGER.info("Parsing environment variable: {}", envVar); - String[] parts = envVar.split("=", 2); - - if (parts.length == 2) { -// LOGGER.info("Adding environment variable - Name: {}, Value: {}", parts[0], parts[1]); - environmentVariables.add(new V1EnvVar().name(parts[0]).value(parts[1])); - } else { - LOGGER.warn("Skipping invalid environment variable: {}", envVar); - } + for (String envVar : env) { + String[] parts = envVar.split("=", 2); + if (parts.length == 2) { + environmentVariables.add(new V1EnvVar().name(parts[0]).value(parts[1])); + } else { + LOGGER.warn("Skipping invalid environment variable: {}", envVar); } - } else { - LOGGER.warn("No environment variables provided."); - } - -// LOGGER.info("Adding secret-based environment variable: GITLAB_TOKEN from gitlab-secret"); -// V1EnvVar gitlabTokenEnvVar = new V1EnvVar() -// .name("GITLAB_TOKEN") -// .valueFrom(new V1EnvVarSource() -// .secretKeyRef(new V1SecretKeySelector() -// .name("gitlab-secret") -// .key("GITLAB_TOKEN"))); - - //environmentVariables.add(gitlabTokenEnvVar); - environmentVariables.add(new V1EnvVar().name("GITLAB_USER").value("gitadmin")); - environmentVariables.add(new V1EnvVar().name("GITLAB_EMAIL").value("gitadmin@project-hobbit.eu")); - environmentVariables.add((new V1EnvVar().name("RUN_ON").value("kubernetes"))); - -// for(V1EnvVar envVar : environmentVariables) { -// LOGGER.info("Adding environment variable: {} = {}", envVar.getName(), envVar.getValue()); -// } - - -// LOGGER.info("Determining container type for parent pod: {}", parentPodName); - String parentType = null; - if(parentPodName != null) { - parentType = getContainerType(parentPodName); } + return environmentVariables; + } + /** + * Adds default environment variables to the given list of {@code V1EnvVar} objects. + * + * @param environmentVariables The list of environment variables to which the default variables will be added. + */ + private void addDefaultEnvironmentVariables(List environmentVariables) { + environmentVariables.add(new V1EnvVar().name("GITLAB_USER").value(DEFAULT_GIT_USERNAME)); + environmentVariables.add(new V1EnvVar().name("GITLAB_EMAIL").value(DEFAULT_GIT_EMAIL)); + environmentVariables.add(new V1EnvVar().name("RUN_ON").value(RUN_ON_KUBERNETES_FLAG)); + } + /** + * Determines the type of the container based on the provided container type or the type of its parent pod. + * + * @param containerType The type of the container. If {@code null} or empty, it will be resolved from the parent pod. + * @param parentPodName The name of the parent pod. If {@code null}, no parent resolution will be attempted. + * @return The determined type of the container, or {@code null} if the type cannot be resolved. + */ + private String determineContainerType(String containerType, String parentPodName) { + String parentType = parentPodName != null ? getContainerType(parentPodName) : null; if (containerType == null || containerType.isEmpty()) { - LOGGER.info("No container type provided, attempting to use parent pod's type."); - if (parentType == null) { - LOGGER.error("Unable to resolve parent container type. Returning null to avoid creating pod with no type."); + LOGGER.error("Unable to resolve parent container type. Returning null."); return null; - } else { - LOGGER.info("Using parent container type: {}", parentType); - containerType = parentType; } + containerType = parentType; } + return containerType; + } - - // Create resource requirements if constraints are provided -// LOGGER.info("Creating resource requirements from constraints."); - V1ResourceRequirements resourceRequirements = createResourceRequirementsFromConstraints(constraints); - - // Prepare the container specification -// LOGGER.info("Preparing container specification with name: {}, image: {}", podName, imageName); - V1Container container = new V1Container() - .name(podName) - .image(imageName) - .env(environmentVariables) - .command(command != null ? Arrays.asList(command) : null) - .resources(resourceRequirements); - - // Add security context with NET_RAW capability - + /** + * Creates a security context for a container based on the provided image name. + * + * @param imageName The name of the Docker image for the container. + * @return A {@code V1SecurityContext} object configured with appropriate security settings. If the image name matches + * "earthquakesan/ckan-solr:2.8.0", a less privileged security context is returned. + */ + private V1SecurityContext createSecurityContext(String imageName) { V1SecurityContext securityContext = new V1SecurityContext(); - - // todo it is temporary - if(!imageName.contains("earthquakesan/ckan-solr:2.8.0")) { + if (!imageName.contains("earthquakesan/ckan-solr:2.8.0")) { securityContext.setCapabilities(new V1Capabilities() .addAddItem("NET_RAW").addAddItem("SYS_ADMIN").addAddItem("AUDIT_WRITE")); - //todo make them variable also for pod - securityContext.setRunAsUser(0L); // Replace with your actual user ID - securityContext.setRunAsGroup(0L); // Replace with your actual group ID + securityContext.setRunAsUser(0L); + securityContext.setRunAsGroup(0L); securityContext.allowPrivilegeEscalation(true); - }else { - LOGGER.info("do not use as admin"); + } else { + LOGGER.debug("do not use as admin"); } + return securityContext; + } + /** + * Creates a container specification for a Kubernetes pod based on the provided parameters. + * + * @param podName The name of the pod. + * @param imageName The Docker image name for the container. + * @param environmentVariables A list of {@code V1EnvVar} objects representing the environment variables for the container. + * @param command An array of strings representing the command to run in the container. If {@code null}, no command is set. + * @param constraints A map of resource constraints that will be used to create resource requirements for the container. + * @return A {@code V1Container} object configured with the provided specifications. + */ + private V1Container createContainerSpec(String podName, String imageName, List environmentVariables, + String[] command, Map constraints) { + V1ResourceRequirements resourceRequirements = createResourceRequirementsFromConstraints(constraints); + return new V1Container() + .name(podName) + .image(imageName) + .env(environmentVariables) + .command(command != null ? Arrays.asList(command) : null) + .resources(resourceRequirements) + .securityContext(createSecurityContext(imageName)); + } - - container.setSecurityContext(securityContext); - - -// LOGGER.info("Container specification created successfully."); - - - // Create a volume and volume mount for shared directories -// V1Volume volume = createVolumeForSharedDirectory(); -// V1VolumeMount volumeMount = new V1VolumeMount() -// .name("shared-dir") -// .mountPath("/shared"); - -// container.setVolumeMounts(Collections.singletonList(volumeMount)); - - - // Create the pod specification -// LOGGER.info("Creating pod specification for container: {}", podName); - V1PodSpec podSpec = new V1PodSpec() - .restartPolicy("Never") - .addContainersItem(container) - .addImagePullSecretsItem( - new V1LocalObjectReference() - .name("gitlab-registry-secret") - //todo make this const - ).addImagePullSecretsItem( - new V1LocalObjectReference() - .name("my-dockerhub-secret") - //todo make this const - );; - //.volumes(Collections.singletonList(volume)); - - //todo make them variable also for container - - - V1PodSecurityContext podSecurityContext = new V1PodSecurityContext(); - // todo it is temporary - if(!imageName.contains("earthquakesan/ckan-solr:2.8.0")) { - podSecurityContext.setRunAsUser(0L); - podSecurityContext.setFsGroup(0L); - } - podSpec.setSecurityContext(podSecurityContext); - -// LOGGER.info("Determining node selector based on container type: {} and parent type: {}", containerType, parentType); + /** + * Applies a node selector to the given pod specification based on the container type and its parent type. + * + * @param podSpec The {@code V1PodSpec} object to which the node selector will be applied. + * @param containerType The type of the container. This determines the appropriate node group for the pod. + * @param parentType The type of the parent container or pod. If {@code null}, it is assumed there is no parent. + */ + private void applyNodeSelector(V1PodSpec podSpec, String containerType, String parentType) { if ((((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType)) && Constants.CONTAINER_TYPE_SYSTEM.equals(containerType)) || Constants.CONTAINER_TYPE_SYSTEM.equals(parentType)) { -// LOGGER.info("Setting node selector to 'system-nodes' for container type: {}", containerType); + LOGGER.debug("Setting node selector to 'system-nodes' for container type: {}", containerType); podSpec.nodeSelector(Collections.singletonMap("node-group", "system-nodes")); -// LOGGER.debug("Assigning container type to SYSTEM."); - containerType = Constants.CONTAINER_TYPE_SYSTEM; - } else if (Constants.CONTAINER_TYPE_DATABASE.equals(containerType) && ((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType) || Constants.CONTAINER_TYPE_DATABASE.equals(parentType))) { -// LOGGER.info("Setting node selector to 'benchmark-nodes' for DATABASE container type."); + LOGGER.debug("Setting node selector to 'benchmark-nodes' for DATABASE container type."); podSpec.nodeSelector(Collections.singletonMap("node-group", "benchmark-nodes")); } else if (Constants.CONTAINER_TYPE_BENCHMARK.equals(containerType) && ((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType))) { -// LOGGER.info("Setting node selector to 'benchmark-nodes' for BENCHMARK container type."); + LOGGER.debug("Setting node selector to 'benchmark-nodes' for BENCHMARK container type."); podSpec.nodeSelector(Collections.singletonMap("node-group", "benchmark-nodes")); } else { LOGGER.error("Got a request to create a container with type={} and parentType={}. " - + "No rule found to determine its type. Returning null.", containerType, parentType); - return null; + + "No rule found to determine its type.", containerType, parentType); + // then apply it where you (KUBERNETES) can + podSpec.nodeSelector(null); } + } -// LOGGER.info("Pod specification created successfully."); + /** + * Creates a pod specification with the given container and additional settings based on the image name, container type, and parent type. + * + * @param container The {@code V1Container} object that will be added to the pod. + * @param imageName The name of the Docker image used for the container. + * @param containerType The type of the container. This determines the appropriate node group for the pod. + * @param parentType The type of the parent container or pod. If {@code null}, it is assumed there is no parent. + * @return A {@code V1PodSpec} object configured with the provided specifications and settings. + */ + private V1PodSpec createPodSpec(V1Container container, String imageName, String containerType, String parentType) { + V1PodSpec podSpec = new V1PodSpec() + .restartPolicy("Never") + .addContainersItem(container) + .addImagePullSecretsItem(new V1LocalObjectReference().name("gitlab-registry-secret")) + .addImagePullSecretsItem(new V1LocalObjectReference().name("my-dockerhub-secret")); + if (!imageName.contains("earthquakesan/ckan-solr:2.8.0")) { + V1PodSecurityContext podSecurityContext = new V1PodSecurityContext(); + podSecurityContext.setFsGroup(0L); + podSecurityContext.setRunAsUser(0L); + podSpec.setSecurityContext(podSecurityContext); + } + + applyNodeSelector(podSpec, containerType, parentType); + return podSpec; + } -// LOGGER.info("Creating labels for pod: {}", podName); + /** + * Creates metadata for a Kubernetes pod, including labels that identify the container type and parent pod. + * + * @param podName The name of the pod. + * @param containerType The type of the container. This will be included as a label in the metadata. + * @param parentPodName The name of the parent pod, if any. This will also be included as a label in the metadata. + * @return A {@code V1ObjectMeta} object containing the metadata for the pod. + */ + private V1ObjectMeta createPodMetadata(String podName, String containerType, String parentPodName) { Map labels = new HashMap<>(); labels.put(LABEL_TYPE, containerType); labels.put(LABEL_PARENT, parentPodName); - labels.put("app",podName); + labels.put("app", podName); + return new V1ObjectMeta().name(podName).namespace(nameSpace).labels(labels); + } -// LOGGER.info("Labels set - Type: {}, Parent: {}", containerType, parentPodName); -// Build the pod metadata -// LOGGER.info("Building pod metadata for pod: {} in namespace: {}", podName, nameSpace); - V1ObjectMeta metadata = new V1ObjectMeta() - .name(podName) - .namespace(nameSpace) - .labels(labels); + /** + * Deploys a Kubernetes pod and monitors its startup. + * + * @param pod The {@code V1Pod} object representing the pod to be deployed. + * @param podName The name of the pod. + * @return A string which is the pod IP as a DNS frinely version, or {@code null} if the deployment fails. + */ + private String deployPod(V1Pod pod, String podName) { + try { + GenericKubernetesApi podClient = new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); + V1Pod createdPod = podClient.create(pod).throwsApiException().getObject(); + return monitorPodStartup(podClient, createdPod); + } catch (ApiException e) { + LOGGER.error("Failed to create pod for image. Returning null.", e); + return null; + } + } -// Build the pod object -// LOGGER.info("Constructing the pod object."); - V1Pod pod = new V1Pod() - .metadata(metadata) - .spec(podSpec); -// LOGGER.info("Pod object created successfully: {}", podName); + /** + * Monitors the startup of a Kubernetes pod and waits until it reaches the "Running" phase with an assigned IP. + * If the pod successfully starts, it converts the pod's IP to a DNS ID and notifies registered observers. + * + * @param podClient The Kubernetes API client for managing pods. + * @param createdPod The newly created pod object. + * @return The converted DNS ID of the pod if it reaches the "Running" phase with an assigned IP within the timeout period, or {@code null} otherwise. + */ + private String monitorPodStartup(GenericKubernetesApi podClient, V1Pod createdPod) { + String createdPodName = createdPod.getMetadata().getName(); + + if (createdPodName != null) { + LOGGER.debug("Successfully created pod with name: {}", createdPodName); + long startTime = System.currentTimeMillis(); + V1PodList podList = podClient.list(nameSpace).getObject(); + while (System.currentTimeMillis() - startTime < TimeUnit.SECONDS.toMillis(TIMEOUT_SECONDS)) { + try { + V1Pod targetPod = podList.getItems().stream() + .filter(podTocheck -> createdPodName.equals(podTocheck.getMetadata().getName())) + .findFirst() + .orElse(null); + + LOGGER.debug("Target pod found: {}", targetPod.getMetadata().getName()); + + String podPhase = targetPod.getStatus().getPhase(); + if ("Running".equals(podPhase)) { + String podIP = targetPod.getStatus().getPodIP(); + if (podIP != null && !podIP.isEmpty()) { + String convertedIP = convertIP2dnsId(podIP); + for (ContainerStateObserver observer : containerObservers) { + observer.addObservedContainer(convertedIP); + } + LOGGER.debug("return this converted IP: {}", convertedIP); + return convertedIP; + } + } + LOGGER.trace("pod phase is {}", podPhase); + podList = podClient.list(nameSpace).getObject(); + }catch (Exception ex){ + LOGGER.error(ex.getMessage()); + } + try { + Thread.sleep(POD_PHASE_CHECK_INTERVAL); // Wait for 2 second before checking again + } catch (InterruptedException e) { + LOGGER.error("Thread interrupted while waiting for pod IP: " + e.getMessage()); + } + } - // Deploy the pod - try { - GenericKubernetesApi podClient = - new GenericKubernetesApi<>(V1Pod.class, V1PodList.class, "", "v1", "pods", client); + LOGGER.warn("Timeout reached. Pod {} IP is still not available.", createdPodName); + } else { + LOGGER.error("Failed to create the pod."); + } + LOGGER.warn("return null"); + return null; // Return null if the IP address is not available within the timeout + } + /** + * Creates and deploys a Kubernetes container within a pod. + * + * @param imageName The name of the Docker image to be used for the container. + * @param podName The name of the pod in which the container will run. + * @param containerType The type of the container, which can influence how it is managed or monitored. + * @param parentPodName The name of the parent pod, if any. This helps in organizing and tracking related containers. + * @param env An array of environment variables to be set for the container. + * @param command An array of commands to be executed within the container. + * @param constraints A map of constraints that may affect the deployment or behavior of the container. + * @return POD name which is a DNS friendly pod IP , or {@code null} if it fails. + */ + private String createContainerKub(String imageName, String podName, String containerType, String parentPodName, + String[] env, String[] command, Map constraints) { + imageName = completeImageName(imageName); + LOGGER.debug("Creating container: Image = {}, Pod Name = {}, Container Type = {}, Parent ID = {}", + imageName, podName, containerType, parentPodName); + env = prepareEnvironmentVariables(env); + env = convertAllNamesInENV(env); -// LOGGER.info("Sending request to create pod with name: {}", podName); + List environmentVariables = parseEnvironmentVariables(env); + addDefaultEnvironmentVariables(environmentVariables); - V1Pod createdPod = podClient.create(pod).throwsApiException().getObject(); - String createdPodName = createdPod.getMetadata().getName(); + containerType = determineContainerType(containerType, parentPodName); + if (containerType == null) return null; - if (createdPodName != null) { - LOGGER.info("Successfully created pod with name: {}", createdPodName); + V1Container container = createContainerSpec(podName, imageName, environmentVariables, command, constraints); - // Wait for the IP address to become available - long startTime = System.currentTimeMillis(); - V1PodList podList = podClient.list(nameSpace).getObject(); - while (System.currentTimeMillis() - startTime < TimeUnit.SECONDS.toMillis(TIMEOUT_SECONDS)) { - try { -// LOGGER.info("Waiting for pod {} to start", createdPodName); - V1Pod targetPod = podList.getItems().stream() - .filter(podTocheck -> createdPodName.equals(podTocheck.getMetadata().getName())) - .findFirst() - .orElse(null); - //todo remove this -// if (targetPod == null) { -// LOGGER.error("No pod found with name: {}", createdPod); - // } - -// LOGGER.info("Target pod found: {}", targetPod.getMetadata().getName()); - - String podPhase = targetPod.getStatus().getPhase(); - if ("Running".equals(podPhase)) { - String podIP = targetPod.getStatus().getPodIP(); -// LOGGER.info("Pod IP: {}", podIP); - if (podIP != null && !podIP.isEmpty()) { -// LOGGER.info("Obtained Pod IP: {}", podIP); - String convertedIP = convertIP2dnsId(podIP); -// LOGGER.info("Converted IP: {}", convertedIP); - - for (ContainerStateObserver observer : containerObservers) { -// LOGGER.info("Notifying observer about created pod with name: {}", convertedIP); - observer.addObservedContainer(convertedIP); - } - LOGGER.info("return this converted IP: {}", convertedIP); - return convertedIP; - } - } -// LOGGER.info("pod phase is {}", podPhase); - podList = podClient.list(nameSpace).getObject(); - }catch (Exception ex){ - LOGGER.error(ex.getMessage()); - } - try { - Thread.sleep(2000); // Wait for 1 second before checking again - } catch (InterruptedException e) { - LOGGER.error("Thread interrupted while waiting for pod IP: " + e.getMessage()); - } - } + String parentType = getParentType(parentPodName); - LOGGER.warn("Timeout reached. Pod {} IP is still not available.", createdPodName); - } else { - LOGGER.error("Failed to create the pod."); - } - LOGGER.warn("return null"); - return null; // Return null if the IP address is not available within the timeout - } catch (ApiException e) { - LOGGER.error("Failed to create pod for image: {}. Returning null.", imageName, e); - return null; + V1PodSpec podSpec = createPodSpec(container, imageName, containerType, parentType); + // this is a patch for some situation which container type is null + if ((((parentType == null) || Constants.CONTAINER_TYPE_BENCHMARK.equals(parentType)) + && Constants.CONTAINER_TYPE_SYSTEM.equals(containerType)) + || Constants.CONTAINER_TYPE_SYSTEM.equals(parentType)) { + containerType = Constants.CONTAINER_TYPE_SYSTEM; + LOGGER.info("TTHHIISS IISS HHAAPPEENNEEDD"); } + V1ObjectMeta metadata = createPodMetadata(podName, containerType, parentPodName); + V1Pod pod = new V1Pod().metadata(metadata).spec(podSpec); + return deployPod(pod, podName); + } + + /** + * Retrieves the type of the parent pod. + * + * @param parentPodName The name of the parent pod. + * @return The type of the parent pod, or {@code null} if the parent pod does not exist or its type cannot be determined. + */ + private String getParentType(String parentPodName) { + String parentType = null; + if(parentPodName != null) { + parentType = getContainerType(parentPodName); + } + return parentType; } + /** + * Checks if a given string is a container name and, if so, replaces it with its corresponding IP address. + * + * @param s The input string to be checked and potentially modified. + * @return The original string if it is not a valid container name, or the modified string with the container name replaced by its IP address. + */ private String changeIfItIsContainerName(String s) { String[] parts = s.split("="); if(parts.length !=2 ){ @@ -743,10 +636,22 @@ private String changeIfItIsContainerName(String s) { } } + /** + * Converts a pod IP address to its corresponding DNS identifier. + * + * @param podIP The IP address of the pod. + * @return A string representing the DNS identifier for the pod, formatted as `ip-address.default.pod.cluster.local`. + */ private String convertIP2dnsId(String podIP) { return podIP.replace(".", "-") + ".default.pod.cluster.local"; } + /** + * Maps a DNS identifier back to the pod name by querying the Kubernetes API. + * + * @param ip The DNS identifier of the pod, typically in the format `ip-address.default.pod.cluster.local`. + * @return The name of the pod corresponding to the given IP address, or {@code null} if no matching pod is found. + */ private String mapIp2Name(String ip) { String podIp = ip.replace("-",".").replace(".default.pod.cluster.local", ""); @@ -763,6 +668,12 @@ private String mapIp2Name(String ip) { return targetPod.getMetadata().getName(); } + /** + * Retrieves a Kubernetes pod by its IP address. + * + * @param podIP The IP address of the pod. + * @return The {@link V1Pod} object corresponding to the given IP address, or {@code null} if no matching pod is found. + */ @Override public V1Pod getPod(String podIP) { //LOGGER.info("getPod with {}",podIP); @@ -783,19 +694,12 @@ public V1Pod getPod(String podIP) { } } - -// /** -// * -// * @param parentId -// * @return String of type based on the label of the parent -// */ -// private String resolveContainerType(String parentId) { -// // Logic to resolve container type based on the parentId -// // return null if resolution fails -// V1Pod parent = getPod(parentId); -// return (parent == null) ? null : parent.getMetadata().getLabels().get(LABEL_TYPE); -// } - + /** + * Creates Kubernetes resource requirements based on the provided constraints. + * + * @param constraints A map of constraints that may include memory and CPU limits. + * @return A {@link V1ResourceRequirements} object representing the resource limits for a pod or container. + */ private V1ResourceRequirements createResourceRequirementsFromConstraints(Map constraints) { V1ResourceRequirements resourceRequirements = new V1ResourceRequirements(); Map limits = new HashMap<>(); @@ -820,10 +724,6 @@ private V1ResourceRequirements createResourceRequirementsFromConstraints(Map getContainers(ContainerCriteria criteria) { @Override public String getContainerPodId(String podIp) { - LOGGER.info("getContainerPodId({})", podIp); String podName = mapIp2Name(podIp); LOGGER.info(" Converted PodId to name ({})", podName); From 5a4285b39d6b8da941da2d9fcb4c569b7ffbf501 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Thu, 3 Apr 2025 16:53:01 +0200 Subject: [PATCH 20/52] remove extra unnecessary codes of methods getContainerPodId and getContainerPodName, convert logs to debug and trace --- .../hobbit/controller/PlatformController.java | 12 +-- .../containers/ContainerManager.java | 2 +- .../kubernetes/ContainerManagerImpl.java | 96 ++++++------------- .../ResourceInformationCollectorImpl.java | 15 +-- 4 files changed, 41 insertions(+), 84 deletions(-) diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 05f05784..8dd028ba 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -537,18 +537,14 @@ private String createContainer(StartCommandData data) { pullImage = true; } - - //TODO here it is not container ID , it is container name - // search for this tag to find tha patch #klhadKA5468WDJnlawd - // in corerct version if possible every method should return pod name and convert - String containerId = containerManager.startContainer(data.image, data.type, data.parent, data.environmentVariables, + String containerDNSFriendlyIP_OR_containerIDForDocker = containerManager.startContainer(data.image, data.type, data.parent, data.environmentVariables, data.networkAliases, null, pullImage, null); - LOGGER.info("-->>--- container ID is {}", containerId); - if (containerId == null) { + LOGGER.info("-->>--- container Identifier is {}", containerDNSFriendlyIP_OR_containerIDForDocker); + if (containerDNSFriendlyIP_OR_containerIDForDocker == null) { return null; } else { LOGGER.info("convert ID to PODNAME"); - return containerManager.getContainerPodName(containerId); + return containerDNSFriendlyIP_OR_containerIDForDocker; } } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java index 3436ab21..64f0d429 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerManager.java @@ -230,7 +230,7 @@ public String startContainer(String imageName, String containerType, String pare public Long getContainerPodExitCode(String serviceName) throws ContainerPodException ,InterruptedException; - //TODO maybe remove this method from interface just keeo the usage in implementation for dokcer + //TODO maybe remove this method from interface just keep the usage in implementation for dokcer // /** // * Returns container info // * diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java index eab06c61..fc5aef4b 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java @@ -30,7 +30,7 @@ public class ContainerManagerImpl implements ContainerManager, KubExtendedContai private static final String DEFAULT_GIT_EMAIL = "gitadmin@project-hobbit.eu"; private static final String RUN_ON_KUBERNETES_FLAG = "kubernetes"; private ApiClient client; - //TODO make configable + //TODO do we need to make config able ? private String nameSpace = "default"; private static final long KUBERNETES_POLL_INTERVAL = 5000; // Poll interval in ms @@ -197,7 +197,7 @@ public String startContainer(String imageName, String containerType, String pare if (parentId != null) { if (!parentId.contains(".pod.cluster.")) { LOGGER.debug("wrong parent ID {}",parentId); - parentId = getContainerPodName(parentId); + //parentId = getContainerPodName(parentId); LOGGER.debug("new parent ID is {}",parentId); } } @@ -886,65 +886,23 @@ public List getContainers(ContainerCriteria criteria) { return null; } + @Override public String getContainerPodId(String podIp) { - LOGGER.info("getContainerPodId({})", podIp); - String podName = mapIp2Name(podIp); - LOGGER.info(" Converted PodId to name ({})", podName); -// String podName = mapIp2Name(podIp); - try { - // Fetch the pod information using its name and namespace - CoreV1Api api = new CoreV1Api(client); - V1Pod pod = api.readNamespacedPod(podName, nameSpace, null); - - // Return the Pod's UID (unique identifier) - return pod.getMetadata().getUid(); - } catch (Exception e) { - LOGGER.error("Failed to fetch Pod ID for Pod name: {} in namespace: {}. Error: {}", podName, nameSpace, e); - return null; - } + return podIp; } + // this is the container name which is the dns friendly IP of a pod @Override public String getContainerPodName(String podId) { - try { - // Fetch the list of all pods in the namespace - CoreV1Api api = new CoreV1Api(client); - V1PodList podList = api.listNamespacedPod(nameSpace, null, null, null, null, null, null, null, null, null, false); - - // Search for the pod with the given UID - for (V1Pod pod : podList.getItems()) { - if (pod.getMetadata().getUid().equals(podId)) { - // Return the Pod's name - return mapName2IP(pod.getMetadata().getName()); - } - } - - // If no matching pod is found, return null - LOGGER.warn("No Pod found with ID: {} in namespace: {}", podId, nameSpace); - LOGGER.warn("check if the input was the name of the pod"); - // todo this code should remove search for this to find the source of the error which head to this patch #klhadKA5468WDJnlawd - for (V1Pod pod : podList.getItems()) { - if (pod.getMetadata().getName().equals(podId)) { - // Return the Pod's name - LOGGER.warn("it is a pod name {}", pod.getMetadata().getName()); - return mapName2IP(pod.getMetadata().getName()); - } - } - - LOGGER.warn("(^^) check if it is the converted IP of the pod : {}",podId); - - if(mapIp2Name(podId)!=null){ - LOGGER.info("it is the dns FriendlyPod IP "); - return podId; - } - LOGGER.error("can't get the name of the pod {}",podId); - return null; - } catch (Exception e) { - LOGGER.error("Failed to fetch Pod name for Pod ID: {} in namespace: {}. Error: {}", podId, nameSpace, e); - return null; - } + return podId; } + /** + * Checks if a given name corresponds to an existing pod in the specified namespace. + * + * @param name The name of the pod to check. + * @return {@code true} if the pod exists, otherwise {@code false}. + */ private Boolean isItContainerName(String name) { try { @@ -954,7 +912,7 @@ private Boolean isItContainerName(String name) { .filter(podTocheck -> name.equals(podTocheck.getMetadata().getName())) .findFirst() .orElse(null); - //todo remove this + if (targetPod == null) { return false; } @@ -965,6 +923,12 @@ private Boolean isItContainerName(String name) { } } + /** + * Maps a pod name to its corresponding IP address and converts it to a DNS-compatible format. + * + * @param name The name of the pod. + * @return The converted DNS-compatible IP address of the pod, or null if the pod is not found or in an unexpected state. + */ private String mapName2IP(String name) { try { CoreV1Api api = new CoreV1Api(client); @@ -973,21 +937,17 @@ private String mapName2IP(String name) { .filter(podTocheck -> name.equals(podTocheck.getMetadata().getName())) .findFirst() .orElse(null); - //todo remove this - if (targetPod == null) { - LOGGER.error("!No pod found with name: {}", name); - } - LOGGER.info("Target pod found: {}", targetPod.getMetadata().getName()); + LOGGER.debug("Target pod found: {}", targetPod.getMetadata().getName()); String podPhase = targetPod.getStatus().getPhase(); if ("Running".equals(podPhase)) { String podIP = targetPod.getStatus().getPodIP(); - LOGGER.info("Pod IP: {}", podIP); + LOGGER.debug("Pod IP: {}", podIP); if (podIP != null && !podIP.isEmpty()) { - LOGGER.info("Obtained Pod IP: {}", podIP); + LOGGER.debug("Obtained Pod IP: {}", podIP); String convertedIP = convertIP2dnsId(podIP); - LOGGER.info("Converted IP: {}", convertedIP); + LOGGER.debug("Converted IP: {}", convertedIP); return convertedIP; } } @@ -1016,9 +976,15 @@ public void pullImage(String imageName) { // } + /** + * Retrieves the type of a container within a Kubernetes pod based on its labels. + * + * @param podIP The IP address of the pod. + * @return The type of the container, or null if the pod or its type label is not found. + */ @Override public String getContainerType(String podIP) { - LOGGER.info("getContainerType({})", podIP); + LOGGER.debug("getContainerType({})", podIP); // Logic to retrieve the parent pod based on the podName V1Pod parent = getPod(podIP); @@ -1032,7 +998,7 @@ public String getContainerType(String podIP) { if (containerType == null) { LOGGER.warn("Container type not found in labels for pod: {}", podIP); } else { - LOGGER.info("Resolved container type for pod {}: {}", podIP, containerType); + LOGGER.debug("Resolved container type for pod {}: {}", podIP, containerType); } return containerType; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java index 8fe97e6e..758ce50b 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java @@ -119,17 +119,12 @@ public SetupHardwareInformation getHardwareInformation() { for (V1Node node : nodes) { V1NodeSystemInfo systemInfo = node.getStatus().getNodeInfo(); - LOGGER.info("Kernel Version: " + systemInfo.getKernelVersion()); - LOGGER.info("Machine ID: " + systemInfo.getMachineID()); - LOGGER.info("Container Runtime Version: " + systemInfo.getContainerRuntimeVersion()); - LOGGER.info("Kubelet Version: " + systemInfo.getKubeletVersion()); - LOGGER.info("KubeProxy Version: " + systemInfo.getKubeProxyVersion()); + LOGGER.debug("Kernel Version: " + systemInfo.getKernelVersion()); + LOGGER.debug("Machine ID: " + systemInfo.getMachineID()); + LOGGER.debug("Container Runtime Version: " + systemInfo.getContainerRuntimeVersion()); + LOGGER.debug("Kubelet Version: " + systemInfo.getKubeletVersion()); + LOGGER.debug("KubeProxy Version: " + systemInfo.getKubeProxyVersion()); - - //TODO test - - String nodeName = node.getMetadata().getName(); - LOGGER.info("nodeName: " + nodeName); Map capacity = node.getStatus().getCapacity(); // Map allocatable = node.getStatus().getAllocatable(); From 8b64ec9960683b18b930895bc28bf9d84bd1a2cb Mon Sep 17 00:00:00 2001 From: farshad68 Date: Fri, 4 Apr 2025 14:34:09 +0200 Subject: [PATCH 21/52] minor changes --- platform-controller/pom.xml | 8 --- .../hobbit/controller/ExperimentManager.java | 39 ++++++------ .../hobbit/controller/PlatformController.java | 61 +++++++++---------- 3 files changed, 47 insertions(+), 61 deletions(-) diff --git a/platform-controller/pom.xml b/platform-controller/pom.xml index a6443ed7..91c86ead 100644 --- a/platform-controller/pom.xml +++ b/platform-controller/pom.xml @@ -30,7 +30,6 @@ 18.0.0 - @@ -122,13 +121,6 @@ client-java ${kubernetes-client.version} - - - - - - - diff --git a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java index 36cdcad5..b722ad99 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java @@ -168,7 +168,6 @@ public void run() { * experiment waiting in the queue. */ public void createNextExperiment() { - //LOGGER.info("create next experiment"); synchronized (experimentMutex) { try { // if there is no benchmark running, the queue has been @@ -189,7 +188,7 @@ public void createNextExperiment() { LOGGER.debug("There is no experiment to start."); return; } - LOGGER.info("Creating next experiment " + config.id + " with benchmark " + config.benchmarkUri + LOGGER.debug("Creating next experiment " + config.id + " with benchmark " + config.benchmarkUri + " and system " + config.systemUri + " to the queue."); experimentStatus = new ExperimentStatus(config, HobbitExperiments.getExperimentURI(config.id)); @@ -198,13 +197,13 @@ public void createNextExperiment() { BenchmarkMetaData benchmark = controller.imageManager().getBenchmark(config.benchmarkUri); if(benchmark==null){ - LOGGER.info("There is no benchmark found for {}",config.benchmarkUri); + LOGGER.debug("There is no benchmark found for {}",config.benchmarkUri); }else{ - LOGGER.info("Benchmark found for {}",config.benchmarkUri); - LOGGER.info("Benchmark name is {}",benchmark.getName()); - LOGGER.info("Benchmark description is {}",benchmark.getDescription()); - LOGGER.info("Benchmark main image is {}",benchmark.getMainImage()); - LOGGER.info("Benchmark uri is {}",benchmark.getUri()); + LOGGER.trace("Benchmark found for {}",config.benchmarkUri); + LOGGER.trace("Benchmark name is {}",benchmark.getName()); + LOGGER.trace("Benchmark description is {}",benchmark.getDescription()); + LOGGER.trace("Benchmark main image is {}",benchmark.getMainImage()); + LOGGER.trace("Benchmark uri is {}",benchmark.getUri()); } if ((benchmark == null) || (benchmark.mainImage == null)) { @@ -217,9 +216,9 @@ public void createNextExperiment() { SystemMetaData system = controller.imageManager().getSystem(config.systemUri); if(system==null){ - LOGGER.info("There is no system found for system " + config.systemUri); + LOGGER.debug("There is no system found for system " + config.systemUri); }else{ - LOGGER.info("System found for benchmark " + config.systemUri); + LOGGER.debug("System found for benchmark " + config.systemUri); } if ((system == null) || (system.mainImage == null)) { // Think about reusing the existing object created above @@ -277,7 +276,7 @@ public void createNextExperiment() { Constants.BENCHMARK_PARAMETERS_MODEL_KEY + "=" + config.serializedBenchParams, Constants.SYSTEM_URI_KEY + "=" + config.systemUri }, null, null, config.id, Collections.emptyMap()); - LOGGER.info("^^> containerID is {}" , containerId); + LOGGER.trace(" containerID is {}" , containerId); if (containerId == null) { experimentStatus.addError(HobbitErrors.BenchmarkCreationError); throw new Exception("Couldn't create benchmark controller " + config.benchmarkUri); @@ -297,7 +296,7 @@ public void createNextExperiment() { Constants.HOBBIT_SESSION_ID_KEY + "=" + config.id, Constants.SYSTEM_PARAMETERS_MODEL_KEY + "=" + serializedSystemParams }, null, null, config.id, getHardwareConstraints(config.serializedBenchParams)); - LOGGER.info("^^^> containerID is {}" , containerId); + LOGGER.debug(" containerID is {}" , containerId); if (containerId == null) { LOGGER.error("Couldn't start the system. Trying to cancel the benchmark."); forceBenchmarkTerminate_unsecured(HobbitErrors.SystemCreationError); @@ -342,29 +341,25 @@ protected static Map getHardwareConstraints(String serializedBen } protected void createRabbitMQ(ExperimentConfiguration config) throws Exception { - LOGGER.info("create RabbitMQ"); + LOGGER.debug("create RabbitMQ"); String rabbitMQAddress = hobbitConfig.getString(RABBIT_MQ_EXPERIMENTS_HOST_NAME_KEY, (String) null); - LOGGER.info("Using the newly started RabbitMQ for the experiment: {}", rabbitMQAddress); + LOGGER.trace("Using the newly started RabbitMQ for the experiment: {}", rabbitMQAddress); if (rabbitMQAddress == null) { - LOGGER.info("Starting new RabbitMQ for the experiment..."); + LOGGER.debug("Starting new RabbitMQ for the experiment..."); String rabbitMQPOD = controller.containerManager.startContainer(hobbitConfig.getString(RABBIT_IMAGE_ENV_KEY), Constants.CONTAINER_TYPE_BENCHMARK, null, new String[] {}, null, null, config.id, Collections.emptyMap()); - //LOGGER.info("Starting service for RabbitMQ for the pod: {}", rabbitMQPOD); - //Map ports = new HashMap<>(); - //ports.put(5672,5672); - //rabbitMQAddress = controller.containerManager.startService(rabbitMQPOD,false,ports ); rabbitMQAddress = rabbitMQPOD; - LOGGER.info("Service initialized for RabbitMQ with this name: {}", rabbitMQAddress); + LOGGER.debug("Service initialized for RabbitMQ with this name: {}", rabbitMQAddress); if (rabbitMQAddress == null) { experimentStatus.addError(HobbitErrors.UnexpectedError); // FIXME throw new Exception("Couldn't start new RabbitMQ for the experiment"); } experimentStatus.setRootContainer(rabbitMQAddress); - LOGGER.info("Using the newly started RabbitMQ for the experiment: {}", rabbitMQAddress); + LOGGER.debug("Using the newly started RabbitMQ for the experiment: {}", rabbitMQAddress); } else { - LOGGER.info("Using the configured RabbitMQ for the experiment: {}", rabbitMQAddress); + LOGGER.debug( "Using the configured RabbitMQ for the experiment: {}", rabbitMQAddress); } experimentStatus.setRabbitMQContainer(rabbitMQAddress); diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 8dd028ba..43d6fc29 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -38,7 +38,6 @@ import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.Configuration; import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.util.ClientBuilder; import io.kubernetes.client.util.Config; import org.apache.commons.configuration2.EnvironmentConfiguration; import org.apache.commons.io.IOUtils; @@ -169,7 +168,8 @@ public class PlatformController extends AbstractComponent implements ContainerTe */ protected DataSender sender2Analysis; /** - * A manager for Docker containers. + * A manager for Kubernetes/Docker containers. + * TODO : is it good way ? */ protected KubExtendedContainerManager containerManager; /** @@ -244,7 +244,7 @@ public PlatformController(ExperimentManager expManager) { public void init() throws Exception { // First initialize the super class super.init(); - LOGGER.info("Platform controller initialization started."); + LOGGER.debug("Platform controller initialization started."); hobbitConfig = new HobbitConfiguration(); hobbitConfig.addConfiguration(new EnvironmentConfiguration()); @@ -253,7 +253,7 @@ public void init() throws Exception { // containers) // Only for prod mode - LOGGER.info("configuration initialized."); + LOGGER.debug("configuration initialized."); // Config.fromConfig("/var/run/secrets/kubernetes.io/serviceaccount/token"); //ApiClient client = Configuration.get(); @@ -263,7 +263,7 @@ public void init() throws Exception { client.setWriteTimeout(TIMEOUT_MILLISECONDS); Configuration.setDefaultApiClient(client); - LOGGER.info("kub client initialized."); + LOGGER.debug("kub client initialized."); clusterManager = new ClusterManagerImpl(client); @@ -277,7 +277,7 @@ public void init() throws Exception { // create container manager containerManager = new ContainerManagerImpl(client); - LOGGER.info("Container manager initialized."); + LOGGER.debug("Container manager initialized."); // Create container observer (polls status every 5s) containerObserver = new ContainerStateObserverImpl(containerManager, 5 * 1000); containerObserver.addTerminationCallback(this); @@ -291,17 +291,17 @@ public void init() throws Exception { List managers = new ArrayList(); if (System.getenv().containsKey(LOCAL_METADATA_DIR_KEY)) { String metadataDirectory = System.getenv().get(LOCAL_METADATA_DIR_KEY); - LOGGER.info("Local metadata directory: {}", metadataDirectory); + LOGGER.debug("Local metadata directory: {}", metadataDirectory); managers.add(new FileBasedImageManager(metadataDirectory)); } else { - LOGGER.info("Using default directory for local metadata."); + LOGGER.debug("Using default directory for local metadata."); managers.add(new FileBasedImageManager()); } boolean useGitlab = true; if (System.getenv().containsKey(USE_GITLAB_KEY)) { try { useGitlab = Boolean.parseBoolean(System.getenv().get(USE_GITLAB_KEY)); - LOGGER.info("Using git lab enabled"); + LOGGER.debug("Using git lab enabled"); } catch (Exception e) { LOGGER.error("Couldn't parse value of " + USE_GITLAB_KEY + ". It will be ignored."); } @@ -340,14 +340,14 @@ public void run() { } }, PUBLISH_CHALLENGES, PUBLISH_CHALLENGES); - LOGGER.info("Platform controller initialized."); + LOGGER.debug("Platform controller initialized."); } /** * This method sets the RabbitMQ connector for the command queue. */ public void setExpRabbitMQConnector(RabbitMQConnector rabbitMQConnector) { - LOGGER.info("Setting experiment's RabbitMQ connector for the command queue: {}", rabbitMQConnector); + LOGGER.debug("Setting experiment's RabbitMQ connector for the command queue: {}", rabbitMQConnector); assert this.rabbitMQConnector == null : "RabbitMQ connector should be null"; this.rabbitMQConnector = rabbitMQConnector; } @@ -358,7 +358,7 @@ public void setExpRabbitMQConnector(RabbitMQConnector rabbitMQConnector) { * @throws Exception */ public void closeExpRabbitMQConnector() { - LOGGER.info("Closing experiment's RabbitMQ connector for the command queue: {}", rabbitMQConnector); + LOGGER.debug("Closing experiment's RabbitMQ connector for the command queue: {}", rabbitMQConnector); if(rabbitMQConnector != null) { IOUtils.closeQuietly(rabbitMQConnector); rabbitMQConnector = null; @@ -392,17 +392,16 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas replyTo = props.getReplyTo(); } - //if (LOGGER.isDebugEnabled()) { - if (true) { + if (LOGGER.isDebugEnabled()) { LOGGER.info("received command: session={}, command={}, data={}", sessionId, Commands.toString(command), data != null ? RabbitMQUtils.readString(data) : "null"); } else { - LOGGER.info("received command: session={}, command={}", sessionId, Commands.toString(command)); + LOGGER.debug("received command: session={}, command={}", sessionId, Commands.toString(command)); } // Determine the command switch (command) { case Commands.DOCKER_CONTAINER_START: { - LOGGER.info("Starting container with name: {}", sessionId); + LOGGER.debug("Starting container with name: {}", sessionId); StartCommandData startParams = null; String containerName = ""; if (expManager.isExpRunning(sessionId)) { @@ -410,7 +409,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas startParams = GsonUtils.deserializeObjectWithGson(gson, data, StartCommandData.class, false); // trigger creation containerName = createContainer(startParams); - LOGGER.info("Starting container with name: {}", containerName); + LOGGER.debug("Starting container with name: {}", containerName); } else { LOGGER.error( "Got a request to start a container for experiment \"{}\" which is either not running or was already stopped. Returning null.", @@ -439,7 +438,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas break; } case Commands.DOCKER_CONTAINER_STOP: { - LOGGER.info("cmd-Stopping container, sessionId : {}", sessionId); + LOGGER.debug("cmd-Stopping container, sessionId : {}", sessionId); // get containerId from params StopCommandData stopParams = GsonUtils.deserializeObjectWithGson(gson, data, StopCommandData.class, false); // trigger stop @@ -447,17 +446,17 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas break; } case Commands.BENCHMARK_READY_SIGNAL: { - LOGGER.info("Ready signal: {}", sessionId); + LOGGER.debug("Ready signal: {}", sessionId); expManager.systemOrBenchmarkReady(false, sessionId); break; } case Commands.SYSTEM_READY_SIGNAL: { - LOGGER.info("System Ready signal: {}", sessionId); + LOGGER.debug("System Ready signal: {}", sessionId); expManager.systemOrBenchmarkReady(true, sessionId); break; } case Commands.TASK_GENERATION_FINISHED: { - LOGGER.info("Task generator finish: {}", sessionId); + LOGGER.debug("Task generator finish: {}", sessionId); expManager.taskGenFinished(sessionId); break; } @@ -473,7 +472,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas // FIXME use the session id to make sure that only containers of this session // are observed ResourceUsageInformation resUsage = resInfoCollector.getSystemUsageInformation(); - LOGGER.info("Returning usage information: {}", resUsage != null ? resUsage.toString() : "null"); + LOGGER.debug("Returning usage information: {}", resUsage != null ? resUsage.toString() : "null"); if (replyTo != null) { byte[] response; if (resUsage != null) { @@ -524,7 +523,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas * @return the name of the created container */ private String createContainer(StartCommandData data) { - LOGGER.info("create Container in platform controller {}",data.toString()); + LOGGER.debug("create Container in platform controller {}",data.toString()); //String parentId = containerManager.getContainerPodId(data.parent); if ((data.parent == null) && (CONTAINER_PARENT_CHECK)) { LOGGER.error("Couldn't create container because the parent \"{}\" is not known.", data.parent); @@ -539,11 +538,11 @@ private String createContainer(StartCommandData data) { String containerDNSFriendlyIP_OR_containerIDForDocker = containerManager.startContainer(data.image, data.type, data.parent, data.environmentVariables, data.networkAliases, null, pullImage, null); - LOGGER.info("-->>--- container Identifier is {}", containerDNSFriendlyIP_OR_containerIDForDocker); + LOGGER.debug("container Identifier is {}", containerDNSFriendlyIP_OR_containerIDForDocker); if (containerDNSFriendlyIP_OR_containerIDForDocker == null) { return null; } else { - LOGGER.info("convert ID to PODNAME"); + LOGGER.debug("convert ID to PODNAME"); return containerDNSFriendlyIP_OR_containerIDForDocker; } } @@ -554,7 +553,7 @@ private String createContainer(StartCommandData data) { * @param containerName name of the container that should be stopped */ public void stopContainer(String containerName) { - LOGGER.info("Stopping container with name: {}", containerName); + LOGGER.debug("Stopping container with name: {}", containerName); //String containerId = containerManager.getContainerPodId(containerName); containerManager.removeContainer(containerName); } @@ -567,7 +566,7 @@ public void run() throws Exception { @Override public void notifyTermination(String containerId, long exitCode) { - LOGGER.info("Container " + containerId + " stopped with exitCode=" + exitCode); + LOGGER.debug("Container " + containerId + " stopped with exitCode=" + exitCode); // Check whether this container was part of an experiment expManager.notifyTermination(containerId, exitCode); // Remove the container from the observer @@ -767,7 +766,7 @@ public void handleFrontEndCmd(byte bytes[], String replyTo, BasicProperties repl case FrontEndApiCommands.GET_SYSTEMS_OF_USER: { // get the user name String email = RabbitMQUtils.readString(buffer); - LOGGER.info("Loading systems of user \"{}\"", email); + LOGGER.debug("Loading systems of user \"{}\"", email); response = RabbitMQUtils.writeString(gson.toJson(imageManager.getSystemsOfUser(email))); break; } @@ -834,7 +833,7 @@ private void handleErrorReport(String sessionId, ErrorData errorData) { LOGGER.error("Got an error report without container ID. It will be ignored."); return; } - LOGGER.info("handle error report for session \"{}\" and container Id {}", sessionId,errorData.getContainerId()); + LOGGER.debug("handle error report for session \"{}\" and container Id {}", sessionId,errorData.getContainerId()); String containerType = containerManager.getContainerType(errorData.getContainerId()); boolean isBenchmarkContainer = Constants.CONTAINER_TYPE_BENCHMARK.equals(containerType); if (!isBenchmarkContainer && (!Constants.CONTAINER_TYPE_SYSTEM.equals(containerType))) { @@ -919,7 +918,7 @@ private void executeChallengeExperiments(String challengeUri) { } // add to queue for (ExperimentConfiguration ex : experiments) { - LOGGER.info("Adding experiment " + ex.id + " with benchmark " + ex.benchmarkUri + " and system " + LOGGER.debug("Adding experiment " + ex.id + " with benchmark " + ex.benchmarkUri + " and system " + ex.systemUri + " to the queue."); queue.add(ex); } @@ -935,7 +934,7 @@ private void executeChallengeExperiments(String challengeUri) { */ protected static synchronized void scheduleDateOfNextExecution(StorageServiceClient storage, String challengeUri, Calendar now) { - LOGGER.info("Scheduling dateOfNextExecution for challenge {}...", challengeUri); + LOGGER.debug("Scheduling dateOfNextExecution for challenge {}...", challengeUri); String query = SparqlQueries.getRepeatableChallengeInfoQuery(challengeUri, Constants.CHALLENGE_DEFINITION_GRAPH_URI); Model challengeModel = storage.sendConstructQuery(query); From 68ee813db06545f6391f1cb093db15308256255f Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 7 Apr 2025 11:33:00 +0200 Subject: [PATCH 22/52] split the code of platform controller init between docker and kubernetes version --- .../hobbit/controller/PlatformController.java | 80 ++++++++++++------- .../controller/containers/ClusterManager.java | 1 - 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 43d6fc29..552b6098 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -35,12 +35,15 @@ import java.util.TimerTask; import java.util.concurrent.Semaphore; +import com.spotify.docker.client.exceptions.DockerCertificateException; +import com.spotify.docker.client.exceptions.DockerException; import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.Configuration; import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.util.Config; import org.apache.commons.configuration2.EnvironmentConfiguration; import org.apache.commons.io.IOUtils; +import org.apache.jena.base.Sys; import org.apache.jena.query.Dataset; import org.apache.jena.query.DatasetFactory; import org.apache.jena.query.QueryExecution; @@ -54,14 +57,6 @@ import org.hobbit.controller.analyze.ExperimentAnalyzer; import org.hobbit.controller.containers.*; import org.hobbit.controller.data.ExperimentConfiguration; -//import org.hobbit.controller.containers.docker.ClusterManagerImpl; -import org.hobbit.controller.containers.kubernetes.ClusterManagerImpl; -//import org.hobbit.controller.containers.docker.ContainerManagerImpl; -import org.hobbit.controller.containers.kubernetes.ContainerManagerImpl; -//import org.hobbit.controller.containers.docker.ContainerStateObserverImpl; -import org.hobbit.controller.containers.kubernetes.ContainerStateObserverImpl; -//import org.hobbit.controller.containers.docker.ResourceInformationCollectorImpl; -import org.hobbit.controller.containers.kubernetes.ResourceInformationCollectorImpl; import org.hobbit.controller.front.FrontEndApiHandler; import org.hobbit.controller.queue.ExperimentQueue; import org.hobbit.controller.queue.ExperimentQueueImpl; @@ -171,7 +166,7 @@ public class PlatformController extends AbstractComponent implements ContainerTe * A manager for Kubernetes/Docker containers. * TODO : is it good way ? */ - protected KubExtendedContainerManager containerManager; + protected ContainerManager containerManager; /** * The observer of docker containers. */ @@ -240,23 +235,13 @@ public PlatformController(ExperimentManager expManager) { expManager.setController(this); } - @Override - public void init() throws Exception { - // First initialize the super class - super.init(); - LOGGER.debug("Platform controller initialization started."); + private void kubernetsInit() throws IOException { + LOGGER.info("Initializing Kubernetes version"); hobbitConfig = new HobbitConfiguration(); hobbitConfig.addConfiguration(new EnvironmentConfiguration()); - - // Set task history limit for swarm cluster to 0 (will remove all terminated - // containers) - // Only for prod mode - LOGGER.debug("configuration initialized."); - // Config.fromConfig("/var/run/secrets/kubernetes.io/serviceaccount/token"); - //ApiClient client = Configuration.get(); ApiClient client = Config.defaultClient(); client.setConnectTimeout(TIMEOUT_MILLISECONDS); client.setReadTimeout(TIMEOUT_MILLISECONDS); @@ -265,28 +250,69 @@ public void init() throws Exception { LOGGER.debug("kub client initialized."); + clusterManager = new org.hobbit.controller.containers.kubernetes.ClusterManagerImpl(client); + containerManager = new org.hobbit.controller.containers.kubernetes.ContainerManagerImpl(client); + LOGGER.debug("Container manager initialized."); + // Create container observer (polls status every 5s) + containerObserver = new org.hobbit.controller.containers.kubernetes.ContainerStateObserverImpl((KubExtendedContainerManager)containerManager, 5 * 1000); + containerObserver.addTerminationCallback(this); + // Tell the manager to add container to the observer + containerManager.addContainerObserver(containerObserver); + resInfoCollector = new org.hobbit.controller.containers.kubernetes.ResourceInformationCollectorImpl(containerManager,client,new CoreV1Api(client)); - clusterManager = new ClusterManagerImpl(client); + containerObserver.startObserving(); + LOGGER.debug("Container observer initialized."); + } + + private void dokcerswarmInit() throws Exception { + LOGGER.info("Initializing Docker swarm version"); + hobbitConfig = new HobbitConfiguration(); + hobbitConfig.addConfiguration(new EnvironmentConfiguration()); + + // Set task history limit for swarm cluster to 0 (will remove all terminated + // containers) + // Only for prod mode + + LOGGER.debug("configuration initialized."); + + clusterManager = new org.hobbit.controller.containers.docker.ClusterManagerImpl(); if (DEPLOY_ENV.equals(DEPLOY_ENV_TESTING) || DEPLOY_ENV.equals(DEPLOY_ENV_DEVELOP)) { LOGGER.debug("Ignoring task history limit parameter. Will remain default (run 'docker info' for details)."); } else { LOGGER.debug( - "Production mode. Setting task history limit to 0. All terminated containers will be removed."); + "Production mode. Setting task history limit to 0. All terminated containers will be removed."); clusterManager.setTaskHistoryLimit(0); } - // create container manager - containerManager = new ContainerManagerImpl(client); + containerManager = new org.hobbit.controller.containers.docker.ContainerManagerImpl(); LOGGER.debug("Container manager initialized."); // Create container observer (polls status every 5s) - containerObserver = new ContainerStateObserverImpl(containerManager, 5 * 1000); + containerObserver = new org.hobbit.controller.containers.docker.ContainerStateObserverImpl(containerManager, 5 * 1000); containerObserver.addTerminationCallback(this); // Tell the manager to add container to the observer containerManager.addContainerObserver(containerObserver); - resInfoCollector = new ResourceInformationCollectorImpl(containerManager,client,new CoreV1Api(client)); + resInfoCollector = new org.hobbit.controller.containers.docker.ResourceInformationCollectorImpl(containerManager); containerObserver.startObserving(); LOGGER.debug("Container observer initialized."); + } + @Override + public void init() throws Exception { + // First initialize the super class + super.init(); + LOGGER.debug("Platform controller initialization started."); + + switch (System.getenv("RUN_ON").toLowerCase()){ + case "docker": + dokcerswarmInit(); + break; + case "kubernetes": + kubernetsInit(); + break; + default: + kubernetsInit(); + break; + } List managers = new ArrayList(); if (System.getenv().containsKey(LOCAL_METADATA_DIR_KEY)) { diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/ClusterManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ClusterManager.java index a1f29e36..5b21db8a 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/ClusterManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ClusterManager.java @@ -1,7 +1,6 @@ package org.hobbit.controller.containers; import com.spotify.docker.client.exceptions.DockerException; -import com.spotify.docker.client.messages.Info; /** * This interface is implemented by classes that can be used to manage and From e3db0391247ca08e8cd3ab09043347dbe1811362 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 7 Apr 2025 14:14:22 +0200 Subject: [PATCH 23/52] remove extra logs --- platform-storage/storage-service/Dockerfile | 27 ----------------- .../storage/service/StorageService.java | 30 +------------------ 2 files changed, 1 insertion(+), 56 deletions(-) diff --git a/platform-storage/storage-service/Dockerfile b/platform-storage/storage-service/Dockerfile index 652a97a1..d8ae9ae3 100644 --- a/platform-storage/storage-service/Dockerfile +++ b/platform-storage/storage-service/Dockerfile @@ -1,40 +1,13 @@ -#FROM maven:3-eclipse-temurin-11 AS build -#WORKDIR /usr/src/hobbit-platform -#COPY parent-pom/pom.xml parent-pom/ -#RUN mvn --file parent-pom -Dmaven.test.skip=true install -#ARG project=platform-storage/storage-service -#COPY ${project}/pom.xml ${project}/ -#RUN mvn --file ${project} dependency:go-offline -#COPY ${project}/src ${project}/src -#RUN mvn --file ${project} -Dmaven.test.skip=true package -# -#FROM eclipse-temurin:11 -#COPY --from=build /usr/src/hobbit-platform/platform-storage/storage-service/target/storage-service.jar . -#CMD ["java", "-cp", "storage-service.jar", "org.hobbit.core.run.ComponentStarter", "org.hobbit.storage.service.StorageService"] - - -# ---- Build Stage ---- FROM maven:3-eclipse-temurin-11 AS build - -# Set the working directory WORKDIR /usr/src/hobbit-platform - -# Copy parent POM COPY parent-pom/pom.xml parent-pom/ RUN mvn --file parent-pom -Dmaven.test.skip=true install - -# Copy project files and build WORKDIR /usr/src/hobbit-platform/platform-storage/storage-service COPY platform-storage/storage-service/pom.xml . RUN mvn dependency:go-offline - COPY platform-storage/storage-service/src src RUN mvn -Dmaven.test.skip=true package - -# ---- Runtime Stage ---- FROM eclipse-temurin:11 - WORKDIR /app COPY --from=build /usr/src/hobbit-platform/platform-storage/storage-service/target/storage-service.jar . - CMD ["java", "-cp", "storage-service.jar", "org.hobbit.core.run.ComponentStarter", "org.hobbit.storage.service.StorageService"] diff --git a/platform-storage/storage-service/src/main/java/org/hobbit/storage/service/StorageService.java b/platform-storage/storage-service/src/main/java/org/hobbit/storage/service/StorageService.java index 922d343e..bd5f64e4 100644 --- a/platform-storage/storage-service/src/main/java/org/hobbit/storage/service/StorageService.java +++ b/platform-storage/storage-service/src/main/java/org/hobbit/storage/service/StorageService.java @@ -216,53 +216,29 @@ else if (query.isAskType()) @Override public void init() throws Exception { - LOGGER.info("Initializing storage service..."); - - // Call parent initialization - LOGGER.debug("Calling super.init()"); super.init(); try { - LOGGER.debug("Fetching SPARQL endpoint URL from environment variables..."); sparqlEndpointUrl = getEnvValue(SPARQL_ENDPOINT_URL_KEY, true) ;//+ "-auth"; - LOGGER.info("SPARQL Endpoint URL: {}", sparqlEndpointUrl); - - LOGGER.debug("Fetching SPARQL endpoint username..."); String username = getEnvValue(SPARQL_ENDPOINT_USERNAME_KEY, true); - LOGGER.info("SPARQL Endpoint Username: {}", username); - - LOGGER.debug("Fetching SPARQL endpoint password..."); String password = getEnvValue(SPARQL_ENDPOINT_PASSWORD_KEY, true); - LOGGER.info("SPARQL Endpoint Password: {}", password); // ⚠️ Consider removing in production - - LOGGER.debug("Creating credentials object..."); credentials = new UsernamePasswordCredentials(username, password); - LOGGER.debug("Building HTTP client with credentials..."); HttpClientBuilder clientBuilder = HttpClientBuilder.create(); clientBuilder.setDefaultCredentialsProvider(this); client = clientBuilder.build(); - LOGGER.info("HTTP client successfully built."); - LOGGER.debug("Initializing QueryExecutionFactory..."); queryExecFactory = new QueryExecutionFactoryHttp(sparqlEndpointUrl, new DatasetDescription(), client); queryExecFactory = new QueryExecutionFactoryPaginated(queryExecFactory, MAX_RESULT_SIZE); - LOGGER.info("QueryExecutionFactory initialized with pagination and max result size: {}", MAX_RESULT_SIZE); - LOGGER.debug("Creating default RabbitMQ queue with name: {}", QUEUE_NAME); queue = incomingDataQueueFactory.createDefaultRabbitQueue(QUEUE_NAME); - LOGGER.debug("Setting channel QoS with max parallel requests: {}", MAX_NUMBER_PARALLEL_REQUESTS); queue.channel.basicQos(MAX_NUMBER_PARALLEL_REQUESTS); - LOGGER.debug("Initializing QueueingConsumer for queue: {}", QUEUE_NAME); consumer = new QueueingConsumer(queue.channel); - LOGGER.info("Starting to consume messages from queue: {}", QUEUE_NAME); queue.channel.basicConsume(QUEUE_NAME, false, consumer); - LOGGER.info("Storage service initialization completed successfully."); - } catch (Exception e) { LOGGER.error("Error during initialization: ", e); throw e; // Re-throw after logging @@ -271,12 +247,10 @@ public void init() throws Exception { @Override public void run() throws Exception { - LOGGER.info("[Storage Service] Awaiting Storage Service requests "+MAX_NUMBER_PARALLEL_REQUESTS); + LOGGER.info("[Storage Service] Awaiting Storage Service requests "); ExecutorService executor = Executors.newFixedThreadPool(MAX_NUMBER_PARALLEL_REQUESTS); - LOGGER.info("executor is ready"+ MAX_NUMBER_PARALLEL_REQUESTS); Delivery delivery; while (true) { - LOGGER.info("Let's wait for a delivery for 60 seconds"); delivery = null; // Let's wait for a delivery for 60 seconds try { @@ -285,10 +259,8 @@ public void run() throws Exception { // interrupted; just continue } if (delivery != null) { - LOGGER.info("delivery is not null"); executor.execute(new DeliveryProcessing(this, delivery, queue)); } else { - LOGGER.info("delivery is null"); // This would be the place at which we could react to signals, e.g., terminate // the service if needed. } From accfcbf45d6fc1c3c6c4fcdc7c007095817a6309 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 7 Apr 2025 16:13:31 +0200 Subject: [PATCH 24/52] add some javadoc --- .../hobbit/controller/ExperimentManager.java | 3 +- .../hobbit/controller/PlatformController.java | 16 ++++++++-- .../containers/GitlabBasedImageManager.java | 16 ++-------- .../kubernetes/ClusterManagerImpl.java | 31 ++++++++++++++++++- .../kubernetes/ContainerManagerImpl.java | 7 +++++ .../ContainerStateObserverImpl.java | 7 ++++- .../ContainerTerminationCallbackImpl.java | 22 ------------- .../ResourceInformationCollectorImpl.java | 13 ++++++-- 8 files changed, 71 insertions(+), 44 deletions(-) delete mode 100644 platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerTerminationCallbackImpl.java diff --git a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java index b722ad99..e59de130 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java @@ -346,10 +346,9 @@ protected void createRabbitMQ(ExperimentConfiguration config) throws Exception { LOGGER.trace("Using the newly started RabbitMQ for the experiment: {}", rabbitMQAddress); if (rabbitMQAddress == null) { LOGGER.debug("Starting new RabbitMQ for the experiment..."); - String rabbitMQPOD = controller.containerManager.startContainer(hobbitConfig.getString(RABBIT_IMAGE_ENV_KEY), + rabbitMQAddress = controller.containerManager.startContainer(hobbitConfig.getString(RABBIT_IMAGE_ENV_KEY), Constants.CONTAINER_TYPE_BENCHMARK, null, new String[] {}, null, null, config.id, Collections.emptyMap()); - rabbitMQAddress = rabbitMQPOD; LOGGER.debug("Service initialized for RabbitMQ with this name: {}", rabbitMQAddress); if (rabbitMQAddress == null) { experimentStatus.addError(HobbitErrors.UnexpectedError); // FIXME diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 552b6098..da0fd97c 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -580,8 +580,20 @@ private String createContainer(StartCommandData data) { */ public void stopContainer(String containerName) { LOGGER.debug("Stopping container with name: {}", containerName); - //String containerId = containerManager.getContainerPodId(containerName); - containerManager.removeContainer(containerName); + switch (System.getenv("RUN_ON").toLowerCase()){ + case "kubernetes": + containerManager.removeContainer(containerName); + break; + case "docker": + String containerId = containerManager.getContainerPodId(containerName); + containerManager.removeContainer(containerId); + break; + default: + containerManager.removeContainer(containerName); + break; + } + + } @Override diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/GitlabBasedImageManager.java b/platform-controller/src/main/java/org/hobbit/controller/containers/GitlabBasedImageManager.java index 848b7839..21f446ca 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/GitlabBasedImageManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/GitlabBasedImageManager.java @@ -54,28 +54,16 @@ public void runWhenGitlabIsReady(Runnable r) { @Override protected List getUncheckedBenchmarks() { - LOGGER.info("Getting unchecked systems for benchmarks"); - List benchmarks = gitlab.getAllProjects().parallelStream().filter(p -> p.benchmarkModel != null) + return gitlab.getAllProjects().parallelStream().filter(p -> p.benchmarkModel != null) .flatMap(p -> MetaDataFactory.modelToBenchmarkMetaData(p.benchmarkModel, p.name, p.createdAt).stream()) .collect(Collectors.toList()); - LOGGER.info("Unchecked systems for benchmarks fetched size :{}", benchmarks.size()); -// for(BenchmarkMetaData benchmark : benchmarks) { -// LOGGER.info("Fetching benchmark {}:{}", benchmark.name,benchmark.uri); -// } - return benchmarks; } @Override protected List getUncheckedSystems() { - LOGGER.info("Getting systems for benchmarks"); - List systems = gitlab.getAllProjects().parallelStream().filter(p -> p.systemModel != null) + return gitlab.getAllProjects().parallelStream().filter(p -> p.systemModel != null) .flatMap(p -> MetaDataFactory.modelToSystemMetaData(p.systemModel, p.name, p.createdAt).stream()) .collect(Collectors.toList()); - LOGGER.info("Unchecked systems for benchmarks fetched size :{}", systems.size()); -// for(SystemMetaData system : systems) { -// LOGGER.info("Fetching system {} : {}", system.name,system.uri); -// } - return systems; } @Override diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java index abc83c81..ef4a7883 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ClusterManagerImpl.java @@ -11,11 +11,22 @@ import java.util.List; +/** + * Implementation of the {@link ClusterManager} interface using Kubernetes API. + * This class provides methods to manage and monitor a Kubernetes cluster, including listing nodes, + * checking cluster health, and managing task history limits. + * @author Farshad Afshari farshad.afshari@uni-paderborn.de + */ public class ClusterManagerImpl implements ClusterManager { private static final Logger LOGGER = LoggerFactory.getLogger(ClusterManagerImpl.class); private final CoreV1Api coreV1Api; private Integer taskHistoryLimit = 0; // Default task history limit + /** + * Constructs a new {@code ClusterManagerImpl} with the given Kubernetes API client. + * + * @param apiClient The Kubernetes API client used to interact with the cluster. + */ public ClusterManagerImpl(ApiClient apiClient) { LOGGER.info("Creating a new cluster manager "); this.coreV1Api = new CoreV1Api(apiClient); @@ -30,7 +41,12 @@ public ClusterManagerImpl(ApiClient apiClient) { } } - + /** + * Returns the total number of nodes in the Kubernetes cluster. + * + * @return The total number of nodes. + * @throws InterruptedException If the operation is interrupted. + */ @Override public long getNumberOfNodes() throws InterruptedException { try { @@ -41,6 +57,13 @@ public long getNumberOfNodes() throws InterruptedException { } } + /** + * Returns the number of nodes in the Kubernetes cluster that match a specific label. + * + * @param label The label selector used to filter nodes. + * @return The number of nodes matching the label. + * @throws InterruptedException If the operation is interrupted. + */ @Override public long getNumberOfNodes(String label) throws InterruptedException { try { @@ -52,6 +75,12 @@ public long getNumberOfNodes(String label) throws InterruptedException { } } + /** + * Checks if the Kubernetes cluster is healthy by verifying that all nodes are in a 'Ready' state. + * + * @return {@code true} if the cluster is healthy, otherwise {@code false}. + * @throws InterruptedException If the operation is interrupted. + */ @Override public boolean isClusterHealthy() throws InterruptedException { //LOGGER.info("Checking cluster health"); diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java index fc5aef4b..9b76b375 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java @@ -23,6 +23,13 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +/** + * KubernetesContainerManager is a class that implements the ContainerManager interface to manage + * containers in a Kubernetes environment. It provides methods for creating, removing, starting, + * stopping, and retrieving information about pods. + * + * @author Farshad Afshari farshad.afshari@uni-paderborn.de + */ public class ContainerManagerImpl implements ContainerManager, KubExtendedContainerManager { private static final Logger LOGGER = LoggerFactory.getLogger(ContainerManagerImpl.class); diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java index 54694a65..05be3681 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java @@ -12,11 +12,16 @@ import java.util.Timer; import java.util.TimerTask; +/** + * A concrete implementation of {@link ContainerStateObserver} that monitors Kubernetes pods and + * notifies registered callbacks when a pod terminates. + */ + public class ContainerStateObserverImpl implements ContainerStateObserver { private static final Logger LOGGER = LoggerFactory.getLogger(ContainerStateObserverImpl.class); - KubExtendedContainerManager manager; + private KubExtendedContainerManager manager; private final List monitoredContainers; private final List terminationCallbacks; private final Timer timer; diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerTerminationCallbackImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerTerminationCallbackImpl.java deleted file mode 100644 index 131203b8..00000000 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerTerminationCallbackImpl.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.hobbit.controller.containers.kubernetes; - -import org.hobbit.controller.containers.ContainerTerminationCallback; - -public class ContainerTerminationCallbackImpl implements ContainerTerminationCallback { - private String containerId; - private long exitCode; - - @Override - public void notifyTermination(String containerId, long exitCode) { - this.containerId = containerId; - this.exitCode = exitCode; - } - - public String getContainerId() { - return containerId; - } - - public long getExitCode() { - return exitCode; - } -} diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java index 758ce50b..0e02fe9a 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ResourceInformationCollectorImpl.java @@ -31,6 +31,17 @@ import java.util.Map; import java.util.stream.Collectors; +/** + * This class implements the {@link ResourceInformationCollector} interface to gather resource usage information and hardware details from a Kubernetes cluster. It uses the Kubernetes Java client to interact with the Kubernetes API. + * + * The implementation provides methods to: + * Get system-wide resource usage information. + * Get resource usage information for specific containers based on criteria. + * Fetch hardware information of the nodes in the Kubernetes cluster. + * + * @author Farshad Afshari farshad.afshari@uni-paderborn.de + */ + public class ResourceInformationCollectorImpl implements ResourceInformationCollector { private static final Logger LOGGER = LoggerFactory.getLogger(ResourceInformationCollectorImpl.class); @@ -38,8 +49,6 @@ public class ResourceInformationCollectorImpl implements ResourceInformationColl //TODO make configable private int TIMEOUT_MILLISECONDS = 60000; private final String namespace = "default"; - private static final long KUBERNETES_POLL_INTERVAL = 5000; // Poll interval in ms - private static final long KUBERNETES_EXITCODE_SIGKILL = 137L; // Equivalent to SIGKILL exit code private ApiClient apiClient; private CoreV1Api coreV1Api; From 21e41c282e9c86150941484b35d094991f229a41 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Mon, 7 Apr 2025 17:06:32 +0200 Subject: [PATCH 25/52] remove extra Override --- .../java/org/hobbit/controller/mocks/DummyContainerManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java index d867994e..63353cc5 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java +++ b/platform-controller/src/test/java/org/hobbit/controller/mocks/DummyContainerManager.java @@ -146,7 +146,7 @@ public void pullImage(String imageName) { System.out.println("..."); } - @Override + //@Override public ContainerStats getStats(String containerId) { return null; } From 3a19415ebcf279dce03139955a4e9218536bdb11 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 8 Apr 2025 10:32:57 +0200 Subject: [PATCH 26/52] add RUN_ON env to git workflow --- .github/workflows/make.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index 5e4e53b0..29e26cae 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -16,3 +16,5 @@ jobs: docker swarm init - run: docker compose -f docker-compose-dev.yml pull cadvisor node-exporter prometheus rabbit redis - run: make test + env: + RUN_ON: "docker" From 659dfc878a46ac54108e125fa170cb541baa3031 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 8 Apr 2025 11:12:08 +0200 Subject: [PATCH 27/52] remove external true from docker compose then make the network itself --- docker-compose-dev.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 888d1661..2e0bacba 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -20,6 +20,7 @@ services: USE_GITLAB: "false" LOCAL_METADATA_DIRECTORY: "/metadata" DOCKER_AUTOPULL: "0" + RUN_ON: "docker" volumes: - /var/run/docker.sock:/var/run/docker.sock - ./metadata:/metadata @@ -145,9 +146,9 @@ services: networks: hobbit: name: hobbit - external: true + #external: true driver: overlay hobbit-core: name: hobbit-core - external: true + #external: true driver: overlay From 53e89d759eaa09d64bf03b8c0c9e971445669ef3 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 8 Apr 2025 11:35:17 +0200 Subject: [PATCH 28/52] try create network for docker --- .github/workflows/make.yml | 5 +++-- docker-compose-dev.yml | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index 29e26cae..31b265cc 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -14,7 +14,8 @@ jobs: node-version: 8 - run: | docker swarm init + - run: make create-networks - run: docker compose -f docker-compose-dev.yml pull cadvisor node-exporter prometheus rabbit redis + - run: docker compose -f docker-compose-dev.yml up -d platform-controller rabbit redis # Start only necessary services - run: make test - env: - RUN_ON: "docker" + - run: docker compose -f docker-compose-dev.yml down # Clean up containers and networks diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 2e0bacba..d6e0ddaa 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -146,9 +146,9 @@ services: networks: hobbit: name: hobbit - #external: true + external: true driver: overlay hobbit-core: name: hobbit-core - #external: true + external: true driver: overlay From 483b17d986f68da9f45d1bd27cfd5cd24f82c5f7 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 8 Apr 2025 14:17:28 +0200 Subject: [PATCH 29/52] undo changes in git make workflow --- .github/workflows/make.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index 31b265cc..5e4e53b0 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -14,8 +14,5 @@ jobs: node-version: 8 - run: | docker swarm init - - run: make create-networks - run: docker compose -f docker-compose-dev.yml pull cadvisor node-exporter prometheus rabbit redis - - run: docker compose -f docker-compose-dev.yml up -d platform-controller rabbit redis # Start only necessary services - run: make test - - run: docker compose -f docker-compose-dev.yml down # Clean up containers and networks From b8ca8cf1965dd39306af9345071b1bf47c2a2335 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 8 Apr 2025 17:23:37 +0200 Subject: [PATCH 30/52] change make.yml to make docker socket reachable --- .github/workflows/make.yml | 60 ++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index 5e4e53b0..d5c9976b 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -1,18 +1,54 @@ +#name: make +#on: push +#jobs: +# make: +# # https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job +# runs-on: ubuntu-22.04 +# steps: +# - uses: actions/checkout@v2 +# - uses: actions/setup-java@v1 +# with: +# java-version: 11 +# - uses: actions/setup-node@v2 +# with: +# node-version: 8 +# - run: | +# docker swarm init +# - run: docker compose -f docker-compose-dev.yml pull cadvisor node-exporter prometheus rabbit redis +# - run: make test name: make on: push + jobs: make: - # https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job runs-on: ubuntu-22.04 + services: + docker: + image: docker:24.0.7-dind + options: --privileged + ports: + - 2375:2375 + env: + DOCKER_TLS_CERTDIR: "" + env: + DOCKER_HOST: tcp://localhost:2375 + DOCKER_DRIVER: overlay2 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 - with: - java-version: 11 - - uses: actions/setup-node@v2 - with: - node-version: 8 - - run: | - docker swarm init - - run: docker compose -f docker-compose-dev.yml pull cadvisor node-exporter prometheus rabbit redis - - run: make test + - uses: actions/checkout@v2 + + - uses: actions/setup-java@v1 + with: + java-version: 11 + + - uses: actions/setup-node@v2 + with: + node-version: 8 + + - name: Wait for Docker to be ready + run: | + echo "Waiting for Docker to start..." + sleep 10 + docker version + + - name: Run make test + run: make test From f3776025e9bf00a2e8496b9b57ae8fba415b5a74 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 8 Apr 2025 17:26:38 +0200 Subject: [PATCH 31/52] init docker swarm --- .github/workflows/make.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index d5c9976b..c59c0dfe 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -50,5 +50,8 @@ jobs: sleep 10 docker version + - name: Initialize Docker Swarm + run: docker swarm init + - name: Run make test run: make test From 92c848f161dc37d194561bf182bf0dd638f0f3e6 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 8 Apr 2025 17:30:07 +0200 Subject: [PATCH 32/52] init docker swarm before anything --- .github/workflows/make.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index c59c0dfe..4d11a41b 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -22,17 +22,20 @@ on: push jobs: make: runs-on: ubuntu-22.04 + services: docker: image: docker:24.0.7-dind options: --privileged - ports: - - 2375:2375 env: DOCKER_TLS_CERTDIR: "" + ports: + - 2375:2375 + env: DOCKER_HOST: tcp://localhost:2375 DOCKER_DRIVER: overlay2 + steps: - uses: actions/checkout@v2 @@ -44,14 +47,16 @@ jobs: with: node-version: 8 - - name: Wait for Docker to be ready + - name: Wait for Docker to start run: | - echo "Waiting for Docker to start..." sleep 10 docker version - name: Initialize Docker Swarm run: docker swarm init + - name: Pull required images + run: docker compose -f docker-compose-dev.yml pull cadvisor node-exporter prometheus rabbit redis + - name: Run make test run: make test From 3aff943ccdeae925dfab4641a6bdedc9181086aa Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 8 Apr 2025 17:55:08 +0200 Subject: [PATCH 33/52] start rabitMQ manually --- .github/workflows/make.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index 4d11a41b..e5a9b052 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -58,5 +58,16 @@ jobs: - name: Pull required images run: docker compose -f docker-compose-dev.yml pull cadvisor node-exporter prometheus rabbit redis + - name: Wait for RabbitMQ to be ready + run: | + echo "Waiting for RabbitMQ..." + for i in {1..30}; do + nc -z rabbit 5672 && echo "RabbitMQ is up!" && exit 0 + echo "Still waiting for RabbitMQ..." + sleep 3 + done + echo "RabbitMQ not responding on port 5672" >&2 + docker ps + exit 1 - name: Run make test run: make test From 9a121377603afb71ab373b08e1b60a78275cfc55 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 9 Apr 2025 13:39:14 +0200 Subject: [PATCH 34/52] add HOBBIT_RABBIT_EXPERIMENTS_HOST to environment of docke compose --- docker-compose-dev.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index d6e0ddaa..4ac128c1 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -9,6 +9,7 @@ services: HOBBIT_RABBIT_IMAGE: "rabbitmq:management" HOBBIT_RABBIT_HOST: "rabbit" HOBBIT_REDIS_HOST: "redis" + HOBBIT_RABBIT_EXPERIMENTS_HOST: "redis" DEPLOY_ENV: "develop" GITLAB_USER: "${GITLAB_USER}" GITLAB_EMAIL: "${GITLAB_EMAIL}" From 1aec5cf825a0e3afdf4d24aa9666d014d64fea58 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 9 Apr 2025 13:54:26 +0200 Subject: [PATCH 35/52] start rabbitmq cluster also in test --- .github/workflows/make.yml | 22 +++++++++++----------- Makefile | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index e5a9b052..cb80ba89 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -58,16 +58,16 @@ jobs: - name: Pull required images run: docker compose -f docker-compose-dev.yml pull cadvisor node-exporter prometheus rabbit redis - - name: Wait for RabbitMQ to be ready - run: | - echo "Waiting for RabbitMQ..." - for i in {1..30}; do - nc -z rabbit 5672 && echo "RabbitMQ is up!" && exit 0 - echo "Still waiting for RabbitMQ..." - sleep 3 - done - echo "RabbitMQ not responding on port 5672" >&2 - docker ps - exit 1 +# - name: Wait for RabbitMQ to be ready +# run: | +# echo "Waiting for RabbitMQ..." +# for i in {1..30}; do +# nc -z rabbit 5672 && echo "RabbitMQ is up!" && exit 0 +# echo "Still waiting for RabbitMQ..." +# sleep 3 +# done +# echo "RabbitMQ not responding on port 5672" >&2 +# docker ps +# exit 1 - name: Run make test run: make test diff --git a/Makefile b/Makefile index 53cfc5ff..bc59e467 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ run-platform-elk: docker stack deploy --compose-file docker-compose-elk.yml elk docker stack deploy --compose-file docker-compose.yml platform -test: create-networks install-parent-pom +test: create-networks install-parent-pom start-rabbitmq-cluster make --directory=platform-controller test cd platform-storage/storage-service && mvn --quiet --update-snapshots clean test cd analysis-component && mvn --quiet --update-snapshots clean test From 1c0889b04bee0f190f31a51870454e7d7e840468 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 9 Apr 2025 14:04:03 +0200 Subject: [PATCH 36/52] print massages in makefile --- Makefile | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index bc59e467..9c725a62 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,9 @@ start-dev: start-rabbitmq-cluster start-dev-platform start-dev-elk: start-rabbitmq-cluster start-dev-platform start-dev-elk start-rabbitmq-cluster: + @echo "πŸ“‘ Starting RabbitMQ cluster..." cd rabbitmq-cluster && make start + @echo "βœ… RabbitMQ cluster started." start-dev-platform: docker-compose -f docker-compose-dev.yml up -d @@ -40,9 +42,19 @@ build-dev-storage-image: docker build -t hobbitproject/hobbit-storage-service:dev --file ./platform-storage/storage-service/Dockerfile . create-networks: - @docker network inspect hobbit >/dev/null || (docker network create -d overlay --attachable --subnet 172.16.100.0/24 hobbit && echo "Created network: hobbit") - @docker network inspect hobbit-core >/dev/null || (docker network create -d overlay --attachable --subnet 172.16.101.0/24 hobbit-core && echo "Created network: hobbit-core") - @docker network inspect hobbit-services >/dev/null || (docker network create -d overlay --attachable --subnet 172.16.102.0/24 hobbit-services && echo "Created network: hobbit-services") +# @docker network inspect hobbit >/dev/null || (docker network create -d overlay --attachable --subnet 172.16.100.0/24 hobbit && echo "Created network: hobbit") +# @docker network inspect hobbit-core >/dev/null || (docker network create -d overlay --attachable --subnet 172.16.101.0/24 hobbit-core && echo "Created network: hobbit-core") +# @docker network inspect hobbit-services >/dev/null || (docker network create -d overlay --attachable --subnet 172.16.102.0/24 hobbit-services && echo "Created network: hobbit-services") + @echo "πŸ”Œ Checking or creating Docker network: hobbit" + @docker network inspect hobbit >/dev/null || (docker network create -d overlay --attachable --subnet 172.16.100.0/24 hobbit && echo "βœ… Created network: hobbit") + + @echo "πŸ”Œ Checking or creating Docker network: hobbit-core" + @docker network inspect hobbit-core >/dev/null || (docker network create -d overlay --attachable --subnet 172.16.101.0/24 hobbit-core && echo "βœ… Created network: hobbit-core") + + @echo "πŸ”Œ Checking or creating Docker network: hobbit-services" + @docker network inspect hobbit-services >/dev/null || (docker network create -d overlay --attachable --subnet 172.16.102.0/24 hobbit-services && echo "βœ… Created network: hobbit-services") + + @echo "🌐 Docker networks ready." set-keycloak-permissions: @chmod --changes 777 config/keycloak @@ -61,15 +73,39 @@ run-platform-elk: docker stack deploy --compose-file docker-compose-elk.yml elk docker stack deploy --compose-file docker-compose.yml platform +# test: create-networks install-parent-pom start-rabbitmq-cluster +# make --directory=platform-controller test +# cd platform-storage/storage-service && mvn --quiet --update-snapshots clean test +# cd analysis-component && mvn --quiet --update-snapshots clean test +# cd hobbit-gui/gui-client && sh -c 'test "$$TRAVIS" = "true" && npm --quiet ci; true' && sh -c 'test "$$TRAVIS" = "true" || npm --quiet install; true' && npm --quiet run lint && npm --quiet run build-prod +# cd hobbit-gui/gui-serverbackend && mvn --quiet --update-snapshots clean test + test: create-networks install-parent-pom start-rabbitmq-cluster + @echo "πŸ”§ Running tests in platform-controller..." make --directory=platform-controller test + + @echo "πŸ’Ύ Running tests in platform-storage/storage-service..." cd platform-storage/storage-service && mvn --quiet --update-snapshots clean test + + @echo "πŸ“Š Running tests in analysis-component..." cd analysis-component && mvn --quiet --update-snapshots clean test - cd hobbit-gui/gui-client && sh -c 'test "$$TRAVIS" = "true" && npm --quiet ci; true' && sh -c 'test "$$TRAVIS" = "true" || npm --quiet install; true' && npm --quiet run lint && npm --quiet run build-prod + + @echo "πŸ–₯️ Running lint and build in hobbit-gui/gui-client..." + cd hobbit-gui/gui-client && \ + sh -c 'test "$$TRAVIS" = "true" && npm --quiet ci; true' && \ + sh -c 'test "$$TRAVIS" = "true" || npm --quiet install; true' && \ + npm --quiet run lint && \ + npm --quiet run build-prod + + @echo "πŸ”™ Running tests in hobbit-gui/gui-serverbackend..." cd hobbit-gui/gui-serverbackend && mvn --quiet --update-snapshots clean test + @echo "βœ… All tests completed successfully!" + install-parent-pom: + @echo "πŸ“¦ Installing parent POM..." cd parent-pom && mvn --quiet install + @echo "βœ… Parent POM installed." local-controller: lc-build lc-run From 0be4951c7b718768ad7144125d0e73c60d40677d Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 9 Apr 2025 14:07:45 +0200 Subject: [PATCH 37/52] docker-compose change with docker compose for rabbitmq --- rabbitmq-cluster/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rabbitmq-cluster/Makefile b/rabbitmq-cluster/Makefile index 085018df..c9e9b0be 100644 --- a/rabbitmq-cluster/Makefile +++ b/rabbitmq-cluster/Makefile @@ -1,11 +1,11 @@ -haproxy=$(shell docker ps -a | grep haproxy | cut -d' ' -f 1) +haproxy=$(shell docker ps -a | grep haproxy | cut -d' ' -f 1) start: - docker-compose up -d + docker compose up -d restart-haproxy: docker stop ${haproxy} && docker rm ${haproxy} - docker-compose up -d + docker compose up -d stop: - docker-compose down + docker compose down From 5efe05372c02a9226b6a7d0df9a42614262d40d2 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 9 Apr 2025 14:25:07 +0200 Subject: [PATCH 38/52] run single rabbitmq --- Makefile | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9c725a62..a58eb229 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,19 @@ start-rabbitmq-cluster: cd rabbitmq-cluster && make start @echo "βœ… RabbitMQ cluster started." +start-rabbitmq: + @echo "πŸ“‘ Starting standalone RabbitMQ container on 'hobbit' network..." + @docker network inspect hobbit >/dev/null || (echo "❌ Network 'hobbit' not found. Run 'make create-networks' first." && exit 1) + @docker rm -f hobbit-rabbitmq >/dev/null 2>&1 || true + @docker run -d \ + --name hobbit-rabbitmq \ + --network hobbit \ + -p 5672:5672 \ + -p 15672:15672 \ + rabbitmq:3-management + @echo "βœ… RabbitMQ is running at:" + @echo " AMQP: amqp://localhost:5672" + @echo " Management: http://localhost:15672 (user: guest, pass: guest)" start-dev-platform: docker-compose -f docker-compose-dev.yml up -d @@ -80,7 +93,7 @@ run-platform-elk: # cd hobbit-gui/gui-client && sh -c 'test "$$TRAVIS" = "true" && npm --quiet ci; true' && sh -c 'test "$$TRAVIS" = "true" || npm --quiet install; true' && npm --quiet run lint && npm --quiet run build-prod # cd hobbit-gui/gui-serverbackend && mvn --quiet --update-snapshots clean test -test: create-networks install-parent-pom start-rabbitmq-cluster +test: create-networks install-parent-pom start-rabbitmq @echo "πŸ”§ Running tests in platform-controller..." make --directory=platform-controller test From 48bbf41f59658f475f59e53aa6512256c6b63cc7 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 9 Apr 2025 14:47:59 +0200 Subject: [PATCH 39/52] try finding where is the problem with rabitmq --- Makefile | 1 + platform-controller/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a58eb229..60d008ec 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ start-rabbitmq: -p 5672:5672 \ -p 15672:15672 \ rabbitmq:3-management + @docker network connect hobbit-core @echo "βœ… RabbitMQ is running at:" @echo " AMQP: amqp://localhost:5672" @echo " Management: http://localhost:15672 (user: guest, pass: guest)" diff --git a/platform-controller/Makefile b/platform-controller/Makefile index 0c52512b..f7e55a12 100644 --- a/platform-controller/Makefile +++ b/platform-controller/Makefile @@ -17,7 +17,7 @@ run: test: # Without HOBBIT_RABBIT_EXPERIMENTS_HOST we won't be able to connect to RabbitMQ - docker compose --file=../docker-compose-dev.yml up -d cadvisor node-exporter prometheus rabbit redis + docker compose --file=../docker-compose-dev.yml up -d cadvisor node-exporter prometheus redis HOBBIT_RABBIT_IMAGE=rabbitmq:management \ HOBBIT_RABBIT_HOST=localhost \ HOBBIT_RABBIT_EXPERIMENTS_HOST=localhost \ From 25cf0f7a665d2f4ee872455f9bce153979406da8 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 9 Apr 2025 14:51:31 +0200 Subject: [PATCH 40/52] connect rabbit to network core --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 60d008ec..1ae9f972 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ start-rabbitmq: -p 5672:5672 \ -p 15672:15672 \ rabbitmq:3-management - @docker network connect hobbit-core + @docker network connect hobbit-core hobbit-rabbitmq @echo "βœ… RabbitMQ is running at:" @echo " AMQP: amqp://localhost:5672" @echo " Management: http://localhost:15672 (user: guest, pass: guest)" From dd3b74dfa3e8fe8e2921deb9b843661caf6383c1 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 9 Apr 2025 15:22:54 +0200 Subject: [PATCH 41/52] ler rabbitmq run from controller test makefile --- Makefile | 30 +++++++++++++++--------------- platform-controller/Makefile | 10 +++++++++- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 1ae9f972..c089a615 100644 --- a/Makefile +++ b/Makefile @@ -21,20 +21,20 @@ start-rabbitmq-cluster: cd rabbitmq-cluster && make start @echo "βœ… RabbitMQ cluster started." -start-rabbitmq: - @echo "πŸ“‘ Starting standalone RabbitMQ container on 'hobbit' network..." - @docker network inspect hobbit >/dev/null || (echo "❌ Network 'hobbit' not found. Run 'make create-networks' first." && exit 1) - @docker rm -f hobbit-rabbitmq >/dev/null 2>&1 || true - @docker run -d \ - --name hobbit-rabbitmq \ - --network hobbit \ - -p 5672:5672 \ - -p 15672:15672 \ - rabbitmq:3-management - @docker network connect hobbit-core hobbit-rabbitmq - @echo "βœ… RabbitMQ is running at:" - @echo " AMQP: amqp://localhost:5672" - @echo " Management: http://localhost:15672 (user: guest, pass: guest)" +# start-rabbitmq: +# @echo "πŸ“‘ Starting standalone RabbitMQ container on 'hobbit' network..." +# @docker network inspect hobbit >/dev/null || (echo "❌ Network 'hobbit' not found. Run 'make create-networks' first." && exit 1) +# @docker rm -f hobbit-rabbitmq >/dev/null 2>&1 || true +# @docker run -d \ +# --name hobbit-rabbitmq \ +# --network hobbit \ +# -p 5672:5672 \ +# -p 15672:15672 \ +# rabbitmq:3-management +# @docker network connect hobbit-core hobbit-rabbitmq +# @echo "βœ… RabbitMQ is running at:" +# @echo " AMQP: amqp://localhost:5672" +# @echo " Management: http://localhost:15672 (user: guest, pass: guest)" start-dev-platform: docker-compose -f docker-compose-dev.yml up -d @@ -94,7 +94,7 @@ run-platform-elk: # cd hobbit-gui/gui-client && sh -c 'test "$$TRAVIS" = "true" && npm --quiet ci; true' && sh -c 'test "$$TRAVIS" = "true" || npm --quiet install; true' && npm --quiet run lint && npm --quiet run build-prod # cd hobbit-gui/gui-serverbackend && mvn --quiet --update-snapshots clean test -test: create-networks install-parent-pom start-rabbitmq +test: create-networks install-parent-pom @echo "πŸ”§ Running tests in platform-controller..." make --directory=platform-controller test diff --git a/platform-controller/Makefile b/platform-controller/Makefile index f7e55a12..f1ed2d8e 100644 --- a/platform-controller/Makefile +++ b/platform-controller/Makefile @@ -16,14 +16,22 @@ run: org.hobbit.controller.PlatformController test: + @echo "πŸ”§ Starting required services with Docker Compose..." # Without HOBBIT_RABBIT_EXPERIMENTS_HOST we won't be able to connect to RabbitMQ - docker compose --file=../docker-compose-dev.yml up -d cadvisor node-exporter prometheus redis + docker compose --file=../docker-compose-dev.yml up -d cadvisor node-exporter prometheus redis rabbit + @echo "βœ… Services started: cadvisor, node-exporter, prometheus, redis , rabbit." + + @echo "πŸ‡ Running RabbitMQ and Redis environment variables setup..." HOBBIT_RABBIT_IMAGE=rabbitmq:management \ HOBBIT_RABBIT_HOST=localhost \ HOBBIT_RABBIT_EXPERIMENTS_HOST=localhost \ HOBBIT_REDIS_HOST=localhost \ PROMETHEUS_HOST=localhost \ + @echo "βœ… Environment variables set for RabbitMQ and Redis." + + @echo "πŸ§ͺ Running tests with Maven..." mvn --quiet --update-snapshots -Dtest=$(test) clean test + @echo "βœ… Tests completed successfully." test-single: docker rmi busybox From 3ed1dfbb57fc42865e738868b21bd60a201f8e0b Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 9 Apr 2025 15:39:07 +0200 Subject: [PATCH 42/52] change in platform controller make file remove extra echo --- platform-controller/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/platform-controller/Makefile b/platform-controller/Makefile index f1ed2d8e..a0e4be28 100644 --- a/platform-controller/Makefile +++ b/platform-controller/Makefile @@ -29,7 +29,6 @@ test: PROMETHEUS_HOST=localhost \ @echo "βœ… Environment variables set for RabbitMQ and Redis." - @echo "πŸ§ͺ Running tests with Maven..." mvn --quiet --update-snapshots -Dtest=$(test) clean test @echo "βœ… Tests completed successfully." From 2d9994794900f8fd5a827fbde6e955b7a23ba7d2 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 9 Apr 2025 15:45:02 +0200 Subject: [PATCH 43/52] change in platform controller make file remove extra echo --- platform-controller/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/platform-controller/Makefile b/platform-controller/Makefile index a0e4be28..2554de43 100644 --- a/platform-controller/Makefile +++ b/platform-controller/Makefile @@ -27,7 +27,6 @@ test: HOBBIT_RABBIT_EXPERIMENTS_HOST=localhost \ HOBBIT_REDIS_HOST=localhost \ PROMETHEUS_HOST=localhost \ - @echo "βœ… Environment variables set for RabbitMQ and Redis." mvn --quiet --update-snapshots -Dtest=$(test) clean test @echo "βœ… Tests completed successfully." From ee3a5e70f19f125f107e18af62e2e6176288f3c2 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 9 Apr 2025 16:31:10 +0200 Subject: [PATCH 44/52] add MAX_EXECUTION_TIME --- platform-controller/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/platform-controller/Makefile b/platform-controller/Makefile index 2554de43..d7d1eed0 100644 --- a/platform-controller/Makefile +++ b/platform-controller/Makefile @@ -19,13 +19,11 @@ test: @echo "πŸ”§ Starting required services with Docker Compose..." # Without HOBBIT_RABBIT_EXPERIMENTS_HOST we won't be able to connect to RabbitMQ docker compose --file=../docker-compose-dev.yml up -d cadvisor node-exporter prometheus redis rabbit - @echo "βœ… Services started: cadvisor, node-exporter, prometheus, redis , rabbit." - - @echo "πŸ‡ Running RabbitMQ and Redis environment variables setup..." HOBBIT_RABBIT_IMAGE=rabbitmq:management \ HOBBIT_RABBIT_HOST=localhost \ HOBBIT_RABBIT_EXPERIMENTS_HOST=localhost \ HOBBIT_REDIS_HOST=localhost \ + MAX_EXECUTION_TIME=1200000 \ PROMETHEUS_HOST=localhost \ mvn --quiet --update-snapshots -Dtest=$(test) clean test From 5a8c43d1da490b63a7b9c9cf402416a7973721d7 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Thu, 10 Apr 2025 14:25:42 +0200 Subject: [PATCH 45/52] now ENV should set correctly ! --- platform-controller/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform-controller/Makefile b/platform-controller/Makefile index d7d1eed0..df5de79f 100644 --- a/platform-controller/Makefile +++ b/platform-controller/Makefile @@ -17,18 +17,18 @@ run: test: @echo "πŸ”§ Starting required services with Docker Compose..." - # Without HOBBIT_RABBIT_EXPERIMENTS_HOST we won't be able to connect to RabbitMQ docker compose --file=../docker-compose-dev.yml up -d cadvisor node-exporter prometheus redis rabbit - HOBBIT_RABBIT_IMAGE=rabbitmq:management \ + @echo "πŸ§ͺ Running tests with environment variables..." + @HOBBIT_RABBIT_IMAGE=rabbitmq:management \ HOBBIT_RABBIT_HOST=localhost \ HOBBIT_RABBIT_EXPERIMENTS_HOST=localhost \ HOBBIT_REDIS_HOST=localhost \ MAX_EXECUTION_TIME=1200000 \ PROMETHEUS_HOST=localhost \ - mvn --quiet --update-snapshots -Dtest=$(test) clean test @echo "βœ… Tests completed successfully." + test-single: docker rmi busybox mvn --update-snapshots clean test -Dtest=org.hobbit.controller.docker.ContainerManagerImplTest#startContainer From 94e8de13a4298647beefc1e479368ed55c6919cb Mon Sep 17 00:00:00 2001 From: farshad68 Date: Thu, 10 Apr 2025 14:38:36 +0200 Subject: [PATCH 46/52] now ENV should set correctly ! --- platform-controller/Makefile | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/platform-controller/Makefile b/platform-controller/Makefile index df5de79f..3346d3c9 100644 --- a/platform-controller/Makefile +++ b/platform-controller/Makefile @@ -18,13 +18,12 @@ run: test: @echo "πŸ”§ Starting required services with Docker Compose..." docker compose --file=../docker-compose-dev.yml up -d cadvisor node-exporter prometheus redis rabbit - @echo "πŸ§ͺ Running tests with environment variables..." - @HOBBIT_RABBIT_IMAGE=rabbitmq:management \ - HOBBIT_RABBIT_HOST=localhost \ - HOBBIT_RABBIT_EXPERIMENTS_HOST=localhost \ - HOBBIT_REDIS_HOST=localhost \ - MAX_EXECUTION_TIME=1200000 \ - PROMETHEUS_HOST=localhost \ + @export HOBBIT_RABBIT_IMAGE=rabbitmq:management && \ + export HOBBIT_RABBIT_HOST=localhost && \ + export HOBBIT_RABBIT_EXPERIMENTS_HOST=localhost && \ + export HOBBIT_REDIS_HOST=localhost && \ + export MAX_EXECUTION_TIME=1200000 && \ + export PROMETHEUS_HOST=localhost && \ mvn --quiet --update-snapshots -Dtest=$(test) clean test @echo "βœ… Tests completed successfully." From b457d77f8bb923e93ffee8dab797e23281aa94b9 Mon Sep 17 00:00:00 2001 From: Denis Kuchelev Date: Mon, 14 Apr 2025 12:04:15 +0200 Subject: [PATCH 47/52] Log the network list after creation --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index c089a615..fd4a76a5 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,7 @@ create-networks: @echo "πŸ”Œ Checking or creating Docker network: hobbit-services" @docker network inspect hobbit-services >/dev/null || (docker network create -d overlay --attachable --subnet 172.16.102.0/24 hobbit-services && echo "βœ… Created network: hobbit-services") + docker network ls --no-trunc @echo "🌐 Docker networks ready." set-keycloak-permissions: From 02632bff5cf340d379f19c063f43629f8bc46c16 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 15 Apr 2025 14:39:48 +0200 Subject: [PATCH 48/52] add ContainerEngine --- docker-compose-dev-temp.yml | 61 +++++++++++++++++++ platform-controller/Makefile | 3 +- .../hobbit/controller/PlatformController.java | 55 ++++++++++------- .../containers/ContainerEngine.java | 6 ++ 4 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 docker-compose-dev-temp.yml create mode 100644 platform-controller/src/main/java/org/hobbit/controller/containers/ContainerEngine.java diff --git a/docker-compose-dev-temp.yml b/docker-compose-dev-temp.yml new file mode 100644 index 00000000..f59216a7 --- /dev/null +++ b/docker-compose-dev-temp.yml @@ -0,0 +1,61 @@ +version: '3.3' +services: + # message bus + rabbit: + image: rabbitmq:management + networks: + - hobbit + - hobbit-core + ports: + - "8081:15672" + # Forwarding the port for testing + - "5672:5672" + + # DB for controller + redis: + image: redis:4.0.7 + volumes: + - ./config/redis-db:/data + command: ["redis-server", "/data/redis.conf"] + networks: + - hobbit-core + ports: + # Forwarding the port for tests + - "6379:6379" + + node-exporter: + image: prom/node-exporter + networks: + - hobbit-core + + cadvisor: + image: gcr.io/cadvisor/cadvisor + networks: + - hobbit-core + volumes: + - /:/rootfs:ro + - /dev/disk:/dev/disk:ro + - /sys:/sys:ro + - /var/lib/docker:/var/lib/docker:ro + - /var/run:/var/run:rw + + prometheus: + image: prom/prometheus + networks: + - hobbit-core + ports: + - "9090:9090" + volumes: + - ./config/prometheus:/config:ro + command: --config.file=/config/prometheus.conf + depends_on: + - node-exporter + - cadvisor + +networks: + hobbit: + external: true + driver: overlay + hobbit-core: + external: true + driver: overlay diff --git a/platform-controller/Makefile b/platform-controller/Makefile index 3346d3c9..47906c31 100644 --- a/platform-controller/Makefile +++ b/platform-controller/Makefile @@ -17,7 +17,7 @@ run: test: @echo "πŸ”§ Starting required services with Docker Compose..." - docker compose --file=../docker-compose-dev.yml up -d cadvisor node-exporter prometheus redis rabbit + docker compose --file=../docker-compose-dev.yml up -d cadvisor node-exporter prometheus redis rabbit @export HOBBIT_RABBIT_IMAGE=rabbitmq:management && \ export HOBBIT_RABBIT_HOST=localhost && \ export HOBBIT_RABBIT_EXPERIMENTS_HOST=localhost && \ @@ -26,6 +26,7 @@ test: export PROMETHEUS_HOST=localhost && \ mvn --quiet --update-snapshots -Dtest=$(test) clean test @echo "βœ… Tests completed successfully." +# docker compose --file=../docker-compose-dev.yml down test-single: diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index da0fd97c..0bcd2a02 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -23,27 +23,15 @@ import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.time.Duration; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; +import java.util.*; import java.util.concurrent.Semaphore; -import com.spotify.docker.client.exceptions.DockerCertificateException; -import com.spotify.docker.client.exceptions.DockerException; import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.Configuration; import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.util.Config; import org.apache.commons.configuration2.EnvironmentConfiguration; import org.apache.commons.io.IOUtils; -import org.apache.jena.base.Sys; import org.apache.jena.query.Dataset; import org.apache.jena.query.DatasetFactory; import org.apache.jena.query.QueryExecution; @@ -216,6 +204,11 @@ public class PlatformController extends AbstractComponent implements ContainerTe protected Timer challengeCheckTimer; protected HobbitConfiguration hobbitConfig; + /** + * keep the variable which framework used Docker swarm or Kubernetes + */ + protected ContainerEngine engine; + //@Value("${container.manager.timeoutMilliSeconds:60000}") private int TIMEOUT_MILLISECONDS = 60000; @@ -224,6 +217,7 @@ public class PlatformController extends AbstractComponent implements ContainerTe */ public PlatformController() { super(); + this.engine = whereAmIRunning(); } /** @@ -233,8 +227,26 @@ public PlatformController(ExperimentManager expManager) { this(); this.expManager = expManager; expManager.setController(this); + this.engine = whereAmIRunning(); } + private ContainerEngine whereAmIRunning() { + String runOn = Optional.ofNullable(System.getenv("RUN_ON")) + .orElse("kubernetes") + .toLowerCase(); + + switch (runOn) { + case "docker": + LOGGER.info("Platform running on Docker Swarm "); + return ContainerEngine.DOCKER_SWARM; + case "kubernetes": + LOGGER.info("Platform running on Kubernetes"); + return ContainerEngine.KUBERNETES; + default: + LOGGER.warn("Unknown RUN_ON value '{}', defaulting to KUBERNETES.", runOn); + return ContainerEngine.KUBERNETES; + } + } private void kubernetsInit() throws IOException { LOGGER.info("Initializing Kubernetes version"); @@ -264,7 +276,7 @@ private void kubernetsInit() throws IOException { LOGGER.debug("Container observer initialized."); } - private void dokcerswarmInit() throws Exception { + private void dockerSwarmInit() throws Exception { LOGGER.info("Initializing Docker swarm version"); hobbitConfig = new HobbitConfiguration(); hobbitConfig.addConfiguration(new EnvironmentConfiguration()); @@ -302,11 +314,11 @@ public void init() throws Exception { super.init(); LOGGER.debug("Platform controller initialization started."); - switch (System.getenv("RUN_ON").toLowerCase()){ - case "docker": - dokcerswarmInit(); + switch (engine){ + case DOCKER_SWARM: + dockerSwarmInit(); break; - case "kubernetes": + case KUBERNETES: kubernetsInit(); break; default: @@ -580,11 +592,11 @@ private String createContainer(StartCommandData data) { */ public void stopContainer(String containerName) { LOGGER.debug("Stopping container with name: {}", containerName); - switch (System.getenv("RUN_ON").toLowerCase()){ - case "kubernetes": + switch (engine){ + case KUBERNETES: containerManager.removeContainer(containerName); break; - case "docker": + case DOCKER_SWARM: String containerId = containerManager.getContainerPodId(containerName); containerManager.removeContainer(containerId); break; @@ -1412,6 +1424,7 @@ private static String readVersion() { IOUtils.closeQuietly(is); } LOGGER.info("Platform has version {}", version); + LOGGER.info("RABITMQ HOST: {}", System.getenv("HOBBIT_RABBIT_HOST")); return version; } } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerEngine.java b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerEngine.java new file mode 100644 index 00000000..cb5278f7 --- /dev/null +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/ContainerEngine.java @@ -0,0 +1,6 @@ +package org.hobbit.controller.containers; + +public enum ContainerEngine { + DOCKER_SWARM, + KUBERNETES; +} From 7aaa7fcb54fca523cc710663a7bde4ca8ea1d574 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 15 Apr 2025 15:48:53 +0200 Subject: [PATCH 49/52] add comments , javadoc --- .../hobbit/controller/PlatformController.java | 6 +- .../kubernetes/ContainerManagerImpl.java | 18 +++-- .../controller/data/ContainerCriteria.java | 79 ++++++++++++++++++- ...tainerCriteriaToServiceCriteriaMapper.java | 3 - 4 files changed, 91 insertions(+), 15 deletions(-) diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 0bcd2a02..2ab753aa 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -316,9 +316,11 @@ public void init() throws Exception { switch (engine){ case DOCKER_SWARM: + LOGGER.info("Platform running on Docker Swarm"); dockerSwarmInit(); break; case KUBERNETES: + LOGGER.info("Platform running on Kubernetes"); kubernetsInit(); break; default: @@ -484,7 +486,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas break; } case Commands.BENCHMARK_READY_SIGNAL: { - LOGGER.debug("Ready signal: {}", sessionId); + LOGGER.debug("Benchmark Ready signal: {}", sessionId); expManager.systemOrBenchmarkReady(false, sessionId); break; } @@ -494,7 +496,7 @@ public void receiveCommand(byte command, byte[] data, String sessionId, AMQP.Bas break; } case Commands.TASK_GENERATION_FINISHED: { - LOGGER.debug("Task generator finish: {}", sessionId); + LOGGER.debug("Task generator finished: {}", sessionId); expManager.taskGenFinished(sessionId); break; } diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java index 9b76b375..0118c570 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerManagerImpl.java @@ -113,17 +113,23 @@ public String startContainer(String imageName, String containerType, String pare return startContainer(imageName, containerType, parentId, env, null, command, "", constraints); } + /** + * Generates a unique pod name based on the given module IRI and container type. + * + * If the {@code containerType} is {@code null}, the method defaults to using "notype" + * as the prefix. The generated name combines the hash code of the {@code moduleIri}, + * multiplied by 31, with the current system time in milliseconds, cast to an integer. + * This ensures a high probability of uniqueness. + * + * @param moduleIri the IRI (Internationalized Resource Identifier) of the module + * @param containerType the type of container (e.g., "docker", "kubernetes"); may be {@code null} + * @return a generated pod name string that includes the container type (or "notype") and a unique numeric suffix + */ public String generatePodName(String moduleIri,String containerType) { - /* - * MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); - * messageDigest.update(moduleIri.getBytes()); String stringHash = new - * String(messageDigest.digest()); - */ if(containerType==null){ return "notype" + (moduleIri.hashCode() * 31 + (int) (System.currentTimeMillis())); } return containerType + (moduleIri.hashCode() * 31 + (int) (System.currentTimeMillis())); - } /** diff --git a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java index 7337a1e4..74f2600e 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java +++ b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java @@ -3,37 +3,91 @@ import java.util.Map; import java.util.HashMap; +/** + * Represents criteria used to identify or filter containers, based on container ID, + * container name, and labels. This class is typically used in scenarios where specific + * container characteristics need to be matched, such as during orchestration or monitoring + * in containerized environments. + * + *

Instances of this class are immutable and should be created using the + * {@link ContainerCriteria.Builder}.

+ */ public class ContainerCriteria { + + /** + * The unique identifier of the container. + */ protected String containerId; + + /** + * The name of the container. + */ protected String containerName; + + /** + * A map of labels associated with the container. + */ protected Map labels; + /** + * Builder class for constructing {@link ContainerCriteria} instances in a flexible and + * readable manner. + */ public static class Builder { private String containerId; private String containerName; private Map labels = new HashMap<>(); + /** + * Sets the container ID. + * + * @param containerId the unique container ID + * @return the builder instance + */ public Builder withContainerId(String containerId) { this.containerId = containerId; return this; } + /** + * Sets the container name. + * + * @param containerName the name of the container + * @return the builder instance + */ public Builder withContainerName(String containerName) { this.containerName = containerName; return this; } + /** + * Adds a map of labels to the container criteria. + * + * @param labels a map of label key-value pairs + * @return the builder instance + */ public Builder withLabels(Map labels) { this.labels.putAll(labels); return this; } + /** + * Adds a single label key-value pair to the container criteria. + * + * @param key the label key + * @param value the label value + * @return the builder instance + */ public Builder withLabel(String key, String value) { this.labels.put(key, value); return this; } - + /** + * Builds and returns a {@link ContainerCriteria} instance with the configured properties. + * + * @return a new {@link ContainerCriteria} instance + */ public ContainerCriteria build() { ContainerCriteria criteria = new ContainerCriteria(); criteria.containerId = this.containerId; @@ -43,24 +97,42 @@ public ContainerCriteria build() { } } - + /** + * Returns the container ID. + * + * @return the container ID, or {@code null} if not set + */ public String getContainerId() { return containerId; } + /** + * Returns the container name. + * + * @return the container name, or {@code null} if not set + */ public String getContainerName() { return containerName; } + /** + * Returns the labels associated with the container. + * + * @return a map of label key-value pairs + */ public Map getLabels() { return labels; } + /** + * Creates a new {@link Builder} instance to construct {@link ContainerCriteria} objects. + * + * @return a new {@link Builder} + */ public static Builder builder() { return new Builder(); } - @Override public String toString() { return "ContainerCriteria{" + @@ -70,4 +142,3 @@ public String toString() { '}'; } } - diff --git a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java index 500ccaea..fc8aa7e6 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java +++ b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java @@ -1,13 +1,10 @@ package org.hobbit.controller.data; import com.spotify.docker.client.messages.swarm.Service; -import org.hobbit.controller.data.ContainerCriteria; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; -import java.util.HashMap; -import java.util.Map; //TODO check the whole mapping concept public class ContainerCriteriaToServiceCriteriaMapper { From 94e1a82c842bda21562603df986332ce193104e0 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Tue, 15 Apr 2025 16:01:11 +0200 Subject: [PATCH 50/52] add more documentation --- ...tainerCriteriaToServiceCriteriaMapper.java | 32 ++++++++++++++++++- .../docker/ClusterManagerImplTest.java | 11 ++++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java index fc8aa7e6..8cbc069f 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java +++ b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java @@ -6,7 +6,37 @@ import java.util.Collections; -//TODO check the whole mapping concept +/** + * Maps Kubernetes-style {@link ContainerCriteria} to Docker Swarm {@link Service.Criteria} + * in order to enable service discovery or filtering across container orchestration platforms. + * + *

This is particularly useful in hybrid environments or migration setups where systems + * originally designed for Kubernetes need to operate within a Docker Swarm context. It allows + * interoperability by translating container selection logic into the format understood by Docker clients.

+ * + *

Mapping Logic:

+ *
    + *
  • {@code containerId} β†’ {@code serviceId}
  • + *
  • {@code containerName} β†’ {@code serviceName}
  • + *
  • {@code labels} β†’ {@code labels}
  • + *
+ * + *

Note: This class logs an error and returns {@code null} if the input + * {@code ContainerCriteria} is {@code null}.

+ * + *

Usage Example:

+ *
{@code
+ * ContainerCriteria criteria = ContainerCriteria.builder()
+ *     .withContainerId("12345")
+ *     .withContainerName("my-service")
+ *     .withLabel("app", "my-app")
+ *     .build();
+ *
+ * Service.Criteria serviceCriteria = ContainerCriteriaToServiceCriteriaMapper.map(criteria);
+ * List services = dockerClient.listServices(serviceCriteria);
+ * }
+ */ + public class ContainerCriteriaToServiceCriteriaMapper { private static final Logger LOGGER = LoggerFactory.getLogger(ContainerCriteriaToServiceCriteriaMapper.class); public static Service.Criteria map(ContainerCriteria containerCriteria) { diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ClusterManagerImplTest.java b/platform-controller/src/test/java/org/hobbit/controller/docker/ClusterManagerImplTest.java index a14a4acf..f6030a19 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ClusterManagerImplTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/docker/ClusterManagerImplTest.java @@ -3,6 +3,7 @@ import com.spotify.docker.client.messages.Info; import org.hobbit.controller.containers.docker.ClusterManagerImpl; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.*; @@ -16,11 +17,11 @@ public void setUp() throws Exception { clusterManager = new ClusterManagerImpl(); } -// @Test -// public void getClusterInfo() throws Exception { -// final Info info = clusterManager.getClusterInfo(); -// assertNotNull(info); -// } + @Ignore + public void getClusterInfo() throws Exception { + final Info info = clusterManager.getClusterInfo(); + assertNotNull(info); + } @Test public void getNumberOfNodes() throws Exception { From 873112672c0434461d2fe968feda9151955948ba Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 16 Apr 2025 14:30:37 +0200 Subject: [PATCH 51/52] add readme.md for yaml files --- kubernetes-yaml-files/README.md | 75 +++++++++++++++++++ .../controller/PlatformControllerTest.java | 2 +- .../docker/ClusterManagerImplTest.java | 2 +- .../docker/ContainerAccessByHostnameTest.java | 3 +- .../docker/ContainerManagerBasedTest.java | 3 +- .../docker/ContainerManagerImplTest.java | 3 +- .../ContainerStateObserverImplTest.java | 4 +- .../ContainerTerminationCallbackImplTest.java | 2 +- .../docker/FileBasedImageManagerTest.java | 2 +- .../docker/GitlabBasedImageManagerTest.java | 2 +- .../docker/LongImageNameTest.java | 2 +- .../docker/MetaDataFactoryTest.java | 2 +- .../ResourceInformationCollectorTest.java | 3 +- .../docker/VersionTagIdentificationTest.java | 7 +- test.yml | 13 ---- 15 files changed, 88 insertions(+), 37 deletions(-) create mode 100644 kubernetes-yaml-files/README.md rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/ClusterManagerImplTest.java (97%) rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/ContainerAccessByHostnameTest.java (94%) rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/ContainerManagerBasedTest.java (95%) rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/ContainerManagerImplTest.java (99%) rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/ContainerStateObserverImplTest.java (96%) rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/ContainerTerminationCallbackImplTest.java (96%) rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/FileBasedImageManagerTest.java (96%) rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/GitlabBasedImageManagerTest.java (99%) rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/LongImageNameTest.java (96%) rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/MetaDataFactoryTest.java (99%) rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/ResourceInformationCollectorTest.java (98%) rename platform-controller/src/test/java/org/hobbit/controller/{ => containers}/docker/VersionTagIdentificationTest.java (89%) delete mode 100644 test.yml diff --git a/kubernetes-yaml-files/README.md b/kubernetes-yaml-files/README.md new file mode 100644 index 00000000..1a7ec546 --- /dev/null +++ b/kubernetes-yaml-files/README.md @@ -0,0 +1,75 @@ +# Kubernetes YAML Files + +This directory contains the Kubernetes YAML configuration files used by the Hobbit project to deploy and manage application components on Kubernetes clusters. These configurations define the deployments, services, ingress rules, and other necessary Kubernetes objects. + +## Overview + +The Kubernetes YAML files in this directory are essential for automating the provisioning and scaling of services. The configurations allow seamless deployments as part of the project's continuous integration and delivery pipelines. They are meant to be used as a starting point and can be customized to better suit different environments or specific deployment requirements. + +## Directory Structure + +The directory is organized to facilitate clarity and ease of use: +- **Deployment Files:** Define how pods are deployed and managed. This usually includes specifications such as replicas, container images, resource limits, and update strategies. +- **Service Files:** Expose the pods to internal or external networks. These YAMLs typically cover ClusterIP, NodePort, or LoadBalancer services. +- **Ingress Files:** Manage external access to the services in the cluster. These files are configured to work with Ingress controllers. +- **ConfigMap/Secret Files:** Provide a way to decouple configuration settings and sensitive data from container images. Adjust these according to your environment’s needs. + +## Prerequisites + +To successfully apply these configurations: +- You must have a working Kubernetes cluster. +- Ensure that `kubectl` is installed and configured to communicate with your cluster. +- Familiarity with Kubernetes concepts (pods, deployments, services, ingress, etc.) is helpful. + +## Usage + +### Applying the Configurations + +1. **Navigate to the Directory:** + Open your terminal and change the current directory to the location where the YAML files are stored. + + ```bash + cd path/to/kubernetes-yaml-files + ``` + +2. **Deploy the Resources:** + Use `kubectl` to apply all the configurations at once: + + ```bash + kubectl apply -f . + ``` + + This command iterates through all YAML files and creates or updates the Kubernetes objects accordingly. + +3. **Verify the Deployment:** + To check if the deployments are running correctly, use: + + ```bash + kubectl get deployments + kubectl get pods + ``` + + Review logs if any of the pods are not running as expected: + + ```bash + kubectl logs [pod-name] + ``` +it is suggester keep the order of files while deploying.(00 until 21 the next ones are for testing and development purpose) + +### Customizing Configurations + +- **Environment Variables:** Some files might reference environment variables. Edit these sections as needed to match your environment. +- **Resource Limits:** Customize CPU and memory resources based on your cluster’s capacity. +- **External Dependencies:** Review and adjust configurations for services like Ingress or persistent storage if your project setup requires it. +- **Define secrets of Git based on your data:** like bellow +```bash +kubectl create secret generic gitlab-secret --from-literal=GITLAB_USER=XXX --from-literal=GITLAB_TOKEN=XXX +```` +and if need to reach docker for images like this + +```bash +kubectl create secret docker-registry gitlab-registry-secret \ --docker-server=[for example:git.project-hobbit.eu:4567] \ --docker-username=XXX \ --docker-password=XXX \ --docker-email=XXX \ -n default + +``` + +``` diff --git a/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java b/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java index bba71039..afca1c04 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/PlatformControllerTest.java @@ -32,7 +32,7 @@ import org.hobbit.controller.data.ExperimentConfiguration; import org.hobbit.controller.data.ExperimentStatus; import org.hobbit.controller.data.ExperimentStatus.States; -import org.hobbit.controller.docker.ContainerManagerBasedTest; +import org.hobbit.controller.containers.docker.ContainerManagerBasedTest; import org.hobbit.controller.containers.docker.ContainerManagerImpl; import org.hobbit.core.Commands; import org.hobbit.core.Constants; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ClusterManagerImplTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ClusterManagerImplTest.java similarity index 97% rename from platform-controller/src/test/java/org/hobbit/controller/docker/ClusterManagerImplTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/ClusterManagerImplTest.java index f6030a19..3d6e5751 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ClusterManagerImplTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ClusterManagerImplTest.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import com.spotify.docker.client.messages.Info; import org.hobbit.controller.containers.docker.ClusterManagerImpl; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerAccessByHostnameTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerAccessByHostnameTest.java similarity index 94% rename from platform-controller/src/test/java/org/hobbit/controller/docker/ContainerAccessByHostnameTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerAccessByHostnameTest.java index cf69db41..314cbdd7 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerAccessByHostnameTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerAccessByHostnameTest.java @@ -14,13 +14,12 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import com.spotify.docker.client.messages.ContainerConfig; -import org.hobbit.controller.containers.docker.ContainerManagerImpl; import org.hobbit.core.Constants; import org.junit.Test; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerBasedTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerManagerBasedTest.java similarity index 95% rename from platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerBasedTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerManagerBasedTest.java index 9b5d14ad..982022e0 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerBasedTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerManagerBasedTest.java @@ -14,13 +14,12 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.util.ArrayList; import java.util.List; import org.hobbit.controller.DockerBasedTest; -import org.hobbit.controller.containers.docker.ContainerManagerImpl; import org.junit.After; import org.junit.Before; import org.slf4j.Logger; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerImplTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerManagerImplTest.java similarity index 99% rename from platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerImplTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerManagerImplTest.java index 8cffa1c4..e100110f 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerManagerImplTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerManagerImplTest.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -29,7 +29,6 @@ import java.util.List; import java.util.stream.Collectors; -import org.hobbit.controller.containers.docker.ContainerManagerImpl; import org.hobbit.core.Constants; import org.junit.Assert; import org.junit.Assume; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerStateObserverImplTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerStateObserverImplTest.java similarity index 96% rename from platform-controller/src/test/java/org/hobbit/controller/docker/ContainerStateObserverImplTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerStateObserverImplTest.java index 1e600cb8..08d01ce6 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerStateObserverImplTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerStateObserverImplTest.java @@ -14,10 +14,8 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; -import org.hobbit.controller.containers.docker.ContainerStateObserverImpl; -import org.hobbit.controller.containers.docker.ContainerTerminationCallbackImpl; import org.hobbit.controller.containers.ContainerManager; import org.junit.Assert; import org.junit.Before; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerTerminationCallbackImplTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerTerminationCallbackImplTest.java similarity index 96% rename from platform-controller/src/test/java/org/hobbit/controller/docker/ContainerTerminationCallbackImplTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerTerminationCallbackImplTest.java index 87cfc5b8..75fe7e71 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ContainerTerminationCallbackImplTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ContainerTerminationCallbackImplTest.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import org.hobbit.controller.containers.docker.ContainerTerminationCallbackImpl; import org.junit.Test; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/FileBasedImageManagerTest.java similarity index 96% rename from platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/FileBasedImageManagerTest.java index 278961ac..c00fcda7 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/FileBasedImageManagerTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/FileBasedImageManagerTest.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import org.hobbit.controller.containers.FileBasedImageManager; import org.hobbit.core.data.BenchmarkMetaData; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/GitlabBasedImageManagerTest.java similarity index 99% rename from platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/GitlabBasedImageManagerTest.java index e8565dc9..5ecdbc1c 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/GitlabBasedImageManagerTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/GitlabBasedImageManagerTest.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.util.ArrayList; import java.util.Collection; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/LongImageNameTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/LongImageNameTest.java similarity index 96% rename from platform-controller/src/test/java/org/hobbit/controller/docker/LongImageNameTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/LongImageNameTest.java index be739fa6..b43bfd53 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/LongImageNameTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/LongImageNameTest.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import static org.junit.Assert.assertNotNull; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/MetaDataFactoryTest.java similarity index 99% rename from platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/MetaDataFactoryTest.java index b73b413f..f2ea0de5 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/MetaDataFactoryTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/MetaDataFactoryTest.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.io.IOException; import java.io.InputStream; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/ResourceInformationCollectorTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorTest.java similarity index 98% rename from platform-controller/src/test/java/org/hobbit/controller/docker/ResourceInformationCollectorTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorTest.java index d252a955..73b95611 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/ResourceInformationCollectorTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/ResourceInformationCollectorTest.java @@ -1,4 +1,4 @@ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import static org.junit.Assert.assertNotNull; @@ -8,7 +8,6 @@ import org.apache.jena.vocabulary.RDF; import org.apache.jena.vocabulary.RDFS; import org.hobbit.controller.containers.ResourceInformationCollector; -import org.hobbit.controller.containers.docker.ResourceInformationCollectorImpl; import org.hobbit.controller.data.SetupHardwareInformation; import org.hobbit.core.Constants; import org.hobbit.core.data.usage.ResourceUsageInformation; diff --git a/platform-controller/src/test/java/org/hobbit/controller/docker/VersionTagIdentificationTest.java b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/VersionTagIdentificationTest.java similarity index 89% rename from platform-controller/src/test/java/org/hobbit/controller/docker/VersionTagIdentificationTest.java rename to platform-controller/src/test/java/org/hobbit/controller/containers/docker/VersionTagIdentificationTest.java index 8449960a..49cbf85b 100644 --- a/platform-controller/src/test/java/org/hobbit/controller/docker/VersionTagIdentificationTest.java +++ b/platform-controller/src/test/java/org/hobbit/controller/containers/docker/VersionTagIdentificationTest.java @@ -14,14 +14,13 @@ * You should have received a copy of the GNU General Public License * along with platform-controller. If not, see . */ -package org.hobbit.controller.docker; +package org.hobbit.controller.containers.docker; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import org.hobbit.controller.containers.docker.ContainerManagerImpl; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -29,10 +28,6 @@ import org.junit.runners.Parameterized.Parameters; -/** - * - * TODO: maybe have a single class implementing the containsVersionTag method independently of Docker swarm or Kubernetes - */ @RunWith(Parameterized.class) public class VersionTagIdentificationTest { diff --git a/test.yml b/test.yml deleted file mode 100644 index 22619ec6..00000000 --- a/test.yml +++ /dev/null @@ -1,13 +0,0 @@ -version: '3.3' -services: - redis: - image: redis:4.0.7 - volumes: - - ./config/redis-db:/data - command: ["redis-server", "/data/redis.conf"] - networks: - - test -networks: - test: - external: true - From b8235fcd0708c286f8e54e8b83b49eb3ee671035 Mon Sep 17 00:00:00 2001 From: farshad68 Date: Wed, 16 Apr 2025 14:35:56 +0200 Subject: [PATCH 52/52] add @author to all files I changed, not the files add log or change package name --- .../src/main/java/org/hobbit/controller/ExperimentManager.java | 2 +- .../src/main/java/org/hobbit/controller/PlatformController.java | 1 + .../containers/kubernetes/ContainerStateObserverImpl.java | 1 + .../main/java/org/hobbit/controller/data/ContainerCriteria.java | 1 + .../data/ContainerCriteriaToServiceCriteriaMapper.java | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java index e59de130..669c236f 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java +++ b/platform-controller/src/main/java/org/hobbit/controller/ExperimentManager.java @@ -74,7 +74,7 @@ * running experiment. * * @author Michael Röder (roeder@informatik.uni-leipzig.de) - * + * @author Farshad Afshari farshad.afshari@uni-paderborn.de */ public class ExperimentManager implements Closeable { private static final Logger LOGGER = LoggerFactory.getLogger(ExperimentManager.class); diff --git a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java index 2ab753aa..ec538a60 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java +++ b/platform-controller/src/main/java/org/hobbit/controller/PlatformController.java @@ -86,6 +86,7 @@ * This class implements the functionality of the central platform controller. * * @author Michael Röder (roeder@informatik.uni-leipzig.de) + * @author Farshad Afshari farshad.afshari@uni-paderborn.de * */ public class PlatformController extends AbstractComponent implements ContainerTerminationCallback, ExperimentAnalyzer { diff --git a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java index 05be3681..d6f487dc 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java +++ b/platform-controller/src/main/java/org/hobbit/controller/containers/kubernetes/ContainerStateObserverImpl.java @@ -15,6 +15,7 @@ /** * A concrete implementation of {@link ContainerStateObserver} that monitors Kubernetes pods and * notifies registered callbacks when a pod terminates. + * @author Farshad Afshari farshad.afshari@uni-paderborn.de */ public class ContainerStateObserverImpl implements ContainerStateObserver { diff --git a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java index 74f2600e..90fb61b7 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java +++ b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteria.java @@ -11,6 +11,7 @@ * *

Instances of this class are immutable and should be created using the * {@link ContainerCriteria.Builder}.

+ * @author Farshad Afshari farshad.afshari@uni-paderborn.de */ public class ContainerCriteria { diff --git a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java index 8cbc069f..58297100 100644 --- a/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java +++ b/platform-controller/src/main/java/org/hobbit/controller/data/ContainerCriteriaToServiceCriteriaMapper.java @@ -35,6 +35,7 @@ * Service.Criteria serviceCriteria = ContainerCriteriaToServiceCriteriaMapper.map(criteria); * List services = dockerClient.listServices(serviceCriteria); * } + * @author Farshad Afshari farshad.afshari@uni-paderborn.de */ public class ContainerCriteriaToServiceCriteriaMapper {