/**
* Copyright 2005-2016 Red Hat, Inc.
*
* Red Hat licenses this file to you 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 io.fabric8.maven;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import io.fabric8.kubernetes.api.Annotations;
import io.fabric8.kubernetes.api.KubernetesHelper;
import io.fabric8.kubernetes.api.extensions.Templates;
import io.fabric8.kubernetes.api.model.*;
import io.fabric8.kubernetes.client.utils.Utils;
import io.fabric8.maven.support.Commandline;
import io.fabric8.maven.support.JsonSchema;
import io.fabric8.maven.support.JsonSchemaProperty;
import io.fabric8.maven.support.VolumeType;
import io.fabric8.openshift.api.model.DeploymentConfig;
import io.fabric8.openshift.api.model.DeploymentConfigBuilder;
import io.fabric8.openshift.api.model.ImageStream;
import io.fabric8.openshift.api.model.ImageStreamBuilder;
import io.fabric8.openshift.api.model.ParameterBuilder;
import io.fabric8.openshift.api.model.Template;
import io.fabric8.openshift.api.model.TemplateBuilder;
import io.fabric8.utils.Base64Encoder;
import io.fabric8.utils.Files;
import io.fabric8.utils.Lists;
import io.fabric8.utils.Objects;
import io.fabric8.utils.PropertiesHelper;
import io.fabric8.utils.Strings;
import io.fabric8.utils.URLUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.model.Scm;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static io.fabric8.kubernetes.api.KubernetesHelper.getName;
import static io.fabric8.kubernetes.api.KubernetesHelper.setName;
import static io.fabric8.utils.Files.guessMediaType;
import static io.fabric8.utils.PropertiesHelper.findPropertiesWithPrefix;
import static io.fabric8.utils.PropertiesHelper.getInteger;
/**
* Generates or copies the Kubernetes JSON file and attaches it to the build so its
* installed and released to maven repositories like other build artifacts.
*/
@Mojo(name = "json", defaultPhase = LifecyclePhase.GENERATE_RESOURCES)
public class JsonMojo extends AbstractFabric8Mojo {
public static final String FABRIC8_PORT_HOST_PREFIX = "docker.port.host.";
public static final String FABRIC8_PORT_CONTAINER_PREFIX = "docker.port.container.";
public static final String FABRIC8_PORT_SERVICE = "fabric8.service.port";
public static final String FABRIC8_CONTAINER_PORT_SERVICE = "fabric8.service.containerPort";
public static final String FABRIC8_NODE_PORT_SERVICE = "fabric8.service.nodePort";
public static final String FABRIC8_PROTOCOL_SERVICE = "fabric8.service.protocol";
public static final String FABRIC8_METRICS_PREFIX = "fabric8.metrics.";
public static final String FABRIC8_METRICS_SCRAPE = FABRIC8_METRICS_PREFIX + "scrape";
public static final String FABRIC8_METRICS_SCRAPE_ANNOTATION = FABRIC8_METRICS_SCRAPE + ".annotation";
public static final String FABRIC8_METRICS_PORT = FABRIC8_METRICS_PREFIX + "port";
public static final String FABRIC8_METRICS_PORT_ANNOTATION = FABRIC8_METRICS_PORT + ".annotation";
public static final String FABRIC8_METRICS_SCHEME = FABRIC8_METRICS_PREFIX + "scheme";
public static final String FABRIC8_METRICS_SCHEME_ANNOTATION = FABRIC8_METRICS_SCHEME + ".annotation";
public static final String FABRIC8_ICON_URL_ANNOTATION = "fabric8.io/iconUrl";
private static final String SERVICE_REGEX = "^fabric8\\.service\\.(?<name>[^. ]+)\\..+$";
private static final Pattern SERVICE_PATTERN = Pattern.compile(SERVICE_REGEX);
private static final String NAME = "name";
private static final String ATTRIBUTE_TYPE = "attributeType";
private static final String VOLUME_MOUNT_PATH = "mountPath";
private static final String VOLUME_REGEX = "fabric8.volume.(?<name>[^. ]*).(?<attributeType>[^. ]*)";
private static final Pattern VOLUME_PATTERN = Pattern.compile(VOLUME_REGEX);
private static final String PARAM_REGEX = "fabric8.parameter.(?<name>[^. ]*)(.)?(?<attributeType>[^ ]*)";
private static final Pattern PARAM_PATTERN = Pattern.compile(PARAM_REGEX);
private static final String TEMPLATE_NAME = "fabric8.template";
private static final String PARAMETER_PREFIX = "fabric8.parameter";
private static final String PARAMETER_NAME_PREFIX = PARAMETER_PREFIX + ".%s";
private static final String PARAMETER_PROPERTY = PARAMETER_NAME_PREFIX + ".%s";
private static final String GENERATE = "generate";
private static final String FROM = "from";
private static final String VALUE = "value";
private static final String DESCRIPTION = "description";
private static final String CPU = "cpu";
private static final String MEMORY = "memory";
@Component
private MavenProjectHelper projectHelper;
/**
* The artifact type for attaching the generated kubernetes json file to the project
*/
@Parameter(property = "fabric8.kubernetes.artifactType", defaultValue = "json")
private String artifactType = "json";
/**
* The artifact classifier for attaching the generated kubernetes json file to the project
*/
@Parameter(property = "fabric8.kubernetes.artifactClassifier", defaultValue = "kubernetes")
private String artifactClassifier = "kubernetes";
/**
* Whether or not we should generate the Kubernetes JSON file using the MVEL template if there is not one specified
* in the build (usually in src/main/resources/kubernetes.json)
*/
@Parameter(property = "fabric8.generateJson", defaultValue = "true")
private boolean generateJson;
/**
* Should we fail the build if no json files could be found
*/
@Parameter(property = "fabric8.failOnMissingJsonFiles", defaultValue = "true")
private boolean failOnMissingJsonFiles;
/**
* Should we generate any required SecurityContextConstraints DTOs in the generated json
*/
@Parameter(property = "fabric8.generateSecurityContextConstraints", defaultValue = "false")
private boolean generateSecurityContextConstraints;
/**
* Whether we should include the namespace in the containers' env vars
*/
@Parameter(property = "fabric8.includeNamespaceEnvVar", defaultValue = "true")
private boolean includeNamespaceEnvVar;
/**
* The name of the env var to add that will contain the namespace at container runtime
*/
@Parameter(property = "fabric8.namespaceEnvVar", defaultValue = "KUBERNETES_NAMESPACE")
private String kubernetesNamespaceEnvVar;
/**
* Whether we should include the namespace in the containers' env vars
*/
@Parameter(property = "fabric8.includePodEnvVar", defaultValue = "false")
private boolean includePodEnvVar;
/**
* The name of the env var to add that will contain the pod name at container runtime
*/
@Parameter(property = "fabric8.podEnvVar", defaultValue = "KUBERNETES_POD")
private String kubernetesPodEnvVar;
/**
* The provider to include as a label. Set to empty to disable.
*/
@Parameter(property = "fabric8.provider", defaultValue = "fabric8")
private String provider;
/**
* The labels passed into the generated Kubernetes JSON template.
* <p/>
* If no value is explicitly configured in the maven plugin then we use all maven properties starting with "fabric8.label."
*/
@Parameter()
private Map<String, String> labels;
/**
* The annotations for the PodSpec
*/
@Parameter()
private Map<String, String> podSpecAnnotations;
/**
* The annotations for the ReplicationController
*/
@Parameter()
private Map<String, String> rcAnnotations;
/**
* The annotations for the Template
*/
@Parameter()
private Map<String, String> templateAnnotations;
/**
* The annotations for the Service
*/
@Parameter()
private Map<String, String> serviceAnnotations;
/**
* The environment variables passed into the generated Kubernetes JSON template.
* <p/>
* If no value is explicitly configured in the maven plugin then we use all maven properties starting with "fabric8.env."
*/
@Parameter()
private List<EnvVar> environmentVariables;
/**
* The container ports passed into the generated Kubernetes JSON template.
*/
@Parameter()
private List<ContainerPort> containerPorts;
/**
* Maps the port names to the default container port numbers
*/
@Parameter()
private Map<String, Integer> defaultContainerPortMap;
/**
* The service ports passed into the generated Kubernetes JSON template.
*/
@Parameter()
private List<ServicePort> servicePorts;
/**
* The ID prefix used in the generated Kubernetes JSON template
*/
@Parameter(property = "fabric8.replicas", defaultValue = "1")
private Integer replicaCount;
/**
* Should we wrap the generated ReplicationController objects in a DeploymentConfig
*/
// TODO lets disable by default until its working :)
@Parameter(property = "fabric8.useDeploymentConfig", defaultValue = "false")
private boolean useDeploymentConfig;
/**
* The last triggered image tag if generating a DeploymentConfig
*/
@Parameter(property = "fabric8.lastTriggeredImageTag", defaultValue = "latest")
private String lastTriggeredImageTag;
/**
* The strategy name for the DeploymentConfig
*/
@Parameter(property = "fabric8.deploymentStrategy", defaultValue = "Recreate")
private String deploymentStrategy;
/**
* The extra additional kubernetes JSON file for things like services
*/
@Parameter(property = "fabric8.extra.json", defaultValue = "${basedir}/target/classes/kubernetes-extra.json")
private File kubernetesExtraJson;
/**
* Temporary directory used for creating the template annotations
*/
@Parameter(property = "fabric8.templateTempDir", defaultValue = "${basedir}/target/fabric8/template-workdir")
private File templateTempDir;
/**
* The URL to use to link to the icon in the generated Template.
* <p/>
* For using a common set of icons, see the {@link #iconRef} option.
*/
@Parameter(property = "fabric8.iconUrl")
private String iconUrl;
/**
* The URL prefix added to the relative path of the icon file
*/
@Parameter(property = "fabric8.iconUrlPrefix")
private String iconUrlPrefix;
/**
* The SCM branch used when creating a URL to the icon file
*/
@Parameter(property = "fabric8.iconBranch", defaultValue = "master")
private String iconBranch;
/**
* The replication controller name used in the generated Kubernetes JSON template
*/
@Parameter(property = "fabric8.replicationController.name", defaultValue = "${project.artifactId}")
private String replicationControllerName;
/**
* The project label used in the generated Kubernetes JSON template
*/
@Parameter(property = "fabric8.label.project", defaultValue = "${project.artifactId}")
private String projectName;
/**
* The project label used in the generated Kubernetes JSON dependencies template
*/
@Parameter(property = "fabric8.combineJson.project", defaultValue = "${project.artifactId}")
private String combineProjectName;
/**
* The group label used in the generated Kubernetes JSON template
*/
@Parameter(property = "fabric8.label.group", defaultValue = "${project.groupId}")
private String groupName;
/**
* The name label used in the generated Kubernetes JSON template
*/
@Parameter(property = "fabric8.container.name", defaultValue = "${project.artifactId}")
private String kubernetesContainerName;
/**
* The service name
*/
@Parameter(property = "fabric8.service.name", defaultValue = "${project.artifactId}")
private String serviceName;
/**
* Should we generate headless services (services with no ports)
*/
// TODO for now lets default to not creating headless services as it barfs when used with kubernetes...
//@Parameter(property = "fabric8.service.headless", defaultValue = "true")
@Parameter(property = "fabric8.service.headless", defaultValue = "false")
private boolean headlessService;
/**
* The <a href="http://releases.k8s.io/HEAD/docs/user-guide/services.md#external-services">Type of the service</a>. Set to
* <code>"LoadBalancer"</code> if you wish an
* <a href="https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/user-guide/services.md#type-loadbalancer"></a>external load balancer</a> to be created
*/
@Parameter(property = "fabric8.service.type")
private String serviceType;
/**
* Annotation value to add for metrics scraping.
*/
@Parameter(property = FABRIC8_METRICS_SCRAPE, defaultValue = "false")
private boolean metricsScrape;
/**
* Annotation to add for metrics scraping.
*/
@Parameter(property = FABRIC8_METRICS_SCRAPE_ANNOTATION, defaultValue = "prometheus.io/scrape")
private String metricsScrapeAnnotation;
/**
* Annotation value to add for metrics port.
*/
@Parameter(property = FABRIC8_METRICS_PORT)
private Integer metricsPort;
/**
* Annotation value to add for metrics port.
*/
@Parameter(property = FABRIC8_METRICS_PORT_ANNOTATION, defaultValue = "prometheus.io/port")
private String metricsPortAnnotation;
/**
* Annotation value to add for metrics scheme.
*/
@Parameter(property = FABRIC8_METRICS_SCHEME)
private String metricsScheme;
/**
* Annotation to add for metrics scheme.
*/
@Parameter(property = FABRIC8_METRICS_SCHEME_ANNOTATION, defaultValue = "prometheus.io/scheme")
private String metricsSchemeAnnotation;
/**
* The service port
*/
@Parameter(property = FABRIC8_PORT_SERVICE)
private Integer servicePort;
/**
* The service container port
*/
@Parameter(property = FABRIC8_CONTAINER_PORT_SERVICE)
private String serviceContainerPort;
/**
* The service node port
*/
@Parameter(property = FABRIC8_NODE_PORT_SERVICE)
private Integer serviceNodePort;
/**
* The service protocol
*/
@Parameter(property = FABRIC8_PROTOCOL_SERVICE, defaultValue = "TCP")
private String serviceProtocol;
/**
* The docker image pull policy for non-snapshots
*/
@Parameter(property = "fabric8.imagePullPolicy")
private String imagePullPolicy;
/**
* The docker image pull policy for snapshot releases (which should pull always)
*/
@Parameter(property = "fabric8.imagePullPolicySnapshot")
private String imagePullPolicySnapshot;
/**
* Whether the plugin should discover all the environment variable json schema files in the classpath and export those into the generated kubernetes JSON
*/
@Parameter(property = "fabric8.includeAllEnvironmentVariables", defaultValue = "true")
private boolean includeAllEnvironmentVariables;
@Parameter(property = "fabric8.containerPrivileged")
protected Boolean containerPrivileged;
@Parameter(property = "fabric8.serviceAccount")
protected String serviceAccount;
/**
* Should we create the ServiceAccount resource as part of the build
*/
@Parameter(property = "fabric8.serviceAccountCreate")
private boolean createServiceAccount;
/**
* The properties file used to specify the OpenShift Template parameter values and descriptions. The properties file should be of the form
* <code>
* <pre>
* FOO.value = ABC
* FOO.description = this is the description of FOO
* </pre>
* </code>
*/
@Parameter(property = "fabric8.templateParametersFile", defaultValue = "${basedir}/src/main/fabric8/templateParameters.properties")
protected File templateParametersPropertiesFile;
/**
* The properties file used to specify the annotations to be added to the generated PodSpec
* <code>
* <pre>
* acme.com/cheese = SOMETHING
* </pre>
* </code>
*/
@Parameter(property = "fabric8.podSpecAnnotationsFile", defaultValue = "${basedir}/src/main/fabric8/podSpecAnnotations.properties")
protected File podSpecAnnotationsFile;
/**
* The properties file used to specify the annotations to be added to the generated ReplicationController
* <code>
* <pre>
* acme.com/cheese = SOMETHING
* </pre>
* </code>
*/
@Parameter(property = "fabric8.rcAnnotationsFile", defaultValue = "${basedir}/src/main/fabric8/rcAnnotations.properties")
protected File rcAnnotationsFile;
/**
* The properties file used to specify the annotations to be added to the generated Template
* <code>
* <pre>
* acme.com/cheese = SOMETHING
* </pre>
* </code>
*/
@Parameter(property = "fabric8.templateAnnotationsFile", defaultValue = "${basedir}/src/main/fabric8/templateAnnotations.properties")
protected File templateAnnotationsFile;
/**
* The properties file used to specify the annotations to be added to the generated Service
* <code>
* <pre>
* acme.com/cheese = SOMETHING
* </pre>
* </code>
*/
@Parameter(property = "fabric8.serviceAnnotationsFile", defaultValue = "${basedir}/src/main/fabric8/serviceAnnotations.properties")
protected File serviceAnnotationsFile;
/**
* Defines the maximum size in kilobytes that the data encoded URL of the icon should be before we defer
* and try to use an external URL
*/
@Parameter(property = "fabric8.maximumDataUrlSizeK", defaultValue = "2")
private int maximumDataUrlSizeK;
@Component
protected ArtifactResolver resolver;
@Parameter(property = "localRepository", readonly = true, required = true)
protected ArtifactRepository localRepository;
@Parameter(property = "project.remoteArtifactRepositories")
protected List remoteRepositories;
/**
* The default requests storage size for a PersistenceVolumeClaim if its created for a persistent volume via a claim
*/
@Parameter(property = "fabric8.defaultPersistentVolumeClaimRequestsStorage", defaultValue = "20")
private String defaultPersistentVolumeClaimRequestsStorage;
/**
* Should we remove the version label from the service selector?
*/
@Parameter(property = "fabric8.removeVersionLabelFromServiceSelector", defaultValue = "true")
private boolean removeVersionLabelFromServiceSelector;
/**
* CPU resource limits
*/
@Parameter(property = "fabric8.resources.limits.cpu", defaultValue = "0")
private String limitsCpu;
/**
* Memory resource limits
*/
@Parameter(property = "fabric8.resources.limits.memory", defaultValue = "0")
private String limitsMemory;
/**
* CPU resource requests
*/
@Parameter(property = "fabric8.resources.requests.cpu", defaultValue = "0")
private String requestsCpu;
/**
* Memory resource requests
*/
@Parameter(property = "fabric8.resources.requests.cpu", defaultValue = "0")
private String requestsMemory;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
File json = getKubernetesJson();
getLog().info("Configured with file: " + json);
if (json == null) {
throw new MojoExecutionException("No kubernetes json file is specified!");
}
if (shouldGenerateForThisProject()) {
if (!isIgnoreProject() || combineDependencies) {
if (generateJson) {
generateKubernetesJson(json);
if (combineDependencies) {
combineDependentJsonFiles(getKubernetesCombineJson() == null ? json : getKubernetesCombineJson());
}
if (kubernetesExtraJson != null && kubernetesExtraJson.exists()) {
combineJsonFiles(json, kubernetesExtraJson);
}
}
if (json.exists() && json.isFile()) {
if (useDeploymentConfig) {
wrapInDeploymentConfigs(json);
}
addEnvironmentAnnotations(json);
}
}
}
}
@Override
protected boolean shouldGenerateForThisProject() {
return super.shouldGenerateForThisProject() || combineDependencies;
}
protected void combineDependentJsonFiles(File json) throws MojoExecutionException {
try {
MavenProject project = getProject();
Set<File> jsonFiles = new LinkedHashSet<>();
Set<Artifact> dependencyArtifacts = project.getDependencyArtifacts();
for (Artifact artifact : dependencyArtifacts) {
String classifier = artifact.getClassifier();
String type = artifact.getType();
File file = artifact.getFile();
if (isKubernetesJsonArtifact(classifier, type)) {
if (file != null) {
System.out.println("Found kubernetes JSON dependency: " + artifact);
jsonFiles.add(file);
} else {
Set<Artifact> artifacts = resolveArtifacts(artifact);
for (Artifact resolvedArtifact : artifacts) {
classifier = resolvedArtifact.getClassifier();
type = resolvedArtifact.getType();
file = resolvedArtifact.getFile();
if (isKubernetesJsonArtifact(classifier, type) && file != null) {
System.out.println("Resolved kubernetes JSON dependency: " + artifact);
jsonFiles.add(file);
}
}
}
}
}
List<Object> jsonObjectList = new ArrayList<>();
for (File file : jsonFiles) {
addKubernetesJsonFileToList(jsonObjectList, file);
}
if (jsonObjectList.isEmpty()) {
if (failOnMissingJsonFiles) {
throw new MojoExecutionException("Could not find any dependent kubernetes JSON files!");
} else {
getLog().warn("Could not find any dependent kubernetes JSON files");
return;
}
}
Object combinedJson;
if (jsonObjectList.size() == 1) {
combinedJson = jsonObjectList.get(0);
} else {
combinedJson = KubernetesHelper.combineJson(jsonObjectList.toArray());
}
if (combinedJson instanceof Template) {
Template template = (Template) combinedJson;
String templateName = getCombineProjectName();
setName(template, templateName);
configureTemplateDescriptionAndIcon(template, getIconUrl());
addLabelIntoObjects(template.getObjects(), "package", templateName);
if (pureKubernetes) {
combinedJson = applyTemplates(template);
}
}
if (pureKubernetes) {
combinedJson = filterPureKubernetes(combinedJson);
}
json.getParentFile().mkdirs();
KubernetesHelper.saveJson(json, combinedJson);
getLog().info("Saved as :" + json.getAbsolutePath());
} catch (Exception e) {
throw new MojoExecutionException("Failed to save combined JSON files " + json + " and " + kubernetesExtraJson + " as " + json + ". " + e, e);
}
}
protected void addLabelIntoObjects(List<HasMetadata> objects, String label, String value) {
for (HasMetadata object : objects) {
addLabelIfNotExist(object, label, value);
if (object instanceof ReplicationController) {
final ReplicationController entity = (ReplicationController) object;
final ReplicationControllerSpec spec = entity.getSpec();
if (spec != null) {
final PodTemplateSpec template = spec.getTemplate();
if (template != null) {
// TODO hack until this is fixed https://github.com/fabric8io/kubernetes-model/issues/112
HasMetadata hasMetadata = new HasMetadata() {
@Override
public ObjectMeta getMetadata() {
return template.getMetadata();
}
@Override
public void setMetadata(ObjectMeta objectMeta) {
template.setMetadata(objectMeta);
}
@Override
public String getKind() {
return "PodTemplateSpec";
}
@Override
public String getApiVersion() {
return entity.getApiVersion();
}
};
addLabelIfNotExist(hasMetadata, label, value);
}
}
}
}
}
protected boolean addLabelIfNotExist(HasMetadata object, String label, String value) {
if (object != null) {
Map<String, String> labels = KubernetesHelper.getOrCreateLabels(object);
if (labels.get(label) == null) {
labels.put(label, value);
return true;
}
}
return false;
}
protected Object applyTemplates(Template template) throws IOException {
overrideTemplateParameters(template);
return Templates.processTemplatesLocally(template, false);
}
protected Object filterPureKubernetes(Object dto) throws IOException {
List<HasMetadata> items = KubernetesHelper.toItemList(dto);
List<HasMetadata> filtered = new ArrayList<>();
for (HasMetadata item : items) {
if (KubernetesHelper.isPureKubernetes(item)) {
filtered.add(item);
}
}
KubernetesList answer = new KubernetesList();
answer.setItems(filtered);
return answer;
}
private void addKubernetesJsonFileToList(List<Object> list, File file) {
if (file.exists() && file.isFile()) {
try {
Object jsonObject = loadJsonFile(file);
if (jsonObject != null) {
list.add(jsonObject);
} else {
getLog().warn("No object found for file: " + file);
}
} catch (MojoExecutionException e) {
getLog().warn("Failed to parse file " + file + ". " + e, e);
}
} else {
getLog().warn("Ignoring missing file " + file);
}
}
protected Set<Artifact> resolveArtifacts(Artifact artifact) {
ArtifactResolutionRequest request = new ArtifactResolutionRequest();
request.setArtifact(artifact);
request.setRemoteRepositories(remoteRepositories);
request.setLocalRepository(localRepository);
ArtifactResolutionResult resolve = resolver.resolve(request);
return resolve.getArtifacts();
}
protected void combineJsonFiles(File json, File kubernetesExtraJson) throws MojoExecutionException {
// lets combine json files together
getLog().info("Combining generated json " + json + " with extra json " + kubernetesExtraJson);
Object extra = loadJsonFile(kubernetesExtraJson);
Object generated = loadJsonFile(json);
try {
Object combinedJson = KubernetesHelper.combineJson(generated, extra);
KubernetesHelper.saveJson(json, combinedJson);
getLog().info("Saved as :" + json.getAbsolutePath());
} catch (IOException e) {
throw new MojoExecutionException("Failed to save combined JSON files " + json + " and " + kubernetesExtraJson + " as " + json + ". " + e, e);
}
}
protected void wrapInDeploymentConfigs(File json) throws MojoExecutionException {
try {
Object dto = loadJsonFile(json);
if (dto instanceof KubernetesList) {
KubernetesList container = (KubernetesList) dto;
List<HasMetadata> items = container.getItems();
items = wrapInDeploymentConfigs(items);
getLog().info("Wrapped in DeploymentConfigs:");
printSummary(items);
container.setItems(items);
KubernetesHelper.saveJson(json, container);
} else if (dto instanceof Template) {
Template container = (Template) dto;
List<HasMetadata> items = container.getObjects();
items = wrapInDeploymentConfigs(items);
getLog().info("Wrapped in DeploymentConfigs:");
printSummary(items);
container.setObjects(items);
getLog().info("Template is now:");
printSummary(container.getObjects());
KubernetesHelper.saveJson(json, container);
}
} catch (IOException e) {
throw new MojoExecutionException("Failed to save combined JSON files " + json + " and " + kubernetesExtraJson + " as " + json + ". " + e, e);
}
}
protected List<HasMetadata> wrapInDeploymentConfigs(List<HasMetadata> items) {
List<HasMetadata> answer = new ArrayList<>();
for (HasMetadata item : items) {
if (item instanceof ReplicationController) {
ReplicationController replicationController = (ReplicationController) item;
wrapInDeploymentConfigs(answer, replicationController);
} else {
answer.add(item);
}
}
return answer;
}
/**
* Wraps the given {@link ReplicationController} in a {@link DeploymentConfig} and adds it to the given list
* along with any other required entities
*/
protected void wrapInDeploymentConfigs(List<HasMetadata> list, ReplicationController replicationController) {
DeploymentConfigBuilder builder = new DeploymentConfigBuilder();
String name = getName(replicationController);
if (Strings.isNotBlank(name)) {
name = Strings.stripSuffix(name, "-controller");
}
if (Strings.isNullOrBlank(name)) {
name = getProject().getArtifactId();
}
String deploymentName = name;
String imageStream = name;
Map<String, String> labels = KubernetesHelper.getLabels(replicationController);
builder = builder.withNewMetadata().withName(deploymentName).withLabels(labels).endMetadata();
ReplicationControllerSpec spec = replicationController.getSpec();
if (spec != null) {
List<String> containerNames = new ArrayList<>();
PodTemplateSpec podTemplateSpec = spec.getTemplate();
if (podTemplateSpec != null) {
PodSpec podSpec = podTemplateSpec.getSpec();
if (podSpec != null) {
List<Container> containers = podSpec.getContainers();
if (containers != null) {
for (Container container : containers) {
String containerName = container.getName();
if (Strings.isNotBlank(containerName)) {
containerNames.add(containerName);
}
}
}
}
}
getOrAddImageStream(list, imageStream, labels);
builder = builder.withNewSpec().
withTemplate(podTemplateSpec).withReplicas(spec.getReplicas()).withSelector(spec.getSelector()).
withNewStrategy().
withType(deploymentStrategy).
endStrategy().
addNewTrigger().
withType("ImageChange").
withNewImageChangeParams().
withAutomatic(true).
withContainerNames(containerNames).
withNewFrom().withName(imageStream + ":" + lastTriggeredImageTag).endFrom().
withLastTriggeredImage(lastTriggeredImageTag).
endImageChangeParams().
endTrigger().
endSpec();
}
DeploymentConfig config = builder.build();
list.add(config);
}
protected ImageStream getOrAddImageStream(List<HasMetadata> list, String imageStreamName, Map<String, String> labels) {
for (HasMetadata item : list) {
if (item instanceof ImageStream) {
ImageStream stream = (ImageStream) item;
if (Objects.equal(imageStreamName, getName(stream))) {
return stream;
}
}
}
ImageStream imageStream = new ImageStreamBuilder().withNewMetadata().withName(imageStreamName).withLabels(labels).endMetadata().build();
list.add(imageStream);
return imageStream;
}
protected void generateKubernetesJson(File kubernetesJson) throws MojoExecutionException {
// TODO populate properties, project etc.
MavenProject project = getProject();
Map<String, String> labelMap = getLabels();
String name = getProjectName();
String group = getGroupName();
if (!labelMap.containsKey("version")) {
labelMap.put("version", project.getVersion());
}
if (!labelMap.containsKey("project") && Strings.isNotBlank(name)) {
labelMap.put("project", name);
}
if (!labelMap.containsKey("group") && Strings.isNotBlank(group)) {
labelMap.put("group", group);
}
if (!labelMap.containsKey("provider") && Strings.isNotBlank(provider)) {
labelMap.put("provider", provider);
}
Map<String,String> podSpecAnnotations = getPodSpecAnnotations();
Map<String,String> rcAnnotations = getRCAnnotations();
KubernetesListBuilder builder = new KubernetesListBuilder();
// lets add a ServiceAccount object if we add any new secret annotations
boolean addedServiceAcount = addServiceAccountIfIUsingSecretAnnotations(builder, podSpecAnnotations);
List<Volume> volumes = getVolumes();
List<VolumeMount> volumeMounts = getVolumeMounts();
Boolean containerPrivileged = getContainerPrivileged();
if (addedServiceAcount) {
addServiceConstraints(builder, volumes, containerPrivileged != null && containerPrivileged.booleanValue());
}
String iconUrl = getIconUrl();
if (Strings.isNotBlank(iconUrl)) {
rcAnnotations.put(FABRIC8_ICON_URL_ANNOTATION, iconUrl);
}
if (Utils.isNotNullOrEmpty(getDockerImage())) {
builder.addNewReplicationControllerItem()
.withNewMetadata()
.withName(KubernetesHelper.validateKubernetesId(replicationControllerName, "fabric8.replicationController.name"))
.withLabels(labelMap)
.withAnnotations(rcAnnotations)
.endMetadata()
.withNewSpec()
.withReplicas(replicaCount)
.withSelector(labelMap)
.withNewTemplate()
.withNewMetadata()
.withLabels(labelMap)
.withAnnotations(podSpecAnnotations)
.endMetadata()
.withNewSpec()
.withServiceAccountName(serviceAccount)
.addNewContainer()
.withName(getKubernetesContainerName())
.withImage(getDockerImage())
.withImagePullPolicy(getImagePullPolicy())
.withNewResources()
.addToLimits(CPU,new Quantity(limitsCpu))
.addToLimits(MEMORY,new Quantity(limitsMemory))
.addToRequests(CPU,new Quantity(requestsCpu))
.addToRequests(MEMORY,new Quantity(requestsMemory))
.endResources()
.withEnv(getEnvironmentVariables())
.withNewSecurityContext()
.withPrivileged(containerPrivileged)
.endSecurityContext()
.withPorts(getContainerPorts())
.withVolumeMounts(volumeMounts)
.withLivenessProbe(getLivenessProbe())
.withReadinessProbe(getReadinessProbe())
.endContainer()
.withVolumes(volumes)
.endSpec()
.endTemplate()
.endSpec()
.endReplicationControllerItem();
}
addPersistentVolumeClaims(builder, volumes);
addServices(builder, labelMap, iconUrl);
Template template = getTemplate();
if (!template.getParameters().isEmpty() || Strings.isNotBlank(iconUrl)) {
configureTemplateDescriptionAndIcon(template, iconUrl);
}
KubernetesList kubernetesList;
List<HasMetadata> items = null;
try {
items = builder.getItems();
} catch (Exception e) {
getLog().warn("Caught: " + e, e);
}
if (Lists.isNullOrEmpty(items)) {
getLog().warn("No Kubernetes resources found! Skipping...");
kubernetesList = new KubernetesList();
} else {
kubernetesList = builder.build();
}
Object result = Templates.combineTemplates(kubernetesList, template);
if (result instanceof Template) {
Template resultTemplate = (Template) result;
defaultIconUrl(resultTemplate.getObjects());
configureTemplateDescriptionAndIcon(resultTemplate, iconUrl);
if (pureKubernetes) {
try {
result = applyTemplates(resultTemplate);
} catch (IOException e) {
throw new MojoExecutionException("Failed to process template locally " + e, e);
}
}
}
try {
defaultIconUrl(KubernetesHelper.toItemList(result));
if (pureKubernetes) {
result = filterPureKubernetes(result);
}
ObjectMapper mapper = new ObjectMapper()
.enable(SerializationFeature.INDENT_OUTPUT);
String generated = mapper.writeValueAsString(result);
Files.writeToFile(kubernetesJson, generated, Charset.defaultCharset());
} catch (Exception e) {
throw new IllegalArgumentException("Failed to generate Kubernetes JSON.", e);
}
}
private void defaultIconUrl(List<HasMetadata> hasMetadatas) {
String iconUrl = getIconUrl();
if (Strings.isNotBlank(iconUrl)) {
for (HasMetadata entity : hasMetadatas) {
if (entity instanceof Service || entity instanceof ServiceAccount) {
Map<String, String> annotations = KubernetesHelper.getOrCreateAnnotations(entity);
if (Strings.isNullOrBlank(annotations.get(FABRIC8_ICON_URL_ANNOTATION))) {
annotations.put(FABRIC8_ICON_URL_ANNOTATION, iconUrl);
}
}
}
}
}
private void addServices(KubernetesListBuilder builder, Map<String, String> labelMap, String iconUrl) throws MojoExecutionException {
MavenProject project = getProject();
Properties properties = getProjectAndFabric8Properties(project);
Set<String> serviceNames = new HashSet<>(Arrays.asList(""));
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
Object key = entry.getKey();
if (key instanceof String) {
String s = (String) key;
Matcher m = SERVICE_PATTERN.matcher(s);
if (m.matches()) {
String name = m.group(NAME);
serviceNames.add(name);
}
}
}
for (String serviceName : serviceNames) {
Map<String, String> serviceAnnotations = getServiceAnnotations();
serviceAnnotations.putAll(getMetricsAnnotations(serviceName));
if (Strings.isNotBlank(this.iconUrl)) {
serviceAnnotations.put(FABRIC8_ICON_URL_ANNOTATION, this.iconUrl);
}
Map<String, String> selector = new HashMap<>(labelMap);
if (removeVersionLabelFromServiceSelector) {
if (selector.remove("version") != null) {
getLog().info("Removed 'version' label from service selector for service `" + serviceName + "`");
}
}
String tempServiceName = serviceName;
if (Strings.isNullOrBlank(tempServiceName)) {
tempServiceName = this.serviceName;
}
ServiceBuilder serviceBuilder = new ServiceBuilder()
.withNewMetadata()
.withName(tempServiceName)
.withLabels(labelMap)
.withAnnotations(serviceAnnotations)
.endMetadata();
ServiceFluent.SpecNested<ServiceBuilder> serviceSpecBuilder = serviceBuilder.withNewSpec().withSelector(selector);
List<ServicePort> servicePorts = getServicePorts(serviceName);
getLog().info("Generated ports: " + servicePorts);
boolean hasPorts = servicePorts != null && !servicePorts.isEmpty();
if (hasPorts) {
serviceSpecBuilder.withPorts(servicePorts);
}
String headlessPrefix = buildServicePrefix(serviceName, "fabric8.service", "headless");
Boolean tempHeadlessService = Boolean.valueOf(properties.getProperty(headlessPrefix));
if (tempHeadlessService) {
serviceSpecBuilder.withClusterIP("None");
// If this is a headless service with no ports then see if metrics is enabled & add that as a port - hacky!
if (!hasPorts && Boolean.parseBoolean(serviceAnnotations.get(metricsScrapeAnnotation))) {
try {
String port = serviceAnnotations.get(metricsPortAnnotation);
Integer metricsPort = Integer.parseInt(port);
if (metricsPort != null) {
ServicePort servicePort = new ServicePort();
servicePort.setPort(metricsPort);
servicePort.setTargetPort(new IntOrString(metricsPort));
serviceSpecBuilder.withPorts(Arrays.asList(servicePort));
}
} catch (NumberFormatException e) {
// Ignore this.
}
}
}
String specificServiceType = getServiceType(serviceName);
if (Strings.isNotBlank(specificServiceType)) {
serviceSpecBuilder.withType(specificServiceType);
}
serviceSpecBuilder.endSpec();
if (tempHeadlessService || hasPorts) {
builder = builder.addToServiceItems(serviceBuilder.build());
}
}
}
private Map<? extends String, ? extends String> getMetricsAnnotations(String serviceName) {
Map<String, String> metricsAnnotations = new HashMap<>();
boolean tempMetricsScrape;
Integer tempMetricsPort = null;
String tempMetricsScheme;
if (Strings.isNotBlank(serviceName)) {
Properties properties = getProjectAndFabric8Properties(getProject());
tempMetricsScrape = Boolean.parseBoolean(properties.getProperty(buildServicePrefix(serviceName, "fabric8.service", "metrics.scrape")));
tempMetricsScheme = properties.getProperty(buildServicePrefix(serviceName, "fabric8.service", "metrics.scheme"));
String port = properties.getProperty(buildServicePrefix(serviceName, "fabric8.service", "metrics.port"));
if (port != null) {
tempMetricsPort = Integer.parseInt(port);
}
} else {
tempMetricsScrape = metricsScrape;
tempMetricsScheme = metricsScheme;
tempMetricsPort = metricsPort;
}
if (tempMetricsScrape) {
metricsAnnotations.put(metricsScrapeAnnotation, Boolean.toString(tempMetricsScrape));
if (tempMetricsPort != null) {
metricsAnnotations.put(metricsPortAnnotation, tempMetricsPort.toString());
}
if (tempMetricsScheme != null) {
metricsAnnotations.put(metricsSchemeAnnotation, tempMetricsScheme);
}
}
return metricsAnnotations;
}
protected void addPersistentVolumeClaims(KubernetesListBuilder builder, List<Volume> volumes) {
for (Volume volume : volumes) {
PersistentVolumeClaimVolumeSource persistentVolumeClaim = volume.getPersistentVolumeClaim();
if (persistentVolumeClaim != null) {
String name = volume.getName();
String claimName = persistentVolumeClaim.getClaimName();
Boolean readOnly = persistentVolumeClaim.getReadOnly();
if (Strings.isNotBlank(claimName)) {
String accessModes;
if (readOnly != null && readOnly.booleanValue()) {
accessModes = "ReadOnly";
} else {
accessModes = "ReadWriteMany";
}
Properties properties = getProjectAndFabric8Properties(getProject());
String requestStorageProperty = String.format(VolumeType.VOLUME_PROPERTY, name, VolumeType.VOLUME_PVC_REQUEST_STORAGE);
String amount = properties.getProperty(requestStorageProperty);
if (Strings.isNullOrBlank(amount)) {
amount = defaultPersistentVolumeClaimRequestsStorage;
getLog().info("No maven property defined for `" + requestStorageProperty + "` so defaulting the requestStorage to " + amount);
} else {
getLog().debug("Maven property `" + requestStorageProperty + "` = " + amount);
}
Map<String, Quantity> requests = new HashMap<>();
Quantity requestLimit = new QuantityBuilder().withAmount(amount).build();
requests.put("storage", requestLimit);
builder.addNewPersistentVolumeClaimItem().
withNewMetadata().withName(claimName).endMetadata().
withNewSpec().withAccessModes(accessModes).withVolumeName(claimName).withNewResources().withRequests(requests).endResources().endSpec().
endPersistentVolumeClaimItem();
} else {
getLog().warn("No claimName for persistent volume " + volume);
}
}
}
}
protected boolean addServiceAccountIfIUsingSecretAnnotations(KubernetesListBuilder builder, Map<String, String> annotations) {
Set<String> secretAnnotations = new HashSet<>(Arrays.asList(
Annotations.Secrets.SSH_KEY,
Annotations.Secrets.SSH_PUBLIC_KEY,
Annotations.Secrets.GPG_KEY
));
Set<Map.Entry<String, String>> entries = annotations.entrySet();
Set<String> secretNameSet = new TreeSet<>();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
if (secretAnnotations.contains(key)) {
List<String> secretNames = parseSecretNames(value);
secretNameSet.addAll(secretNames);
}
}
List<ObjectReference> secrets = new ArrayList<>();
for (String secretName : secretNameSet) {
ObjectReference secretRef = new ObjectReferenceBuilder().withName(secretName).build();
secrets.add(secretRef);
}
if (!secrets.isEmpty() || createServiceAccount) {
if (Strings.isNullOrBlank(serviceAccount)) {
serviceAccount = getProject().getArtifactId();
}
builder.addNewServiceAccountItem()
.withNewMetadata().withName(serviceAccount).endMetadata()
.withSecrets(secrets)
.endServiceAccountItem();
return true;
}
return false;
}
protected void addServiceConstraints(KubernetesListBuilder builder, List<Volume> volumes, boolean containerPrivileged) {
if (generateSecurityContextConstraints) {
boolean hostVolume = hasHostVolume(volumes);
if (hostVolume || containerPrivileged) {
RunAsUserStrategyOptions runAsUser;
builder.addNewSecurityContextConstraintsItem().
withNewMetadata().withName(serviceAccount).endMetadata().
withAllowHostDirVolumePlugin(hostVolume).withAllowPrivilegedContainer(containerPrivileged).
withNewRunAsUser().withType("RunAsAny").endRunAsUser().
withNewSeLinuxContext().withType("RunAsAny").endSeLinuxContext().
withUsers("system:serviceaccount:" + getNamespace() + ":" + serviceAccount).
endSecurityContextConstraintsItem();
}
}
}
protected boolean hasHostVolume(List<Volume> volumes) {
if (volumes != null) {
for (Volume volume : volumes) {
HostPathVolumeSource hostPath = volume.getHostPath();
if (hostPath != null && Strings.isNotBlank(hostPath.getPath())) {
return true;
}
}
}
return false;
}
public static List<String> parseSecretNames(String value) {
// lets split by [...] first removing those out
List<String> answer = new ArrayList<>();
String[] split = value.split("\\[|\\]");
if (split != null && split.length > 0) {
int i = 0;
while (i < split.length) {
String name = split[i];
if (name.startsWith(",")) {
name = name.substring(1);
}
splitCommas(name, answer);
// ignore next which is the conetnts of the array
i += 2;
}
} else {
splitCommas(value, answer);
}
return answer;
}
private static void splitCommas(String value, List<String> answer) {
String[] split = value.split(",");
if (split != null && split.length > 0) {
answer.addAll(Arrays.asList(split));
} else {
answer.add(value);
}
}
protected void configureTemplateDescriptionAndIcon(Template template, String iconUrl) {
Map<String, String> annotations = KubernetesHelper.getOrCreateAnnotations(template);
addDocumentationAnnotations(template, annotations);
if (Strings.isNotBlank(iconUrl)) {
annotations.put(getTemplateKey(template, AnnotationKeys.ICON_URL), iconUrl);
}
}
protected String getTemplateKey(Template template, String key) {
String name = getName(template);
if (Strings.isNullOrBlank(name)) {
name = getProject().getArtifactId();
}
return AnnotationKeys.PREFIX + name + "/" + key;
}
protected void addDocumentationAnnotations(Template template, Map<String, String> annotations) {
// we want summary before description
try {
copySummaryText(templateTempDir);
copyReadMe(templateTempDir);
} catch (IOException e) {
getLog().warn("Failed to copy documentation: " + e, e);
}
File summary = new File(templateTempDir, "Summary.md");
if (summary.exists() && summary.isFile()) {
try {
String text = Files.toString(summary);
annotations.put(getTemplateKey(template, AnnotationKeys.SUMMARY), text);
} catch (IOException e) {
getLog().warn("Failed to load " + summary + ". " + e, e);
}
}
String description = null;
File readme = new File(templateTempDir, "ReadMe.md");
if (readme.exists() && readme.isFile()) {
try {
description = Files.toString(readme);
} catch (IOException e) {
getLog().warn("Failed to load " + readme + ". " + e, e);
}
}
if (description == null) {
description = getProject().getDescription();
}
if (Strings.isNotBlank(description)) {
annotations.put(AnnotationKeys.DESCRIPTION, description);
}
}
/**
* Generate a URL for the icon.
*
* Lets use a data URL if possible if the icon is relatively small; otherwise lets try convert the icon name
* to an external link (e.g. using github).
*/
protected String getIconUrl() {
String answer = iconUrl;
if (Strings.isNullOrBlank(answer)) {
try {
if (templateTempDir != null) {
templateTempDir.mkdirs();
File iconFile = copyIconToFolder(templateTempDir);
if (iconFile == null) {
copyAppConfigFiles(templateTempDir, appConfigDir);
// lets find the icon file...
for (String ext : ICON_EXTENSIONS) {
File file = new File(templateTempDir, "icon" + ext);
if (file.exists() && file.isFile()) {
iconFile = file;
break;
}
}
}
if (iconFile != null) {
answer = convertIconFileToURL(iconFile);
}
}
} catch (Exception e) {
getLog().warn("Failed to load icon file: " + e, e);
}
}
if (Strings.isNullOrBlank(answer)) {
// maybe its a common icon that is embedded in fabric8-console
String embeddedIcon = embeddedIconsInConsole(iconRef, "img/icons/");
if (embeddedIcon != null) {
return embeddedIcon;
}
}
if (Strings.isNullOrBlank(answer)) {
getLog().debug("No icon file found for this project");
} else {
getLog().info("Icon URL: " + answer);
}
return answer;
}
protected String convertIconFileToURL(File iconFile) throws IOException {
long length = iconFile.length();
int sizeK = Math.round(length / 1024);
byte[] bytes = Files.readBytes(iconFile);
byte[] encoded = Base64Encoder.encode(bytes);
int base64SizeK = Math.round(encoded.length / 1024);
if (base64SizeK < maximumDataUrlSizeK) {
String mimeType = guessMediaType(iconFile);
return "data:" + mimeType + ";charset=UTF-8;base64," + new String(encoded);
} else {
File iconSourceFile = new File(appConfigDir, iconFile.getName());
if (iconSourceFile.exists()) {
File rootProjectFolder = getRootProjectFolder();
if (rootProjectFolder != null) {
String relativePath = Files.getRelativePath(rootProjectFolder, iconSourceFile);
String relativeParentPath = Files.getRelativePath(rootProjectFolder, getProject().getBasedir());
String urlPrefix = iconUrlPrefix;
if (Strings.isNullOrBlank(urlPrefix)) {
Scm scm = getProject().getScm();
if (scm != null) {
String url = scm.getUrl();
if (url != null) {
String[] prefixes = {"http://github.com/", "https://github.com/"};
for (String prefix : prefixes) {
if (url.startsWith(prefix)) {
url = URLUtils.pathJoin("https://cdn.rawgit.com/", url.substring(prefix.length()));
break;
}
}
if (url.endsWith(relativeParentPath)) {
url = url.substring(0, url.length() - relativeParentPath.length());
}
urlPrefix = url;
}
}
}
if (Strings.isNullOrBlank(urlPrefix)) {
getLog().warn("No iconUrlPrefix defined or could be found via SCM in the pom.xml so cannot add an icon URL!");
} else {
String answer = URLUtils.pathJoin(urlPrefix, iconBranch, relativePath);
return answer;
}
}
} else {
String embeddedIcon = embeddedIconsInConsole(iconRef, "img/icons/");
if (embeddedIcon != null) {
return embeddedIcon;
} else {
getLog().warn("Cannot find url for icon to use " + iconUrl);
}
}
}
return null;
}
/**
* To use embedded icons provided by the fabric8-console
*
* @param iconRef name of icon file
* @param prefix prefix location for the icons in the fabric8-console
* @return the embedded icon ref, or <tt>null</tt> if no embedded icon found to be used
*/
protected String embeddedIconsInConsole(String iconRef, String prefix) {
if (iconRef == null) {
return null;
}
if (iconRef.startsWith("icons/")) {
iconRef = iconRef.substring(6);
}
// special for fabric8 as its in a different dir
if (iconRef.contains("fabric8")) {
return "img/fabric8_icon.svg";
}
if (iconRef.contains("activemq")) {
return prefix + "activemq.svg";
} else if (iconRef.contains("apiman")) {
return prefix + "apiman.png";
} else if (iconRef.contains("api-registry")) {
return prefix + "api-registry.svg";
} else if (iconRef.contains("brackets")) {
return prefix + "brackets.svg";
} else if (iconRef.contains("camel")) {
return prefix + "camel.svg";
} else if (iconRef.contains("chaos-monkey")) {
return prefix + "chaos-monkey.png";
} else if (iconRef.contains("docker-registry")) {
return prefix + "docker-registry.png";
} else if (iconRef.contains("elasticsearch")) {
return prefix + "elasticsearch.png";
} else if (iconRef.contains("fluentd")) {
return prefix + "fluentd.png";
} else if (iconRef.contains("forge")) {
return prefix + "forge.svg";
} else if (iconRef.contains("gerrit")) {
return prefix + "gerrit.png";
} else if (iconRef.contains("gitlab")) {
return prefix + "gitlab.svg";
} else if (iconRef.contains("gogs")) {
return prefix + "gogs.png";
} else if (iconRef.contains("grafana")) {
return prefix + "grafana.png";
} else if (iconRef.contains("hubot-irc")) {
return prefix + "hubot-irc.png";
} else if (iconRef.contains("hubot-letschat")) {
return prefix + "hubot-letschat.png";
} else if (iconRef.contains("hubot-notifier")) {
return prefix + "hubot-notifier.png";
} else if (iconRef.contains("hubot-slack")) {
return prefix + "hubot-slack.png";
} else if (iconRef.contains("image-linker")) {
return prefix + "image-linker.svg";
} else if (iconRef.contains("javascript")) {
return prefix + "javascript.png";
} else if (iconRef.contains("java")) {
return prefix + "java.svg";
} else if (iconRef.contains("jenkins")) {
return prefix + "jenkins.svg";
} else if (iconRef.contains("jetty")) {
return prefix + "jetty.svg";
} else if (iconRef.contains("karaf")) {
return prefix + "karaf.svg";
} else if (iconRef.contains("keycloak")) {
return prefix + "keycloak.svg";
} else if (iconRef.contains("kibana")) {
return prefix + "kibana.svg";
} else if (iconRef.contains("kiwiirc")) {
return prefix + "kiwiirc.png";
} else if (iconRef.contains("letschat")) {
return prefix + "letschat.png";
} else if (iconRef.contains("mule")) {
return prefix + "mule.svg";
} else if (iconRef.contains("nexus")) {
return prefix + "nexus.png";
} else if (iconRef.contains("node")) {
return prefix + "node.svg";
} else if (iconRef.contains("orion")) {
return prefix + "orion.png";
} else if (iconRef.contains("prometheus")) {
return prefix + "prometheus.png";
} else if (iconRef.contains("django") || iconRef.contains("python")) {
return prefix + "python.png";
} else if (iconRef.contains("spring-boot")) {
return prefix + "spring-boot.svg";
} else if (iconRef.contains("taiga")) {
return prefix + "taiga.png";
} else if (iconRef.contains("tomcat")) {
return prefix + "tomcat.svg";
} else if (iconRef.contains("tomee")) {
return prefix + "tomee.svg";
} else if (iconRef.contains("vertx")) {
return prefix + "vertx.svg";
} else if (iconRef.contains("wildfly")) {
return prefix + "wildfly.svg";
} else if (iconRef.contains("weld")) {
return prefix + "weld.svg";
} else if (iconRef.contains("zipkin")) {
return prefix + "zipkin.png";
}
return null;
}
protected Probe getLivenessProbe() {
return getProbe("fabric8.livenessProbe");
}
protected Probe getReadinessProbe() {
return getProbe("fabric8.readinessProbe");
}
protected Probe getProbe(String prefix) {
Probe probe = new Probe();
Properties properties = getProjectAndFabric8Properties(getProject());
Integer initialDelaySeconds = getInteger(properties, prefix + ".initialDelaySeconds");
if (initialDelaySeconds != null) {
probe.setInitialDelaySeconds(initialDelaySeconds);
}
Integer timeoutSeconds = getInteger(properties, prefix + ".timeoutSeconds");
if (timeoutSeconds != null) {
probe.setTimeoutSeconds(timeoutSeconds);
}
HTTPGetAction httpGetAction = getHTTPGetAction(prefix, properties);
if (httpGetAction != null) {
probe.setHttpGet(httpGetAction);
return probe;
}
ExecAction execAction = getExecAction(prefix, properties);
if (execAction != null) {
probe.setExec(execAction);
return probe;
}
TCPSocketAction tcpSocketAction = getTCPSocketAction(prefix, properties);
if (tcpSocketAction != null) {
probe.setTcpSocket(tcpSocketAction);
return probe;
}
return null;
}
private HTTPGetAction getHTTPGetAction(String prefix, Properties properties) {
HTTPGetAction action = null;
String httpGetPath = properties.getProperty(prefix + ".httpGet.path");
String httpGetPort = properties.getProperty(prefix + ".httpGet.port");
String httpGetHost = properties.getProperty(prefix + ".httpGet.host");
String httpGetScheme = properties.getProperty(prefix + ".httpGet.scheme");
if (Strings.isNotBlank(httpGetPath)) {
action = new HTTPGetAction();
action.setPath(httpGetPath);
action.setHost(httpGetHost);
if (Strings.isNotBlank(httpGetScheme)) {
action.setScheme(httpGetScheme.toUpperCase());
}
if (Strings.isNotBlank(httpGetPort)) {
IntOrString httpGetPortIntOrString = KubernetesHelper.createIntOrString(httpGetPort);
action.setPort(httpGetPortIntOrString);
}
}
return action;
}
private TCPSocketAction getTCPSocketAction(String prefix, Properties properties) {
TCPSocketAction action = null;
String port = properties.getProperty(prefix + ".port");
if (Strings.isNotBlank(port)) {
IntOrString portObj = new IntOrString();
try {
Integer portInt = Integer.parseInt(port);
portObj.setIntVal(portInt);
} catch (NumberFormatException e) {
portObj.setStrVal(port);
}
action = new TCPSocketAction(portObj);
}
return action;
}
private ExecAction getExecAction(String prefix, Properties properties) {
ExecAction action = null;
String execCmd = properties.getProperty(prefix + ".exec");
if (Strings.isNotBlank(execCmd)) {
List<String> splitCommandLine = Commandline.translateCommandline(execCmd);
if (!splitCommandLine.isEmpty()) {
action = new ExecAction(splitCommandLine);
}
}
return action;
}
public Boolean getContainerPrivileged() {
return containerPrivileged;
}
public String getImagePullPolicy() {
MavenProject project = getProject();
String pullPolicy = imagePullPolicy;
if (project != null) {
String version = project.getVersion();
if (Strings.isNullOrBlank(pullPolicy)) {
if (version != null && version.endsWith("SNAPSHOT")) {
// TODO pullPolicy = "PullAlways";
pullPolicy = imagePullPolicySnapshot;
}
}
}
return pullPolicy;
}
public String getKubernetesContainerName() {
if (Strings.isNullOrBlank(kubernetesContainerName)) {
// lets generate it from the docker user and the camelCase artifactId
String groupPrefix = null;
MavenProject project = getProject();
String imageName = getDockerImage();
if (Strings.isNotBlank(imageName)) {
String[] paths = imageName.split("/");
if (paths != null) {
if (paths.length == 2) {
groupPrefix = paths[0];
} else if (paths.length == 3) {
groupPrefix = paths[1];
}
}
}
if (Strings.isNullOrBlank(groupPrefix)) {
groupPrefix = project.getGroupId();
}
kubernetesContainerName = groupPrefix + "-" + project.getArtifactId();
}
return kubernetesContainerName;
}
public void setKubernetesContainerName(String kubernetesContainerName) {
this.kubernetesContainerName = kubernetesContainerName;
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public String getCombineProjectName() {
return combineProjectName;
}
public void setCombineProjectName(String combineProjectName) {
this.combineProjectName = combineProjectName;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public Map<String, Integer> getDefaultContainerPortMap() {
if (defaultContainerPortMap == null) {
defaultContainerPortMap = new HashMap<>();
}
if (defaultContainerPortMap.isEmpty()) {
// lets populate default values
defaultContainerPortMap.put("jolokia", 8778);
defaultContainerPortMap.put("web", 8080);
}
return defaultContainerPortMap;
}
public void setDefaultContainerPortMap(Map<String, Integer> defaultContainerPortMap) {
this.defaultContainerPortMap = defaultContainerPortMap;
}
public List<ContainerPort> getContainerPorts() {
if (containerPorts == null) {
containerPorts = new ArrayList<>();
}
if (containerPorts.isEmpty()) {
Map<String, ContainerPort> portMap = new HashMap<>();
Properties properties1 = getProjectAndFabric8Properties(getProject());
Map<String, String> hostPorts = findPropertiesWithPrefix(properties1, FABRIC8_PORT_HOST_PREFIX);
Properties properties = getProjectAndFabric8Properties(getProject());
Map<String, String> containerPortsMap = findPropertiesWithPrefix(properties, FABRIC8_PORT_CONTAINER_PREFIX);
for (Map.Entry<String, String> entry : containerPortsMap.entrySet()) {
String name = entry.getKey();
String portText = entry.getValue();
Integer portNumber = parsePort(portText, FABRIC8_PORT_CONTAINER_PREFIX + name);
if (portNumber != null) {
ContainerPort port = getOrCreatePort(portMap, name);
port.setContainerPort(portNumber);
port.setName(name);
}
}
for (Map.Entry<String, String> entry : hostPorts.entrySet()) {
String name = entry.getKey();
String portText = entry.getValue();
Integer portNumber = parsePort(portText, FABRIC8_PORT_HOST_PREFIX + name);
if (portNumber != null) {
ContainerPort port = getOrCreatePort(portMap, name);
port.setHostPort(portNumber);
// if the container port isn't set, lets try default that using defaults
if (port.getContainerPort() == null) {
port.setContainerPort(getDefaultContainerPortMap().get(name));
}
}
}
getLog().info("Generated port mappings: " + portMap);
getLog().debug("from host ports: " + hostPorts);
getLog().debug("from containerPorts ports: " + containerPorts);
containerPorts.addAll(portMap.values());
}
return containerPorts;
}
protected static ContainerPort getOrCreatePort(Map<String, ContainerPort> portMap, String name) {
ContainerPort answer = portMap.get(name);
if (answer == null) {
answer = new ContainerPort();
portMap.put(name, answer);
answer.setName(name);
}
return answer;
}
private String buildServicePrefix(String name, String prefix, String suffix) {
String servicePrefix = prefix;
if (Strings.isNotBlank(name)) {
servicePrefix += "." + name;
}
return servicePrefix + "." + suffix;
}
private List<ServicePort> getServicePorts(String serviceName) throws MojoExecutionException {
String servicePortPrefix = buildServicePrefix(serviceName, "fabric8.service", "port");
String serviceContainerPortPrefix = buildServicePrefix(serviceName, "fabric8.service", "containerPort");
String serviceNodePortPrefix = buildServicePrefix(serviceName, "fabric8.service", "nodePort");
String serviceProtocolPrefix = buildServicePrefix(serviceName, "fabric8.service", "protocol");
Properties properties1 = getProjectAndFabric8Properties(getProject());
List<ServicePort> servicePorts = new ArrayList<>();
Map<String, String> servicePortProperties = findPropertiesWithPrefix(properties1, servicePortPrefix + ".");
Map<String, String> serviceContainerPortProperties = findPropertiesWithPrefix(properties1, serviceContainerPortPrefix + ".");
Map<String, String> serviceNodePortProperties = findPropertiesWithPrefix(properties1, serviceNodePortPrefix + ".");
Map<String, String> serviceProtocolProperties = findPropertiesWithPrefix(properties1, serviceProtocolPrefix + ".");
for (Map.Entry<String, String> entry : servicePortProperties.entrySet()) {
String name = entry.getKey();
String servicePortText = entry.getValue();
Integer servicePortNumber = parsePort(servicePortText, servicePortPrefix + name);
if (servicePortNumber != null) {
String containerPort = serviceContainerPortProperties.get(name);
if (Strings.isNullOrBlank(containerPort)) {
getLog().warn("Missing container port for service - need to specify " + serviceContainerPortPrefix + name + " property");
} else {
ServicePort servicePort = new ServicePort();
servicePort.setName(name);
servicePort.setPort(servicePortNumber);
IntOrString containerPortSpec = getPortSpec(containerPort, serviceContainerPortPrefix, name);
servicePort.setTargetPort(containerPortSpec);
String nodePort = serviceNodePortProperties.get(name);
if (nodePort != null) {
IntOrString nodePortSpec = getPortSpec(nodePort, serviceNodePortPrefix, name);
Integer nodePortInt = nodePortSpec.getIntVal();
if (nodePortInt != null) {
servicePort.setNodePort(nodePortInt);
}
}
String portProtocol = serviceProtocolProperties.get(name);
if (portProtocol != null) {
servicePort.setProtocol(portProtocol);
}
servicePorts.add(servicePort);
}
}
}
Integer tempPort;
String tempContainerPort;
Integer tempNodePort;
String tempServiceProtocol;
if (Strings.isNotBlank(serviceName)) {
tempPort = parsePort(properties1.getProperty(servicePortPrefix), servicePortPrefix);
tempContainerPort = properties1.getProperty(serviceContainerPortPrefix);
tempNodePort = parsePort(properties1.getProperty(serviceNodePortPrefix), serviceNodePortPrefix);
tempServiceProtocol = properties1.getProperty(serviceProtocolPrefix, "TCP");
} else {
tempPort = servicePort;
tempContainerPort = serviceContainerPort;
tempNodePort = serviceNodePort;
tempServiceProtocol = serviceProtocol;
}
if (tempContainerPort != null || tempPort != null) {
if (servicePorts.size() > 0) {
throw new MojoExecutionException("Multi-port services must use the " + servicePortPrefix + "<name> format");
}
ServicePort actualServicePort = new ServicePort();
IntOrString containerPort = getPortSpec(tempContainerPort, serviceContainerPortPrefix, null);
actualServicePort.setTargetPort(containerPort);
actualServicePort.setPort(tempPort);
if (tempNodePort != null) {
actualServicePort.setNodePort(tempNodePort);
}
if (tempServiceProtocol != null) {
actualServicePort.setProtocol(tempServiceProtocol);
servicePorts.add(actualServicePort);
}
}
return servicePorts;
}
private IntOrString getPortSpec(String portText, String portServicePrefix, String name) {
IntOrString portSpec = new IntOrString();
String portServiceName = portServicePrefix;
if (name != null) {
portServiceName = portServicePrefix + name;
}
Integer portNumber = parsePort(portText, portServiceName);
if (portNumber != null) {
portSpec.setIntVal(portNumber);
} else {
portSpec.setStrVal(portText);
}
return portSpec;
}
private String getServiceType(String serviceName) throws MojoExecutionException {
String serviceSpecificTypeName = buildServicePrefix(serviceName, "fabric8.service", "type");
Properties properties = getProjectAndFabric8Properties(getProject());
String serviceSpecificType = properties.getProperty(serviceSpecificTypeName);
if (Strings.isNullOrBlank(serviceSpecificType)) {
serviceSpecificType = this.serviceType;
}
return serviceSpecificType;
}
protected static EnvVar getOrCreateEnv(Map<String, EnvVar> envMap, String name) {
EnvVar answer = envMap.get(name);
if (answer == null) {
answer = new EnvVar();
envMap.put(name, answer);
}
return answer;
}
protected Integer parsePort(String portText, String propertyName) {
if (Strings.isNotBlank(portText)) {
try {
return Integer.parseInt(portText);
} catch (NumberFormatException e) {
getLog().debug("Failed to parse port text: " + portText + " from maven property " + propertyName + ". " + e, e);
}
}
return null;
}
public void setContainerPorts(List<ContainerPort> ports) {
this.containerPorts = ports;
}
public void setServicePorts(List<ServicePort> ports) {
this.servicePorts = ports;
}
public Map<String, String> getLabels() {
if (labels == null) {
labels = new HashMap<>();
}
if (labels.isEmpty()) {
labels = findPropertiesWithPrefix(getProjectAndFabric8Properties(getProject()), "fabric8.label.", Strings.toLowerCaseFunction());
}
return labels;
}
public Map<String, String> getPodSpecAnnotations() throws MojoExecutionException {
if (podSpecAnnotations == null) {
podSpecAnnotations = loadAnnotations(podSpecAnnotationsFile, "fabric8.annotations.podSpec.", "PodSpec");
}
return podSpecAnnotations;
}
public Map<String, String> getRCAnnotations() throws MojoExecutionException {
if (rcAnnotations == null) {
rcAnnotations = loadAnnotations(rcAnnotationsFile, "fabric8.annotations.rc.", "RC");
}
return rcAnnotations;
}
public Map<String, String> getTemplateAnnotations() throws MojoExecutionException {
if (templateAnnotations == null) {
templateAnnotations = loadAnnotations(templateAnnotationsFile, "fabric8.annotations.template.", "Template");
}
return templateAnnotations;
}
public Map<String, String> getServiceAnnotations() throws MojoExecutionException {
Map<String, String> serviceAnnotations = loadAnnotations(serviceAnnotationsFile, "fabric8.annotations.service.", "Service");
return serviceAnnotations;
}
protected Map<String, String> loadAnnotations(File annotationsFile, String propertiesPrefix, String annotationsName) throws MojoExecutionException {
Map<String, String> answer = findPropertiesWithPrefix(getProjectAndFabric8Properties(getProject()), propertiesPrefix, Strings.toLowerCaseFunction());
if (annotationsFile != null && annotationsFile.exists() && annotationsFile.isFile()) {
try {
Properties properties = new Properties();
properties.load(new FileInputStream(annotationsFile));
Map<String, String> fileAnnotations = PropertiesHelper.toMap(properties);
answer.putAll(fileAnnotations);
} catch (IOException e) {
throw new MojoExecutionException("Failed to load podSpecAnnotationsFile properties file " + podSpecAnnotationsFile + ". " + e, e);
}
}
//kubernetes annotation keys can be prefixed by namespace like namespace/name, but
//xml tags can't contain slashes. So by convention we will change the last "." into a "/".
//for example 'apiman.io.servicepath' will be turned into 'apiman.io/servicepath'
Map<String, String> newAnswer = new HashMap<String,String>();
for (String key: answer.keySet()) {
int lastDot = key.lastIndexOf(".");
if (! key.contains("/") && lastDot > 0) {
String namespace = key.substring(0, lastDot);
String name = key.substring(lastDot + 1);
newAnswer.put(namespace + "/" + name, answer.get(key));
} else {
newAnswer.put(key, answer.get(key));
}
}
return newAnswer;
}
public List<EnvVar> getEnvironmentVariables() throws MojoExecutionException {
if (environmentVariables == null) {
environmentVariables = new ArrayList<EnvVar>();
}
if (environmentVariables.isEmpty()) {
Map<String, EnvVar> envMap = new HashMap<>();
Map<String, String> envs = getExportedEnvironmentVariables();
for (Map.Entry<String, String> entry : envs.entrySet()) {
String name = entry.getKey();
String value = entry.getValue();
if (name != null) {
EnvVar env = getOrCreateEnv(envMap, name);
env.setName(name);
if (env.getValue() == null) {
env.setValue(value);
}
}
}
getLog().info("Generated env mappings: " + envMap);
getLog().debug("from envs: " + envs);
environmentVariables.addAll(envMap.values());
}
if (includeNamespaceEnvVar) {
environmentVariables.add(
new EnvVarBuilder().withName(kubernetesNamespaceEnvVar).
withNewValueFrom().withNewFieldRef().
withFieldPath("metadata.namespace").endFieldRef().
endValueFrom().
build());
}
if (includePodEnvVar) {
environmentVariables.add(
new EnvVarBuilder().withName(kubernetesPodEnvVar).
withNewValueFrom().withNewFieldRef().
withFieldPath("metadata.name").endFieldRef().
endValueFrom().
build());
}
return environmentVariables;
}
public Map<String, String> getExportedEnvironmentVariables() throws MojoExecutionException {
if (includeAllEnvironmentVariables) {
try {
JsonSchema schema = getEnvironmentVariableJsonSchema();
Map<String, String> answer = new TreeMap<>();
Map<String, JsonSchemaProperty> properties = schema.getProperties();
Set<Map.Entry<String, JsonSchemaProperty>> entries = properties.entrySet();
for (Map.Entry<String, JsonSchemaProperty> entry : entries) {
String name = entry.getKey();
String value = entry.getValue().getDefaultValue();
if (value == null) {
value = "";
}
answer.put(name, value);
}
Map<String, String> mavenEnvVars = getEnvironmentVariableProperties();
answer.putAll(mavenEnvVars);
return answer;
} catch (IOException e) {
throw new MojoExecutionException("Failed to load environment variable json schema files: " + e, e);
}
} else {
return getEnvironmentVariableProperties();
}
}
public List<VolumeMount> getVolumeMounts() {
List<VolumeMount> volumeMount = new ArrayList<>();
MavenProject project = getProject();
for (Map.Entry<Object, Object> entry : getProjectAndFabric8Properties(project).entrySet()) {
Object key = entry.getKey();
if (key instanceof String) {
String s = (String) key;
Matcher m = VOLUME_PATTERN.matcher(s);
if (m.matches()) {
String name = m.group(NAME);
String type = m.group(ATTRIBUTE_TYPE);
if (type.equals(VOLUME_MOUNT_PATH)) {
String path = String.valueOf(entry.getValue());
volumeMount.add(new VolumeMountBuilder()
.withName(name)
.withMountPath(path)
.withReadOnly(false).build());
}
}
}
}
return volumeMount;
}
public List<Volume> getVolumes() {
List<Volume> volumes = new ArrayList<>();
MavenProject project = getProject();
Properties properties = getProjectAndFabric8Properties(project);
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
Object key = entry.getKey();
if (key instanceof String) {
String s = (String) key;
Matcher m = VOLUME_PATTERN.matcher(s);
if (m.matches()) {
String name = m.group(NAME);
String type = m.group(ATTRIBUTE_TYPE);
VolumeType volumeType = VolumeType.typeFor(type);
if (volumeType != null) {
volumes.add(volumeType.fromProperties(name, properties));
}
}
}
}
return volumes;
}
public Template getTemplate() throws MojoExecutionException {
List<io.fabric8.openshift.api.model.Parameter> parameters = new ArrayList<>();
MavenProject project = getProject();
Properties projectProperties = getProjectAndFabric8Properties(getProject());
Set<String> paramNames = new HashSet<>();
if (templateParametersPropertiesFile != null && templateParametersPropertiesFile.isFile() && templateParametersPropertiesFile.exists()) {
final String valuePostfix = ".value";
final String descriptionPostfix = ".description";
try {
Properties properties = new Properties();
properties.load(new FileInputStream(templateParametersPropertiesFile));
// lets append the prefix
Set<Object> keys = properties.keySet();
Properties prefixedProperties = new Properties();
for (Object key : keys) {
if (key != null) {
String name = key.toString();
String value = properties.getProperty(name);
prefixedProperties.put(PARAMETER_PREFIX + "." + name, value);
}
}
loadParametersFromProperties(prefixedProperties, parameters, paramNames);
} catch (IOException e) {
throw new MojoExecutionException("Failed to load templateParameters properties file " + templateParametersPropertiesFile + ". " + e, e);
}
}
loadParametersFromProperties(projectProperties, parameters, paramNames);
String templateName = projectProperties.containsKey(TEMPLATE_NAME) ?
String.valueOf(projectProperties.getProperty(TEMPLATE_NAME)) :
project.getArtifactId();
Template template = new Template();
template.setMetadata(new ObjectMetaBuilder().withName(templateName).withAnnotations(getTemplateAnnotations()).build());
template.setParameters(parameters);
return template;
}
protected void loadParametersFromProperties(Properties properties, List<io.fabric8.openshift.api.model.Parameter> parameters, Set<String> paramNames) {
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
Object key = entry.getKey();
if (key instanceof String) {
String s = (String) key;
Matcher m = PARAM_PATTERN.matcher(s);
if (m.matches()) {
String name = m.group(NAME);
if (paramNames.add(name)) {
String value = properties.getProperty(String.format(PARAMETER_PROPERTY, name, VALUE));
String from = properties.getProperty(String.format(PARAMETER_PROPERTY, name, FROM));
String description = properties.getProperty(String.format(PARAMETER_PROPERTY, name, DESCRIPTION));
String generate = properties.getProperty(String.format(PARAMETER_PROPERTY, name, GENERATE));
//If neither value nor from has been specified read the value inline.
if (Strings.isNullOrBlank(value) && Strings.isNullOrBlank(from)) {
value = properties.getProperty(String.format(PARAMETER_NAME_PREFIX, name));
}
getLog().info("Found Template parameter: " + name +
labelValueOrBlank("value", value) +
labelValueOrBlank("from", from) +
labelValueOrBlank("generate", generate) +
labelValueOrBlank("description", description));
parameters.add(new ParameterBuilder()
.withName(name)
.withFrom(from)
.withValue(value)
.withGenerate(generate)
.withDescription(description)
.build());
}
}
}
}
}
private String labelValueOrBlank(String label, String value) {
if (Strings.isNotBlank(value)) {
return " " + label + ": " + value;
} else {
return "";
}
}
public void setLabels(Map<String, String> labels) {
this.labels = labels;
}
protected static void addIfNotDefined(Map<String, Object> variables, String key, String value) {
if (!variables.containsKey(key)) {
variables.put(key, value);
}
}
}