Skip to content

Commit

Permalink
Merge pull request #35 from kiwigrid/support-local-helm-binary
Browse files Browse the repository at this point in the history
Support usage of local HELM installation.
  • Loading branch information
axdotl authored Jan 31, 2019
2 parents 1c3f8a6 + 29130e0 commit 66975f5
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 81 deletions.
33 changes: 33 additions & 0 deletions .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
**Is this a request for help?**:

---

**Is this a BUG REPORT or FEATURE REQUEST?** (choose one):

<!--
If this is a BUG REPORT, please:
- Fill in as much of the template below as you can. If you leave out
information, we can't help you as well.
If this is a FEATURE REQUEST, please:
- Describe *in detail* the feature/behavior/change you'd like to see.
In both cases, be ready for followup questions, and please respond in a timely
manner. If we can't reproduce a bug or think a feature already exists, we
might close your issue. If we're wrong, PLEASE feel free to reopen it and
explain why.
-->

**Environment (plugin version, maven version, OS, ...)**:


**What happened**:


**What you expected to happen**:


**How to reproduce it** (as minimally and precisely as possible):


**Anything else we need to know**:
119 changes: 80 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,96 +18,137 @@ Currently (October 2017) there is no simple Maven plugin to package existing HEL

# How?

The plugin downloads HELM in a specific version and runs the tool in the background.
By default the plugin downloads HELM in a specific version. Next to that it is possible to specify a local HELM binary.
In both cases HELM will be executed in the background.

