diff --git a/README.md b/README.md
index 8ad9e7e..95d43ca 100644
--- a/README.md
+++ b/README.md
@@ -186,6 +186,7 @@ jenkins:
image: name=jenkins
mode: NORMAL
numExecutors: 1
+ placementGroup: "key1=value1&key2=value2"
connector:
root:
sshCredentialsId: 'ssh-private-key'
@@ -199,6 +200,7 @@ jenkins:
network: subsystem=cd
labelStr: java
numExecutors: 3
+ placementGroup: "1000656"
connectivity: "public-only"
connector:
root:
diff --git a/pom.xml b/pom.xml
index ae91b3c..590f586 100644
--- a/pom.xml
+++ b/pom.xml
@@ -122,7 +122,7 @@
cloud.dnation.integrationhetzner-cloud-client-java
- 1.1.0
+ 1.3.0org.jenkins-ci.plugins
diff --git a/src/main/java/cloud/dnation/jenkins/plugins/hetzner/ConfigurationValidator.java b/src/main/java/cloud/dnation/jenkins/plugins/hetzner/ConfigurationValidator.java
index 309119e..d81ea66 100644
--- a/src/main/java/cloud/dnation/jenkins/plugins/hetzner/ConfigurationValidator.java
+++ b/src/main/java/cloud/dnation/jenkins/plugins/hetzner/ConfigurationValidator.java
@@ -22,6 +22,8 @@
import cloud.dnation.hetznerclient.GetLocationsResponse;
import cloud.dnation.hetznerclient.GetNetworkByIdResponse;
import cloud.dnation.hetznerclient.GetNetworksBySelectorResponse;
+import cloud.dnation.hetznerclient.GetPlacementGroupByIdResponse;
+import cloud.dnation.hetznerclient.GetPlacementGroupsResponse;
import cloud.dnation.hetznerclient.GetServerTypesResponse;
import cloud.dnation.hetznerclient.HetznerApi;
import com.google.common.base.Preconditions;
@@ -136,6 +138,28 @@ static ValidationResult verifyNetwork(String network, String credentialsId) {
}, credentialsId);
}
+ static ValidationResult verifyPlacementGroup(String placementGroup, String credentialsId) {
+ if (Strings.isNullOrEmpty(placementGroup)) {
+ return new ValidationResult(false, "Placement group expression is empty");
+ }
+ return validateWithClient(api -> {
+ if (Helper.isLabelExpression(placementGroup)) {
+ final GetPlacementGroupsResponse result = api.getPlacementGroups(placementGroup).execute().body();
+ Preconditions.checkArgument(result.getPlacementGroups().size() == 1,
+ "Expected exactly one result, got %s", result.getPlacementGroups().size());
+ return new ValidationResult(true, "Found: " +
+ result.getPlacementGroups().get(0).getName() + " " +
+ result.getPlacementGroups().get(0).getId());
+ } else if (Helper.isPossiblyInteger(placementGroup)) {
+ final GetPlacementGroupByIdResponse result = api.getPlacementGroupById(Integer.parseInt(placementGroup)).execute().body();
+ return new ValidationResult(true, "Found: " +
+ result.getPlacementGroup().getName() + " " + result.getPlacementGroup().getId());
+ } else {
+ return new ValidationResult(false, "Placement group expression unsupported : " + placementGroup);
+ }
+ }, credentialsId);
+ }
+
/**
* Attempt to validate given server type name.
*
diff --git a/src/main/java/cloud/dnation/jenkins/plugins/hetzner/HetznerCloudResourceManager.java b/src/main/java/cloud/dnation/jenkins/plugins/hetzner/HetznerCloudResourceManager.java
index dacba73..d174490 100644
--- a/src/main/java/cloud/dnation/jenkins/plugins/hetzner/HetznerCloudResourceManager.java
+++ b/src/main/java/cloud/dnation/jenkins/plugins/hetzner/HetznerCloudResourceManager.java
@@ -23,6 +23,7 @@
import cloud.dnation.hetznerclient.CreateSshKeyResponse;
import cloud.dnation.hetznerclient.GetImagesBySelectorResponse;
import cloud.dnation.hetznerclient.GetNetworksBySelectorResponse;
+import cloud.dnation.hetznerclient.GetPlacementGroupsResponse;
import cloud.dnation.hetznerclient.GetServerByIdResponse;
import cloud.dnation.hetznerclient.GetServersBySelectorResponse;
import cloud.dnation.hetznerclient.GetSshKeysBySelectorResponse;
@@ -136,6 +137,21 @@ private int getNetworkIdForLabelExpression(String labelExpression) throws IOExce
GetNetworksBySelectorResponse::getNetworks);
}
+ /**
+ * Attempt to obtain placement group based on label expression.
+ * It's expected that provided label expression resolves to single placement group.
+ *
+ * @param labelExpression label expression used to filter placement group
+ * @return placement group ID
+ * @throws IOException if fails to make API call
+ * @throws IllegalStateException if there was invalid response from API server
+ * @throws IllegalArgumentException if label expression didn't yield single placement group
+ */
+ private int getPlacementGroupForLabelExpression(String labelExpression) throws IOException {
+ return searchResourceByLabelExpression(labelExpression, proxy()::getPlacementGroups,
+ GetPlacementGroupsResponse::getPlacementGroups);
+ }
+
private int searchResourceByLabelExpression(
String labelExpression,
Function> searchFunction,
@@ -254,6 +270,14 @@ public HetznerServerInfo createServer(HetznerServerAgent agent) {
createServerRequest.setNetworks(Lists.newArrayList(networkId));
}
}
+ final String placementGroup = agent.getTemplate().getPlacementGroup();
+ if (!Strings.isNullOrEmpty(placementGroup)) {
+ if(Helper.isPossiblyInteger(placementGroup)) {
+ createServerRequest.setPlacementGroup(Integer.parseInt(placementGroup));
+ } else {
+ createServerRequest.setPlacementGroup(getPlacementGroupForLabelExpression(placementGroup));
+ }
+ }
createServerRequest.setServerType(agent.getTemplate().getServerType());
createServerRequest.setImage(imageId);
createServerRequest.setName(agent.getNodeName());
diff --git a/src/main/java/cloud/dnation/jenkins/plugins/hetzner/HetznerServerTemplate.java b/src/main/java/cloud/dnation/jenkins/plugins/hetzner/HetznerServerTemplate.java
index a0f114c..364dbe2 100644
--- a/src/main/java/cloud/dnation/jenkins/plugins/hetzner/HetznerServerTemplate.java
+++ b/src/main/java/cloud/dnation/jenkins/plugins/hetzner/HetznerServerTemplate.java
@@ -51,6 +51,7 @@
import static cloud.dnation.jenkins.plugins.hetzner.ConfigurationValidator.verifyImage;
import static cloud.dnation.jenkins.plugins.hetzner.ConfigurationValidator.verifyLocation;
import static cloud.dnation.jenkins.plugins.hetzner.ConfigurationValidator.verifyNetwork;
+import static cloud.dnation.jenkins.plugins.hetzner.ConfigurationValidator.verifyPlacementGroup;
import static cloud.dnation.jenkins.plugins.hetzner.ConfigurationValidator.verifyServerType;
import static cloud.dnation.jenkins.plugins.hetzner.Helper.getStringOrDefault;
import static cloud.dnation.jenkins.plugins.hetzner.HetznerConstants.DEFAULT_REMOTE_FS;
@@ -89,6 +90,10 @@ public class HetznerServerTemplate extends AbstractDescribableImpl
+
+
+
+
diff --git a/src/main/resources/cloud/dnation/jenkins/plugins/hetzner/HetznerServerTemplate/help-placementGroup.html b/src/main/resources/cloud/dnation/jenkins/plugins/hetzner/HetznerServerTemplate/help-placementGroup.html
new file mode 100644
index 0000000..a8575ed
--- /dev/null
+++ b/src/main/resources/cloud/dnation/jenkins/plugins/hetzner/HetznerServerTemplate/help-placementGroup.html
@@ -0,0 +1,27 @@
+
+
+ ID of placement group
+ or label expression that resolves to single placement group
+ To obtain list of all placement groups, use following curl command:
+