Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {

allprojects {
group = 'org.eclipse'
version = '3.5.2'
version = '3.5.3'
}

subprojects {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,10 @@ private final Future<Boolean> processChanges(JsonObject changes) {
resetChanges = false;
}
}

// Notify ProcessManager to immediately restart monitoring thread
// This ensures containers are processed without waiting for the next scheduled interval
ProcessManager.getInstance().update();

if (execSessions) {
logDebug("Processing exec sessions changes");
Expand Down Expand Up @@ -1019,7 +1023,8 @@ private Function<JsonObject, Microservice> containerJsonObjectToMicroserviceFunc
microservice.setRuntime(jsonObj.getString("runtime"));
}
microservice.setRebuild(jsonObj.getBoolean("rebuild"));
microservice.setRootHostAccess(jsonObj.getBoolean("rootHostAccess"));
microservice.setHostNetworkMode(jsonObj.getBoolean("hostNetworkMode"));
microservice.setIsPrivileged(jsonObj.getBoolean("isPrivileged"));
microservice.setRegistryId(jsonObj.getInt("registryId"));
microservice.setSchedule(jsonObj.getInt("schedule"));
microservice.setLogSize(jsonObj.getJsonNumber("logSize").longValue());
Expand All @@ -1033,6 +1038,7 @@ private Function<JsonObject, Microservice> containerJsonObjectToMicroserviceFunc
microservice.setRouter(jsonObj.getBoolean("isRouter"));
if (jsonObj.getBoolean("isRouter")) {
Configuration.setRouterUuid(jsonObj.getString("uuid"));
Configuration.setRouterInterior(jsonObj.getBoolean("hostNetworkMode"));
}
microservice.setExecEnabled(jsonObj.getBoolean("execEnabled"));

Expand Down Expand Up @@ -1914,6 +1920,9 @@ public void start() {
List<Microservice> microservices = loadMicroservices(!isConnected);
processMicroserviceConfig(microservices);
processRoutes(microservices);
// Notify ProcessManager to immediately restart monitoring thread
// This ensures containers are processed during initialization without waiting
ProcessManager.getInstance().update();
loadEdgeResources(!isConnected);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public class Microservice {
private int registryId;
private String containerIpAddress;
private boolean rebuild;
private boolean rootHostAccess;
private boolean hostNetworkMode;
private boolean isPrivileged;
private long logSize;
private List<VolumeMapping> volumeMappings;
private boolean isUpdating;
Expand Down Expand Up @@ -153,12 +154,20 @@ public String getImageName() {
return imageName;
}

public boolean isRootHostAccess() {
return rootHostAccess;
public boolean isPrivileged() {
return isPrivileged;
}

public void setRootHostAccess(boolean rootHostAccess) {
this.rootHostAccess = rootHostAccess;
public boolean isHostNetworkMode() {
return hostNetworkMode;
}

public void setHostNetworkMode(boolean hostNetworkMode) {
this.hostNetworkMode = hostNetworkMode;
}

public void setIsPrivileged(boolean isPrivileged) {
this.isPrivileged = isPrivileged;
}

public boolean isExecEnabled() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,14 @@ public class Registry {
private final int id;
private final String url;
private final boolean isPublic;
private final boolean secure;
private final String certificate;
private final boolean requiresCertificate;
private final String userName;
private final String password;
private final String userEmail;

private Registry(final int id, final String url, final boolean isPublic, final boolean secure, final String certificate, final boolean requiresCertificate,
final String userName, final String password, final String userEmail) {
private Registry(final int id, final String url, final boolean isPublic, final String userName, final String password, final String userEmail) {
this.id = id;
this.url = url;
this.isPublic = isPublic;
this.secure = secure;
this.certificate = certificate;
this.requiresCertificate = requiresCertificate;
this.userName = userName;
this.password = password;
this.userEmail = userEmail;
Expand All @@ -56,18 +49,6 @@ public boolean getIsPublic() {
return isPublic;
}

public boolean isSecure() {
return secure;
}

public String getCertificate() {
return certificate;
}

public boolean isRequiresCertificate() {
return requiresCertificate;
}

public String getUserName() {
return userName;
}
Expand Down Expand Up @@ -100,9 +81,6 @@ public static class RegistryBuilder {
private int id;
private String url;
private boolean isPublic;
private boolean secure;
private String certificate;
private boolean requiresCertificate;
private String userName;
private String password;
private String userEmail;
Expand All @@ -122,21 +100,6 @@ public RegistryBuilder setIsPublic(boolean isPublic) {
return this;
}

public RegistryBuilder setSecure(boolean secure) {
this.secure = secure;
return this;
}

public RegistryBuilder setCertificate(String certificate) {
this.certificate = certificate;
return this;
}

public RegistryBuilder setRequiresCertificate(boolean requiresCertificate) {
this.requiresCertificate = requiresCertificate;
return this;
}

public RegistryBuilder setUserName(String userName) {
this.userName = userName;
return this;
Expand All @@ -153,7 +116,7 @@ public RegistryBuilder setUserEmail(String userEmail) {
}

public Registry build() {
return new Registry(id, url, isPublic, secure, certificate, requiresCertificate, userName, password, userEmail);
return new Registry(id, url, isPublic, userName, password, userEmail);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ public long getContainerStartedAt(String id) {
public boolean areMicroserviceAndContainerEqual(String containerId, Microservice microservice) {
LoggingService.logDebug(MODULE_NAME ,"Are Microservice And Container Equal microservice : " + microservice.getImageName() + "container id : " + containerId);
InspectContainerResponse inspectInfo = dockerClient.inspectContainerCmd(containerId).exec();
return isPortMappingEqual(inspectInfo, microservice) && isNetworkModeEqual(inspectInfo, microservice);
return isPortMappingEqual(inspectInfo, microservice) && isNetworkModeEqual(inspectInfo, microservice) && isEnvVarsEqual(inspectInfo, microservice);
}

/**
Expand All @@ -534,10 +534,10 @@ public boolean areMicroserviceAndContainerEqual(String containerId, Microservice
*/
private boolean isNetworkModeEqual(InspectContainerResponse inspectInfo, Microservice microservice) {
LoggingService.logDebug(MODULE_NAME ,"is NetworkMode Equal for microservice : " + microservice.getImageName());
boolean isRootHostAccess = microservice.isRootHostAccess();
boolean isHostNetworkMode = microservice.isHostNetworkMode();
HostConfig hostConfig = inspectInfo.getHostConfig();
return (isRootHostAccess && "host".equals(hostConfig.getNetworkMode()))
|| !isRootHostAccess && (hostConfig != null && hostConfig.getExtraHosts() != null && hostConfig.getExtraHosts().length > 0);
return (isHostNetworkMode && "host".equals(hostConfig.getNetworkMode()))
|| !isHostNetworkMode && (hostConfig != null && hostConfig.getExtraHosts() != null && hostConfig.getExtraHosts().length > 0);
}

/**
Expand All @@ -560,6 +560,58 @@ private boolean isPortMappingEqual(InspectContainerResponse inspectInfo, Microse
return areEqual;
}

/**
* compares if microservice environment variables are equal to container environment variables
*
* @param inspectInfo result of docker inspect command
* @param microservice microservice
* @return boolean
*/
private boolean isEnvVarsEqual(InspectContainerResponse inspectInfo, Microservice microservice) {
LoggingService.logDebug(MODULE_NAME, "is EnvVars Equal for microservice : " + microservice.getImageName());

// Get microservice environment variables
List<EnvVar> microserviceEnvVars = microservice.getEnvVars();
if (microserviceEnvVars == null || microserviceEnvVars.isEmpty()) {
microserviceEnvVars = new ArrayList<>();
}

// Get container environment variables from inspect info
String[] containerEnvArray = inspectInfo.getConfig().getEnv();
Map<String, String> containerEnvVars = new HashMap<>();
if (containerEnvArray != null) {
for (String envVar : containerEnvArray) {
if (envVar != null && envVar.contains("=")) {
String[] parts = envVar.split("=", 2);
if (parts.length == 2) {
containerEnvVars.put(parts[0], parts[1]);
}
}
}
}

// Check if all microservice env vars exist in container with same values
for (EnvVar microserviceEnvVar : microserviceEnvVars) {
String key = microserviceEnvVar.getKey();
String expectedValue = microserviceEnvVar.getValue();

if (!containerEnvVars.containsKey(key)) {
LoggingService.logDebug(MODULE_NAME, "Env var key not found in container: " + key);
return false;
}

String actualValue = containerEnvVars.get(key);
if (!expectedValue.equals(actualValue)) {
LoggingService.logDebug(MODULE_NAME, "Env var value mismatch for key " + key +
". Expected: " + expectedValue + ", Actual: " + actualValue);
return false;
}
}

LoggingService.logDebug(MODULE_NAME, "Env vars are equal for microservice " + microservice.getImageName());
return true;
}

private List<PortMapping> getMicroservicePorts(Microservice microservice) {
LoggingService.logDebug(MODULE_NAME ,"get list of Microservice Ports for microservice : " + microservice.getImageName());
return microservice.getPortMappings() != null ? microservice.getPortMappings() : new ArrayList<>();
Expand Down Expand Up @@ -763,12 +815,19 @@ public String createContainer(Microservice microservice, String host) throws Not
}

// Add service.local host for non-router microservices
if (!microservice.isRootHostAccess() && !microservice.isRouter()) {
String routerIP = getRouterMicroserviceIP();
if (routerIP != null) {
if (!microservice.isHostNetworkMode() && !microservice.isRouter()) {
if (!Configuration.isRouterInterior()) {
String routerIP = getRouterMicroserviceIP();
if (routerIP != null) {
String[] newHosts = new String[hosts.length + 1];
System.arraycopy(hosts, 0, newHosts, 0, hosts.length);
newHosts[hosts.length] = "service.local:" + routerIP;
hosts = newHosts;
}
} else {
String[] newHosts = new String[hosts.length + 1];
System.arraycopy(hosts, 0, newHosts, 0, hosts.length);
newHosts[hosts.length] = "service.local:" + routerIP;
newHosts[hosts.length] = "service.local:" + host;
hosts = newHosts;
}
}
Expand Down Expand Up @@ -853,23 +912,29 @@ public String createContainer(Microservice microservice, String host) throws Not
}

if (SystemUtils.IS_OS_WINDOWS) {
if(microservice.isRootHostAccess()){
hostConfig.withNetworkMode("host").withExtraHosts(hosts).withPrivileged(true);
if(microservice.isHostNetworkMode()){
hostConfig.withNetworkMode("host").withExtraHosts(hosts);
} else if(hosts[hosts.length - 1] != null) {
hostConfig.withNetworkMode("pot").withExtraHosts(hosts).withPrivileged(false);
hostConfig.withNetworkMode("pot").withExtraHosts(hosts);
}
} else if (SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC) {
if(microservice.isRootHostAccess()){
hostConfig.withNetworkMode("host").withPrivileged(true);
if(microservice.isHostNetworkMode()){
hostConfig.withNetworkMode("host");
} else if(hosts[hosts.length - 1] != null) {
hostConfig.withNetworkMode("pot").withExtraHosts(hosts).withPrivileged(false);
hostConfig.withNetworkMode("pot").withExtraHosts(hosts);
}
}

if (microservice.isPrivileged()) {
hostConfig.withPrivileged(true);
} else {
hostConfig.withPrivileged(false);
}

if (microservice.getRuntime() != null && !microservice.getRuntime().isEmpty()) {
hostConfig.withRuntime(microservice.getRuntime());
}

// TODO: Test cdi devices if this one is not working, either add capabilities "gpu" or add controller microservice cdi definition capabilities
if (microservice.getCdiDevs() != null && !microservice.getCdiDevs().isEmpty()) {
List<String> deviceIds = microservice.getCdiDevs();
DeviceRequest deviceRequest = new DeviceRequest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class ProcessManager implements IOFogModule {
private DockerUtil docker;
private ContainerManager containerManager;
private static ProcessManager instance;
private final Object monitorLock = new Object();

private ProcessManager() {
}
Expand Down Expand Up @@ -91,26 +92,45 @@ private void updateRegistriesStatus() {
*/
public void update() {
updateRegistriesStatus();
// Notify the monitor thread to restart immediately instead of waiting
notifyMonitorThread();
}

/**
* Notifies the containers monitor thread to wake up immediately
* and process microservice changes without waiting for the next scheduled interval
*/
private void notifyMonitorThread() {
synchronized (monitorLock) {
monitorLock.notifyAll();
}
}

/**
* monitor containers
* removes {@link Container} if does not exists in list of {@link Microservice}
* restarts {@link Container} if it has been stopped
* updates {@link Container} if restarting failed!
*
* Uses wait/notify pattern to allow immediate restart when microservices change,
* instead of waiting for the full sleep interval.
*/
private final Runnable containersMonitor = () -> {
while (true) {
try {
Thread.sleep(Configuration.getMonitorContainersStatusFreqSeconds() * 1000);
} catch (InterruptedException e) {
logError("Error while sleeping thread",
new AgentSystemException(e.getMessage(), e));
synchronized (monitorLock) {
try {
// Wait for the configured interval, but can be woken up early by notifyMonitorThread()
monitorLock.wait(Configuration.getMonitorContainersStatusFreqSeconds() * 1000);
} catch (InterruptedException e) {
logError("Error while waiting for monitor interval",
new AgentSystemException(e.getMessage(), e));
// Restore interrupted status
Thread.currentThread().interrupt();
}
}
logDebug("Start Monitoring containers");

try {

handleLatestMicroservices();
deleteRemainingMicroservices();
updateRunningMicroservicesCount();
Expand Down
Loading
Loading