diff --git a/pom.xml b/pom.xml
index 8a1f54d1..aff1e656 100644
--- a/pom.xml
+++ b/pom.xml
@@ -103,6 +103,11 @@
plain-credentials
1.7
+
+ org.apache.commons
+ commons-collections4
+ 4.4
+
diff --git a/src/main/java/hudson/plugins/spotinst/api/SpotinstApi.java b/src/main/java/hudson/plugins/spotinst/api/SpotinstApi.java
index f1a6fa41..f64ab14c 100644
--- a/src/main/java/hudson/plugins/spotinst/api/SpotinstApi.java
+++ b/src/main/java/hudson/plugins/spotinst/api/SpotinstApi.java
@@ -7,6 +7,10 @@
import hudson.plugins.spotinst.model.aws.*;
import hudson.plugins.spotinst.model.azure.*;
import hudson.plugins.spotinst.model.gcp.*;
+import hudson.plugins.spotinst.model.redis.UnlockGroupControllerResponse;
+import hudson.plugins.spotinst.model.redis.GetGroupControllerLockResponse;
+import hudson.plugins.spotinst.model.redis.LockGroupControllerRequest;
+import hudson.plugins.spotinst.model.redis.LockGroupControllerResponse;
import jenkins.model.Jenkins;
import org.apache.commons.httpclient.HttpStatus;
import org.slf4j.Logger;
@@ -19,7 +23,7 @@ public class SpotinstApi {
//region Members
private static final Logger LOGGER = LoggerFactory.getLogger(SpotinstApi.class);
- private final static String SPOTINST_API_HOST = "https://api.spotinst.io";
+ private final static String SPOTINST_API_HOST = "http://localhost:3100";
private final static String HEADER_AUTH = "Authorization";
private final static String AUTH_PREFIX = "Bearer ";
private final static String HEADER_CONTENT_TYPE = "Content-Type";
@@ -89,8 +93,9 @@ public static AwsScaleUpResult awsScaleUp(String groupId, int adjustment, String
Map queryParams = buildQueryParams(accountId);
queryParams.put(QUERY_PARAM_ADJUSTMENT, String.valueOf(adjustment));
- RestResponse response = RestClient
- .sendPut(SPOTINST_API_HOST + "/aws/ec2/group/" + groupId + "/scale/up", null, headers, queryParams);
+ RestResponse response =
+ RestClient.sendPut(SPOTINST_API_HOST + "/aws/ec2/group/" + groupId + "/scale/up", null, headers,
+ queryParams);
AwsScaleUpResponse scaleUpResponse = getCastedResponse(response, AwsScaleUpResponse.class);
@@ -125,13 +130,12 @@ public static List getAllAwsInstanceTypes(String accountId) thr
List retVal;
Map headers = buildHeaders();
Map queryParams = buildQueryParams(accountId);
- queryParams.put("distinctTypesList","true");
+ queryParams.put("distinctTypesList", "true");
- RestResponse response =
- RestClient.sendGet(SPOTINST_API_HOST + "/aws/ec2/instanceType", headers, queryParams);
+ RestResponse response = RestClient.sendGet(SPOTINST_API_HOST + "/aws/ec2/instanceType", headers, queryParams);
- AwsInstanceTypesResponse
- allAwsInstanceTypesResponse = getCastedResponse(response, AwsInstanceTypesResponse.class);
+ AwsInstanceTypesResponse allAwsInstanceTypesResponse =
+ getCastedResponse(response, AwsInstanceTypesResponse.class);
retVal = allAwsInstanceTypesResponse.getResponse().getItems();
@@ -149,8 +153,9 @@ public static GcpScaleUpResult gcpScaleUp(String groupId, int adjustment, String
Map queryParams = buildQueryParams(accountId);
queryParams.put(QUERY_PARAM_ADJUSTMENT, String.valueOf(adjustment));
- RestResponse response = RestClient
- .sendPut(SPOTINST_API_HOST + "/gcp/gce/group/" + groupId + "/scale/up", null, headers, queryParams);
+ RestResponse response =
+ RestClient.sendPut(SPOTINST_API_HOST + "/gcp/gce/group/" + groupId + "/scale/up", null, headers,
+ queryParams);
GcpScaleUpResponse scaleUpResponse = getCastedResponse(response, GcpScaleUpResponse.class);
@@ -171,9 +176,9 @@ public static Boolean gcpDetachInstance(String groupId, String instanceName, Str
request.setShouldTerminateInstances(true);
String body = JsonMapper.toJson(request);
- RestResponse response = RestClient
- .sendPut(SPOTINST_API_HOST + "/gcp/gce/group/" + groupId + "/detachInstances", body, headers,
- queryParams);
+ RestResponse response =
+ RestClient.sendPut(SPOTINST_API_HOST + "/gcp/gce/group/" + groupId + "/detachInstances", body, headers,
+ queryParams);
getCastedResponse(response, ApiEmptyResponse.class);
Boolean retVal = true;
@@ -206,8 +211,9 @@ public static List getAzureGroupInstances(String groupId,
Map headers = buildHeaders();
Map queryParams = buildQueryParams(accountId);
- RestResponse response = RestClient
- .sendGet(SPOTINST_API_HOST + "/compute/azure/group/" + groupId + "/status", headers, queryParams);
+ RestResponse response =
+ RestClient.sendGet(SPOTINST_API_HOST + "/compute/azure/group/" + groupId + "/status", headers,
+ queryParams);
AzureGroupInstancesResponse instancesResponse = getCastedResponse(response, AzureGroupInstancesResponse.class);
@@ -224,9 +230,9 @@ public static Boolean azureScaleUp(String groupId, int adjustment, String accoun
Map queryParams = buildQueryParams(accountId);
queryParams.put("adjustment", String.valueOf(adjustment));
- RestResponse response = RestClient
- .sendPut(SPOTINST_API_HOST + "/compute/azure/group/" + groupId + "/scale/up", null, headers,
- queryParams);
+ RestResponse response =
+ RestClient.sendPut(SPOTINST_API_HOST + "/compute/azure/group/" + groupId + "/scale/up", null, headers,
+ queryParams);
getCastedResponse(response, ApiEmptyResponse.class);
Boolean retVal = true;
@@ -243,9 +249,9 @@ public static Boolean azureDetachInstance(String groupId, String instanceId, Str
request.setShouldDecrementTargetCapacity(true);
String body = JsonMapper.toJson(request);
- RestResponse response = RestClient
- .sendPut(SPOTINST_API_HOST + "/compute/azure/group/" + groupId + "/detachInstances", body, headers,
- queryParams);
+ RestResponse response =
+ RestClient.sendPut(SPOTINST_API_HOST + "/compute/azure/group/" + groupId + "/detachInstances", body,
+ headers, queryParams);
getCastedResponse(response, ApiEmptyResponse.class);
Boolean retVal = true;
@@ -260,9 +266,9 @@ public static AzureGroupStatus getAzureVmGroupStatus(String groupId, String acco
Map headers = buildHeaders();
Map queryParams = buildQueryParams(accountId);
- RestResponse response = RestClient
- .sendGet(SPOTINST_API_HOST + AZURE_VM_SERVICE_PREFIX + "/group/" + groupId + "/status", headers,
- queryParams);
+ RestResponse response =
+ RestClient.sendGet(SPOTINST_API_HOST + AZURE_VM_SERVICE_PREFIX + "/group/" + groupId + "/status",
+ headers, queryParams);
AzureGroupStatusResponse vmsResponse = getCastedResponse(response, AzureGroupStatusResponse.class);
@@ -281,9 +287,9 @@ public static List azureVmScaleUp(String groupId, int a
Map queryParams = buildQueryParams(accountId);
queryParams.put("adjustment", String.valueOf(adjustment));
- RestResponse response = RestClient
- .sendPut(SPOTINST_API_HOST + AZURE_VM_SERVICE_PREFIX + "/group/" + groupId + "/scale/up", null, headers,
- queryParams);
+ RestResponse response =
+ RestClient.sendPut(SPOTINST_API_HOST + AZURE_VM_SERVICE_PREFIX + "/group/" + groupId + "/scale/up",
+ null, headers, queryParams);
AzureScaleUpResponse scaleUpResponse = getCastedResponse(response, AzureScaleUpResponse.class);
@@ -303,9 +309,9 @@ public static Boolean azureVmDetach(String groupId, String vmId, String accountI
request.setShouldDecrementTargetCapacity(true);
request.setShouldTerminateVms(true);
String body = JsonMapper.toJson(request);
- RestResponse response = RestClient
- .sendPut(SPOTINST_API_HOST + AZURE_VM_SERVICE_PREFIX + "/group/" + groupId + "/detachVms", body,
- headers, queryParams);
+ RestResponse response =
+ RestClient.sendPut(SPOTINST_API_HOST + AZURE_VM_SERVICE_PREFIX + "/group/" + groupId + "/detachVms",
+ body, headers, queryParams);
getCastedResponse(response, ApiEmptyResponse.class);
Boolean retVal = true;
@@ -313,6 +319,67 @@ public static Boolean azureVmDetach(String groupId, String vmId, String accountI
}
//endregion
+ //Redis
+ public static String getGroupLockValueById(String groupId, String accountId) throws ApiException {
+ String retVal = null;
+
+ Map headers = buildHeaders();
+
+ Map queryParams = buildQueryParams(accountId);
+
+ RestResponse response =
+ RestClient.sendGet(SPOTINST_API_HOST + "/aws/ec2/group/" + groupId + "/jenkinsPlugin/lock", headers,
+ queryParams);
+
+ GetGroupControllerLockResponse lockResponse = getCastedResponse(response, GetGroupControllerLockResponse.class);
+
+ if (CollectionUtils.isEmpty(lockResponse.getResponse().getItems()) == false) {
+ retVal = lockResponse.getResponse().getItems().get(0);
+ }
+
+ return retVal;
+ }
+
+ public static String LockGroupController(String lockKey, String accountId, String lockValue,
+ Integer ttl) throws ApiException {
+ String retVal = null;
+ Map headers = buildHeaders();
+ Map queryParams = buildQueryParams(accountId);
+ LockGroupControllerRequest request = new LockGroupControllerRequest(lockKey, lockValue, ttl);
+ String body = JsonMapper.toJson(request);
+
+ RestResponse response =
+ RestClient.sendPost(SPOTINST_API_HOST + "/aws/ec2/group/jenkinsPlugin/lock", body, headers,
+ queryParams);
+
+ LockGroupControllerResponse lockControllerValue =
+ getCastedResponse(response, LockGroupControllerResponse.class);
+ //TODO: check optimizer and service response
+ if (lockControllerValue.getResponse().getItems().size() > 0) {
+ retVal = lockControllerValue.getResponse().getItems().get(0);
+ }
+
+ return retVal;
+ }
+
+ public static Integer UnlockGroupController(String groupId, String accountId) throws ApiException {
+ Integer retVal = null;
+
+ Map headers = buildHeaders();
+ Map queryParams = buildQueryParams(accountId);
+ RestResponse response =
+ RestClient.sendDelete(SPOTINST_API_HOST + "/aws/ec2/group/" + groupId + "/jenkinsPlugin/lock", headers,
+ queryParams);
+ UnlockGroupControllerResponse redisValue = getCastedResponse(response, UnlockGroupControllerResponse.class);
+
+ if (redisValue.getResponse().getItems().size() > 0) {
+ retVal = redisValue.getResponse().getItems().get(0);
+ }
+
+ return retVal;
+ }
+ //endregion
+
//region Private Methods
private static String buildUserAgent() {
String retVal = null;
diff --git a/src/main/java/hudson/plugins/spotinst/api/infra/RestClient.java b/src/main/java/hudson/plugins/spotinst/api/infra/RestClient.java
index f5dbded5..5c6c9d7d 100644
--- a/src/main/java/hudson/plugins/spotinst/api/infra/RestClient.java
+++ b/src/main/java/hudson/plugins/spotinst/api/infra/RestClient.java
@@ -61,6 +61,40 @@ public static RestResponse sendPut(String url, String body, Map
return retVal;
}
+
+ public static RestResponse sendDelete(String url, Map headers,
+ Map queryParams) throws ApiException {
+
+ HttpDelete getRequest = new HttpDelete(url);
+ addQueryParams(getRequest, queryParams);
+ addHeaders(getRequest, headers);
+ RestResponse retVal = sendRequest(getRequest);
+
+ return retVal;
+ }
+
+ public static RestResponse sendPost(String url, String body, Map headers,
+ Map queryParams) throws ApiException {
+
+ HttpPost postRequest = new HttpPost(url);
+
+ if (body != null) {
+ StringEntity entity = null;
+ try {
+ entity = new StringEntity(body);
+ }
+ catch (UnsupportedEncodingException e) {
+ LOGGER.error("Exception when building put body", e);
+ }
+ postRequest.setEntity(entity);
+ }
+
+ addQueryParams(postRequest, queryParams);
+ addHeaders(postRequest, headers);
+ RestResponse retVal = sendRequest(postRequest);
+
+ return retVal;
+ }
//endregion
//region Private Methods
diff --git a/src/main/java/hudson/plugins/spotinst/cloud/AwsSpotinstCloud.java b/src/main/java/hudson/plugins/spotinst/cloud/AwsSpotinstCloud.java
index 387080ac..66b2b05f 100644
--- a/src/main/java/hudson/plugins/spotinst/cloud/AwsSpotinstCloud.java
+++ b/src/main/java/hudson/plugins/spotinst/cloud/AwsSpotinstCloud.java
@@ -18,6 +18,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.*;
@@ -32,7 +33,7 @@ public class AwsSpotinstCloud extends BaseSpotinstCloud {
private static final String CLOUD_URL = "aws/ec2";
protected Map executorsByInstanceType;
private List extends SpotinstInstanceWeight> executorsForTypes;
- private List invalidInstanceTypes;
+ private List invalidInstanceTypes;
//endregion
//region Constructor
@@ -117,7 +118,7 @@ public Boolean detachInstance(String instanceId) {
}
@Override
- public void syncGroupInstances() {
+ protected void handleSyncGroupInstances() {
IAwsGroupRepo awsGroupRepo = RepoManager.getInstance().getAwsGroupRepo();
ApiResponse> instancesResponse = awsGroupRepo.getGroupInstances(groupId, this.accountId);
@@ -136,8 +137,6 @@ public void syncGroupInstances() {
addNewSlaveInstances(instances);
removeOldSlaveInstances(instances);
-
-
}
else {
LOGGER.error(String.format("Failed to get group %s instances. Errors: %s", groupId,
@@ -145,12 +144,12 @@ public void syncGroupInstances() {
}
}
- @Override
- public Map getInstanceIpsById() {
- Map retVal = new HashMap<>();
- IAwsGroupRepo awsGroupRepo = RepoManager.getInstance().getAwsGroupRepo();
- ApiResponse> instancesResponse = awsGroupRepo.getGroupInstances(groupId, this.accountId);
+ @Override
+ public Map handleGetInstanceIpsById() {
+ Map retVal = new HashMap<>();
+ IAwsGroupRepo awsGroupRepo = RepoManager.getInstance().getAwsGroupRepo();
+ ApiResponse> instancesResponse = awsGroupRepo.getGroupInstances(groupId, accountId);
if (instancesResponse.isRequestSucceed()) {
List instances = instancesResponse.getValue();
@@ -208,7 +207,7 @@ protected int getOverridedNumberOfExecutors(String instanceType) {
LOGGER.info(String.format("We have a weight definition for this type of %s", retVal));
}
else {
- retVal = NO_OVERRIDED_NUM_OF_EXECUTORS;
+ retVal = NO_OVERRIDDEN_NUM_OF_EXECUTORS;
}
return retVal;
@@ -380,7 +379,7 @@ private void initExecutorsByInstanceType() {
String type = instance.getAwsInstanceTypeFromAPIInput();
this.executorsByInstanceType.put(type, executors);
- if(instance.getIsValid() == false){
+ if (instance.getIsValid() == false) {
LOGGER.error(String.format("Invalid type \'%s\' in group \'%s\'", type, this.getGroupId()));
invalidInstanceTypes.add(type);
}
@@ -404,6 +403,7 @@ public List getInvalidInstanceTypes() {
@Extension
public static class DescriptorImpl extends BaseSpotinstCloud.DescriptorImpl {
+ @Nonnull
@Override
public String getDisplayName() {
return "Spot AWS Elastigroup";
diff --git a/src/main/java/hudson/plugins/spotinst/cloud/AzureSpotCloud.java b/src/main/java/hudson/plugins/spotinst/cloud/AzureSpotCloud.java
index f7bf5a5d..4b496ee1 100644
--- a/src/main/java/hudson/plugins/spotinst/cloud/AzureSpotCloud.java
+++ b/src/main/java/hudson/plugins/spotinst/cloud/AzureSpotCloud.java
@@ -23,6 +23,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
@@ -107,7 +108,7 @@ protected Integer getPendingThreshold() {
}
@Override
- public void syncGroupInstances() {
+ protected void handleSyncGroupInstances() {
IAzureVmGroupRepo azureVmGroupRepo = RepoManager.getInstance().getAzureVmGroupRepo();
ApiResponse> instancesResponse = azureVmGroupRepo.getGroupVms(groupId, this.accountId);
@@ -135,11 +136,11 @@ public void syncGroupInstances() {
}
@Override
- public Map getInstanceIpsById() {
+ public Map handleGetInstanceIpsById() {
Map retVal = new HashMap<>();
IAzureVmGroupRepo awsGroupRepo = RepoManager.getInstance().getAzureVmGroupRepo();
- ApiResponse> instancesResponse = awsGroupRepo.getGroupVms(groupId, this.accountId);
+ ApiResponse> instancesResponse = awsGroupRepo.getGroupVms(groupId, accountId);
if (instancesResponse.isRequestSucceed()) {
List instances = instancesResponse.getValue();
@@ -193,7 +194,7 @@ private List handleNewVms(List newVms, S
}
private SpotinstSlave handleNewVm(String vmName, String vmSize, String label) {
- Integer executors = getNumOfExecutors(vmSize);
+ Integer executors = getNumOfExecutors(vmSize);
addToPending(vmName, executors, PendingInstance.StatusEnum.PENDING, label);
SpotinstSlave retVal = buildSpotinstSlave(vmName, vmSize, String.valueOf(executors));
return retVal;
@@ -260,8 +261,8 @@ private void addSpotinstSlave(AzureGroupVm vm) {
SpotinstSlave slave = null;
if (vm.getVmName() != null) {
- String vmSize = vm.getVmSize();
- Integer executors = getNumOfExecutors(vmSize);
+ String vmSize = vm.getVmSize();
+ Integer executors = getNumOfExecutors(vmSize);
slave = buildSpotinstSlave(vm.getVmName(), vmSize, String.valueOf(executors));
}
@@ -292,6 +293,7 @@ private Boolean isSlaveExistForInstance(AzureGroupVm vm) {
@Extension
public static class DescriptorImpl extends BaseSpotinstCloud.DescriptorImpl {
+ @Nonnull
@Override
public String getDisplayName() {
return "Spot Azure Elastigroup";
diff --git a/src/main/java/hudson/plugins/spotinst/cloud/AzureSpotinstCloud.java b/src/main/java/hudson/plugins/spotinst/cloud/AzureSpotinstCloud.java
index 99e25a99..c8160efd 100644
--- a/src/main/java/hudson/plugins/spotinst/cloud/AzureSpotinstCloud.java
+++ b/src/main/java/hudson/plugins/spotinst/cloud/AzureSpotinstCloud.java
@@ -21,6 +21,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.*;
@@ -73,7 +74,7 @@ public Boolean detachInstance(String instanceId) {
Boolean retVal = false;
IAzureGroupRepo azureGroupRepo = RepoManager.getInstance().getAzureGroupRepo();
ApiResponse detachInstanceResponse =
- azureGroupRepo.detachInstance(groupId, instanceId, this.accountId);
+ azureGroupRepo.detachInstance(groupId, instanceId, accountId);
if (detachInstanceResponse.isRequestSucceed()) {
LOGGER.info(String.format("Instance %s detached", instanceId));
@@ -93,7 +94,12 @@ public void syncGroupInstances() {
}
@Override
- public Map getInstanceIpsById() {
+ protected void handleSyncGroupInstances() {
+
+ }
+
+ @Override
+ public Map getInstanceIpsById() {//TODO: check if is different
Map retVal = new HashMap<>();
IAzureGroupRepo awsGroupRepo = RepoManager.getInstance().getAzureGroupRepo();
@@ -104,7 +110,7 @@ public Map getInstanceIpsById() {
List instances = instancesResponse.getValue();
for (AzureGroupInstance instance : instances) {
- if (this.getShouldUsePrivateIp()) {
+ if (getShouldUsePrivateIp()) {
retVal.put(instance.getInstanceId(), instance.getPrivateIp());
}
else {
@@ -121,6 +127,11 @@ public Map getInstanceIpsById() {
return retVal;
}
+ @Override
+ protected Map handleGetInstanceIpsById() {
+ return null;
+ }
+
@Override
public void monitorInstances() {
IAzureGroupRepo azureGroupRepo = RepoManager.getInstance().getAzureGroupRepo();
@@ -322,6 +333,7 @@ private void addToGroupPending(ProvisionRequest request) {
@Extension
public static class DescriptorImpl extends BaseSpotinstCloud.DescriptorImpl {
+ @Nonnull
@Override
public String getDisplayName() {
return "Spot Azure LPVM (old)";
diff --git a/src/main/java/hudson/plugins/spotinst/cloud/BaseSpotinstCloud.java b/src/main/java/hudson/plugins/spotinst/cloud/BaseSpotinstCloud.java
index 4071b270..6e55e94f 100644
--- a/src/main/java/hudson/plugins/spotinst/cloud/BaseSpotinstCloud.java
+++ b/src/main/java/hudson/plugins/spotinst/cloud/BaseSpotinstCloud.java
@@ -1,11 +1,14 @@
package hudson.plugins.spotinst.cloud;
-import edu.umd.cs.findbugs.annotations.CheckForNull;
import hudson.DescriptorExtensionList;
import hudson.model.*;
import hudson.model.labels.LabelAtom;
+import hudson.plugins.spotinst.api.infra.ApiResponse;
import hudson.plugins.spotinst.api.infra.JsonMapper;
+import hudson.plugins.spotinst.cloud.helpers.TimeHelper;
import hudson.plugins.spotinst.common.*;
+import hudson.plugins.spotinst.repos.ILockRepo;
+import hudson.plugins.spotinst.repos.RepoManager;
import hudson.plugins.spotinst.slave.*;
import hudson.plugins.sshslaves.SSHConnector;
import hudson.slaves.*;
@@ -15,6 +18,7 @@
import hudson.tools.ToolLocationNodeProperty;
import jenkins.model.Jenkins;
import org.apache.commons.lang.BooleanUtils;
+import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.DataBoundSetter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -24,6 +28,8 @@
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import static hudson.plugins.spotinst.common.SpotinstCloudCommunicationState.*;
+
/**
* Created by ohadmuchnik on 25/05/2016.
*/
@@ -32,7 +38,7 @@ public abstract class BaseSpotinstCloud extends Cloud {
//region Members
private static final Logger LOGGER = LoggerFactory.getLogger(BaseSpotinstCloud.class);
- protected static final int NO_OVERRIDED_NUM_OF_EXECUTORS = -1;
+ protected static final int NO_OVERRIDDEN_NUM_OF_EXECUTORS = -1;
protected String accountId;
protected String groupId;
protected Map pendingInstances;
@@ -110,6 +116,10 @@ public BaseSpotinstCloud(String groupId, String labelString, String idleTerminat
else {
this.globalExecutorOverride = new SpotGlobalExecutorOverride(false, 1);
}
+
+ if (StringUtils.isNotEmpty(groupId) && StringUtils.isNotEmpty(accountId)) {
+ syncGroupsOwner();
+ }
}
//endregion
@@ -119,28 +129,33 @@ public Collection provision(Label label, int excessWorkload) {
ProvisionRequest request = new ProvisionRequest(label, excessWorkload);
LOGGER.info(String.format("Got provision slave request: %s", JsonMapper.toJson(request)));
+ boolean isGroupManagedByThisController = isCloudReadyForGroupCommunication(groupId);
- setNumOfNeededExecutors(request);
+ if (isGroupManagedByThisController) {
+ setNumOfNeededExecutors(request);
- if (request.getExecutors() > 0) {
- LOGGER.info(String.format("Need to scale up %s units", request.getExecutors()));
+ if (request.getExecutors() > 0) {
+ LOGGER.info(String.format("Need to scale up %s units", request.getExecutors()));
+ List slaves = provisionSlaves(request);
- List slaves = provisionSlaves(request);
-
- if (slaves.size() > 0) {
- for (final SpotinstSlave slave : slaves) {
-
- try {
- Jenkins.getInstance().addNode(slave);
- }
- catch (IOException e) {
- LOGGER.error(String.format("Failed to create node for slave: %s", slave.getInstanceId()), e);
+ if (slaves.size() > 0) {
+ for (final SpotinstSlave slave : slaves) {
+ try {
+ Jenkins.getInstance().addNode(slave);
+ }
+ catch (IOException e) {
+ LOGGER.error(String.format("Failed to create node for slave: %s", slave.getInstanceId()),
+ e);
+ }
}
}
}
+ else {
+ LOGGER.info("No need to scale up new slaves, there are some that are initiating");
+ }
}
else {
- LOGGER.info("No need to scale up new slaves, there are some that are initiating");
+ handleGroupDoesNotManageByThisController(accountId, groupId);
}
return Collections.emptyList();
@@ -198,7 +213,7 @@ public void monitorInstances() {
Integer pendingThreshold = getPendingThreshold();
Boolean isPendingOverThreshold =
- TimeUtils.isTimePassed(pendingInstance.getCreatedAt(), pendingThreshold);
+ TimeUtils.isTimePassedInMinutes(pendingInstance.getCreatedAt(), pendingThreshold);
if (isPendingOverThreshold) {
LOGGER.info(String.format(
@@ -329,7 +344,7 @@ protected void terminateOfflineSlaves(SpotinstSlave slave, String slaveInstanceI
Date slaveCreatedAt = slave.getCreatedAt();
- Boolean isOverOfflineThreshold = TimeUtils.isTimePassed(slaveCreatedAt, offlineThreshold);
+ Boolean isOverOfflineThreshold = TimeUtils.isTimePassedInMinutes(slaveCreatedAt, offlineThreshold);
if (isSlaveOffline && isSlaveConnecting == false && isOverOfflineThreshold && temporarilyOffline == false &&
isOverIdleThreshold) {
@@ -347,14 +362,44 @@ public SlaveInstanceDetails getSlaveDetails(String instanceId) {
return retVal;
}
+
+ // public boolean isCloudReadyForGroupCommunication(String groupId) {
+ // boolean retVal = false;
+ //
+ // if (StringUtils.isNotEmpty(groupId)) {
+ // SpotinstCloudCommunicationState state = getCloudInitializationResultByGroupId(groupId);
+ //
+ // if (state != null) {
+ // if (state.equals(SpotinstCloudCommunicationState.SPOTINST_CLOUD_COMMUNICATION_READY)) {
+ // retVal = true;
+ // }
+ // }
+ // }
+ //
+ // return retVal;
+ // }
+
+ public boolean isCloudReadyForGroupCommunication(String groupId) {
+ boolean retVal = false;
+
+ if (StringUtils.isNotEmpty(groupId)) {
+ GroupStateTracker stateDetails = SpotinstContext.getInstance().getConnectionStateByGroupId().get(groupId);
+
+ if (stateDetails != null) {
+ retVal = stateDetails.getState().equals(SPOTINST_CLOUD_COMMUNICATION_READY);
+ }
+ }
+
+ return retVal;
+ }
//endregion
//region Private Methods
private synchronized List provisionSlaves(ProvisionRequest request) {
LOGGER.info(String.format("Scale up group: %s with %s workload units", groupId, request.getExecutors()));
- List slaves = scaleUp(request);
- return slaves;
+ List retVal = scaleUp(request);
+ return retVal;
}
private void setNumOfNeededExecutors(ProvisionRequest request) {
@@ -434,6 +479,46 @@ private boolean isGlobalExecutorOverrideValid() {
return retVal;
}
+
+ private Boolean LockGroupController(String controllerIdentifier) {
+ Boolean retVal = null;
+ ILockRepo lockRepo = RepoManager.getInstance().getLockRepo();
+ ApiResponse lockGroupControllerResponse =
+ lockRepo.Lock(groupId, accountId, controllerIdentifier, Constants.LOCK_TIME_TO_LIVE_IN_SECONDS);
+
+ if (lockGroupControllerResponse.isRequestSucceed()) {
+ String responseValue = lockGroupControllerResponse.getValue();
+
+ if (Constants.LOCK_OK_STATUS.equals(responseValue)) {
+ LOGGER.info(String.format("Successfully locked group %s controller", groupId));
+
+ retVal = true;
+ }
+ else {
+ LOGGER.error(String.format("Failed locking group %s controller", groupId));
+ retVal = false;
+ }
+ }
+ else {
+ LOGGER.error("lock request failed");
+ }
+
+ return retVal;
+ }
+
+ // private SpotinstCloudCommunicationState getCloudInitializationResultByGroupId(String groupId) {
+ // SpotinstCloudCommunicationState state = null;
+ //
+ // for (Map.Entry cloudsInitializationStateEntry : SpotinstContext.getInstance()
+ // .getCloudsInitializationState()
+ // .entrySet()) {
+ // if (cloudsInitializationStateEntry.getKey().getGroupId().equals(groupId)) {
+ // state = cloudsInitializationStateEntry.getValue();
+ // }
+ // }
+ //
+ // return state;
+ // }
//endregion
//region Protected Methods
@@ -594,10 +679,10 @@ protected Integer getNumOfExecutors(String instanceType) {
retVal = 1;
}
else {
- int overridedNumOfExecutors = getOverridedNumberOfExecutors(instanceType);
- boolean isNumOfExecutorsOverrided = overridedNumOfExecutors != NO_OVERRIDED_NUM_OF_EXECUTORS;
+ int overridedNumOfExecutors = getOverridedNumberOfExecutors(instanceType);
+ boolean isNumOfExecutorsOverrided = overridedNumOfExecutors != NO_OVERRIDDEN_NUM_OF_EXECUTORS;
- if(isNumOfExecutorsOverrided){
+ if (isNumOfExecutorsOverrided) {
retVal = overridedNumOfExecutors;
}
else {
@@ -633,7 +718,7 @@ protected Integer getNumOfExecutors(String instanceType) {
}
protected int getOverridedNumberOfExecutors(String instanceType) {
- return NO_OVERRIDED_NUM_OF_EXECUTORS;
+ return NO_OVERRIDDEN_NUM_OF_EXECUTORS;
}
protected Integer getPendingThreshold() {
@@ -643,6 +728,174 @@ protected Integer getPendingThreshold() {
protected Integer getSlaveOfflineThreshold() {
return Constants.SLAVE_OFFLINE_THRESHOLD_IN_MINUTES;
}
+
+ // public void handleGroupDosNotManageByThisController(String groupId) {
+ // boolean isGroupExistInCandidateGroupsForControllerOwnership =
+ // SpotinstContext.getInstance().getCandidateGroupsForControllerOwnership().containsKey(groupId);
+ //
+ // if (isGroupExistInCandidateGroupsForControllerOwnership) {
+ // Boolean hasValidState = SpotinstContext.getInstance().getCloudsInitializationState().containsKey(this);
+ //
+ // if (hasValidState == false) {
+ // SpotinstContext.getInstance().getCloudsInitializationState()
+ // .put(this, SPOTINST_CLOUD_COMMUNICATION_INITIALIZING);
+ // }
+ // }
+ // else {
+ // SpotinstContext.getInstance().getCloudsInitializationState()
+ // .put(this, SpotinstCloudCommunicationState.SPOTINST_CLOUD_COMMUNICATION_FAILED);
+ // }
+ // }
+
+ public void handleGroupDoesNotManageByThisController(String accountId, String groupId) {
+ GroupStateTracker groupStateDetails = SpotinstContext.getInstance().getConnectionStateByGroupId().get(groupId);
+
+ if (groupStateDetails == null || groupStateDetails.getState().equals(SPOTINST_CLOUD_COMMUNICATION_READY)) {
+ groupStateDetails = new GroupStateTracker(groupId, accountId);
+ SpotinstContext.getInstance().getConnectionStateByGroupId().put(groupId, groupStateDetails);
+ }
+ else if (groupStateDetails.getState().equals(SPOTINST_CLOUD_COMMUNICATION_INITIALIZING)) {
+ boolean shouldFail = TimeHelper.isTimePassedInSeconds(groupStateDetails.getTimeStamp());
+
+ if (shouldFail) {
+ groupStateDetails.setState(SPOTINST_CLOUD_COMMUNICATION_FAILED);
+ SpotinstContext.getInstance().getConnectionStateByGroupId().put(groupId, groupStateDetails);
+ }
+ }
+ }
+
+ // public void syncGroupsOwner(BaseSpotinstCloud cloud) {
+ // String groupId = cloud.getGroupId();
+ // String accountId = cloud.getAccountId();
+ // LOGGER.info(String.format("try fetching controller identifier for group %s from redis", groupId));
+ //
+ // ILockRepo redisRepo = RepoManager.getInstance().getRedisRepo();
+ // ApiResponse