From fc771b561d0f22e912ec76016d1f31e21bfa68ff Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 8 Jul 2015 11:23:42 +0200 Subject: [PATCH 01/34] GCloud SDK auto-installer --- .../plugins/gcloud/GCloudBuildWrapper.java | 59 +++++++++++++++-- .../plugins/gcloudsdk/GCloudInstallation.java | 64 ++++++++++++++++++ .../plugins/gcloudsdk/GCloudInstaller.java | 65 +++++++++++++++++++ .../gcloud/GCloudBuildWrapper/config.jelly | 8 ++- .../gcloud/GCloudSDKBuilder/config.jelly | 3 +- .../lib/gcloud/selectGCloudInstallation.jelly | 23 +++++++ src/main/resources/lib/gcloud/taglib | 1 + 7 files changed, 216 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java create mode 100644 src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java create mode 100644 src/main/resources/lib/gcloud/selectGCloudInstallation.jelly create mode 100644 src/main/resources/lib/gcloud/taglib diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java index 96445cf..4b799e4 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java @@ -1,15 +1,28 @@ package com.byclosure.jenkins.plugins.gcloud; +import com.cloudbees.jenkins.plugins.gcloudsdk.GCloudInstallation; +import com.cloudbees.plugins.credentials.CredentialsMatcher; +import com.cloudbees.plugins.credentials.CredentialsMatchers; +import com.cloudbees.plugins.credentials.CredentialsProvider; +import com.cloudbees.plugins.credentials.common.StandardListBoxModel; +import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder; import com.google.jenkins.plugins.credentials.domains.RequiresDomain; +import com.google.jenkins.plugins.credentials.oauth.GoogleRobotPrivateKeyCredentials; import hudson.Extension; import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.BuildListener; +import hudson.model.Item; +import hudson.security.ACL; import hudson.tasks.BuildWrapper; import hudson.tasks.BuildWrapperDescriptor; +import hudson.tools.ToolInstallation; +import hudson.util.ListBoxModel; import net.sf.json.JSONObject; +import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import java.io.IOException; @@ -19,15 +32,21 @@ @RequiresDomain(value = GCloudScopeRequirement.class) public class GCloudBuildWrapper extends BuildWrapper { private static final Logger LOGGER = Logger.getLogger(GCloudBuildWrapper.class.getName()); + + private final String installation; private final String credentialsId; @DataBoundConstructor - public GCloudBuildWrapper(String credentialsId) { - this.credentialsId = credentialsId; - } + public GCloudBuildWrapper(String installation, String credentialsId) { + this.installation = installation; + this.credentialsId = credentialsId; + } @Override public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + + final ToolInstallation sdk = getSDK().translate(build, listener); + final GCloudServiceAccount serviceAccount = GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId); @@ -55,7 +74,22 @@ public boolean tearDown(AbstractBuild build, final BuildListener listener) throw }; } - public String getCredentialsId() { + public GCloudInstallation getSDK() { + GCloudInstallation[] installations = GCloudInstallation.getInstallations(); + if (installations.length == 1) return installations[0]; + for (GCloudInstallation sdk : installations) { + if (installation.equals(sdk.getName())) return sdk; + } + throw new IllegalArgumentException("Invalid GCloud SDK installation "+installation); + } + + + + public String getInstallation() { + return installation; + } + + public String getCredentialsId() { return credentialsId; } @@ -80,5 +114,22 @@ public boolean configure(StaplerRequest req, JSONObject formData) throws FormExc save(); return super.configure(req, formData); } + + public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item project, + @QueryParameter String serverAddress) { + if (project == null || !project.hasPermission(Item.CONFIGURE)) { + return new StandardListBoxModel(); + } + return new StandardListBoxModel() + .withEmptySelection() + .withMatching( + MATCHER, + CredentialsProvider.lookupCredentials(GoogleRobotPrivateKeyCredentials.class, + project, + ACL.SYSTEM, + URIRequirementBuilder.fromUri(serverAddress).build())); + } + + public static final CredentialsMatcher MATCHER = CredentialsMatchers.anyOf(CredentialsMatchers.instanceOf(GoogleRobotPrivateKeyCredentials.class)); } } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java new file mode 100644 index 0000000..50d5222 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java @@ -0,0 +1,64 @@ +package com.cloudbees.jenkins.plugins.gcloudsdk; + +import hudson.EnvVars; +import hudson.Extension; +import hudson.model.EnvironmentSpecific; +import hudson.model.Node; +import hudson.model.TaskListener; +import hudson.slaves.NodeSpecific; +import hudson.tools.ToolDescriptor; +import hudson.tools.ToolInstallation; +import hudson.tools.ToolProperty; +import jenkins.model.Jenkins; +import org.kohsuke.stapler.DataBoundConstructor; + +import java.io.IOException; +import java.util.List; + +/** + * @author Nicolas De Loof + */ +public class GCloudInstallation extends ToolInstallation implements NodeSpecific, EnvironmentSpecific { + + @DataBoundConstructor + public GCloudInstallation(String name, String home, List> properties) { + super(name, home, properties); + } + + + public void buildEnvVars(EnvVars env) { + env.override("PATH+GCLOUD", getHome()); + } + + + public GCloudInstallation forNode(Node node, TaskListener log) throws IOException, InterruptedException { + return new GCloudInstallation(getName(), translateFor(node, log), getProperties().toList()); + } + + public GCloudInstallation forEnvironment(EnvVars environment) { + return new GCloudInstallation(getName(), environment.expand(getHome()), getProperties().toList()); + } + + public static GCloudInstallation[] getInstallations() { + return Jenkins.getInstance().getDescriptorByType(DescriptorImpl.class).getInstallations(); + } + + @Extension + public static class DescriptorImpl extends ToolDescriptor { + + @Override + public String getDisplayName() { + return "Google Cloud SDK"; + } + + public DescriptorImpl() { + load(); + } + + public void setInstallations(GCloudInstallation... installations) { + super.setInstallations(installations); + save(); + } + + } +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java new file mode 100644 index 0000000..9de51c2 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java @@ -0,0 +1,65 @@ +package com.cloudbees.jenkins.plugins.gcloudsdk; + +import hudson.Extension; +import hudson.FilePath; +import hudson.Launcher; +import hudson.model.Node; +import hudson.model.TaskListener; +import hudson.tools.DownloadFromUrlInstaller; +import hudson.tools.ToolInstallation; +import org.kohsuke.stapler.DataBoundConstructor; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +/** + * @author Nicolas De Loof + */ +public class GCloudInstaller extends DownloadFromUrlInstaller { + + @DataBoundConstructor + public GCloudInstaller(String id) { + super(id); + } + + @Override + public FilePath performInstallation(ToolInstallation tool, Node node, TaskListener log) throws IOException, InterruptedException { + FilePath installation = super.performInstallation(tool, node, log); + + Launcher launcher = node.createLauncher(log); + launcher.launch() + .stdout(log) + .cmds( installation.child(launcher.isUnix() ? "install.sh" : "install.bat").getRemote(), + "--usage-reporting=false", "--path-update=false", "--bash-completion=false") + .join(); + + return installation; + } + + @Override + public Installable getInstallable() throws IOException { + return SDK; + } + + @Extension + public static final class DescriptorImpl extends DownloadFromUrlInstaller.DescriptorImpl { + public String getDisplayName() { + return "Install from google.com"; + } + + @Override + public List getInstallables() throws IOException { + return Collections.singletonList(SDK); + } + } + + + public static Installable SDK = new Installable() { + { + id = "google-cloud-sdk"; + url = "https://dl.google.com/dl/cloudsdk/release/google-cloud-sdk.zip"; + name = "latest"; + } + }; +} diff --git a/src/main/resources/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper/config.jelly b/src/main/resources/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper/config.jelly index b6f26ea..ca98dc4 100644 --- a/src/main/resources/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper/config.jelly +++ b/src/main/resources/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper/config.jelly @@ -1,5 +1,9 @@ - + xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:a="/lib/auth" xmlns:g="/lib/gcloud" xmlns:c="/lib/credentials"> + + + + + diff --git a/src/main/resources/com/byclosure/jenkins/plugins/gcloud/GCloudSDKBuilder/config.jelly b/src/main/resources/com/byclosure/jenkins/plugins/gcloud/GCloudSDKBuilder/config.jelly index dd261a7..1db5265 100644 --- a/src/main/resources/com/byclosure/jenkins/plugins/gcloud/GCloudSDKBuilder/config.jelly +++ b/src/main/resources/com/byclosure/jenkins/plugins/gcloud/GCloudSDKBuilder/config.jelly @@ -1,6 +1,7 @@ + xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:a="/lib/auth" > + diff --git a/src/main/resources/lib/gcloud/selectGCloudInstallation.jelly b/src/main/resources/lib/gcloud/selectGCloudInstallation.jelly new file mode 100644 index 0000000..e76bf66 --- /dev/null +++ b/src/main/resources/lib/gcloud/selectGCloudInstallation.jelly @@ -0,0 +1,23 @@ + + + + + Renders a form field to select a GCloud installation. + The field is expected to be a String tool name, with Util.fixEmpty on the @DataBoundSetter to account for the default. + + Form field name. Used for databinding. + + + + + + + + + + diff --git a/src/main/resources/lib/gcloud/taglib b/src/main/resources/lib/gcloud/taglib new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/main/resources/lib/gcloud/taglib @@ -0,0 +1 @@ + From 7889cd974358fe071f4c3174c1ea058ba8744aae Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 8 Jul 2015 15:29:56 +0200 Subject: [PATCH 02/34] Use a temporary configuration dir --- .../plugins/gcloud/GCloudBuildWrapper.java | 4 +++- .../gcloud/GCloudSDKWithAuthBuilder.java | 12 ++++++++---- .../plugins/gcloud/GCloudServiceAccount.java | 19 ++++++++++++------- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java index 4b799e4..a9a9d5c 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java @@ -9,6 +9,7 @@ import com.google.jenkins.plugins.credentials.domains.RequiresDomain; import com.google.jenkins.plugins.credentials.oauth.GoogleRobotPrivateKeyCredentials; import hudson.Extension; +import hudson.FilePath; import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; @@ -46,9 +47,10 @@ public GCloudBuildWrapper(String installation, String credentialsId) { public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { final ToolInstallation sdk = getSDK().translate(build, listener); + final FilePath configDir = build.getWorkspace().createTempDir("gcloud", "config"); final GCloudServiceAccount serviceAccount = - GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId); + GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId, configDir); if (!serviceAccount.activate()) { serviceAccount.cleanUp(); diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java index 3c32d87..9645c84 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java @@ -3,6 +3,7 @@ import com.google.jenkins.plugins.credentials.domains.RequiresDomain; import hudson.Extension; +import hudson.FilePath; import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; @@ -36,15 +37,17 @@ public String getCommand() { @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + + final FilePath configDir = build.getWorkspace().createTempDir("gcloud", "config"); final GCloudServiceAccount serviceAccount = - GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId); + GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId, configDir); if (!serviceAccount.activate()) { serviceAccount.cleanUp(); return false; } - if (!executeGCloudCLI(build, launcher, listener)) { + if (!executeGCloudCLI(build, launcher, listener, configDir)) { serviceAccount.revoke(); serviceAccount.cleanUp(); return false; @@ -59,12 +62,13 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListener lis return true; } - private boolean executeGCloudCLI(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + private boolean executeGCloudCLI(AbstractBuild build, Launcher launcher, BuildListener listener, FilePath configDir) throws IOException, InterruptedException { int retCode = launcher.launch() .pwd(build.getWorkspace()) .cmdAsSingleString("gcloud " + command) .stdout(listener.getLogger()) - .join(); + .envs("CLOUDSDK_CONFIG=" + configDir.getRemote()) + .join(); if (retCode != 0) { return false; diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java index 6de977e..7f64528 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java @@ -5,6 +5,7 @@ import com.google.jenkins.plugins.credentials.oauth.JsonServiceAccountConfig; import com.google.jenkins.plugins.credentials.oauth.P12ServiceAccountConfig; import com.google.jenkins.plugins.credentials.oauth.ServiceAccountConfig; +import hudson.FilePath; import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.BuildListener; @@ -19,9 +20,10 @@ public class GCloudServiceAccount { private final BuildListener listener; private final String accountId; private final TemporaryKeyFile tmpKeyFile; + private final FilePath configDir; - public static GCloudServiceAccount getServiceAccount(AbstractBuild build, Launcher launcher, - BuildListener listener, String credentialsId) throws IOException, InterruptedException { + public static GCloudServiceAccount getServiceAccount(AbstractBuild build, Launcher launcher, + BuildListener listener, String credentialsId, FilePath configDir) throws IOException, InterruptedException { final GoogleRobotPrivateKeyCredentials credential = CredentialsProvider.findCredentialById( credentialsId, GoogleRobotPrivateKeyCredentials.class, @@ -37,7 +39,7 @@ public static GCloudServiceAccount getServiceAccount(AbstractBuild build, Launch TemporaryKeyFile tmpKeyFile = new TemporaryKeyFile(build, launcher, keyFile); tmpKeyFile.copyToTmpDir(); - return new GCloudServiceAccount(build, launcher, listener, accountId, tmpKeyFile); + return new GCloudServiceAccount(build, launcher, listener, accountId, tmpKeyFile, configDir); } private static File getKeyFile(ServiceAccountConfig serviceAccount) { @@ -52,22 +54,24 @@ private static File getKeyFile(ServiceAccountConfig serviceAccount) { return new File(keyFilePath); } - private GCloudServiceAccount(AbstractBuild build, Launcher launcher, BuildListener listener, String accountId, TemporaryKeyFile tmpKeyFile) { + private GCloudServiceAccount(AbstractBuild build, Launcher launcher, BuildListener listener, String accountId, TemporaryKeyFile tmpKeyFile, FilePath configDir) { this.build = build; this.launcher = launcher; this.listener = listener; this.accountId = accountId; this.tmpKeyFile = tmpKeyFile; + this.configDir = configDir; } boolean activate() throws IOException, InterruptedException { final String authCmd = "gcloud auth activate-service-account " + accountId + " --key-file " + tmpKeyFile.getKeyFile().getRemote(); int retCode = launcher.launch() - .pwd(build.getWorkspace()) + .pwd(build.getWorkspace()) .cmdAsSingleString(authCmd) - .stdout(listener.getLogger()) - .join(); + .stdout(listener.getLogger()) + .envs("CLOUDSDK_CONFIG=" + configDir.getRemote()) + .join(); if (retCode != 0) { return false; @@ -93,5 +97,6 @@ boolean revoke() throws IOException, InterruptedException { void cleanUp() throws IOException, InterruptedException { tmpKeyFile.remove(); + configDir.deleteRecursive(); } } \ No newline at end of file From 44a8bcaa88e5de4647f1cb5d39bdb5ff8e79279f Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 8 Jul 2015 15:46:00 +0200 Subject: [PATCH 03/34] decorate launcher to use the configured SDK installation --- .../plugins/gcloud/GCloudBuildWrapper.java | 43 ++++++++++++++++--- .../plugins/gcloudsdk/GCloudInstallation.java | 3 +- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java index a9a9d5c..cc20010 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java @@ -8,13 +8,18 @@ import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder; import com.google.jenkins.plugins.credentials.domains.RequiresDomain; import com.google.jenkins.plugins.credentials.oauth.GoogleRobotPrivateKeyCredentials; +import hudson.EnvVars; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; +import hudson.Launcher.DecoratedLauncher; +import hudson.Proc; +import hudson.Util; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.BuildListener; import hudson.model.Item; +import hudson.model.Run; import hudson.security.ACL; import hudson.tasks.BuildWrapper; import hudson.tasks.BuildWrapperDescriptor; @@ -26,6 +31,7 @@ import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; +import javax.annotation.CheckForNull; import java.io.IOException; import java.util.Map; import java.util.logging.Logger; @@ -43,10 +49,37 @@ public GCloudBuildWrapper(String installation, String credentialsId) { this.credentialsId = credentialsId; } - @Override - public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + + @Override + public Launcher decorateLauncher(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, Run.RunnerAbortedException { final ToolInstallation sdk = getSDK().translate(build, listener); + + return new Launcher.DecoratedLauncher(launcher) { + + @Override + public Proc launch(ProcStarter starter) throws IOException { + EnvVars vars = toEnvVars(starter.envs()); + if (sdk != null) { + sdk.buildEnvVars(vars); + } + return super.launch(starter.envs(Util.mapToEnv(vars))); + } + + private EnvVars toEnvVars(String[] envs) { + EnvVars vars = new EnvVars(); + for (String line : envs) { + vars.addLine(line); + } + return vars; + } + }; + + } + + @Override + public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + final FilePath configDir = build.getWorkspace().createTempDir("gcloud", "config"); final GCloudServiceAccount serviceAccount = @@ -72,17 +105,15 @@ public boolean tearDown(AbstractBuild build, final BuildListener listener) throw serviceAccount.cleanUp(); return true; } - }; } - public GCloudInstallation getSDK() { + public @CheckForNull GCloudInstallation getSDK() { GCloudInstallation[] installations = GCloudInstallation.getInstallations(); - if (installations.length == 1) return installations[0]; for (GCloudInstallation sdk : installations) { if (installation.equals(sdk.getName())) return sdk; } - throw new IllegalArgumentException("Invalid GCloud SDK installation "+installation); + return null; } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java index 50d5222..c24aaff 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java @@ -27,7 +27,8 @@ public GCloudInstallation(String name, String home, List Date: Fri, 10 Jul 2015 11:26:28 +0100 Subject: [PATCH 04/34] configuring pom for hosting in jenkins --- pom.xml | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index b599c88..da9d8b4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,42 +9,43 @@ 1.580.1 + com.byclosure.jenkins.plugins gcloud-sdk 1.0-SNAPSHOT hpi GCloud SDK Plugin - GCloud SDK Plugin allows the invocation of the gcloud CLI as a job step. - https://wiki.jenkins-ci.org/display/JENKINS/TODO+Plugin + GCloud SDK Plugin allows users to invoke gcloud tools with jenkins credentials. + https://wiki.jenkins-ci.org/display/JENKINS/GCloud+SDK+Plugin MIT License http://opensource.org/licenses/MIT - - + + + + scm:git:git://github.com/jenkinsci/gcloud-sdk-plugin.git + scm:git:git@github.com:jenkinsci/gcloud-sdk-plugin.git + https://github.com/jenkinsci/gcloud-sdk-plugin + + repo.jenkins-ci.org http://repo.jenkins-ci.org/public/ + repo.jenkins-ci.org From 12166bfdbe2a92e8207b022977d5e1e314968562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Lui=CC=81s?= Date: Fri, 10 Jul 2015 11:29:16 +0100 Subject: [PATCH 05/34] add license --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9123a6d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Byclosure + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From 01397ce218db243e91b60c35851a0fd3147cb30f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Lui=CC=81s?= Date: Fri, 10 Jul 2015 12:52:31 +0100 Subject: [PATCH 06/34] releasing version 0.0.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index da9d8b4..34ea0e2 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ com.byclosure.jenkins.plugins gcloud-sdk - 1.0-SNAPSHOT + 0.0.1 hpi GCloud SDK Plugin From 8556034e7a00174a4747eb35b25cee0dfd3de459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Lui=CC=81s?= Date: Fri, 10 Jul 2015 12:57:37 +0100 Subject: [PATCH 07/34] releasing version 0.0.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 34ea0e2..9e2efd7 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ com.byclosure.jenkins.plugins gcloud-sdk - 0.0.1 + 0.0.1-SNAPSHOT hpi GCloud SDK Plugin From ea4f1a67fbcfc1749d83ed5c868e2e50319a08bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Lui=CC=81s?= Date: Fri, 10 Jul 2015 13:07:20 +0100 Subject: [PATCH 08/34] [maven-release-plugin] prepare release 0.0.1 --- pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 9e2efd7..a42c7ac 100644 --- a/pom.xml +++ b/pom.xml @@ -1,18 +1,17 @@ - + 4.0.0 org.jenkins-ci.plugins plugin 1.580.1 - + com.byclosure.jenkins.plugins gcloud-sdk - 0.0.1-SNAPSHOT + 0.0.1 hpi GCloud SDK Plugin @@ -37,7 +36,8 @@ scm:git:git://github.com/jenkinsci/gcloud-sdk-plugin.git scm:git:git@github.com:jenkinsci/gcloud-sdk-plugin.git https://github.com/jenkinsci/gcloud-sdk-plugin - + 0.0.1 + From 4e11951134574cbf4b22a2724b94fc9dfc5d5c11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Lui=CC=81s?= Date: Fri, 10 Jul 2015 13:21:01 +0100 Subject: [PATCH 09/34] [maven-release-plugin] rollback the release of 0.0.1 --- pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index a42c7ac..9e2efd7 100644 --- a/pom.xml +++ b/pom.xml @@ -1,17 +1,18 @@ - + 4.0.0 org.jenkins-ci.plugins plugin 1.580.1 - + com.byclosure.jenkins.plugins gcloud-sdk - 0.0.1 + 0.0.1-SNAPSHOT hpi GCloud SDK Plugin @@ -36,8 +37,7 @@ scm:git:git://github.com/jenkinsci/gcloud-sdk-plugin.git scm:git:git@github.com:jenkinsci/gcloud-sdk-plugin.git https://github.com/jenkinsci/gcloud-sdk-plugin - 0.0.1 - + From 710d7145861620c938e694896954f9f3f9f35ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Lui=CC=81s?= Date: Fri, 10 Jul 2015 13:22:36 +0100 Subject: [PATCH 10/34] [maven-release-plugin] prepare release 0.0.1 --- pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 9e2efd7..a42c7ac 100644 --- a/pom.xml +++ b/pom.xml @@ -1,18 +1,17 @@ - + 4.0.0 org.jenkins-ci.plugins plugin 1.580.1 - + com.byclosure.jenkins.plugins gcloud-sdk - 0.0.1-SNAPSHOT + 0.0.1 hpi GCloud SDK Plugin @@ -37,7 +36,8 @@ scm:git:git://github.com/jenkinsci/gcloud-sdk-plugin.git scm:git:git@github.com:jenkinsci/gcloud-sdk-plugin.git https://github.com/jenkinsci/gcloud-sdk-plugin - + 0.0.1 + From 5d32a2dd1ccfa847e383d737c8aefc8e32798d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joa=CC=83o=20Lui=CC=81s?= Date: Fri, 10 Jul 2015 13:22:41 +0100 Subject: [PATCH 11/34] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a42c7ac..12277df 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ com.byclosure.jenkins.plugins gcloud-sdk - 0.0.1 + 0.0.2-SNAPSHOT hpi GCloud SDK Plugin @@ -36,7 +36,7 @@ scm:git:git://github.com/jenkinsci/gcloud-sdk-plugin.git scm:git:git@github.com:jenkinsci/gcloud-sdk-plugin.git https://github.com/jenkinsci/gcloud-sdk-plugin - 0.0.1 + HEAD From 7b0d1faef40d16a13642d03b1fdeed418583bc3a Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 15 Jul 2015 12:34:09 +0200 Subject: [PATCH 12/34] as we delete configDir no need to cleanup/revoke --- .../plugins/gcloud/GCloudBuildWrapper.java | 4 +-- .../gcloud/GCloudSDKWithAuthBuilder.java | 29 +++++++------------ .../plugins/gcloud/GCloudServiceAccount.java | 24 +-------------- .../plugins/gcloud/TemporaryKeyFile.java | 27 ++--------------- 4 files changed, 17 insertions(+), 67 deletions(-) diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java index cc20010..3a4f556 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java @@ -85,8 +85,8 @@ public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener l final GCloudServiceAccount serviceAccount = GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId, configDir); - if (!serviceAccount.activate()) { - serviceAccount.cleanUp(); + if (!serviceAccount.activate(sdk)) { + configDir.deleteRecursive(); throw new InterruptedException("Couldn't activate GCloudServiceAccount"); } diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java index 9645c84..35a1c1e 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java @@ -41,25 +41,18 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListener lis final FilePath configDir = build.getWorkspace().createTempDir("gcloud", "config"); final GCloudServiceAccount serviceAccount = GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId, configDir); - - if (!serviceAccount.activate()) { - serviceAccount.cleanUp(); - return false; - } - - if (!executeGCloudCLI(build, launcher, listener, configDir)) { - serviceAccount.revoke(); - serviceAccount.cleanUp(); - return false; - } - - if (!serviceAccount.revoke()) { - serviceAccount.cleanUp(); - return false; + try { + if (!serviceAccount.activate(null)) { + return false; + } + + if (!executeGCloudCLI(build, launcher, listener, configDir)) { + return false; + } + return true; + } finally { + configDir.deleteRecursive(); } - - serviceAccount.cleanUp(); - return true; } private boolean executeGCloudCLI(AbstractBuild build, Launcher launcher, BuildListener listener, FilePath configDir) throws IOException, InterruptedException { diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java index 7f64528..ac77870 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java @@ -36,8 +36,7 @@ public static GCloudServiceAccount getServiceAccount(AbstractBuild build, Launch final String accountId = serviceAccountConfig.getAccountId(); final File keyFile = getKeyFile(serviceAccountConfig); - TemporaryKeyFile tmpKeyFile = new TemporaryKeyFile(build, launcher, keyFile); - tmpKeyFile.copyToTmpDir(); + TemporaryKeyFile tmpKeyFile = new TemporaryKeyFile(configDir, keyFile); return new GCloudServiceAccount(build, launcher, listener, accountId, tmpKeyFile, configDir); } @@ -78,25 +77,4 @@ boolean activate() throws IOException, InterruptedException { } return true; } - - boolean revoke() throws IOException, InterruptedException { - final String revokeCmd = "gcloud auth revoke " + accountId; - - int retCode = launcher.launch() - .pwd(build.getWorkspace()) - .cmdAsSingleString(revokeCmd) - .stdout(listener.getLogger()) - .join(); - - if (retCode != 0) { - return false; - } - return true; - } - - - void cleanUp() throws IOException, InterruptedException { - tmpKeyFile.remove(); - configDir.deleteRecursive(); - } } \ No newline at end of file diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/TemporaryKeyFile.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/TemporaryKeyFile.java index d702d27..b038eb2 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/TemporaryKeyFile.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/TemporaryKeyFile.java @@ -8,35 +8,14 @@ import java.io.IOException; class TemporaryKeyFile { - private AbstractBuild build; - private Launcher launcher; - private File keyFile; - private FilePath tmpDir; private FilePath tmpKeyFile; - public TemporaryKeyFile(AbstractBuild build, Launcher launcher, File keyFile) { - this.build = build; - this.launcher = launcher; - this.keyFile = keyFile; - } - - public FilePath getDir() { - return tmpDir; + public TemporaryKeyFile(FilePath configDir, File keyFile) throws IOException, InterruptedException { + tmpKeyFile = configDir.createTempFile("gcloud", "key"); + tmpKeyFile.copyFrom(new FilePath(keyFile)); } public FilePath getKeyFile() { return tmpKeyFile; } - - public TemporaryKeyFile copyToTmpDir() throws IOException, InterruptedException { - tmpDir = build.getWorkspace().createTempDir("gcloud", null); - tmpKeyFile = new FilePath(launcher.getChannel(), - new File(tmpDir.getRemote(), keyFile.getName()).getPath()); - tmpKeyFile.copyFrom(new FilePath(keyFile)); - return this; - } - - void remove() throws IOException, InterruptedException { - tmpDir.deleteRecursive(); - } } From 6f11d53500b487de45b60e45e6f705b26cab485a Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 15 Jul 2015 12:34:33 +0200 Subject: [PATCH 13/34] simplify --- .../plugins/gcloud/GCloudSDKWithAuthBuilder.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java index 35a1c1e..975a39d 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java @@ -31,6 +31,11 @@ public GCloudSDKWithAuthBuilder(String credentialsId, String command) { this.command = command; } + public String getCredentialsId() { + return credentialsId; + } + + public String getCommand() { return command; } @@ -63,10 +68,7 @@ private boolean executeGCloudCLI(AbstractBuild build, Launcher launcher, BuildLi .envs("CLOUDSDK_CONFIG=" + configDir.getRemote()) .join(); - if (retCode != 0) { - return false; - } - return true; + return retCode == 0; } @Override @@ -74,10 +76,6 @@ public DescriptorImpl getDescriptor() { return (DescriptorImpl) super.getDescriptor(); } - public String getCredentialsId() { - return credentialsId; - } - @Extension public static final class DescriptorImpl extends BuildStepDescriptor { public DescriptorImpl() { From 97dcdb0c5112925b4424f8cda4beadc1441f1cb3 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 15 Jul 2015 12:35:57 +0200 Subject: [PATCH 14/34] activate to use the configured GCloudInstallation --- .../jenkins/plugins/gcloud/GCloudServiceAccount.java | 9 ++++++--- .../jenkins/plugins/gcloudsdk/GCloudInstallation.java | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java index ac77870..4e44068 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java @@ -62,11 +62,14 @@ private GCloudServiceAccount(AbstractBuild build, Launcher launcher, BuildListen this.configDir = configDir; } - boolean activate() throws IOException, InterruptedException { - final String authCmd = "gcloud auth activate-service-account " + accountId + " --key-file " + tmpKeyFile.getKeyFile().getRemote(); + boolean activate(GCloudInstallation sdk) throws IOException, InterruptedException { + String exec = "gcloud"; + if (sdk != null) { + exec = sdk.getExecutable(); + } + final String authCmd = exec + " auth activate-service-account " + accountId + " --key-file " + tmpKeyFile.getKeyFile().getRemote(); int retCode = launcher.launch() - .pwd(build.getWorkspace()) .cmdAsSingleString(authCmd) .stdout(listener.getLogger()) .envs("CLOUDSDK_CONFIG=" + configDir.getRemote()) diff --git a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java index c24aaff..ae2b9eb 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java @@ -44,6 +44,10 @@ public static GCloudInstallation[] getInstallations() { return Jenkins.getInstance().getDescriptorByType(DescriptorImpl.class).getInstallations(); } + public String getExecutable() { + return getHome()+"/bin/gcloud"; + } + @Extension public static class DescriptorImpl extends ToolDescriptor { From e55fbb3f08c10038c2eea37fa41c15b6d979f963 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 15 Jul 2015 12:36:43 +0200 Subject: [PATCH 15/34] bug --- .../byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java index 4e44068..6c6229c 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java @@ -46,7 +46,7 @@ private static File getKeyFile(ServiceAccountConfig serviceAccount) { if (serviceAccount instanceof JsonServiceAccountConfig) { keyFilePath = ((JsonServiceAccountConfig)serviceAccount).getJsonKeyFile(); - } else if (serviceAccount instanceof JsonServiceAccountConfig) { + } else if (serviceAccount instanceof P12ServiceAccountConfig) { keyFilePath = ((P12ServiceAccountConfig)serviceAccount).getP12KeyFile(); } From 9350abf72591959043e407b4ca69f1c49b1f466c Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 15 Jul 2015 12:37:05 +0200 Subject: [PATCH 16/34] use SimpleBuildWrapper for workflow compliance --- pom.xml | 2 +- .../plugins/gcloud/GCloudBuildWrapper.java | 83 ++++++++----------- .../plugins/gcloud/GCloudServiceAccount.java | 15 ++-- .../plugins/gcloudsdk/GCloudInstallation.java | 5 ++ 4 files changed, 47 insertions(+), 58 deletions(-) diff --git a/pom.xml b/pom.xml index 12277df..b4d33e7 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 1.580.1 + 1.609 diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java index 3a4f556..1059797 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java @@ -18,13 +18,16 @@ import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.BuildListener; +import hudson.model.Computer; import hudson.model.Item; import hudson.model.Run; +import hudson.model.TaskListener; import hudson.security.ACL; import hudson.tasks.BuildWrapper; import hudson.tasks.BuildWrapperDescriptor; import hudson.tools.ToolInstallation; import hudson.util.ListBoxModel; +import jenkins.tasks.SimpleBuildWrapper; import net.sf.json.JSONObject; import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; @@ -33,11 +36,12 @@ import javax.annotation.CheckForNull; import java.io.IOException; +import java.io.Serializable; import java.util.Map; import java.util.logging.Logger; @RequiresDomain(value = GCloudScopeRequirement.class) -public class GCloudBuildWrapper extends BuildWrapper { +public class GCloudBuildWrapper extends SimpleBuildWrapper { private static final Logger LOGGER = Logger.getLogger(GCloudBuildWrapper.class.getName()); private final String installation; @@ -49,38 +53,12 @@ public GCloudBuildWrapper(String installation, String credentialsId) { this.credentialsId = credentialsId; } - - @Override - public Launcher decorateLauncher(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, Run.RunnerAbortedException { - - final ToolInstallation sdk = getSDK().translate(build, listener); - - return new Launcher.DecoratedLauncher(launcher) { - - @Override - public Proc launch(ProcStarter starter) throws IOException { - EnvVars vars = toEnvVars(starter.envs()); - if (sdk != null) { - sdk.buildEnvVars(vars); - } - return super.launch(starter.envs(Util.mapToEnv(vars))); - } - - private EnvVars toEnvVars(String[] envs) { - EnvVars vars = new EnvVars(); - for (String line : envs) { - vars.addLine(line); - } - return vars; - } - }; - - } - @Override - public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + public void setUp(Context context, Run build, FilePath workspace, Launcher launcher, TaskListener listener, EnvVars initialEnvironment) throws IOException, InterruptedException { - final FilePath configDir = build.getWorkspace().createTempDir("gcloud", "config"); + GCloudInstallation sdk = getSDK(); + sdk = sdk.translate(workspace.toComputer().getNode(), initialEnvironment, listener); + final FilePath configDir = workspace.createTempDir("gcloud", "config"); final GCloudServiceAccount serviceAccount = GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId, configDir); @@ -90,22 +68,13 @@ public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener l throw new InterruptedException("Couldn't activate GCloudServiceAccount"); } - return new Environment() { - @Override - public void buildEnvVars(Map env) { - } - - @Override - public boolean tearDown(AbstractBuild build, final BuildListener listener) throws IOException, InterruptedException { - if (!serviceAccount.revoke()) { - serviceAccount.cleanUp(); - return false; - } - - serviceAccount.cleanUp(); - return true; - } - }; + sdk.buildEnvVars(initialEnvironment); + for (Map.Entry entry : initialEnvironment.entrySet()) { + context.env(entry.getKey(), entry.getValue()); + } + context.env("CLOUDSDK_CONFIG", configDir.getRemote()); + + context.setDisposer(new GCloudConfigDisposer(configDir)); } public @CheckForNull GCloudInstallation getSDK() { @@ -116,8 +85,6 @@ public boolean tearDown(AbstractBuild build, final BuildListener listener) throw return null; } - - public String getInstallation() { return installation; } @@ -134,7 +101,7 @@ public DescriptorImpl() { @Override public String getDisplayName() { - return "GCloud authentication"; + return "GCloud SDK authentication"; } @Override @@ -165,4 +132,20 @@ public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item project, public static final CredentialsMatcher MATCHER = CredentialsMatchers.anyOf(CredentialsMatchers.instanceOf(GoogleRobotPrivateKeyCredentials.class)); } + + private static class GCloudConfigDisposer extends Disposer { + + private static final long serialVersionUID = 5723296082223871496L; + + private final FilePath configDir; + + public GCloudConfigDisposer(FilePath configDir) { + this.configDir = configDir; + } + + @Override + public void tearDown(Run build, FilePath workspace, Launcher launcher, TaskListener listener) throws IOException, InterruptedException { + configDir.deleteRecursive(); + } + } } diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java index 6c6229c..6984ce7 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java @@ -1,5 +1,6 @@ package com.byclosure.jenkins.plugins.gcloud; +import com.cloudbees.jenkins.plugins.gcloudsdk.GCloudInstallation; import com.cloudbees.plugins.credentials.CredentialsProvider; import com.google.jenkins.plugins.credentials.oauth.GoogleRobotPrivateKeyCredentials; import com.google.jenkins.plugins.credentials.oauth.JsonServiceAccountConfig; @@ -9,21 +10,22 @@ import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.BuildListener; +import hudson.model.Run; +import hudson.model.TaskListener; import java.io.File; import java.io.IOException; public class GCloudServiceAccount { - private final AbstractBuild build; private final Launcher launcher; - private final BuildListener listener; + private final TaskListener listener; private final String accountId; private final TemporaryKeyFile tmpKeyFile; private final FilePath configDir; - public static GCloudServiceAccount getServiceAccount(AbstractBuild build, Launcher launcher, - BuildListener listener, String credentialsId, FilePath configDir) throws IOException, InterruptedException { + public static GCloudServiceAccount getServiceAccount(Run build, Launcher launcher, + TaskListener listener, String credentialsId, FilePath configDir) throws IOException, InterruptedException { final GoogleRobotPrivateKeyCredentials credential = CredentialsProvider.findCredentialById( credentialsId, GoogleRobotPrivateKeyCredentials.class, @@ -38,7 +40,7 @@ public static GCloudServiceAccount getServiceAccount(AbstractBuild build, Launch TemporaryKeyFile tmpKeyFile = new TemporaryKeyFile(configDir, keyFile); - return new GCloudServiceAccount(build, launcher, listener, accountId, tmpKeyFile, configDir); + return new GCloudServiceAccount(launcher, listener, accountId, tmpKeyFile, configDir); } private static File getKeyFile(ServiceAccountConfig serviceAccount) { @@ -53,8 +55,7 @@ private static File getKeyFile(ServiceAccountConfig serviceAccount) { return new File(keyFilePath); } - private GCloudServiceAccount(AbstractBuild build, Launcher launcher, BuildListener listener, String accountId, TemporaryKeyFile tmpKeyFile, FilePath configDir) { - this.build = build; + private GCloudServiceAccount(Launcher launcher, TaskListener listener, String accountId, TemporaryKeyFile tmpKeyFile, FilePath configDir) { this.launcher = launcher; this.listener = listener; this.accountId = accountId; diff --git a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java index ae2b9eb..1faae81 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java @@ -32,6 +32,11 @@ public void buildEnvVars(EnvVars env) { } + @Override + public GCloudInstallation translate(Node node, EnvVars envs, TaskListener listener) throws IOException, InterruptedException { + return (GCloudInstallation) super.translate(node, envs, listener); + } + public GCloudInstallation forNode(Node node, TaskListener log) throws IOException, InterruptedException { return new GCloudInstallation(getName(), translateFor(node, log), getProperties().toList()); } From ee580256ee551c1aa7b0df7460b52d4ef2cf120f Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 15 Jul 2015 14:57:59 +0200 Subject: [PATCH 17/34] option to install additional components --- .../plugins/gcloudsdk/GCloudInstaller.java | 22 ++++++++++++++++--- .../gcloudsdk/GCloudInstaller/config.jelly | 7 ++++++ 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller/config.jelly diff --git a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java index 9de51c2..2b81659 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java @@ -7,6 +7,8 @@ import hudson.model.TaskListener; import hudson.tools.DownloadFromUrlInstaller; import hudson.tools.ToolInstallation; +import hudson.util.ArgumentListBuilder; +import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.DataBoundConstructor; import java.io.IOException; @@ -18,9 +20,17 @@ */ public class GCloudInstaller extends DownloadFromUrlInstaller { + + private String additionalComponents; + @DataBoundConstructor - public GCloudInstaller(String id) { + public GCloudInstaller(String id, String additionalComponents) { super(id); + this.additionalComponents = additionalComponents; + } + + public String getAdditionalComponents() { + return additionalComponents; } @Override @@ -28,10 +38,16 @@ public FilePath performInstallation(ToolInstallation tool, Node node, TaskListen FilePath installation = super.performInstallation(tool, node, log); Launcher launcher = node.createLauncher(log); + + ArgumentListBuilder args = new ArgumentListBuilder(); + args.add(installation.child(launcher.isUnix() ? "install.sh" : "install.bat").getRemote()) + .add("--usage-reporting=false", "--path-update=false", "--bash-completion=false"); + if (StringUtils.isNotBlank(additionalComponents)) + args.add("--additional-components", additionalComponents); + launcher.launch() .stdout(log) - .cmds( installation.child(launcher.isUnix() ? "install.sh" : "install.bat").getRemote(), - "--usage-reporting=false", "--path-update=false", "--bash-completion=false") + .cmds(args.toCommandArray()) .join(); return installation; diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller/config.jelly b/src/main/resources/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller/config.jelly new file mode 100644 index 0000000..5c4c52a --- /dev/null +++ b/src/main/resources/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller/config.jelly @@ -0,0 +1,7 @@ + + + + + + + From 711f39945a166da8bb5a69589037e8394b0a0e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Camilo?= Date: Mon, 27 Feb 2017 16:40:49 +0000 Subject: [PATCH 18/34] new version of google credentials and fix gcloud path --- pom.xml | 2 +- .../plugins/gcloud/GCloudBuildWrapper.java | 1 + .../plugins/gcloud/GCloudSDKBuilder.java | 9 +++- .../plugins/gcloud/GCloudServiceAccount.java | 46 +++++++++++-------- .../plugins/gcloud/TemporaryKeyFile.java | 12 +++-- .../plugins/gcloudsdk/GCloudInstallation.java | 1 + 6 files changed, 45 insertions(+), 26 deletions(-) diff --git a/pom.xml b/pom.xml index b4d33e7..d5c1015 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ org.jenkins-ci.plugins google-oauth-plugin - 0.3 + 0.4 diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java index 1059797..c7a7e34 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java @@ -73,6 +73,7 @@ public void setUp(Context context, Run build, FilePath workspace, Launcher context.env(entry.getKey(), entry.getValue()); } context.env("CLOUDSDK_CONFIG", configDir.getRemote()); + context.env("GOOGLE_APPLICATION_CREDENTIALS", serviceAccount.getKeyFile().getRemote()); context.setDisposer(new GCloudConfigDisposer(configDir)); } diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKBuilder.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKBuilder.java index 7522330..d6215db 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKBuilder.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKBuilder.java @@ -2,6 +2,7 @@ import com.google.jenkins.plugins.credentials.domains.RequiresDomain; +import hudson.EnvVars; import hudson.Extension; import hudson.Launcher; import hudson.model.AbstractBuild; @@ -17,9 +18,11 @@ import javax.servlet.ServletException; import java.io.IOException; +import java.util.logging.Logger; @RequiresDomain(value = GCloudScopeRequirement.class) public class GCloudSDKBuilder extends Builder { + private static final Logger LOGGER = Logger.getLogger(GCloudSDKBuilder.class.getName()); private final String command; @@ -42,9 +45,13 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListener lis } private boolean executeGCloudCLI(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + EnvVars env = build.getEnvironment(listener); + String binariesPath = env.get("CLOUDSDK_DIR")+"/bin/"; + int retCode = launcher.launch() .pwd(build.getWorkspace()) - .cmdAsSingleString("gcloud " + command) + .cmdAsSingleString(binariesPath + "gcloud " + command) + .envs(env) .stdout(listener.getLogger()) .join(); diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java index 6984ce7..49ca3df 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java @@ -2,22 +2,19 @@ import com.cloudbees.jenkins.plugins.gcloudsdk.GCloudInstallation; import com.cloudbees.plugins.credentials.CredentialsProvider; -import com.google.jenkins.plugins.credentials.oauth.GoogleRobotPrivateKeyCredentials; -import com.google.jenkins.plugins.credentials.oauth.JsonServiceAccountConfig; -import com.google.jenkins.plugins.credentials.oauth.P12ServiceAccountConfig; -import com.google.jenkins.plugins.credentials.oauth.ServiceAccountConfig; +import com.google.api.client.json.jackson.JacksonFactory; +import com.google.jenkins.plugins.credentials.oauth.*; import hudson.FilePath; import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; import hudson.model.Run; import hudson.model.TaskListener; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.util.logging.Logger; public class GCloudServiceAccount { - private final Launcher launcher; private final TaskListener listener; private final String accountId; @@ -36,23 +33,30 @@ public static GCloudServiceAccount getServiceAccount(Run build, Launcher launche final ServiceAccountConfig serviceAccountConfig = credential.getServiceAccountConfig(); final String accountId = serviceAccountConfig.getAccountId(); - final File keyFile = getKeyFile(serviceAccountConfig); - - TemporaryKeyFile tmpKeyFile = new TemporaryKeyFile(configDir, keyFile); + final TemporaryKeyFile tmpKeyFile = getKeyFile(serviceAccountConfig, configDir); return new GCloudServiceAccount(launcher, listener, accountId, tmpKeyFile, configDir); } - private static File getKeyFile(ServiceAccountConfig serviceAccount) { - String keyFilePath = null; - - if (serviceAccount instanceof JsonServiceAccountConfig) { - keyFilePath = ((JsonServiceAccountConfig)serviceAccount).getJsonKeyFile(); - } else if (serviceAccount instanceof P12ServiceAccountConfig) { - keyFilePath = ((P12ServiceAccountConfig)serviceAccount).getP12KeyFile(); + private static TemporaryKeyFile getKeyFile(ServiceAccountConfig serviceAccount, FilePath configDir) { + TemporaryKeyFile tmpKeyFile = null; + + try { + if (serviceAccount instanceof JsonServiceAccountConfig) { + String keyFilePath = ((JsonServiceAccountConfig)serviceAccount).getJsonKeyFile(); + JsonKey key = JsonKey.load(new JacksonFactory(), new FileInputStream(new File(keyFilePath))); + tmpKeyFile = new TemporaryKeyFile(configDir, key.toPrettyString()); + } else if (serviceAccount instanceof P12ServiceAccountConfig) { + String keyFilePath = ((P12ServiceAccountConfig)serviceAccount).getP12KeyFile(); + tmpKeyFile = new TemporaryKeyFile(configDir, keyFilePath); + } + } catch (IOException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); } - return new File(keyFilePath); + return tmpKeyFile; } private GCloudServiceAccount(Launcher launcher, TaskListener listener, String accountId, TemporaryKeyFile tmpKeyFile, FilePath configDir) { @@ -68,7 +72,7 @@ boolean activate(GCloudInstallation sdk) throws IOException, InterruptedExceptio if (sdk != null) { exec = sdk.getExecutable(); } - final String authCmd = exec + " auth activate-service-account " + accountId + " --key-file " + tmpKeyFile.getKeyFile().getRemote(); + final String authCmd = exec + " auth activate-service-account " + accountId + " --key-file \"" + tmpKeyFile.getKeyFile().getRemote() + "\""; int retCode = launcher.launch() .cmdAsSingleString(authCmd) @@ -81,4 +85,8 @@ boolean activate(GCloudInstallation sdk) throws IOException, InterruptedExceptio } return true; } + + FilePath getKeyFile(){ + return tmpKeyFile.getKeyFile(); + } } \ No newline at end of file diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/TemporaryKeyFile.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/TemporaryKeyFile.java index b038eb2..511395e 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/TemporaryKeyFile.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/TemporaryKeyFile.java @@ -1,18 +1,20 @@ package com.byclosure.jenkins.plugins.gcloud; import hudson.FilePath; -import hudson.Launcher; -import hudson.model.AbstractBuild; -import java.io.File; import java.io.IOException; class TemporaryKeyFile { private FilePath tmpKeyFile; - public TemporaryKeyFile(FilePath configDir, File keyFile) throws IOException, InterruptedException { + public TemporaryKeyFile(FilePath configDir, String content) throws IOException, InterruptedException { tmpKeyFile = configDir.createTempFile("gcloud", "key"); - tmpKeyFile.copyFrom(new FilePath(keyFile)); + tmpKeyFile.write(content, "UTF-8"); + } + + public TemporaryKeyFile(FilePath configDir, FilePath file) throws IOException, InterruptedException { + tmpKeyFile = configDir.createTempFile("gcloud", "key"); + tmpKeyFile.copyFrom(file); } public FilePath getKeyFile() { diff --git a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java index 1faae81..d8afe22 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java @@ -28,6 +28,7 @@ public GCloudInstallation(String name, String home, List Date: Tue, 24 Oct 2017 11:35:28 -0700 Subject: [PATCH 19/34] Restrict GCloudInstaller to GCloudInstallation types --- .../cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java index 2b81659..491a701 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java @@ -68,6 +68,11 @@ public String getDisplayName() { public List getInstallables() throws IOException { return Collections.singletonList(SDK); } + + @Override + public boolean isApplicable(Class toolType) { + return GCloudInstallation.class.isAssignableFrom(toolType); + } } From bb04e5e6ddf87114d89e8457ae81d0c663f2f9a6 Mon Sep 17 00:00:00 2001 From: Tad Fisher Date: Tue, 24 Oct 2017 16:06:05 -0700 Subject: [PATCH 20/34] Add symbol definition to GCloudInstallation Allows for using in declarative pipeline "tools" block. --- pom.xml | 5 +++++ .../jenkins/plugins/gcloudsdk/GCloudInstallation.java | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d5c1015..9d5ef97 100644 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,11 @@ google-oauth-plugin 0.4 + + org.jenkins-ci.plugins + structs + 1.2 + diff --git a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java index d8afe22..e69bf5c 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java @@ -10,6 +10,7 @@ import hudson.tools.ToolInstallation; import hudson.tools.ToolProperty; import jenkins.model.Jenkins; +import org.jenkinsci.Symbol; import org.kohsuke.stapler.DataBoundConstructor; import java.io.IOException; @@ -54,7 +55,7 @@ public String getExecutable() { return getHome()+"/bin/gcloud"; } - @Extension + @Extension @Symbol("gcloud") public static class DescriptorImpl extends ToolDescriptor { @Override From 06427a629c5408920a52060df736cae0f270a41a Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Tue, 8 Oct 2019 18:24:55 +0200 Subject: [PATCH 21/34] Use HTTPS URLs in pom.xml --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9d5ef97..18afc39 100644 --- a/pom.xml +++ b/pom.xml @@ -42,14 +42,14 @@ repo.jenkins-ci.org - http://repo.jenkins-ci.org/public/ + https://repo.jenkins-ci.org/public/ repo.jenkins-ci.org - http://repo.jenkins-ci.org/public/ + https://repo.jenkins-ci.org/public/ From 2eed88bbd596d4ada803114c6b5af29e1c217647 Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Wed, 11 Jul 2018 19:32:55 -0700 Subject: [PATCH 22/34] Remove unused imports --- .../jenkins/plugins/gcloud/GCloudBuildWrapper.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java index c7a7e34..27df200 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java @@ -12,20 +12,12 @@ import hudson.Extension; import hudson.FilePath; import hudson.Launcher; -import hudson.Launcher.DecoratedLauncher; -import hudson.Proc; -import hudson.Util; -import hudson.model.AbstractBuild; import hudson.model.AbstractProject; -import hudson.model.BuildListener; -import hudson.model.Computer; import hudson.model.Item; import hudson.model.Run; import hudson.model.TaskListener; import hudson.security.ACL; -import hudson.tasks.BuildWrapper; import hudson.tasks.BuildWrapperDescriptor; -import hudson.tools.ToolInstallation; import hudson.util.ListBoxModel; import jenkins.tasks.SimpleBuildWrapper; import net.sf.json.JSONObject; @@ -36,7 +28,6 @@ import javax.annotation.CheckForNull; import java.io.IOException; -import java.io.Serializable; import java.util.Map; import java.util.logging.Logger; From ae83b79b4607df715390dee53c3ca25b62d50d57 Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Wed, 11 Jul 2018 19:10:09 -0700 Subject: [PATCH 23/34] Support selecting the "(Default)" installation getSDK() was previously changed to scan all installations to find the one that matches the selected installation. But when "(Default)" is selected, `installation` is an empty string, and none of the installed installations will match that. So when (Default) was selected, just look for the first available installation. --- .../byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java index 27df200..5193e99 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java @@ -71,6 +71,11 @@ public void setUp(Context context, Run build, FilePath workspace, Launcher public @CheckForNull GCloudInstallation getSDK() { GCloudInstallation[] installations = GCloudInstallation.getInstallations(); + + if (installation.isEmpty() && installations.length > 0) { + return installations[0]; + } + for (GCloudInstallation sdk : installations) { if (installation.equals(sdk.getName())) return sdk; } From d9c3ddd5b31fa4305598fe6508e3a0ba97005268 Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Wed, 11 Jul 2018 19:30:09 -0700 Subject: [PATCH 24/34] Give better feedback when the SDK could not be selected --- .../byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java index 5193e99..f2ef76a 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java @@ -48,6 +48,11 @@ public GCloudBuildWrapper(String installation, String credentialsId) { public void setUp(Context context, Run build, FilePath workspace, Launcher launcher, TaskListener listener, EnvVars initialEnvironment) throws IOException, InterruptedException { GCloudInstallation sdk = getSDK(); + + if (sdk == null) { + throw new RuntimeException("Could not find a matching Google Cloud SDK installation: " + installation); + } + sdk = sdk.translate(workspace.toComputer().getNode(), initialEnvironment, listener); final FilePath configDir = workspace.createTempDir("gcloud", "config"); From dbb60d7d6ebb09ff22334f08c654abe84101df0c Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Wed, 11 Jul 2018 19:43:57 -0700 Subject: [PATCH 25/34] Allow a blank GCloud service account to be selected. The default credential selection ("-none-") implies that there should be no authentication performed. Normally this would be unusual because most gcloud commands will require auth (but not all!). Since there is also the option to execute a gcloud command with auth, that also gives another chance to select a different service account. And if the gcloud command does require auth, it will fail with: ERROR: (gcloud.the.command.that.ran) You do not currently have an active account selected. which should be sufficient to indicate that they need to select credentials. --- .../plugins/gcloud/GCloudBuildWrapper.java | 21 ++++++++++++------- .../plugins/gcloud/GCloudServiceAccount.java | 4 ++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java index f2ef76a..df1c0a2 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java @@ -56,20 +56,25 @@ public void setUp(Context context, Run build, FilePath workspace, Launcher sdk = sdk.translate(workspace.toComputer().getNode(), initialEnvironment, listener); final FilePath configDir = workspace.createTempDir("gcloud", "config"); - final GCloudServiceAccount serviceAccount = - GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId, configDir); + final GCloudServiceAccount serviceAccount = + GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId, configDir); - if (!serviceAccount.activate(sdk)) { - configDir.deleteRecursive(); - throw new InterruptedException("Couldn't activate GCloudServiceAccount"); - } + if (serviceAccount != null) { + if (!serviceAccount.activate(sdk)) { + configDir.deleteRecursive(); + throw new InterruptedException("Couldn't activate GCloudServiceAccount"); + } + + context.env("GOOGLE_APPLICATION_CREDENTIALS", serviceAccount.getKeyFile().getRemote()); + } + + context.env("CLOUDSDK_CONFIG", configDir.getRemote()); sdk.buildEnvVars(initialEnvironment); for (Map.Entry entry : initialEnvironment.entrySet()) { context.env(entry.getKey(), entry.getValue()); } - context.env("CLOUDSDK_CONFIG", configDir.getRemote()); - context.env("GOOGLE_APPLICATION_CREDENTIALS", serviceAccount.getKeyFile().getRemote()); + context.setDisposer(new GCloudConfigDisposer(configDir)); } diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java index 49ca3df..8549fce 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java @@ -30,6 +30,10 @@ public static GCloudServiceAccount getServiceAccount(Run build, Launcher launche new GCloudScopeRequirement() ); + if (credential == null) { + return null; + } + final ServiceAccountConfig serviceAccountConfig = credential.getServiceAccountConfig(); final String accountId = serviceAccountConfig.getAccountId(); From 3a32e094ad890258ad206ba1da5eee5f11ff22a4 Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Tue, 18 Jun 2019 16:54:21 -0400 Subject: [PATCH 26/34] Use google-oauth-plugin v0.8 As of v0.8, the key is no longer exposed as a JSON file, but instead it only exposes the accountId and privateKey. In order to use the key with the gcloud SDK, we need to be able to pass the path to a JSON file. --- pom.xml | 14 +++++++++++++- .../plugins/gcloud/GCloudServiceAccount.java | 11 ++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 18afc39..65a4ea1 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,12 @@ 0.0.2-SNAPSHOT hpi + + 2.60.3 + 8 + none + + GCloud SDK Plugin GCloud SDK Plugin allows users to invoke gcloud tools with jenkins credentials. https://wiki.jenkins-ci.org/display/JENKINS/GCloud+SDK+Plugin @@ -54,10 +60,16 @@ + + org.kohsuke + access-modifier-suppressions + 1.16 + compile + org.jenkins-ci.plugins google-oauth-plugin - 0.4 + 0.8 org.jenkins-ci.plugins diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java index 8549fce..b50f4e9 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java @@ -2,17 +2,17 @@ import com.cloudbees.jenkins.plugins.gcloudsdk.GCloudInstallation; import com.cloudbees.plugins.credentials.CredentialsProvider; +import com.cloudbees.plugins.credentials.SecretBytes; import com.google.api.client.json.jackson.JacksonFactory; import com.google.jenkins.plugins.credentials.oauth.*; import hudson.FilePath; import hudson.Launcher; import hudson.model.Run; import hudson.model.TaskListener; +import org.kohsuke.accmod.restrictions.suppressions.SuppressRestrictedWarnings; -import java.io.File; -import java.io.FileInputStream; +import java.io.ByteArrayInputStream; import java.io.IOException; -import java.util.logging.Logger; public class GCloudServiceAccount { private final Launcher launcher; @@ -42,13 +42,14 @@ public static GCloudServiceAccount getServiceAccount(Run build, Launcher launche return new GCloudServiceAccount(launcher, listener, accountId, tmpKeyFile, configDir); } + @SuppressRestrictedWarnings(JsonServiceAccountConfig.class) private static TemporaryKeyFile getKeyFile(ServiceAccountConfig serviceAccount, FilePath configDir) { TemporaryKeyFile tmpKeyFile = null; try { if (serviceAccount instanceof JsonServiceAccountConfig) { - String keyFilePath = ((JsonServiceAccountConfig)serviceAccount).getJsonKeyFile(); - JsonKey key = JsonKey.load(new JacksonFactory(), new FileInputStream(new File(keyFilePath))); + SecretBytes secretKey = ((JsonServiceAccountConfig) serviceAccount).getSecretJsonKey(); + JsonKey key = JsonKey.load(new JacksonFactory(), new ByteArrayInputStream(secretKey.getPlainData())); tmpKeyFile = new TemporaryKeyFile(configDir, key.toPrettyString()); } else if (serviceAccount instanceof P12ServiceAccountConfig) { String keyFilePath = ((P12ServiceAccountConfig)serviceAccount).getP12KeyFile(); From e9e197f8cedbb989219d344ec0ecbcb3501279bb Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Fri, 10 Jan 2020 16:24:56 -0500 Subject: [PATCH 27/34] Add Jenkinsfile for ci.jenkins.io --- Jenkinsfile | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..0cbabc2 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,2 @@ +// Build on ci.jenkins.io; see https://github.com/jenkins-infra/pipeline-library +buildPlugin() From 2cf8951e7d7e7005049117ff231931e65ad02a0f Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Fri, 10 Jan 2020 17:05:42 -0500 Subject: [PATCH 28/34] Update parent POM version to 2.7 See: https://jenkins.io/doc/developer/plugin-development/updating-parent/ --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 65a4ea1..39007c7 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 1.609 + 2.7 @@ -74,7 +74,7 @@ org.jenkins-ci.plugins structs - 1.2 + 1.7 From fc78346af0d76b513064529d80487a94585466c4 Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Fri, 10 Jan 2020 17:27:09 -0500 Subject: [PATCH 29/34] Fix findbugs errors --- .../jenkins/plugins/gcloud/GCloudBuildWrapper.java | 9 ++++++++- .../jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java | 9 ++++++++- .../jenkins/plugins/gcloud/GCloudServiceAccount.java | 9 +++++++-- .../jenkins/plugins/gcloudsdk/GCloudInstallation.java | 2 ++ .../jenkins/plugins/gcloudsdk/GCloudInstaller.java | 2 +- 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java index df1c0a2..7ffc866 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudBuildWrapper.java @@ -13,7 +13,9 @@ import hudson.FilePath; import hudson.Launcher; import hudson.model.AbstractProject; +import hudson.model.Computer; import hudson.model.Item; +import hudson.model.Node; import hudson.model.Run; import hudson.model.TaskListener; import hudson.security.ACL; @@ -53,7 +55,12 @@ public void setUp(Context context, Run build, FilePath workspace, Launcher throw new RuntimeException("Could not find a matching Google Cloud SDK installation: " + installation); } - sdk = sdk.translate(workspace.toComputer().getNode(), initialEnvironment, listener); + Computer computer = workspace.toComputer(); + if (computer == null) throw new RuntimeException("Unable to get workspace node."); + Node node = computer.getNode(); + if (node == null) throw new RuntimeException("Unable to get workspace node."); + + sdk = sdk.translate(node, initialEnvironment, listener); final FilePath configDir = workspace.createTempDir("gcloud", "config"); final GCloudServiceAccount serviceAccount = diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java index 975a39d..4e5122c 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudSDKWithAuthBuilder.java @@ -42,11 +42,18 @@ public String getCommand() { @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + final FilePath ws = build.getWorkspace(); + if (ws == null) throw new RuntimeException("Unable to get build workspace."); - final FilePath configDir = build.getWorkspace().createTempDir("gcloud", "config"); + final FilePath configDir = ws.createTempDir("gcloud", "config"); final GCloudServiceAccount serviceAccount = GCloudServiceAccount.getServiceAccount(build, launcher, listener, credentialsId, configDir); + try { + if (serviceAccount == null) { + return false; + } + if (!serviceAccount.activate(null)) { return false; } diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java index b50f4e9..c7da74c 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java @@ -11,6 +11,7 @@ import hudson.model.TaskListener; import org.kohsuke.accmod.restrictions.suppressions.SuppressRestrictedWarnings; +import javax.annotation.Nullable; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -43,14 +44,18 @@ public static GCloudServiceAccount getServiceAccount(Run build, Launcher launche } @SuppressRestrictedWarnings(JsonServiceAccountConfig.class) + @Nullable private static TemporaryKeyFile getKeyFile(ServiceAccountConfig serviceAccount, FilePath configDir) { TemporaryKeyFile tmpKeyFile = null; try { if (serviceAccount instanceof JsonServiceAccountConfig) { SecretBytes secretKey = ((JsonServiceAccountConfig) serviceAccount).getSecretJsonKey(); - JsonKey key = JsonKey.load(new JacksonFactory(), new ByteArrayInputStream(secretKey.getPlainData())); - tmpKeyFile = new TemporaryKeyFile(configDir, key.toPrettyString()); + + if (secretKey != null) { + JsonKey key = JsonKey.load(new JacksonFactory(), new ByteArrayInputStream(secretKey.getPlainData())); + tmpKeyFile = new TemporaryKeyFile(configDir, key.toPrettyString()); + } } else if (serviceAccount instanceof P12ServiceAccountConfig) { String keyFilePath = ((P12ServiceAccountConfig)serviceAccount).getP12KeyFile(); tmpKeyFile = new TemporaryKeyFile(configDir, keyFilePath); diff --git a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java index e69bf5c..1b9151b 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstallation.java @@ -39,10 +39,12 @@ public GCloudInstallation translate(Node node, EnvVars envs, TaskListener listen return (GCloudInstallation) super.translate(node, envs, listener); } + @Override public GCloudInstallation forNode(Node node, TaskListener log) throws IOException, InterruptedException { return new GCloudInstallation(getName(), translateFor(node, log), getProperties().toList()); } + @Override public GCloudInstallation forEnvironment(EnvVars environment) { return new GCloudInstallation(getName(), environment.expand(getHome()), getProperties().toList()); } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java index 491a701..70b610d 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/gcloudsdk/GCloudInstaller.java @@ -76,7 +76,7 @@ public boolean isApplicable(Class toolType) { } - public static Installable SDK = new Installable() { + public static final Installable SDK = new Installable() { { id = "google-cloud-sdk"; url = "https://dl.google.com/dl/cloudsdk/release/google-cloud-sdk.zip"; From 43bbb1b90c5a685f27b08bb12e37623f70a540d0 Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Fri, 10 Jan 2020 17:49:54 -0500 Subject: [PATCH 30/34] [maven-release-plugin] prepare release gcloud-sdk-0.0.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 39007c7..2c730f0 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ com.byclosure.jenkins.plugins gcloud-sdk - 0.0.2-SNAPSHOT + 0.0.2 hpi @@ -42,7 +42,7 @@ scm:git:git://github.com/jenkinsci/gcloud-sdk-plugin.git scm:git:git@github.com:jenkinsci/gcloud-sdk-plugin.git https://github.com/jenkinsci/gcloud-sdk-plugin - HEAD + gcloud-sdk-0.0.2 From 50dbebe3fe3a0608194bcd5421d26ec822d75b2f Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Fri, 10 Jan 2020 17:50:00 -0500 Subject: [PATCH 31/34] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2c730f0..04c8af5 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ com.byclosure.jenkins.plugins gcloud-sdk - 0.0.2 + 0.0.3-SNAPSHOT hpi @@ -42,7 +42,7 @@ scm:git:git://github.com/jenkinsci/gcloud-sdk-plugin.git scm:git:git@github.com:jenkinsci/gcloud-sdk-plugin.git https://github.com/jenkinsci/gcloud-sdk-plugin - gcloud-sdk-0.0.2 + HEAD From 26dbd99f842cf706893587d262d8d7daa1feaf31 Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Tue, 22 Oct 2019 11:51:48 -0400 Subject: [PATCH 32/34] Explicitly depend on http-client-jackson2 --- pom.xml | 5 +++++ .../jenkins/plugins/gcloud/GCloudServiceAccount.java | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 04c8af5..81b19d6 100644 --- a/pom.xml +++ b/pom.xml @@ -66,6 +66,11 @@ 1.16 compile + + com.google.http-client + google-http-client-jackson2 + 1.24.1 + org.jenkins-ci.plugins google-oauth-plugin diff --git a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java index c7da74c..6f74348 100644 --- a/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java +++ b/src/main/java/com/byclosure/jenkins/plugins/gcloud/GCloudServiceAccount.java @@ -3,7 +3,7 @@ import com.cloudbees.jenkins.plugins.gcloudsdk.GCloudInstallation; import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.SecretBytes; -import com.google.api.client.json.jackson.JacksonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; import com.google.jenkins.plugins.credentials.oauth.*; import hudson.FilePath; import hudson.Launcher; From b170c07e641114bdb6909ddc95cd05d794bed175 Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Fri, 10 Jan 2020 18:32:44 -0500 Subject: [PATCH 33/34] [maven-release-plugin] prepare release gcloud-sdk-0.0.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 81b19d6..d8304d6 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ com.byclosure.jenkins.plugins gcloud-sdk - 0.0.3-SNAPSHOT + 0.0.3 hpi @@ -42,7 +42,7 @@ scm:git:git://github.com/jenkinsci/gcloud-sdk-plugin.git scm:git:git@github.com:jenkinsci/gcloud-sdk-plugin.git https://github.com/jenkinsci/gcloud-sdk-plugin - HEAD + gcloud-sdk-0.0.3 From 57bd90061775e96fa0106908f46a9f12d6703d6c Mon Sep 17 00:00:00 2001 From: Joe Hansche Date: Fri, 10 Jan 2020 18:32:50 -0500 Subject: [PATCH 34/34] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d8304d6..27ad822 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ com.byclosure.jenkins.plugins gcloud-sdk - 0.0.3 + 0.0.4-SNAPSHOT hpi @@ -42,7 +42,7 @@ scm:git:git://github.com/jenkinsci/gcloud-sdk-plugin.git scm:git:git@github.com:jenkinsci/gcloud-sdk-plugin.git https://github.com/jenkinsci/gcloud-sdk-plugin - gcloud-sdk-0.0.3 + HEAD