-
Notifications
You must be signed in to change notification settings - Fork 90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make most ITs work with both linux and windows #143
Changes from 14 commits
e0860ed
43ae720
a608c41
60b2464
7aaa488
df8e355
5423f9d
31a07f2
98069b1
7149c5c
5fbf016
70e6a1f
6bb42b9
fee03f9
7f0dc57
5bcb4fc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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]) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,21 +51,12 @@ protected Optional<Connection> setupConnection( | |
logWarning(computer, listener, "Non-windows node provided"); | ||
return Optional.empty(); | ||
} | ||
boolean isBootstrapped = bootstrap(computer, listener); | ||
if (!isBootstrapped) { | ||
Optional<Connection> 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,8 +78,7 @@ private boolean authenticateSSH( | |
return isAuthenticated; | ||
} | ||
|
||
private boolean bootstrap(ComputeEngineComputer computer, TaskListener listener) | ||
throws IOException, Exception { // TODO(evanbrown): better exceptions | ||
private Optional<Connection> bootstrap(ComputeEngineComputer computer, TaskListener listener) { | ||
if (computer == null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preconditions.checkNotNull() |
||
throw new IllegalArgumentException("A null ComputeEngineComputer was provided"); | ||
} | ||
|
@@ -125,14 +115,15 @@ private boolean bootstrap(ComputeEngineComputer computer, TaskListener listener) | |
} | ||
if (!isAuthenticated) { | ||
logWarning(computer, listener, "Authentication failed"); | ||
return false; | ||
return Optional.empty(); | ||
} | ||
} finally { | ||
} catch (Exception e) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above re: swallowing exceptions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added logging |
||
if (bootstrapConn != null) { | ||
bootstrapConn.close(); | ||
} | ||
return Optional.empty(); | ||
} | ||
return true; | ||
return Optional.ofNullable(bootstrapConn); | ||
} | ||
|
||
@Override | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,7 +33,7 @@ | |
*/ | ||
final class PreemptedCheckCallable extends MasterToSlaveCallable<Boolean, IOException> { | ||
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<Boolean, IOExce | |
*/ | ||
@Override | ||
public Boolean call() throws IOException { | ||
HttpRequest request = createMetadataRequest(); | ||
HttpRequest initialRequest = createMetadataRequest(false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This came up in #148 as well. Having the preemption event occur before the agent is running and listening for preemption events is rare, but given that it can and does happen it makes sense to check that it's not already preempted before beginning the long poll to wait for a change to the metadata (which won't happen in that case). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense. |
||
HttpResponse initialResponse = initialRequest.execute(); | ||
final String initialResult = IOUtils.toString(initialResponse.getContent(), Charsets.UTF_8); | ||
initialResponse.disconnect(); | ||
if ("TRUE".equals(initialResult)) { | ||
listener | ||
.getLogger() | ||
.println("Instance was already preempted before monitoring metadata changes."); | ||
return true; | ||
} | ||
|
||
HttpRequest request = createMetadataRequest(true); | ||
listener.getLogger().println("Preemptive instance, listening to metadata for preemption event"); | ||
HttpResponse response = request.execute(); | ||
final String result = IOUtils.toString(response.getContent(), Charsets.UTF_8); | ||
|
@@ -67,12 +78,16 @@ public Boolean call() throws IOException { | |
return "TRUE".equals(result); | ||
} | ||
|
||
private HttpRequest createMetadataRequest() throws IOException { | ||
private HttpRequest createMetadataRequest(boolean waitForChange) throws IOException { | ||
HttpTransport transport = new NetHttpTransport(); | ||
GenericUrl metadata = new GenericUrl(METADATA_SERVER_URL); | ||
GenericUrl metadata = new GenericUrl(getMetadataServerUrl(waitForChange)); | ||
HttpRequest request = transport.createRequestFactory().buildGetRequest(metadata); | ||
request.setHeaders(new HttpHeaders().set("Metadata-Flavor", "Google")); | ||
request.setReadTimeout(Integer.MAX_VALUE); | ||
return request; | ||
} | ||
|
||
private static String getMetadataServerUrl(boolean waitForChange) { | ||
return String.format(METADATA_SERVER_URL, waitForChange); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.google.jenkins.plugins.computeengine.integration; | ||
|
||
import lombok.Getter; | ||
|
||
/** | ||
* An enum defining commands that can be run on both linux and windows agents, with corresponding | ||
* String format values for each platform. | ||
*/ | ||
@Getter | ||
public enum Commands { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing javadoc header. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
ECHO("echo %s", "echo %s"), | ||
EXIT("exit /b %s", "exit %s"), | ||
SLEEP("ping /n %s /l 1024 google.com ", "sleep %s"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is a little weird. I was not able to get the proper windows equivalent "timeout" to work. Looking around I found that there are some weird issues with running the command in non-interactive scripts, discussed in places such as this comment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense. Is using Powershell a viable alternative to batch? If so, we could consider using -NonInteractive: https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Core/About/about_PowerShell_exe?view=powershell-5.1#-noninteractive There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the tip, while I had trouble using powershell within the existing batch scripts, this led me to finding the Powershell plugin which automatically applies the NonInteractive flag when running scripts, and I was able to remove this hack. |
||
|
||
private String windows; | ||
private String linux; | ||
|
||
Commands(String windows, String linux) { | ||
this.windows = windows; | ||
this.linux = linux; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I'm weary of swallowing exceptions like this. I think at the very least we should consider logging it as a warning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added logging