diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6fcca0d0..58770f2e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -41,9 +41,12 @@ An essential part of getting your change through is to make sure all existing te
#### Prerequisites
* Maven to build and run tests.
-* A GCP project to test on with the compute engine API enabled with all relevant permissions enabled, especially billing. Running integration tests will also incur billing.
+* A GCP project to test on with the compute engine API enabled with all relevant permissions
+ enabled, especially billing. Running integration tests will also incur billing.
* For development, IntelliJ is recommended.
-* **For Windows Images/VM's**, have Java and OpenSSH pre-installed. We have suggested startup-scripts for installing both if you do not want to pre-install, but pre-installing is advised.
+* **For Windows Images/VM's**, have Java and OpenSSH pre-installed. We have suggested
+ startup-scripts for installing both if you do not want to pre-install,
+ but pre-installing is advised.
#### Running the tests
@@ -58,12 +61,16 @@ mvn test
```
##### Integration Tests
-* The following environment variables are required to run the integration tests. 3. and 4. are only required when running a windows integration test.
+* The following environment variables are required to run the integration tests. 5, 6, and 7 are
+ only required when running a windows integration test.
1. GOOGLE_PROJECT_ID
1. GOOGLE_CREDENTIALS
+1. GOOGLE_REGION
+1. GOOGLE_ZONE
1. GOOGLE_BOOT_DISK_PROJECT_ID
1. GOOGLE_BOOT_DISK_IMAGE_NAME
+1. GOOGLE_JENKINS_PASSWORD
* Run the following:
```
@@ -71,23 +78,18 @@ mvn verify
```
###### Windows Integration Test
-* By default, in the pom.xml file, exclude running the Windows Integration test unless a windows-related change was made since it will require a windows image built with Packer.
-* Exclusion is in these couple of lines between the excludes tags:
-```
-
- true
- false
- ...
-
- **/ComputeEngineCloudWindowsIT.java
- **/ConfigAsCodeWindowsIT.java
- ...
-
-
+* By default, the integration tests only use linux based agents for testing. If you make a
+ windows-related change, or otherwise want to test that a change still works for windows agents,
+ run the tests with the flag `-Dit.windows=true` like this:
+```bash
+mvn verify -Dit.windows=true
```
-* If you do make a **windows-related change**, remove the windows exclusions temporarily and run the
-integration test with mvn verify,
+Make sure you have these extra environment variables configured:
* GOOGLE_BOOT_DISK_PROJECT_ID will be the same as your project id.
- * GOOGLE_BOOT_DISK_IMAGE_NAME will be the name of the image you created using packer in google cloud console.
- * More information on building your baseline windows image can be found [here](WINDOWS.md) and an example file can be found [here](windows-it-install.ps1).
\ No newline at end of file
+ * GOOGLE_BOOT_DISK_IMAGE_NAME will be the name of the image you created using packer in Google
+ cloud console.
+ * GOOGLE_JENKINS_PASSWORD will be the password you set when creating the image with packer, used
+ for password based ssh authentication.
+ * More information on building your baseline windows image can be found [here](WINDOWS.md)
+ and an example powershell script for setup can be found [here](windows-it-install.ps1).
\ No newline at end of file
diff --git a/Jenkinsfile b/Jenkinsfile.linux
similarity index 92%
rename from Jenkinsfile
rename to Jenkinsfile.linux
index 078f7ba9..5dc4b996 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile.linux
@@ -28,7 +28,8 @@ pipeline {
GOOGLE_ZONE = "${GCE_IT_ZONE}"
GOOGLE_SA_NAME = "${GCE_IT_SA}"
BUILD_ARTIFACTS_BUCKET = "${GCE_IT_BUCKET}"
- BUILD_ARTIFACTS = "build-${BRANCH_NAME}-${BUILD_ID}.tar.gz"
+ CLEAN_BRANCH_NAME = "${BRANCH_NAME}".replaceAll("[/&;<>|\\]]", "_")
+ BUILD_ARTIFACTS = "build-${CLEAN_BRANCH_NAME}-${BUILD_ID}.tar.gz"
}
stages {
diff --git a/Jenkinsfile.windows b/Jenkinsfile.windows
new file mode 100644
index 00000000..479812e0
--- /dev/null
+++ b/Jenkinsfile.windows
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Windows Agent IT pipeline, run manually.
+pipeline {
+ agent {
+ kubernetes {
+ cloud 'kubernetes'
+ label 'maven-pod'
+ yamlFile 'jenkins/maven-pod.yaml'
+ }
+ }
+
+ environment {
+ GOOGLE_PROJECT_ID = "${GCE_IT_PROJECT_ID}"
+ GOOGLE_REGION = "${GCE_IT_REGION}"
+ GOOGLE_ZONE = "${GCE_IT_ZONE}"
+ GOOGLE_SA_NAME = "${GCE_IT_SA}"
+ GOOGLE_BOOT_DISK_PROJECT_ID = "${GCE_WINDOWS_IT_IMAGE_PROJECT}"
+ GOOGLE_BOOT_DISK_IMAGE_NAME = "${GCE_WINDOWS_IT_IMAGE_NAME}"
+ BUILD_ARTIFACTS_BUCKET = "${GCE_IT_BUCKET}"
+ CLEAN_BRANCH_NAME = "${BRANCH_NAME}".replaceAll("[/&;<>|\\]]", "_")
+ BUILD_ARTIFACTS = "windows-${CLEAN_BRANCH_NAME}-${BUILD_ID}.tar.gz"
+ }
+
+ stages {
+ stage("Build and test") {
+ steps {
+ container('maven') {
+ withCredentials([[$class: 'StringBinding', credentialsId: env.GCE_IT_CRED_ID, variable: 'GOOGLE_CREDENTIALS'],
+ [$class: 'StringBinding', credentialsId: env.GCE_WINDOWS_IT_JENKINS_PASSWORD, variable: 'GOOGLE_JENKINS_PASSWORD']]) {
+ catchError {
+ // build
+ sh "mvn clean package -ntp"
+
+ // run tests
+ sh "mvn verify -ntp -Dit.windows=true"
+ }
+
+ sh "jenkins/saveAndCompress.sh"
+ step([$class: 'ClassicUploadStep', credentialsId: env.GCE_BUCKET_CRED_ID, bucket: "gs://${BUILD_ARTIFACTS_BUCKET}", pattern: env.BUILD_ARTIFACTS])
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 8d608db3..90a9b625 100644
--- a/pom.xml
+++ b/pom.xml
@@ -73,8 +73,11 @@
1.8
1.8
${skipTests}
+ false
1.14
+ 1.3
10
+ balanced
@@ -172,6 +175,12 @@
${configuration-as-code.version}
test
+
+ org.jenkins-ci.plugins
+ powershell
+ ${powershell.version}
+ test
+
@@ -262,14 +271,13 @@
0.5
100
1.0
+ ${it.windows}
- **/ComputeEngineCloudWindowsIT.java
- **/ConfigAsCodeWindowsIT.java
**/ITUtil.java
-Djenkins.test.timeout=${jenkinsRuleTimeout}
- balanced
+ ${it.runOrder}
@@ -332,5 +340,18 @@
4
+
+ windows-agents
+
+
+ it.windows
+ true
+
+
+
+ 8
+ reversealphabetical
+
+
diff --git a/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineComputer.java b/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineComputer.java
index 181b29d1..8ba56e5c 100644
--- a/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineComputer.java
+++ b/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineComputer.java
@@ -19,14 +19,12 @@
import com.google.api.services.compute.model.Instance;
import com.google.api.services.compute.model.Scheduling;
import hudson.model.Executor;
-import hudson.model.Result;
import hudson.model.TaskListener;
import hudson.slaves.AbstractCloudComputer;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
-import jenkins.model.CauseOfInterruption;
import lombok.extern.java.Log;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.HttpRedirect;
@@ -76,14 +74,7 @@ private Boolean getPreemptedStatus(TaskListener listener, String nodeName) {
private void interruptExecutor(Executor executor, String nodeName) {
log.log(Level.INFO, "Terminating executor " + executor + " node " + nodeName);
- executor.interrupt(
- Result.FAILURE,
- new CauseOfInterruption() {
- @Override
- public String getShortDescription() {
- return "Instance " + nodeName + " was preempted";
- }
- });
+ executor.abortResult();
}
/**
diff --git a/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineLinuxLauncher.java b/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineLinuxLauncher.java
index f3d2b793..eb7b52da 100644
--- a/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineLinuxLauncher.java
+++ b/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineLinuxLauncher.java
@@ -51,27 +51,18 @@ protected Optional setupConnection(
return Optional.empty();
}
- Connection cleanupConn;
GoogleKeyPair kp = node.getSSHKeyPair().get();
- boolean isBootstrapped = bootstrap(kp, computer, listener);
- if (isBootstrapped) {
- // connect fresh as ROOT
- logInfo(computer, listener, "connect fresh as root");
- cleanupConn = connectToSsh(computer, listener);
- if (!cleanupConn.authenticateWithPublicKey(
- node.getSshUser(), kp.getPrivateKey().toCharArray(), "")) {
- logWarning(computer, listener, "Authentication failed");
- return Optional.empty(); // failed to connect
- }
- } else {
+ Optional bootstrapConn = bootstrap(kp, computer, listener);
+ if (!bootstrapConn.isPresent()) {
logWarning(computer, listener, "bootstrapresult failed");
return Optional.empty();
}
- return Optional.of(cleanupConn);
+ return bootstrapConn;
}
- private boolean bootstrap(GoogleKeyPair kp, ComputeEngineComputer computer, TaskListener listener)
+ private Optional bootstrap(
+ GoogleKeyPair kp, ComputeEngineComputer computer, TaskListener listener)
throws IOException, Exception { // TODO: better exceptions
logInfo(computer, listener, "bootstrap");
ComputeEngineInstance node = computer.getNode();
@@ -105,14 +96,16 @@ private boolean bootstrap(GoogleKeyPair kp, ComputeEngineComputer computer, Task
}
if (!isAuthenticated) {
logWarning(computer, listener, "Authentication failed");
- return false;
+ return Optional.empty();
}
- } finally {
+ } catch (Exception e) {
+ logException(computer, listener, "Failed to authenticate with exception: ", e);
if (bootstrapConn != null) {
bootstrapConn.close();
}
+ return Optional.empty();
}
- return true;
+ return Optional.of(bootstrapConn);
}
@Override
diff --git a/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineWindowsLauncher.java b/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineWindowsLauncher.java
index 9f775325..7c50e2ca 100644
--- a/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineWindowsLauncher.java
+++ b/src/main/java/com/google/jenkins/plugins/computeengine/ComputeEngineWindowsLauncher.java
@@ -16,6 +16,7 @@
import com.cloudbees.jenkins.plugins.sshcredentials.SSHAuthenticator;
import com.google.api.services.compute.model.Operation;
+import com.google.common.base.Preconditions;
import com.trilead.ssh2.Connection;
import hudson.model.TaskListener;
import java.io.IOException;
@@ -51,21 +52,12 @@ protected Optional setupConnection(
logWarning(computer, listener, "Non-windows node provided");
return Optional.empty();
}
- boolean isBootstrapped = bootstrap(computer, listener);
- if (!isBootstrapped) {
+ Optional bootstrapConn = bootstrap(computer, listener);
+ if (!bootstrapConn.isPresent()) {
logWarning(computer, listener, "bootstrapresult failed");
return Optional.empty();
}
-
- // connect fresh as ROOT
- logInfo(computer, listener, "connect fresh as root");
- Connection cleanupConn = connectToSsh(computer, listener);
- if (!authenticateSSH(node.getSshUser(), node.getWindowsConfig(), cleanupConn, listener)) {
- logWarning(computer, listener, "Authentication failed");
- return Optional.empty(); // failed to connect
- }
-
- return Optional.of(cleanupConn);
+ return bootstrapConn;
}
private boolean authenticateSSH(
@@ -87,11 +79,8 @@ private boolean authenticateSSH(
return isAuthenticated;
}
- private boolean bootstrap(ComputeEngineComputer computer, TaskListener listener)
- throws IOException, Exception { // TODO(evanbrown): better exceptions
- if (computer == null) {
- throw new IllegalArgumentException("A null ComputeEngineComputer was provided");
- }
+ private Optional bootstrap(ComputeEngineComputer computer, TaskListener listener) {
+ Preconditions.checkNotNull(computer, "A null ComputeEngineComputer was provided");
logInfo(computer, listener, "bootstrap");
ComputeEngineInstance node = computer.getNode();
@@ -125,14 +114,16 @@ private boolean bootstrap(ComputeEngineComputer computer, TaskListener listener)
}
if (!isAuthenticated) {
logWarning(computer, listener, "Authentication failed");
- return false;
+ return Optional.empty();
}
- } finally {
+ } catch (Exception e) {
+ logException(computer, listener, "Failed to authenticate with exception: ", e);
if (bootstrapConn != null) {
bootstrapConn.close();
}
+ return Optional.empty();
}
- return true;
+ return Optional.ofNullable(bootstrapConn);
}
@Override
diff --git a/src/main/java/com/google/jenkins/plugins/computeengine/PreemptedCheckCallable.java b/src/main/java/com/google/jenkins/plugins/computeengine/PreemptedCheckCallable.java
index 8cd37945..dc74a9db 100644
--- a/src/main/java/com/google/jenkins/plugins/computeengine/PreemptedCheckCallable.java
+++ b/src/main/java/com/google/jenkins/plugins/computeengine/PreemptedCheckCallable.java
@@ -33,7 +33,7 @@
*/
final class PreemptedCheckCallable extends MasterToSlaveCallable {
private static final String METADATA_SERVER_URL =
- "http://metadata.google.internal/computeMetadata/v1/instance/preempted?wait_for_change=true";
+ "http://metadata.google.internal/computeMetadata/v1/instance/preempted?wait_for_change=%s";
private final TaskListener listener;
@@ -58,7 +58,18 @@ final class PreemptedCheckCallable extends MasterToSlaveCallable label =
- getLabel(ComputeEngineCloudMultipeMatchingConfigurationsIT.class);
+ getLabel(ComputeEngineCloudMultipleMatchingConfigurationsIT.class);
private static Collection planned;
@BeforeClass
@@ -80,7 +81,6 @@ public static void init() throws Exception {
InstanceConfiguration configuration1 =
instanceConfigurationBuilder()
- .startupScript(DEB_JAVA_STARTUP_SCRIPT)
.numExecutorsStr(NUM_EXECUTORS)
.labels(LABEL)
.template(NULL_TEMPLATE)
@@ -90,7 +90,6 @@ public static void init() throws Exception {
InstanceConfiguration configuration2 =
instanceConfigurationBuilder()
- .startupScript(DEB_JAVA_STARTUP_SCRIPT)
.numExecutorsStr(NUM_EXECUTORS)
.labels(LABEL)
.template(NULL_TEMPLATE)
@@ -109,21 +108,24 @@ public static void teardown() throws IOException {
}
@Test
- public void testMultipleLabelsProvisionedWithLabels() throws Exception {
+ public void testMultipleLabelsProvisionedWithLabels() {
assertEquals(2, planned.size());
final Iterator iterator = planned.iterator();
- PlannedNode plannedNode = iterator.next();
- checkOneNode(plannedNode, DESC_1);
- plannedNode = iterator.next();
- checkOneNode(plannedNode, DESC_2);
+ PlannedNode firstNode = iterator.next();
+ PlannedNode secondNode = iterator.next();
+ if (checkOneNode(firstNode, DESC_1)) {
+ assertTrue(checkOneNode(secondNode, DESC_2));
+ } else if (checkOneNode(secondNode, DESC_1)) {
+ assertTrue(checkOneNode(firstNode, DESC_2));
+ } else {
+ fail("Nodes did not have expected values");
+ }
}
- private void checkOneNode(PlannedNode plannedNode, String desc)
- throws InterruptedException, java.util.concurrent.ExecutionException {
+ private boolean checkOneNode(PlannedNode plannedNode, String desc) {
String name = plannedNode.displayName;
- plannedNode.future.get();
Node node = jenkinsRule.jenkins.getNode(name);
- assertEquals(desc, node.getNodeDescription());
+ return desc.equals(node.getNodeDescription());
}
}
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudNoSnapshotCreatedIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudNoSnapshotCreatedIT.java
index 8fc80963..857d1294 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudNoSnapshotCreatedIT.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudNoSnapshotCreatedIT.java
@@ -16,13 +16,14 @@
package com.google.jenkins.plugins.computeengine.integration;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.DEB_JAVA_STARTUP_SCRIPT;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NULL_TEMPLATE;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NUM_EXECUTORS;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.PROJECT_ID;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.SNAPSHOT_LABEL;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.SNAPSHOT_TIMEOUT;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.TEST_TIMEOUT_MULTIPLIER;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.ZONE;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.execute;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.getLabel;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initClient;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initCloud;
@@ -40,7 +41,6 @@
import hudson.model.Node;
import hudson.model.labels.LabelAtom;
import hudson.tasks.Builder;
-import hudson.tasks.Shell;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -80,7 +80,6 @@ public static void init() throws Exception {
InstanceConfiguration instanceConfiguration =
ITUtil.instanceConfigurationBuilder()
- .startupScript(DEB_JAVA_STARTUP_SCRIPT)
.numExecutorsStr(NUM_EXECUTORS)
.labels(SNAPSHOT_LABEL)
.oneShot(true)
@@ -96,7 +95,7 @@ public static void init() throws Exception {
.isCreateSnapshot());
FreeStyleProject project = jenkinsRule.createFreeStyleProject();
- Builder step = new Shell("echo works");
+ Builder step = execute(Commands.ECHO, "works");
project.getBuildersList().add(step);
project.setAssignedLabel(new LabelAtom(SNAPSHOT_LABEL));
@@ -125,7 +124,7 @@ public void testNoSnapshotCreatedInstanceStopping() {
public void testNoSnapshotCreatedSnapshotNull() throws Exception {
// Wait for one-shot instance to terminate and create the snapshot
Awaitility.await()
- .timeout(2, TimeUnit.MINUTES)
+ .timeout(SNAPSHOT_TIMEOUT, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.SECONDS)
.until(() -> jenkinsRule.jenkins.getNode(name) == null);
client.getSnapshot(PROJECT_ID, name);
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudNonStandardJavaIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudNonStandardJavaIT.java
index 90216806..93d8e2eb 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudNonStandardJavaIT.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudNonStandardJavaIT.java
@@ -28,7 +28,9 @@
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initCredentials;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.instanceConfigurationBuilder;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.teardownResources;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.windows;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeFalse;
import com.google.api.services.compute.model.Instance;
import com.google.cloud.graphite.platforms.plugin.client.ComputeClient;
@@ -81,6 +83,7 @@ public class ComputeEngineCloudNonStandardJavaIT {
@BeforeClass
public static void init() throws Exception {
+ assumeFalse(windows);
log.info("init");
initCredentials(jenkinsRule);
ComputeEngineCloud cloud = initCloud(jenkinsRule);
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudOneShotInstanceIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudOneShotInstanceIT.java
index 7b9e310c..79a8a02c 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudOneShotInstanceIT.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudOneShotInstanceIT.java
@@ -16,11 +16,11 @@
package com.google.jenkins.plugins.computeengine.integration;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.DEB_JAVA_STARTUP_SCRIPT;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.LABEL;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NULL_TEMPLATE;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NUM_EXECUTORS;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.PROJECT_ID;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.execute;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.getLabel;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initClient;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initCloud;
@@ -40,7 +40,6 @@
import hudson.model.Result;
import hudson.model.labels.LabelAtom;
import hudson.tasks.Builder;
-import hudson.tasks.Shell;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
@@ -81,7 +80,6 @@ public static void init() throws Exception {
cloud.setConfigurations(
ImmutableList.of(
instanceConfigurationBuilder()
- .startupScript(DEB_JAVA_STARTUP_SCRIPT)
.numExecutorsStr(NUM_EXECUTORS)
.labels(LABEL)
.oneShot(true)
@@ -92,13 +90,13 @@ public static void init() throws Exception {
jenkinsRule.jenkins.getNodesObject().setNodes(Collections.emptyList());
FreeStyleProject project = jenkinsRule.createFreeStyleProject();
- Builder step = new Shell("echo works");
+ Builder step = execute(Commands.ECHO, "works");
project.getBuildersList().add(step);
project.setAssignedLabel(new LabelAtom(LABEL));
Future buildFuture = project.scheduleBuild2(0);
FreeStyleProject otherProject = jenkinsRule.createFreeStyleProject();
- Builder otherStep = new Shell("echo \"also works\"");
+ Builder otherStep = execute(Commands.ECHO, "\"also works\"");
otherProject.getBuildersList().add(otherStep);
otherProject.setAssignedLabel(new LabelAtom(LABEL));
otherBuildFuture = otherProject.scheduleBuild2(0);
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudRestartPreemptedIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudRestartPreemptedIT.java
index a7012018..c9202535 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudRestartPreemptedIT.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudRestartPreemptedIT.java
@@ -16,13 +16,13 @@
package com.google.jenkins.plugins.computeengine.integration;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.DEB_JAVA_STARTUP_SCRIPT;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.LABEL;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NULL_TEMPLATE;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NUM_EXECUTORS;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.PROJECT_ID;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.TEST_TIMEOUT_MULTIPLIER;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.ZONE;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.execute;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.getLabel;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initClient;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initCloud;
@@ -46,7 +46,6 @@
import hudson.model.queue.QueueTaskFuture;
import hudson.slaves.NodeProvisioner.PlannedNode;
import hudson.tasks.Builder;
-import hudson.tasks.Shell;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
@@ -85,7 +84,6 @@ public static void init() throws Exception {
InstanceConfiguration configuration =
instanceConfigurationBuilder()
- .startupScript(DEB_JAVA_STARTUP_SCRIPT)
.numExecutorsStr(NUM_EXECUTORS)
.labels(LABEL)
.template(NULL_TEMPLATE)
@@ -115,7 +113,7 @@ public void testIfNodeWasPreempted() throws Exception {
assertTrue("Configuration was set as preemptible but saw as not", computer.getPreemptible());
FreeStyleProject project = jenkinsRule.createFreeStyleProject();
- Builder step = new Shell("sleep 60");
+ Builder step = execute(Commands.SLEEP, "60");
project.getBuildersList().add(step);
project.setAssignedLabel(new LabelAtom(LABEL));
QueueTaskFuture taskFuture = project.scheduleBuild2(0);
@@ -131,10 +129,10 @@ public void testIfNodeWasPreempted() throws Exception {
assertEquals(FAILURE, freeStyleBuild.getResult());
Awaitility.await()
- .timeout(9, TimeUnit.MINUTES)
- .until(
- () ->
- freeStyleBuild.getNextBuild() != null
- && freeStyleBuild.getNextBuild().getResult() == SUCCESS);
+ .timeout(5, TimeUnit.MINUTES)
+ .until(() -> freeStyleBuild.getNextBuild() != null);
+ FreeStyleBuild nextBuild = freeStyleBuild.getNextBuild();
+ Awaitility.await().timeout(5, TimeUnit.MINUTES).until(() -> nextBuild.getResult() != null);
+ assertEquals(SUCCESS, nextBuild.getResult());
}
}
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudSnapshotCreatedIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudSnapshotCreatedIT.java
index a8575e07..a24f6b7f 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudSnapshotCreatedIT.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudSnapshotCreatedIT.java
@@ -16,12 +16,13 @@
package com.google.jenkins.plugins.computeengine.integration;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.DEB_JAVA_STARTUP_SCRIPT;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NULL_TEMPLATE;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NUM_EXECUTORS;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.PROJECT_ID;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.SNAPSHOT_LABEL;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.SNAPSHOT_TIMEOUT;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.TEST_TIMEOUT_MULTIPLIER;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.execute;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.getLabel;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initClient;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initCloud;
@@ -43,7 +44,6 @@
import hudson.model.Result;
import hudson.model.labels.LabelAtom;
import hudson.tasks.Builder;
-import hudson.tasks.Shell;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -64,10 +64,8 @@
public class ComputeEngineCloudSnapshotCreatedIT {
private static Logger log = Logger.getLogger(ComputeEngineCloudSnapshotCreatedIT.class.getName());
- private static final int SNAPSHOT_TEST_TIMEOUT = 120;
-
@ClassRule
- public static Timeout timeout = new Timeout(10 * TEST_TIMEOUT_MULTIPLIER, TimeUnit.MINUTES);
+ public static Timeout timeout = new Timeout(15 * TEST_TIMEOUT_MULTIPLIER, TimeUnit.MINUTES);
@ClassRule public static JenkinsRule jenkinsRule = new JenkinsRule();
@@ -84,7 +82,6 @@ public static void init() throws Exception {
InstanceConfiguration instanceConfiguration =
instanceConfigurationBuilder()
- .startupScript(DEB_JAVA_STARTUP_SCRIPT)
.numExecutorsStr(NUM_EXECUTORS)
.labels(SNAPSHOT_LABEL)
.oneShot(true)
@@ -100,7 +97,7 @@ public static void init() throws Exception {
.isCreateSnapshot());
FreeStyleProject project = jenkinsRule.createFreeStyleProject();
- Builder step = new Shell("exit 1");
+ Builder step = execute(Commands.EXIT, "1");
project.getBuildersList().add(step);
project.setAssignedLabel(new LabelAtom(SNAPSHOT_LABEL));
@@ -110,7 +107,7 @@ public static void init() throws Exception {
// Need time for one-shot instance to terminate and create the snapshot
Awaitility.await()
- .timeout(SNAPSHOT_TEST_TIMEOUT, TimeUnit.SECONDS)
+ .timeout(SNAPSHOT_TIMEOUT, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.SECONDS)
.until(() -> jenkinsRule.jenkins.getNode(worker.getNodeName()) == null);
@@ -139,7 +136,7 @@ public void testSnapshotCreatedStatusReady() {
@Test
public void testSnapshotCreatedOneShotInstanceDeleted() {
Awaitility.await()
- .timeout(SNAPSHOT_TEST_TIMEOUT, TimeUnit.SECONDS)
+ .timeout(SNAPSHOT_TIMEOUT, TimeUnit.SECONDS)
.until(() -> client.listInstancesWithLabel(PROJECT_ID, label).isEmpty());
}
}
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudTemplateIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudTemplateIT.java
index a1540275..044ea394 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudTemplateIT.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudTemplateIT.java
@@ -17,10 +17,11 @@
package com.google.jenkins.plugins.computeengine.integration;
import static com.google.cloud.graphite.platforms.plugin.client.util.ClientUtil.nameFromSelfLink;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.DEB_JAVA_STARTUP_SCRIPT;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.LABEL;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NUM_EXECUTORS;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.PROJECT_ID;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.RUN_AS_USER;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.SSH_PRIVATE_KEY;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.TEST_TIMEOUT_MULTIPLIER;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.ZONE;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.createTemplate;
@@ -44,7 +45,6 @@
import com.google.jenkins.plugins.computeengine.ComputeEngineCloud;
import com.google.jenkins.plugins.computeengine.InstanceConfiguration;
import com.trilead.ssh2.Connection;
-import com.trilead.ssh2.ServerHostKeyVerifier;
import hudson.model.labels.LabelAtom;
import hudson.slaves.NodeProvisioner.PlannedNode;
import java.io.IOException;
@@ -93,7 +93,6 @@ public static void init() throws Exception {
cloud.setConfigurations(
ImmutableList.of(
instanceConfigurationBuilder()
- .startupScript(DEB_JAVA_STARTUP_SCRIPT)
.numExecutorsStr(NUM_EXECUTORS)
.labels(LABEL)
.oneShot(false)
@@ -156,18 +155,11 @@ public void testConnectionWithTemplateSshKey() throws IOException, Exception {
int port = SSH_PORT;
conn = new Connection(host, port);
conn.connect(
- new ServerHostKeyVerifier() {
- public boolean verifyServerHostKey(
- String hostname, int port, String serverHostKeyAlgorithm, byte[] serverHostKey)
- throws Exception {
- return true;
- }
- },
+ (hostname, portnum, serverHostKeyAlgorithm, serverHostKey) -> true,
SSH_TIMEOUT,
SSH_TIMEOUT);
- assertTrue(
- conn.authenticateWithPublicKey(
- ITUtil.SSH_USER, ITUtil.SSH_PRIVATE_KEY.toCharArray(), ""));
+ log.info(String.format("Connected to SSH. Authenticating as user %s", RUN_AS_USER));
+ assertTrue(conn.authenticateWithPublicKey(RUN_AS_USER, SSH_PRIVATE_KEY.toCharArray(), ""));
} finally {
if (conn != null) {
conn.close();
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudTemplateNoGoogleLabelsIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudTemplateNoGoogleLabelsIT.java
index b0bb75ef..97016619 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudTemplateNoGoogleLabelsIT.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudTemplateNoGoogleLabelsIT.java
@@ -17,7 +17,6 @@
package com.google.jenkins.plugins.computeengine.integration;
import static com.google.cloud.graphite.platforms.plugin.client.util.ClientUtil.nameFromSelfLink;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.DEB_JAVA_STARTUP_SCRIPT;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.LABEL;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NUM_EXECUTORS;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.PROJECT_ID;
@@ -85,7 +84,6 @@ public static void init() throws Exception {
cloud.setConfigurations(
ImmutableList.of(
instanceConfigurationBuilder()
- .startupScript(DEB_JAVA_STARTUP_SCRIPT)
.numExecutorsStr(NUM_EXECUTORS)
.labels(LABEL)
.oneShot(false)
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudWindowsIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudWindowsIT.java
deleted file mode 100644
index 89184e9f..00000000
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudWindowsIT.java
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.jenkins.plugins.computeengine.integration;
-
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.CLOUD_NAME;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.LABEL;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NULL_TEMPLATE;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NUM_EXECUTORS;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.PROJECT_ID;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.SNAPSHOT_LABEL;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.ZONE;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initCredentials;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey;
-import com.cloudbees.plugins.credentials.Credentials;
-import com.cloudbees.plugins.credentials.CredentialsScope;
-import com.cloudbees.plugins.credentials.CredentialsStore;
-import com.cloudbees.plugins.credentials.SystemCredentialsProvider;
-import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
-import com.cloudbees.plugins.credentials.domains.Domain;
-import com.google.api.services.compute.model.Image;
-import com.google.api.services.compute.model.Instance;
-import com.google.api.services.compute.model.Operation;
-import com.google.api.services.compute.model.Snapshot;
-import com.google.cloud.graphite.platforms.plugin.client.ClientFactory;
-import com.google.cloud.graphite.platforms.plugin.client.ComputeClient;
-import com.google.common.collect.ImmutableList;
-import com.google.jenkins.plugins.computeengine.ComputeEngineCloud;
-import com.google.jenkins.plugins.computeengine.InstanceConfiguration;
-import com.google.jenkins.plugins.computeengine.WindowsConfiguration;
-import com.google.jenkins.plugins.computeengine.client.ClientUtil;
-import com.google.jenkins.plugins.computeengine.ssh.GoogleKeyPair;
-import hudson.ProxyConfiguration;
-import hudson.model.FreeStyleBuild;
-import hudson.model.FreeStyleProject;
-import hudson.model.Node;
-import hudson.model.Result;
-import hudson.model.labels.LabelAtom;
-import hudson.slaves.NodeProvisioner;
-import hudson.tasks.BatchFile;
-import hudson.tasks.Builder;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.logging.LogManager;
-import java.util.logging.Logger;
-import java.util.logging.SimpleFormatter;
-import java.util.logging.StreamHandler;
-import jenkins.model.Jenkins;
-import org.awaitility.Awaitility;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.rules.Timeout;
-import org.jvnet.hudson.test.JenkinsRule;
-
-/** Integration test for launching windows VM. Tests that agents can be created properly. */
-public class ComputeEngineCloudWindowsIT {
- private static Logger log = Logger.getLogger(ComputeEngineCloudWindowsIT.class.getName());
-
- private static final String BOOT_DISK_SIZE_GB_STR = "50";
- private static final String RUN_AS_USER = "jenkins";
-
- private static Map INTEGRATION_LABEL;
-
- static {
- INTEGRATION_LABEL = new HashMap<>();
- INTEGRATION_LABEL.put("integration", "delete");
- }
-
- private static final String RETENTION_TIME_MINUTES_STR = "600";
- private static final String LAUNCH_TIMEOUT_SECONDS_STR = "3000";
-
- private static Logger cloudLogger;
- private static Logger clientLogger;
- private static StreamHandler sh;
- private static ByteArrayOutputStream logOutput;
-
- private static ComputeClient client;
- private static String bootDiskProjectId;
- private static String bootDiskImageName;
-
- private static String publicKey;
- private static String windowsPrivateKeyCredentialId;
-
- @ClassRule public static JenkinsRule r = new JenkinsRule();
- @ClassRule public static Timeout timeout = new Timeout(20, TimeUnit.MINUTES);
-
- @BeforeClass
- public static void init() throws Exception {
- log.info("init");
- logOutput = new ByteArrayOutputStream();
- sh = new StreamHandler(logOutput, new SimpleFormatter());
-
- bootDiskProjectId = System.getenv("GOOGLE_BOOT_DISK_PROJECT_ID");
- assertNotNull("GOOGLE_BOOT_DISK_PROJECT_ID env var must be set", bootDiskProjectId);
-
- bootDiskImageName = System.getenv("GOOGLE_BOOT_DISK_IMAGE_NAME");
- assertNotNull("GOOGLE_BOOT_DISK_IMAGE_NAME env var must be set", bootDiskImageName);
-
- Credentials c = initCredentials(r);
-
- // Create credentials for SSH
- GoogleKeyPair kp = GoogleKeyPair.generate("");
- // Have to reformat since GoogleKeyPair's format is for metadata server and not typical public
- // key format
- publicKey = kp.getPublicKey().trim().substring(1);
-
- StandardUsernameCredentials windowsPrivateKeyCredential =
- new BasicSSHUserPrivateKey(
- CredentialsScope.GLOBAL,
- null,
- RUN_AS_USER,
- new BasicSSHUserPrivateKey.DirectEntryPrivateKeySource(kp.getPrivateKey()),
- null,
- "integration test private key for windows");
- CredentialsStore store = new SystemCredentialsProvider.ProviderImpl().getStore(r.jenkins);
- store.addCredentials(Domain.global(), windowsPrivateKeyCredential);
- windowsPrivateKeyCredentialId = windowsPrivateKeyCredential.getId();
-
- // Add Cloud plugin
- ComputeEngineCloud gcp = new ComputeEngineCloud(CLOUD_NAME, PROJECT_ID, PROJECT_ID, "10");
-
- // Capture log output to make sense of most failures
- cloudLogger =
- LogManager.getLogManager()
- .getLogger("com.google.jenkins.plugins.computeengine.ComputeEngineCloud");
- if (cloudLogger != null) cloudLogger.addHandler(sh);
-
- assertEquals(0, r.jenkins.clouds.size());
- r.jenkins.clouds.add(gcp);
- assertEquals(1, r.jenkins.clouds.size());
-
- // Get a compute client for out-of-band calls to GCE
- ClientFactory clientFactory = ClientUtil.getClientFactory(r.jenkins, PROJECT_ID);
- client = clientFactory.computeClient();
- assertNotNull("ComputeClient can not be null", client);
-
- // Other logging
- clientLogger =
- LogManager.getLogManager()
- .getLogger("com.google.jenkins.plugins.computeengine.ComputeClient");
- if (clientLogger != null) clientLogger.addHandler(sh);
-
- deleteIntegrationInstances(true);
- }
-
- @AfterClass
- public static void teardown() throws Exception {
- log.info("teardown");
- deleteIntegrationInstances(false);
- sh.close();
- log.info(logOutput.toString());
- }
-
- @Before
- public void before() {
- ComputeEngineCloud cloud = (ComputeEngineCloud) r.jenkins.clouds.get(0);
- cloud.setConfigurations(new ArrayList<>());
- }
-
- @After
- public void after() throws IOException {
- Jenkins jenkins = r.getInstance();
- jenkins.proxy = null;
- jenkins.save();
- }
-
- @Test
- public void testGoogleCredentialsCreated() {
- List creds =
- new SystemCredentialsProvider.ProviderImpl()
- .getStore(r.jenkins)
- .getCredentials(Domain.global());
- assertEquals(2, creds.size());
- }
-
- @Test // TODO: Group client tests into their own test class
- public void testGetImage() throws Exception {
- ComputeEngineCloud cloud = (ComputeEngineCloud) r.jenkins.clouds.get(0);
- Image i = cloud.getClient().getImage(this.bootDiskProjectId, this.bootDiskImageName);
- assertNotNull(i);
- }
-
- // TODO: JENKINS-56163 need to de-dupe integration tests
- @Test(timeout = 300000)
- public void testWorkerCreated() throws Exception {
- // TODO: each test method should probably have its own handler.
- logOutput.reset();
-
- InstanceConfiguration ic = validInstanceConfiguration1(LABEL, false, false);
- ComputeEngineCloud cloud = (ComputeEngineCloud) r.jenkins.clouds.get(0);
- cloud.setConfigurations(ImmutableList.of(ic));
-
- // Add a new node
- Collection planned = cloud.provision(new LabelAtom(LABEL), 1);
-
- // There should be a planned node
- assertEquals(logs(), 1, planned.size());
-
- String name = planned.iterator().next().displayName;
-
- // Wait for the node creation to finish
- planned.iterator().next().future.get();
-
- // There should be no warning logs
- assertEquals(logs(), false, logs().contains("WARNING"));
-
- Instance i = cloud.getClient().getInstance(PROJECT_ID, ZONE, name);
-
- // The created instance should have 3 labels
- assertEquals(logs(), 3, i.getLabels().size());
-
- // Instance should have a label with key CONFIG_LABEL_KEY and value equal to the config's name
- // prefix
- assertEquals(
- logs(), ic.getNamePrefix(), i.getLabels().get(ComputeEngineCloud.CONFIG_LABEL_KEY));
- // proper id label to properly count instances
- assertEquals(
- logs(), cloud.getInstanceId(), i.getLabels().get(ComputeEngineCloud.CLOUD_ID_LABEL_KEY));
- }
-
- // Tests snapshot is created when we have failure builds for given node
- // Snapshot creation is longer for windows one-shot vm's.
- @Test(timeout = 800000)
- public void testSnapshotCreated() throws Exception {
- logOutput.reset();
-
- ComputeEngineCloud cloud = (ComputeEngineCloud) r.jenkins.clouds.get(0);
- cloud.setConfigurations(ImmutableList.of(snapshotInstanceConfiguration()));
-
- FreeStyleProject project = r.createFreeStyleProject();
- Builder step = new BatchFile("exit 1");
- project.getBuildersList().add(step);
- project.setAssignedLabel(new LabelAtom(SNAPSHOT_LABEL));
-
- FreeStyleBuild build = r.assertBuildStatus(Result.FAILURE, project.scheduleBuild2(0));
- Node worker = build.getBuiltOn();
-
- try {
- // Need time for one-shot instance to terminate and create the snapshot
- Awaitility.await()
- .timeout(15, TimeUnit.MINUTES)
- .until(
- () ->
- r.jenkins.getNode(worker.getNodeName())
- == null); // Assert that there is 0 nodes after job finished
-
- Snapshot createdSnapshot = client.getSnapshot(PROJECT_ID, worker.getNodeName());
- assertNotNull(logs(), createdSnapshot);
- assertEquals(logs(), createdSnapshot.getStatus(), "READY");
- } finally {
- try {
- // cleanup
- client.deleteSnapshotAsync(PROJECT_ID, worker.getNodeName());
- } catch (Exception e) {
- }
- }
- }
-
- // TODO(google-compute-engine-plugin/issues/49): Remove this test when refactoring windows tests.
- @Test(timeout = 500000)
- public void testIgnoreProxy() throws Exception {
- logOutput.reset();
-
- ComputeEngineCloud cloud = (ComputeEngineCloud) r.jenkins.clouds.get(0);
- Jenkins jenkins = r.getInstance();
- jenkins.proxy = new ProxyConfiguration("127.0.0.1", 8080);
- jenkins.proxy.save();
- jenkins.save();
- InstanceConfiguration instanceConfiguration = validInstanceConfiguration1(LABEL, false, true);
- instanceConfiguration.setIgnoreProxy(true);
- cloud.setConfigurations(ImmutableList.of(instanceConfiguration));
-
- FreeStyleProject project = r.createFreeStyleProject();
- Builder step = new BatchFile("echo works");
- project.getBuildersList().add(step);
- project.setAssignedLabel(new LabelAtom(LABEL));
-
- r.buildAndAssertSuccess(project);
-
- cloud.getConfigurations().get(0).setIgnoreProxy(false);
- Future buildFuture = project.scheduleBuild2(0);
- FreeStyleBuild build;
- try {
- build = buildFuture.get(120, TimeUnit.SECONDS);
- } catch (TimeoutException e) {
- e.printStackTrace();
- return;
- }
- assertNotNull(build);
- assertEquals(Result.FAILURE, build.getResult());
- }
-
- /**
- * Creates an instance configuration for a node that will get a snapshot created upon deletion if
- * there is a build failure.
- *
- * @return InstanceConfiguration proper instance configuration to test snapshot creation.
- */
- private static InstanceConfiguration snapshotInstanceConfiguration() {
- return validInstanceConfiguration1(SNAPSHOT_LABEL, true, true);
- }
-
- /**
- * Given a job label and whether or not to create a snapshot upon deletion, gives working instance
- * configuration to launch an instance.
- *
- * @param labels What job label to run the instance on.
- * @param createSnapshot Whether or not to create a snapshot for the provisioned instance upon
- * deletion.
- * @return InstanceConfiguration working instance configuration to provision an instance.
- */
- private static InstanceConfiguration validInstanceConfiguration1(
- String labels, boolean createSnapshot, boolean oneShot) {
-
- String startupScript =
- "Stop-Service sshd\n"
- + "$ConfiguredPublicKey = "
- + "\""
- + publicKey
- + "\"\n"
- + "Write-Output \"Second phase\"\n"
- + "# We are in the second phase of startup where we need to set up authorized_keys for the specified user.\n"
- + "# Create the .ssh folder and authorized_keys file.\n"
- + "Set-Content -Path $env:PROGRAMDATA\\ssh\\administrators_authorized_keys -Value $ConfiguredPublicKey\n"
- + "icacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /inheritance:r\n"
- + "icacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /grant SYSTEM:`(F`)\n"
- + "icacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /grant BUILTIN\\Administrators:`(F`)\n"
- + "Restart-Service sshd";
-
- return ITUtil.instanceConfigurationBuilder()
- .numExecutorsStr(NUM_EXECUTORS)
- .startupScript(startupScript)
- .labels(labels)
- .bootDiskSourceImageName(
- "projects/" + bootDiskProjectId + "/global/images/" + bootDiskImageName)
- .bootDiskSourceImageProject(bootDiskProjectId)
- .bootDiskSizeGbStr(BOOT_DISK_SIZE_GB_STR)
- .windowsConfiguration(
- WindowsConfiguration.builder()
- .passwordCredentialsId("")
- .privateKeyCredentialsId(windowsPrivateKeyCredentialId)
- .build())
- .createSnapshot(createSnapshot)
- .retentionTimeMinutesStr(RETENTION_TIME_MINUTES_STR)
- .launchTimeoutSecondsStr(LAUNCH_TIMEOUT_SECONDS_STR)
- .oneShot(oneShot)
- .template(NULL_TEMPLATE)
- .googleLabels(INTEGRATION_LABEL)
- .build();
- }
-
- private static void deleteIntegrationInstances(boolean waitForCompletion) throws IOException {
- List instances = client.listInstancesWithLabel(PROJECT_ID, INTEGRATION_LABEL);
- for (Instance i : instances) {
- safeDelete(i.getName(), waitForCompletion);
- }
- }
-
- private static void safeDelete(String instanceId, boolean waitForCompletion) {
- try {
- Operation op = client.terminateInstanceAsync(PROJECT_ID, ZONE, instanceId);
- if (waitForCompletion)
- client.waitForOperationCompletion(PROJECT_ID, op.getName(), op.getZone(), 3 * 60 * 1000);
- } catch (Exception e) {
- log.warning(String.format("Error deleting instance %s: %s", instanceId, e.getMessage()));
- }
- }
-
- private static String logs() {
- sh.flush();
- return logOutput.toString();
- }
-}
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudWorkerCreatedIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudWorkerCreatedIT.java
index 11344dff..a0ef65c4 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudWorkerCreatedIT.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudWorkerCreatedIT.java
@@ -16,7 +16,6 @@
package com.google.jenkins.plugins.computeengine.integration;
-import static com.google.jenkins.plugins.computeengine.integration.ITUtil.DEB_JAVA_STARTUP_SCRIPT;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.LABEL;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NULL_TEMPLATE;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.NUM_EXECUTORS;
@@ -79,7 +78,6 @@ public static void init() throws Exception {
instanceConfiguration =
instanceConfigurationBuilder()
- .startupScript(DEB_JAVA_STARTUP_SCRIPT)
.numExecutorsStr(NUM_EXECUTORS)
.labels(LABEL)
.oneShot(false)
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudWorkerFailedIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudWorkerFailedIT.java
index 2abd4010..3b527f3f 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudWorkerFailedIT.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ComputeEngineCloudWorkerFailedIT.java
@@ -26,6 +26,7 @@
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initCredentials;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.instanceConfigurationBuilder;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.teardownResources;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.windows;
import com.google.cloud.graphite.platforms.plugin.client.ComputeClient;
import com.google.common.collect.ImmutableList;
@@ -39,6 +40,7 @@
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import org.junit.AfterClass;
+import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
@@ -63,6 +65,7 @@ public class ComputeEngineCloudWorkerFailedIT {
@BeforeClass
public static void init() throws Exception {
+ Assume.assumeFalse(windows);
log.info("init");
initCredentials(jenkinsRule);
ComputeEngineCloud cloud = initCloud(jenkinsRule);
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ConfigAsCodeWindowsIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ConfigAsCodeNonStandardJavaIT.java
similarity index 56%
rename from src/test/java/com/google/jenkins/plugins/computeengine/integration/ConfigAsCodeWindowsIT.java
rename to src/test/java/com/google/jenkins/plugins/computeengine/integration/ConfigAsCodeNonStandardJavaIT.java
index 336ff0d7..344b3336 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ConfigAsCodeWindowsIT.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ConfigAsCodeNonStandardJavaIT.java
@@ -1,20 +1,28 @@
package com.google.jenkins.plugins.computeengine.integration;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.PROJECT_ID;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.TEST_TIMEOUT_MULTIPLIER;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.ZONE;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.execute;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.getLabel;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initClient;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.initCredentials;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.teardownResources;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.windows;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeFalse;
+import com.google.api.services.compute.model.Instance;
import com.google.cloud.graphite.platforms.plugin.client.ComputeClient;
import com.google.jenkins.plugins.computeengine.ComputeEngineCloud;
import hudson.model.FreeStyleProject;
import hudson.model.labels.LabelAtom;
-import hudson.tasks.BatchFile;
+import hudson.slaves.NodeProvisioner.PlannedNode;
import hudson.tasks.Builder;
import io.jenkins.plugins.casc.ConfigurationAsCode;
import java.io.IOException;
+import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
@@ -25,25 +33,24 @@
import org.junit.rules.Timeout;
import org.jvnet.hudson.test.JenkinsRule;
-public class ConfigAsCodeWindowsIT {
-
- private static Logger log = Logger.getLogger(ConfigAsCodeWindowsIT.class.getName());
+/**
+ * Integration tests for Jenkins agents configured with Configuration as Code with a non-standard
+ * java path.
+ */
+public class ConfigAsCodeNonStandardJavaIT {
+ private static Logger log = Logger.getLogger(ConfigAsCodeNonStandardJavaIT.class.getName());
@ClassRule public static JenkinsRule jenkinsRule = new JenkinsRule();
@ClassRule
- public static Timeout timeout = new Timeout(10 * TEST_TIMEOUT_MULTIPLIER, TimeUnit.MINUTES);
+ public static Timeout timeout = new Timeout(5 * TEST_TIMEOUT_MULTIPLIER, TimeUnit.MINUTES);
private static ComputeClient client;
- private static Map label = getLabel(ConfigAsCodeWindowsIT.class);
+ private static Map label = getLabel(ConfigAsCodeNonStandardJavaIT.class);
@BeforeClass
public static void init() throws Exception {
+ assumeFalse(windows);
log.info("init");
- ConfigurationAsCode.get()
- .configure(
- ConfigAsCodeWindowsIT.class
- .getResource("configuration-as-code-windows-it.yml")
- .toString());
initCredentials(jenkinsRule);
client = initClient(jenkinsRule, label, log);
}
@@ -54,7 +61,13 @@ public static void teardown() throws IOException {
}
@Test
- public void testWindowsWorkerCreated() throws Exception {
+ public void testNonStandardJavaWorkerCreated() throws Exception {
+ assumeFalse(windows);
+ ConfigurationAsCode.get()
+ .configure(
+ this.getClass()
+ .getResource("configuration-as-code-non-standard-java-it.yml")
+ .toString());
ComputeEngineCloud cloud =
(ComputeEngineCloud) jenkinsRule.jenkins.clouds.getByName("gce-integration");
@@ -62,11 +75,22 @@ public void testWindowsWorkerCreated() throws Exception {
assertEquals(1, cloud.getConfigurations().size());
cloud.getConfigurations().get(0).setGoogleLabels(label);
+ // Add a new node
+ Collection planned =
+ cloud.provision(new LabelAtom("integration-non-standard-java"), 1);
+
+ // There should be a planned node
+ assertEquals(1, planned.size());
+ String name = planned.iterator().next().displayName;
+
+ // Wait for the node creation to finish
+ planned.iterator().next().future.get();
+ Instance instance = client.getInstance(PROJECT_ID, ZONE, name);
+ assertNotNull(instance);
+
FreeStyleProject project = jenkinsRule.createFreeStyleProject();
- Builder step = new BatchFile("echo works");
+ Builder step = execute(Commands.ECHO, "works");
project.getBuildersList().add(step);
- project.setAssignedLabel(new LabelAtom("integration-windows"));
-
jenkinsRule.buildAndAssertSuccess(project);
}
}
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ConfigAsCodeTestIT.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ConfigAsCodeTestIT.java
index c6cc1114..7fff58bc 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ConfigAsCodeTestIT.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ConfigAsCodeTestIT.java
@@ -1,5 +1,6 @@
package com.google.jenkins.plugins.computeengine.integration;
+import static com.google.jenkins.plugins.computeengine.integration.ITUtil.CONFIG_AS_CODE_PATH;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.PROJECT_ID;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.TEST_TIMEOUT_MULTIPLIER;
import static com.google.jenkins.plugins.computeengine.integration.ITUtil.ZONE;
@@ -21,6 +22,7 @@
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
+import org.awaitility.Awaitility;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
@@ -41,6 +43,8 @@ public class ConfigAsCodeTestIT {
@BeforeClass
public static void init() throws Exception {
log.info("init");
+ ConfigurationAsCode.get()
+ .configure(ConfigAsCodeTestIT.class.getResource(CONFIG_AS_CODE_PATH).toString());
initCredentials(jenkinsRule);
client = initClient(jenkinsRule, label, log);
}
@@ -52,8 +56,6 @@ public static void teardown() throws IOException {
@Test
public void testWorkerCreated() throws Exception {
- ConfigurationAsCode.get()
- .configure(this.getClass().getResource("configuration-as-code-it.yml").toString());
ComputeEngineCloud cloud =
(ComputeEngineCloud) jenkinsRule.jenkins.clouds.getByName("gce-integration");
@@ -66,35 +68,7 @@ public void testWorkerCreated() throws Exception {
cloud.provision(new LabelAtom("integration"), 1);
// There should be a planned node
- assertEquals(1, planned.size());
- String name = planned.iterator().next().displayName;
-
- // Wait for the node creation to finish
- planned.iterator().next().future.get();
- Instance instance = client.getInstance(PROJECT_ID, ZONE, name);
- assertNotNull(instance);
- }
-
- @Test
- public void testNonStandardJavaWorkerCreated() throws Exception {
- ConfigurationAsCode.get()
- .configure(
- this.getClass()
- .getResource("configuration-as-code-non-standard-java-it.yml")
- .toString());
- ComputeEngineCloud cloud =
- (ComputeEngineCloud) jenkinsRule.jenkins.clouds.getByName("gce-integration");
-
- // Should be 1 configuration
- assertEquals(1, cloud.getConfigurations().size());
- cloud.getConfigurations().get(0).setGoogleLabels(label);
-
- // Add a new node
- Collection planned =
- cloud.provision(new LabelAtom("integration-non-standard-java"), 1);
-
- // There should be a planned node
- assertEquals(1, planned.size());
+ Awaitility.await().timeout(2, TimeUnit.MINUTES).until(() -> planned.size() == 1);
String name = planned.iterator().next().displayName;
// Wait for the node creation to finish
diff --git a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ITUtil.java b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ITUtil.java
index a8ce757d..dbafee0c 100644
--- a/src/test/java/com/google/jenkins/plugins/computeengine/integration/ITUtil.java
+++ b/src/test/java/com/google/jenkins/plugins/computeengine/integration/ITUtil.java
@@ -20,6 +20,7 @@
import static com.google.common.collect.ImmutableList.copyOf;
import static com.google.common.collect.ImmutableList.of;
import static com.google.jenkins.plugins.computeengine.InstanceConfiguration.METADATA_LINUX_STARTUP_SCRIPT_KEY;
+import static com.google.jenkins.plugins.computeengine.InstanceConfiguration.METADATA_WINDOWS_STARTUP_SCRIPT_KEY;
import static com.google.jenkins.plugins.computeengine.InstanceConfiguration.NAT_NAME;
import static com.google.jenkins.plugins.computeengine.InstanceConfiguration.NAT_TYPE;
import static org.junit.Assert.assertEquals;
@@ -27,10 +28,13 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
+import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey;
import com.cloudbees.plugins.credentials.Credentials;
+import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.CredentialsStore;
import com.cloudbees.plugins.credentials.SecretBytes;
import com.cloudbees.plugins.credentials.SystemCredentialsProvider;
+import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
import com.cloudbees.plugins.credentials.domains.Domain;
import com.google.api.services.compute.model.AccessConfig;
import com.google.api.services.compute.model.AttachedDisk;
@@ -51,11 +55,15 @@
import com.google.jenkins.plugins.computeengine.AutofilledNetworkConfiguration;
import com.google.jenkins.plugins.computeengine.ComputeEngineCloud;
import com.google.jenkins.plugins.computeengine.InstanceConfiguration;
+import com.google.jenkins.plugins.computeengine.WindowsConfiguration;
import com.google.jenkins.plugins.computeengine.client.ClientUtil;
import com.google.jenkins.plugins.computeengine.ssh.GoogleKeyPair;
import com.google.jenkins.plugins.credentials.oauth.GoogleRobotPrivateKeyCredentials;
import com.google.jenkins.plugins.credentials.oauth.JsonServiceAccountConfig;
import hudson.model.Node;
+import hudson.plugins.powershell.PowerShell;
+import hudson.tasks.Builder;
+import hudson.tasks.Shell;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -63,12 +71,16 @@
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
+import jenkins.util.SystemProperties;
import org.apache.commons.lang.SystemUtils;
import org.jvnet.hudson.test.JenkinsRule;
/** Common logic and constants used throughout the integration tests. */
class ITUtil {
- static final String DEB_JAVA_STARTUP_SCRIPT =
+ static final boolean windows =
+ Boolean.parseBoolean(
+ SystemProperties.getString(ITUtil.class.getName() + ".windows", "false"));
+ private static final String DEB_JAVA_STARTUP_SCRIPT =
"#!/bin/bash\n"
+ "/etc/init.d/ssh stop\n"
+ "echo \"deb http://http.debian.net/debian stretch-backports main\" | \\\n"
@@ -95,14 +107,19 @@ class ITUtil {
private static final String CONFIG_DESC = "integration";
private static final String BOOT_DISK_TYPE = ZONE_BASE + "/diskTypes/pd-ssd";
private static final boolean BOOT_DISK_AUTODELETE = true;
- private static final String BOOT_DISK_PROJECT_ID = "debian-cloud";
+ private static final String BOOT_DISK_PROJECT_ID =
+ windows ? System.getenv("GOOGLE_BOOT_DISK_PROJECT_ID") : "debian-cloud";
private static final String BOOT_DISK_IMAGE_NAME =
- "projects/debian-cloud/global/images/family/debian-9";
- private static final String BOOT_DISK_SIZE_GB_STR = "10";
+ windows
+ ? String.format(
+ "projects/%s/global/images/%s",
+ BOOT_DISK_PROJECT_ID, System.getenv("GOOGLE_BOOT_DISK_IMAGE_NAME"))
+ : "projects/debian-cloud/global/images/family/debian-9";
+ private static final String BOOT_DISK_SIZE_GB_STR = windows ? "50" : "10";
private static final Node.Mode NODE_MODE = Node.Mode.EXCLUSIVE;
private static final String ACCELERATOR_NAME = "";
private static final String ACCELERATOR_COUNT = "";
- private static final String RUN_AS_USER = "jenkins";
+ static final String RUN_AS_USER = "jenkins";
static final String NULL_TEMPLATE = null;
private static final String NETWORK_NAME = format("projects/%s/global/networks/default");
private static final String SUBNETWORK_NAME = "default";
@@ -112,10 +129,30 @@ class ITUtil {
String.format("%s@%s.iam.gserviceaccount.com", System.getenv("GOOGLE_SA_NAME"), PROJECT_ID);
private static final String RETENTION_TIME_MINUTES_STR = "";
private static final String LAUNCH_TIMEOUT_SECONDS_STR = "";
- static final String SSH_USER = "test-user";
- private static final GoogleKeyPair SSH_KEY = GoogleKeyPair.generate(SSH_USER);
+ static final int SNAPSHOT_TIMEOUT = windows ? 600 : 300;
+ private static final GoogleKeyPair SSH_KEY = GoogleKeyPair.generate(RUN_AS_USER);
static final String SSH_PRIVATE_KEY = SSH_KEY.getPrivateKey();
+ private static final String WINDOWS_STARTUP_SCRIPT =
+ "Stop-Service sshd\n"
+ + "$ConfiguredPublicKey = "
+ + "\""
+ + SSH_KEY.getPublicKey().trim().substring(RUN_AS_USER.length() + 1)
+ + "\"\n"
+ + "Write-Output \"Second phase\"\n"
+ + "# We are in the second phase of startup where we need to set up authorized_keys for the specified user.\n"
+ + "# Create the .ssh folder and authorized_keys file.\n"
+ + "Set-Content -Path $env:PROGRAMDATA\\ssh\\administrators_authorized_keys -Value $ConfiguredPublicKey\n"
+ + "icacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /inheritance:r\n"
+ + "icacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /grant SYSTEM:`(F`)\n"
+ + "icacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /grant BUILTIN\\Administrators:`(F`)\n"
+ + "Restart-Service sshd";
+ private static final String STARTUP_SCRIPT =
+ windows ? WINDOWS_STARTUP_SCRIPT : DEB_JAVA_STARTUP_SCRIPT;
static final int TEST_TIMEOUT_MULTIPLIER = SystemUtils.IS_OS_WINDOWS ? 3 : 1;
+ static final String CONFIG_AS_CODE_PATH =
+ windows ? "configuration-as-code-windows-it.yml" : "configuration-as-code-it.yml";
+
+ private static String windowsPrivateKeyCredentialsId;
static String format(String s) {
assertNotNull("GOOGLE_PROJECT_ID env var must be set", PROJECT_ID);
@@ -154,9 +191,25 @@ static Credentials initCredentials(JenkinsRule r) throws Exception {
CredentialsStore store = new SystemCredentialsProvider.ProviderImpl().getStore(r.jenkins);
assertNotNull("Credentials store can not be null", store);
store.addCredentials(Domain.global(), credentials);
+ if (windows) {
+ windowsPrivateKeyCredentialsId = initWindowsSshCredentials(store);
+ }
return credentials;
}
+ private static String initWindowsSshCredentials(CredentialsStore store) throws IOException {
+ StandardUsernameCredentials windowsPrivateKeyCredentials =
+ new BasicSSHUserPrivateKey(
+ CredentialsScope.GLOBAL,
+ null,
+ RUN_AS_USER,
+ new BasicSSHUserPrivateKey.DirectEntryPrivateKeySource(SSH_KEY.getPrivateKey()),
+ null,
+ "integration test private key for windows");
+ store.addCredentials(Domain.global(), windowsPrivateKeyCredentials);
+ return windowsPrivateKeyCredentials.getId();
+ }
+
// Add Cloud plugin
static ComputeEngineCloud initCloud(JenkinsRule jenkinsRule) {
ComputeEngineCloud gcp = new ComputeEngineCloud(CLOUD_NAME, PROJECT_ID, PROJECT_ID, "10");
@@ -176,6 +229,13 @@ static ComputeClient initClient(JenkinsRule jenkinsRule, Map lab
return client;
}
+ static Builder execute(Commands command, String argument) {
+ if (windows) {
+ return new PowerShell(String.format(command.getWindows(), argument));
+ }
+ return new Shell(String.format(command.getLinux(), argument));
+ }
+
static void teardownResources(ComputeClient client, Map label, Logger log)
throws IOException {
log.info("teardown");
@@ -206,8 +266,11 @@ static InstanceTemplate createTemplate(Map googleLabels, String
.setItems(
of(
new Metadata.Items()
- .setKey(METADATA_LINUX_STARTUP_SCRIPT_KEY)
- .setValue(DEB_JAVA_STARTUP_SCRIPT),
+ .setKey(
+ windows
+ ? METADATA_WINDOWS_STARTUP_SCRIPT_KEY
+ : METADATA_LINUX_STARTUP_SCRIPT_KEY)
+ .setValue(STARTUP_SCRIPT),
new Metadata.Items()
.setKey(InstanceConfiguration.SSH_METADATA_KEY)
.setValue(SSH_KEY.getPublicKey()))));
@@ -235,7 +298,13 @@ static InstanceConfiguration.Builder instanceConfigurationBuilder() {
.bootDiskSourceImageName(BOOT_DISK_IMAGE_NAME)
.bootDiskSourceImageProject(BOOT_DISK_PROJECT_ID)
.bootDiskSizeGbStr(BOOT_DISK_SIZE_GB_STR)
- .windowsConfiguration(null)
+ .windowsConfiguration(
+ windows
+ ? WindowsConfiguration.builder()
+ .passwordCredentialsId("")
+ .privateKeyCredentialsId(windowsPrivateKeyCredentialsId)
+ .build()
+ : null)
.remoteFs(null)
.networkConfiguration(new AutofilledNetworkConfiguration(NETWORK_NAME, SUBNETWORK_NAME))
.externalAddress(EXTERNAL_ADDR)
@@ -247,7 +316,8 @@ static InstanceConfiguration.Builder instanceConfigurationBuilder() {
.launchTimeoutSecondsStr(LAUNCH_TIMEOUT_SECONDS_STR)
.mode(NODE_MODE)
.acceleratorConfiguration(new AcceleratorConfiguration(ACCELERATOR_NAME, ACCELERATOR_COUNT))
- .runAsUser(RUN_AS_USER);
+ .runAsUser(RUN_AS_USER)
+ .startupScript(STARTUP_SCRIPT);
}
/*
diff --git a/src/test/resources/com/google/jenkins/plugins/computeengine/integration/configuration-as-code-windows-it.yml b/src/test/resources/com/google/jenkins/plugins/computeengine/integration/configuration-as-code-windows-it.yml
index bfa0bb9f..a4fcb5dd 100644
--- a/src/test/resources/com/google/jenkins/plugins/computeengine/integration/configuration-as-code-windows-it.yml
+++ b/src/test/resources/com/google/jenkins/plugins/computeengine/integration/configuration-as-code-windows-it.yml
@@ -6,12 +6,12 @@ jenkins:
instanceCapStr: 10
credentialsId: ${env.GOOGLE_PROJECT_ID}
configurations:
- - namePrefix: integration-windows
- description: integration-windows
+ - namePrefix: integration
+ description: integration
launchTimeoutSecondsStr: 3000
retentionTimeMinutesStr: 600
mode: EXCLUSIVE
- labelString: integration-windows
+ labelString: integration
numExecutorsStr: 1
runAsUser: jenkins
remoteFs: ''
@@ -20,13 +20,13 @@ jenkins:
privateKeyCredentialsId: ''
oneShot: true
createSnapshot: false
- region: "https://www.googleapis.com/compute/v1/projects/${env.GOOGLE_PROJECT_ID}/regions/us-west1"
- zone: "https://www.googleapis.com/compute/v1/projects/${env.GOOGLE_PROJECT_ID}/zones/us-west1-a"
+ region: "https://www.googleapis.com/compute/v1/projects/${env.GOOGLE_PROJECT_ID}/regions/${env.GOOGLE_REGION}"
+ zone: "https://www.googleapis.com/compute/v1/projects/${env.GOOGLE_PROJECT_ID}/zones/${env.GOOGLE_ZONE}"
template: '' # tried not setting, added when 'saved' in UI
- machineType: "https://www.googleapis.com/compute/v1/projects/${env.GOOGLE_PROJECT_ID}/zones/us-west1-a/machineTypes/n1-standard-1"
+ machineType: "https://www.googleapis.com/compute/v1/projects/${env.GOOGLE_PROJECT_ID}/zones/${env.GOOGLE_ZONE}/machineTypes/n1-standard-1"
preemptible: false
minCpuPlatform: '' # tried not setting, added when 'saved' in UI
- startupScript: "Stop-Service sshd\n$ConfiguredPublicKey = \":${env.GOOGLE_PUBLIC_KEY}\"\nWrite-Output \"Second phase\"\nSet-Content -Path $env:PROGRAMDATA\\ssh\\administrators_authorized_keys -Value $ConfiguredPublicKey\nicacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /inheritance:r\nicacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /grant SYSTEM:`(F`)\nicacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /grant BUILTIN\\Administrators:`(F`)\nRestart-Service sshd"
+ startupScript: "Stop-Service sshd\n$ConfiguredPublicKey = \"jenkins:${env.GOOGLE_PUBLIC_KEY}\"\nWrite-Output \"Second phase\"\nSet-Content -Path $env:PROGRAMDATA\\ssh\\administrators_authorized_keys -Value $ConfiguredPublicKey\nicacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /inheritance:r\nicacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /grant SYSTEM:`(F`)\nicacls $env:PROGRAMDATA\\ssh\\administrators_authorized_keys /grant BUILTIN\\Administrators:`(F`)\nRestart-Service sshd"
networkConfiguration:
autofilled:
network: default
@@ -36,10 +36,10 @@ jenkins:
useInternalAddress: false
bootDiskSourceImageProject: ${env.GOOGLE_BOOT_DISK_PROJECT_ID}
bootDiskSourceImageName: "projects/${env.GOOGLE_BOOT_DISK_PROJECT_ID}/global/images/${env.GOOGLE_BOOT_DISK_IMAGE_NAME}"
- bootDiskType: "https://www.googleapis.com/compute/v1/projects/${env.GOOGLE_PROJECT_ID}/zones/us-west1-a/diskTypes/pd-ssd"
+ bootDiskType: "https://www.googleapis.com/compute/v1/projects/${env.GOOGLE_PROJECT_ID}/zones/${env.GOOGLE_ZONE}/diskTypes/pd-ssd"
bootDiskSizeGbStr: 50
bootDiskAutoDelete: true
- serviceAccountEmail: ''
+ serviceAccountEmail: "${env.GOOGLE_SA_NAME}@${env.GOOGLE_PROJECT_ID}.iam.gserviceaccount.com"
credentials:
system:
domainCredentials:
diff --git a/windows-it-install.ps1 b/windows-it-install.ps1
index aa72b0bf..a666bf13 100644
--- a/windows-it-install.ps1
+++ b/windows-it-install.ps1
@@ -35,7 +35,7 @@ choco install -y jre8
# Following Step is needed for the startup script in the integration test to work, even if you already configured your own user.
Write-Output "Adding build user..."
$username = "jenkins"
-$password = ConvertTo-SecureString "P4ssword1" -AsPlainText -Force
+$password = ConvertTo-SecureString $env:WINDOWS_PASSWORD -AsPlainText -Force
New-LocalUser -Name $username -Password $password
Add-LocalGroupMember -Group "Administrators" -Member "$username"
@@ -43,3 +43,6 @@ Add-LocalGroupMember -Group "Administrators" -Member "$username"
Write-Output "Simulating login to register user..."
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username,$password
Start-Process cmd /c -WindowStyle Hidden -Credential $cred -ErrorAction SilentlyContinue
+
+# Close the door on the way out
+choco install undo-winrmconfig-during-shutdown --confirm