All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.microbean.helm.maven.InstallReleaseMojo Maven / Gradle / Ivy

There is a newer version: 2.8.2.1.1.2
Show newest version
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
 *
 * Copyright © 2017 MicroBean.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License.
 */
package org.microbean.helm.maven;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

import java.net.URI;
import java.net.URL;

import java.nio.charset.StandardCharsets;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import java.util.Objects;

import java.util.concurrent.Callable;
import java.util.concurrent.Future;

import java.util.regex.Matcher;

import javax.inject.Inject;

import hapi.chart.ChartOuterClass.Chart;

import hapi.release.ReleaseOuterClass.Release;

import hapi.services.tiller.Tiller.InstallReleaseRequest;
import hapi.services.tiller.Tiller.InstallReleaseResponse;

import org.apache.maven.execution.MavenSession;

import org.apache.maven.plugin.MojoExecutionException;

import org.apache.maven.plugin.logging.Log;

import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import org.apache.maven.project.MavenProject;

import org.microbean.helm.ReleaseManager;

import org.microbean.helm.chart.AbstractChartLoader;
import org.microbean.helm.chart.URLChartLoader;

/**
 * Installs
 * a chart and hence creates a release.
 *
 * @author Laird Nelson
 */
@Mojo(name = "install")
public class InstallReleaseMojo extends AbstractMutatingReleaseMojo {


  /*
   * Instance fields.
   */


  /**
   * The {@link MavenProject} in effect.
   */
  private final MavenProject project;

  /**
   * The {@link MavenSession} in effect.
   */
  private final MavenSession session;

  /**
   * The name of the release to install.  If omitted, a release name
   * will be generated and used instead.
   *
   * @see #getReleaseName()
   *
   * @see #setReleaseName(String)
   *
   * @see #validateReleaseName(String)
   */
  /*
   * This field shadows the AbstractSingleReleaseMojo#releaseName
   * field on purpose to relax its "required" nature.
   */
  @Parameter
  private String releaseName;

  /**
   * The namespace
   * into which the release will be installed.
   */
  @Parameter
  private String releaseNamespace;

  /**
   * Whether to reuse the release name for repeated installations.  It
   * is strongly recommended that you not set this to {@code true} in
   * production scenarios.
   */
  @Parameter(defaultValue = "false")
  private boolean reuseReleaseName;

  /**
   * Whether a missing or non-resolvable {@code chartUrl} parameter
   * will result in skipped execution or an error.
   */
  @Parameter(defaultValue = "false")
  private boolean lenient;

  /**
   * YAML-formatted values to supply at the time of installation.
   *
   * If this parameter and the {@code valuesYamlUri} parameter are
   * both specified, this parameter is preferred if its value is
   * non-{@code null} and non-empty.
   */
  @Parameter(property = "helm.install.valuesYaml")
  private String valuesYaml;

  /**
   * A URI identifying a document containing YAML-formatted values to
   * supply at the time of installation.
   *
   * If this parameter and the {@code valuesYaml} parameter are both
   * specified, this parameter is ignored if the value of the {@code
   * valuesYaml} parameter is non-{@code null} and non-empty.
   */
  @Parameter(property = "helm.install.valuesYamlUri")
  private URI valuesYamlUri;
  
  /**
   * A {@link URL} representing the chart to install.  If omitted,
   * file:/${project.build.directory}/generated-sources/helm/charts/${project.artifactId}
   * will be used instead.
   */
  @Parameter(required = true,
             defaultValue = "file:${project.build.directory}/generated-sources/helm/charts/${project.artifactId}",
             property = "helm.install.chartUrl"
  )
  private URL chartUrl;

  
  /*
   * Constructors.
   */
  

  /**
   * Creates a new {@link InstallReleaseMojo}.
   *
   * @param project the {@link MavenProject} in effect; must not be
   * {@code null}
   *
   * @param session the {@link MavenSession} in effect; must not be
   * {@code null}
   *
   * @exception NullPointerException if either {@code project} or
   * {@code session} is {@code null}
   */
  @Inject
  public InstallReleaseMojo(final MavenProject project, final MavenSession session) {
    super();
    Objects.requireNonNull(project);
    Objects.requireNonNull(session);
    this.project = project;
    this.session = session;
  }


  /*
   * Instance methods.
   */