Add following dependency to your pom.xml:
```
```xml
<dependency>
<groupId>com.kiwigrid</groupId>
<artifactId>helm-maven-plugin</artifactId>
<version>3.4</version>
<version>4.0</version>
</dependency>
```

Configure plugin with explicit credentials:
## Configuration Examples

### Usage with Downloaded Binary
```xml
<build>
<plugins>
...
<plugin>
<groupId>com.kiwigrid</groupId>
<artifactId>helm-maven-plugin</artifactId>
<version>4.0</version>
<configuration>
<chartDirectory>${project.basedir}</chartDirectory>
<chartVersion>${project.version}</chartVersion>
<!-- This is the related section when using binary download -->
<helmDownloadUrl>https://storage.googleapis.com/kubernetes-helm/helm-v2.12.3-linux-amd64.tar.gz</helmDownloadUrl>
<helmHomeDirectory>${project.basedir}/target/helm/home</helmHomeDirectory>
</configuration>
</plugin>
...
</plugins>
</build>
```

### Usage with Local Binary
```xml
<build>
<plugins>
...
<plugin>
<groupId>com.kiwigrid</groupId>
<artifactId>helm-maven-plugin</artifactId>
<version>4.0</version>
<configuration>
<chartDirectory>${project.basedir}</chartDirectory>
<chartVersion>${project.version}</chartVersion>
<!-- This is the related section to use local binary -->
<useLocalHelmBinary>true</useLocalHelmBinary>
<helmExecutableDirectory>/usr/local/bin</helmExecutableDirectory>
</configuration>
</plugin>
...
</plugins>
</build>
```
...
<properties>
<helm.download.url>https://storage.googleapis.com/kubernetes-helm/helm-v2.12.0-linux-amd64.tar.gz</helm.download.url>
</properties>
...

### Configure Plugin to Use Credentials from settings.xml for Upload
```xml
<build>
<plugins>
...
<plugin>
<groupId>com.kiwigrid</groupId>
<artifactId>helm-maven-plugin</artifactId>
<version>3.4</version>
<version>4.0</version>
<configuration>
<chartDirectory>${project.basedir}</chartDirectory>
<chartVersion>${project.version}</chartVersion>
<!-- This is the related section to configure upload repos -->
<uploadRepoStable>
<name>stable-repo</name>
<url>https://repo.example.com/artifactory/helm-stable</url>
<!-- Artifacotry requires basic authentication -->
<!-- which is supported from HELM version >= 2.9 -->
<type>ARTIFACTORY</type>
<username>foo</username>
<password>bar</password>
</uploadRepoStable>
<uploadRepoSnapshot>
<name>snapshot-repo</name>
<url>https://my.chart.museum/api/charts</url>
<url>https://my.chart.museum:8080/api/charts</url>
<type>CHARTMUSEUM</type>
</uploadRepoSnapshot>
<helmDownloadUrl>${helm.download.url}</helmDownloadUrl>
<helmDownloadUrl>https://storage.googleapis.com/kubernetes-helm/helm-v2.12.3-linux-amd64.tar.gz</helmDownloadUrl>
<helmHomeDirectory>${project.basedir}/target/helm/home</helmHomeDirectory>
<skipRefresh>false</skipRefresh>
<excludes>
<exclude>${project.basedir}/excluded</exclude>
</excludes>
<helmExtraRepos>
<helmRepo>
<name>incubator</name>
<url>https://kubernetes-charts-incubator.storage.googleapis.com</url>
</helmRepo>
</helmExtraRepos>
</configuration>
</plugin>
...
</plugins>
</build>
```

Configure plugin using credentials from settings.xml:
```
...
<properties>
<helm.download.url>https://storage.googleapis.com/kubernetes-helm/helm-v2.12.0-linux-amd64.tar.gz</helm.download.url>
</properties>
...
### More Complex Example
```xml
<build>
<plugins>
...
<plugin>
<groupId>com.kiwigrid</groupId>
<artifactId>helm-maven-plugin</artifactId>
<version>3.4</version>
<version>4.0</version>
<configuration>
<chartDirectory>${project.basedir}</chartDirectory>
<chartVersion>${project.version}</chartVersion>
<uploadRepoStable>
<name>stable-repo</name>
<url>https://repo.example.com/artifactory/helm-stable</url>
<!-- Artifacotry requires basic authentication -->
<!-- which is supported from HELM version >= 2.9 -->
<type>ARTIFACTORY</type>
<username>foo</username>
<password>bar</password>
</uploadRepoStable>
<uploadRepoSnapshot>
<name>snapshot-repo</name>
<url>https://my.chart.museum:8080/api/charts</url>
<url>https://my.chart.museum/api/charts</url>
<type>CHARTMUSEUM</type>
</uploadRepoSnapshot>
<helmDownloadUrl>${helm.download.url}</helmDownloadUrl>
<helmDownloadUrl>https://storage.googleapis.com/kubernetes-helm/helm-v2.12.3-linux-amd64.tar.gz</helmDownloadUrl>
<helmHomeDirectory>${project.basedir}/target/helm/home</helmHomeDirectory>
<!-- Skip a single goal -->
<skipRefresh>false</skipRefresh>
<!-- Exclude a directory to avoid processing -->
<excludes>
<exclude>${project.basedir}/excluded</exclude>
</excludes>
<!-- Add an additional repo -->
<helmExtraRepos>
<helmRepo>
<name>kiwigrid</name>
<url>https://kiwigrid.github.io</url>
</helmRepo>
</helmExtraRepos>
</configuration>
</plugin>
...
Expand All @@ -122,7 +163,7 @@ Configure plugin using credentials from settings.xml:
- Recursive chart detection (subcharts)
- Helm does not need to be installed
- Upload to [ChartMuseum](https://github.com/kubernetes-helm/chartmuseum) or [Artifactory](https://jfrog.com/artifactory/)
- Repository names are interpreted as server ids to retrieve basic authentication from server list in settings.xml.
- Repository names are interpreted as server IDs to retrieve basic authentication from server list in settings.xml.

# Usage

Expand All @@ -144,8 +185,8 @@ Parameter | Type | User Property | Required | Description
`<appVersion>` | string | helm.appVersion | false | The version of the app. This needn't be SemVer.
`<helmDownloadUrl>` | string | helm.downloadUrl | false | URL to download helm
`<excludes>` | list of strings | helm.excludes | false | list of chart directories to exclude
`<useLocalHelmBinary>` | boolean | helm.useLocalHelmBinary | false | Controls whether a local binary should be used instead of downloading it. If set to `true` path has to be set with property `executableDirectory`
`<helmExecutableDirectory>` | string | helm.executableDirectory | false | directory of your helm installation (default: `${project.build.directory}/helm`)
`<helmExecutable>` | string | helm.executable | false | path to your helm executable (default: `${project.build.directory}/helm/linux-amd64/helm`)
`<outputDirectory>` | string | helm.outputDirectory | false | chart output directory (default: `${project.build.directory}/helm/repo`)
`<helmHomeDirectory>` | string | helm.homeDirectory | false | path to helm home directory; useful for concurrent Jenkins builds! (default: `~/.helm`)
`<helmExtraRepos>` | list of [HelmRepository](./src/main/java/com/kiwigrid/helm/maven/plugin/HelmRepository.java) | helm.extraRepos | false | adds extra repositories while init
Expand All @@ -161,7 +202,7 @@ Parameter | Type | User Property | Required | Description
`<skipUpload>` | boolean | helm.upload.skip | false | skip upload goal
`<security>` | string | helm.security | false | path to your [settings-security.xml](https://maven.apache.org/guides/mini/guide-encryption.html) (default: `~/.m2/settings-security.xml`)

## Packaging with the helm lifecycle
## Packaging with the Helm Lifecycle

To keep your pom files small you can use 'helm' packaging. This binds `helm:init` to the initialize phase, `helm:lint` to the test phase, `helm:package` to the package phase and `helm:upload` to the deploy phase.

Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

<groupId>com.kiwigrid</groupId>
<artifactId>helm-maven-plugin</artifactId>
<version>3.5-SNAPSHOT</version>
<version>4.0-SNAPSHOT</version>

<name>${project.groupId}:${project.artifactId}</name>
<description>
A plugin for executing HELM (https://docs.helm.sh).
HELM itself will be downloaded during build.
HELM itself will be downloaded during build or local binary can be provided.
</description>
<url>https://github.com/kiwigrid/helm-maven-plugin</url>

Expand Down
33 changes: 14 additions & 19 deletions src/main/java/com/kiwigrid/helm/maven/plugin/AbstractHelmMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,12 @@ public abstract class AbstractHelmMojo extends AbstractMojo {
@Component(role = org.sonatype.plexus.components.sec.dispatcher.SecDispatcher.class, hint = "default")
private SecDispatcher securityDispatcher;

@Parameter(property = "helm.useLocalHelmBinary", defaultValue = "false")
private boolean useLocalHelmBinary;

@Parameter(property = "helm.executableDirectory", defaultValue = "${project.build.directory}/helm")
private String helmExecutableDirectory;

/**
* If no executeable is set this plugin tries to determine helm executeable based on operation system.
*/
@Parameter(property = "helm.executable")
private String helmExecuteable;

@Parameter(property = "helm.outputDirectory", defaultValue = "${project.build.directory}/helm/repo")
private String outputDirectory;

Expand Down Expand Up @@ -87,12 +84,10 @@ public abstract class AbstractHelmMojo extends AbstractMojo {
private Settings settings;

Path getHelmExecuteablePath() throws MojoExecutionException {
if (helmExecuteable == null) {
helmExecuteable = SystemUtils.IS_OS_WINDOWS ? "helm.exe" : "helm";
}
Path path = Paths.get(helmExecutableDirectory, helmExecuteable).toAbsolutePath();
String helmExecutable = SystemUtils.IS_OS_WINDOWS ? "helm.exe" : "helm";
Path path = Paths.get(helmExecutableDirectory, helmExecutable).toAbsolutePath();
if (!path.toFile().exists()) {
throw new MojoExecutionException("Helm executeable at " + path + " not found.");
throw new MojoExecutionException("Helm executable at " + path + " not found.");
}
return path;
}
Expand Down Expand Up @@ -248,14 +243,6 @@ protected SecDispatcher getSecDispatcher() {
return securityDispatcher;
}

public String getHelmExecuteable() {
return helmExecuteable;
}

public void setHelmExecuteable(String helmExecuteable) {
this.helmExecuteable = helmExecuteable;
}

public String getOutputDirectory() {
return outputDirectory;
}
Expand Down Expand Up @@ -355,4 +342,12 @@ public void setHelmSecurity(String helmSecurity) {
public Settings getSettings() {
return settings;
}

public boolean isUseLocalHelmBinary() {
return useLocalHelmBinary;
}

public void setUseLocalHelmBinary(boolean useLocalHelmBinary) {
this.useLocalHelmBinary = useLocalHelmBinary;
}
}
46 changes: 30 additions & 16 deletions src/main/java/com/kiwigrid/helm/maven/plugin/InitMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,33 @@ public void execute()
getLog().info("Creating output directory...");
callCli("mkdir -p " + getOutputDirectory(), "Unable to create output directory at " + getOutputDirectory(),
false);

if(isUseLocalHelmBinary()) {
verifyLocalHelmBinary();
getLog().info("Using local HELM binary ["+ getHelmExecutableDirectory() +"]");
} else {
downloadAndUnpackHelm();
}

if (getHelmExtraRepos() != null) {
for (HelmRepository repository : getHelmExtraRepos()) {
getLog().info("Adding repo " + repository);
PasswordAuthentication auth = getAuthentication(repository);
callCli(getHelmExecutableDirectory()
+ File.separator
+ "helm repo add "
+ repository.getName()
+ " "
+ repository.getUrl()
+ (StringUtils.isNotEmpty(getHelmHomeDirectory()) ? " --home=" + getHelmHomeDirectory() : "")
+ (auth != null ? " --username=" + auth.getUserName() + " --password=" + String.valueOf(auth.getPassword()) : ""),
"Unable add repo",
false);
}
}
}

protected void downloadAndUnpackHelm() throws MojoExecutionException {
getLog().info("Downloading Helm...");
callCli("wget -qO "
+ getHelmExecutableDirectory()
Expand All @@ -56,23 +83,10 @@ public void execute()
+ (StringUtils.isNotEmpty(getHelmHomeDirectory()) ? " --home=" + getHelmHomeDirectory() : ""),
"Unable to call helm init",
false);
}

if (getHelmExtraRepos() != null) {
for (HelmRepository repository : getHelmExtraRepos()) {
getLog().info("Adding repo " + repository);
PasswordAuthentication auth = getAuthentication(repository);
callCli(getHelmExecutableDirectory()
+ File.separator
+ "helm repo add "
+ repository.getName()
+ " "
+ repository.getUrl()
+ (StringUtils.isNotEmpty(getHelmHomeDirectory()) ? " --home=" + getHelmHomeDirectory() : "")
+ (auth != null ? " --username=" + auth.getUserName() + " --password=" + String.valueOf(auth.getPassword()) : ""),
"Unable add repo",
false);
}
}
private void verifyLocalHelmBinary() throws MojoExecutionException {
callCli(getHelmExecuteablePath() + " version --client", "Unable to verify local HELM binary", false);
}

public boolean isSkipRefresh() {
Expand Down
Loading

0 comments on commit 66975f5

Please sign in to comment.