  /**
   * {@inheritDoc}
   *
   * 

This implementation installs * the chart * residing at the {@linkplain #getChartUrl() indicated URL} and * thus creates a release.

*/ @Override protected void execute(final Callable releaseManagerCallable) throws Exception { Objects.requireNonNull(releaseManagerCallable); final Log log = this.getLog(); assert log != null; URL chartUrl = this.getChartUrl(); if (chartUrl == null) { final Path chartPath = Paths.get(new StringBuilder(this.project.getBuild().getDirectory()).append("/generated-sources/helm/charts/").append(this.project.getArtifactId()).toString()); assert chartPath != null; chartUrl = chartPath.toUri().toURL(); if (!Files.isDirectory(chartPath)) { if (this.isLenient()) { if (log.isWarnEnabled()) { log.warn("Non-existent or unresolvable default chartUrl (" + chartUrl + "); skipping execution"); } chartUrl = null; } else { throw new MojoExecutionException("Non-existent or unresolvable default chartUrl: " + chartUrl); } } } if (chartUrl != null) { if (log.isDebugEnabled()) { log.debug("chartUrl: " + chartUrl); } Chart.Builder chartBuilder = null; try (final AbstractChartLoader chartLoader = this.createChartLoader()) { if (chartLoader == null) { throw new IllegalStateException("createChartLoader() == null"); } if (log.isDebugEnabled()) { log.debug("chartLoader: " + chartLoader); log.debug("Loading Helm chart from " + chartUrl); } chartBuilder = chartLoader.load(chartUrl); } if (chartBuilder == null) { throw new IllegalStateException("chartBuilder.load(\"" + chartUrl + "\") == null"); } if (log.isInfoEnabled()) { log.info("Loaded Helm chart from " + chartUrl); } final InstallReleaseRequest.Builder requestBuilder = InstallReleaseRequest.newBuilder(); assert requestBuilder != null; requestBuilder.setDisableHooks(this.getDisableHooks()); requestBuilder.setDryRun(this.getDryRun()); final String releaseName = this.getReleaseName(); if (releaseName != null) { requestBuilder.setName(releaseName); } final String releaseNamespace = this.getReleaseNamespace(); if (releaseNamespace != null) { requestBuilder.setNamespace(releaseNamespace); } requestBuilder.setReuseName(this.getReuseReleaseName()); requestBuilder.setTimeout(this.getTimeout()); String valuesYaml = this.getValuesYaml(); if (valuesYaml == null || valuesYaml.isEmpty()) { final URI valuesYamlUri = this.getValuesYamlUri(); if (valuesYamlUri != null) { final URL yamlUrl = valuesYamlUri.toURL(); assert yamlUrl != null; try (final Reader reader = new BufferedReader(new InputStreamReader(yamlUrl.openStream(), StandardCharsets.UTF_8))) { final StringBuilder sb = new StringBuilder(); final char[] buffer = new char[4096]; int charsRead = -1; while ((charsRead = reader.read(buffer, 0, buffer.length)) >= 0) { sb.append(buffer, 0, charsRead); } valuesYaml = sb.toString(); } } } if (valuesYaml != null && !valuesYaml.isEmpty()) { final hapi.chart.ConfigOuterClass.Config.Builder values = requestBuilder.getValuesBuilder(); assert values != null; values.setRaw(valuesYaml); } requestBuilder.setWait(this.getWait()); final ReleaseManager releaseManager = releaseManagerCallable.call(); if (releaseManager == null) { throw new IllegalStateException("releaseManagerCallable.call() == null"); } if (log.isInfoEnabled()) { log.info("Installing release " + requestBuilder.getName()); } final Future installReleaseResponseFuture = releaseManager.install(requestBuilder, chartBuilder); assert installReleaseResponseFuture != null; final InstallReleaseResponse installReleaseResponse = installReleaseResponseFuture.get(); assert installReleaseResponse != null; if (log.isInfoEnabled()) { final Release release = installReleaseResponse.getRelease(); assert release != null; log.info("Installed release " + release.getName()); } } } /** * Creates and returns an {@link AbstractChartLoader} capable of * loading a Helm chart from a {@link URL}. * *

This method never returns {@code null}.

* *

Overrides of this method must not return {@code null}.

* *

This implementation returns a new {@link URLChartLoader}.

* * @return a new {@link AbstractChartLoader} implementation; never * {@code null} */ protected AbstractChartLoader createChartLoader() { return new URLChartLoader(); } /** * Returns a {@link URL} identifying a Helm chart that can be read * by the {@link AbstractChartLoader} produced by the {@link * #createChartLoader()} method. * *

This method may return {@code null}.

* * @return a {@link URL} to a Helm chart, or {@code null} * * @see #setChartUrl(URL) */ public URL getChartUrl() { return this.chartUrl; } /** * Sets the {@link URL} identifying a Helm chart that can be read * by the {@link AbstractChartLoader} produced by the {@link * #createChartLoader()} method. * * @param chartUrl the {@link URL} identifying a Helm chart that can * be read by the {@link AbstractChartLoader} produced by the {@link * #createChartLoader()} method; may be {@code null} */ public void setChartUrl(final URL chartUrl) { this.chartUrl = chartUrl; } /** * Returns {@code true} if this {@link InstallReleaseMojo} is * lenient; if {@code true}, a missing or unresolvable * {@link #getChartUrl() chartUrl} parameter will result in * execution being skipped rather than a {@link * MojoExecutionException} being thrown. * * @return {@code true} if this {@link InstallReleaseMojo} is * lenient; {@code false} otherwise */ public boolean isLenient() { return this.lenient; } /** * Sets whether this {@link InstallReleaseMojo} is lenient; * if {@code true} is supplied, a missing or unresolvable {@link * #getChartUrl() chartUrl} parameter will result in execution being * skipped rather than a {@link MojoExecutionException} being * thrown. * * @param lenient whether this {@link InstallReleaseMojo} is * lenient; if {@code true}, a missing or unresolvable * {@link #getChartUrl() chartUrl} parameter will result in * execution being skipped rather than a {@link * MojoExecutionException} being thrown */ public void setLenient(final boolean lenient) { this.lenient = lenient; } /** * Returns the namespace * into which the release will be installed. * *

This method may return {@code null}.

* * @return the namespace * into which the release will be installed, or {@code null} * * @see #setReleaseNamespace(String) */ public String getReleaseNamespace() { return this.releaseNamespace; } /** * Sets the namespace * into which the release will be installed. * * @param releaseNamespace the namespace * into which the release will be installed; may be {@code null} * * @see #getReleaseNamespace() */ public void setReleaseNamespace(final String releaseNamespace) { this.releaseNamespace = releaseNamespace; } /** * Returns {@code true} if the {@linkplain #getReleaseName() * supplied release name} should be reused across installations. * * @return {@code true} if the {@linkplain #getReleaseName() * supplied release name} should be reused across installations; * {@code false} otherwise * * @see #setReuseReleaseName(boolean) */ public boolean getReuseReleaseName() { return this.reuseReleaseName; } /** * Sets whether the {@linkplain #getReleaseName() supplied release * name} should be reused across installations. * * @param reuseReleaseName whether the {@linkplain #getReleaseName() * supplied release name} should be reused across installations * * @see #getReuseReleaseName() */ public void setReuseReleaseName(final boolean reuseReleaseName) { this.reuseReleaseName = reuseReleaseName; } /** * Returns a YAML {@link String} representing the values to use to * customize the installation. * *

This method may return {@code null}.

* *

Overrides of this method may return {@code null}.

* * @return a YAML {@link String} representing the values to use to * customize the installation, or {@code null} * * @see #setValuesYaml(String) */ public String getValuesYaml() { return this.valuesYaml; } /** * Installs a YAML {@link String} representing the values to use to * customize the installation. * * @param valuesYaml the YAML {@link String} representing the values to use to * customize the installation; may be {@code null} * * @see #getValuesYaml() */ public void setValuesYaml(final String valuesYaml) { this.valuesYaml = valuesYaml; } /** * Returns a {@link URI} identifying a YAML document containing the * values to use to customize the installation. * *

This method may return {@code null}.

* *

Overrides of this method may return {@code null}.

* * @return a {@link URI} identifying a YAML document containing the * values to use to customize the installation, or {@code null} * * @see #setValuesYamlUri(URI) */ public URI getValuesYamlUri() { return this.valuesYamlUri; } /** * Sets the {@link URI} identifying a YAML document containing the * values to use to customize the installation. * * @param valuesYamlUri the {@link URI} identifying a YAML document * containing the values to use to customize the installation; may * be {@code null} * * @see #getValuesYamlUri() */ public void setValuesYamlUri(final URI valuesYamlUri) { this.valuesYamlUri = valuesYamlUri; } /** * {@inheritDoc} * *

This implementation allows the supplied {@code name} to be * {@code null} or {@linkplain String#isEmpty() empty}.

*/ @Override protected void validateReleaseName(final String name) { if (name != null && !name.isEmpty()) { super.validateReleaseName(name); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy