
org.distributeme.servicebuilder.mojo.ServiceMojo Maven / Gradle / Ivy
package org.distributeme.servicebuilder.mojo;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
import net.anotheria.util.IOUtils;
import net.anotheria.util.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* TODO comment this class
*
* @author lrosenberg
* @since 14/02/2017 13:40
*/
@Mojo(name="service")
public class ServiceMojo extends AbstractMojo {
@Parameter
private File definitionsFile;
@Parameter
private String dockerImageName;
@Parameter
private String outputDirectory = "distribution";
@Parameter
private String dockerOutputDirectory = "docker";
@Parameter
private String binDirectoryName = "bin";
private String libDirectoryName = "lib";
private String confDirectoryName = "conf";
private String logDirectoryName = "logs";
private String locallibDirectoryName = "locallib";
private String localconfDirectoryName = "localconf";
@Parameter
private String pathToEnvironmentSh;
@Parameter
private String dockerRepository;
private HashMap> knownProfiles = new HashMap<>();
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
getLog().info( "Building distributeme-based services." );
if (definitionsFile == null){
getLog().info("Definition file is null");
throw new MojoExecutionException("Can't process definition file, it is not set");
}
if (!definitionsFile.exists()){
getLog().info("Definition file doesn't exists - " + definitionsFile.getAbsolutePath());
throw new MojoExecutionException("Can't process definition file, it doesn't exists "+definitionsFile.getAbsolutePath());
}
byte[] fileData = null;
try {
fileData = IOUtils.readFileAtOnce(definitionsFile);
}catch(IOException e){
throw new MojoExecutionException("Can't read file "+definitionsFile.getAbsolutePath(), e);
}
JsonParser jsonParser = new JsonParser();
JsonObject jo = (JsonObject)jsonParser.parse(new String(fileData));
//read profiles
JsonArray profiles = jo.getAsJsonArray("profiles");
for (int i=0; i());
}
JsonArray jsonArr = jo.getAsJsonArray("services");
Gson gson = new GsonBuilder().create();
Type listType = new TypeToken>() {}.getType();
ArrayList list = gson.fromJson(jsonArr, listType);
for (ServiceEntry entry : list){
try{
generateService(entry);
}catch(IOException ex){
throw new MojoExecutionException("Can't create service "+entry.getName(), ex);
}
}
//generate generic start script for all services.
try{
generateCommonPart();
}catch(IOException ex){
throw new MojoExecutionException("Can't create common directories", ex);
}
//generate generic scripts for docker service instances.
if (!StringUtils.isEmpty(dockerImageName)) {
try {
generateDocker(list);
}catch(IOException e){
throw new MojoExecutionException("Can't create docker directories and content", e);
}
}
}
private void generateDocker(ArrayList services) throws IOException{
getLog().info("Generating docker files");
String target = "target/"+dockerOutputDirectory+"/";
File targetDirFile = new File(target);
if (!targetDirFile.exists()){
targetDirFile.mkdirs();
}
String containerDir = target+"service/";
String scriptsDir = target+"scripts/";
File containerDirFile = new File(containerDir); containerDirFile.mkdirs();
File scriptsDirFile = new File(scriptsDir); scriptsDirFile.mkdirs();
writeOutScript(containerDirFile, "docker/start.sh", "start.sh");
writeOutScript(containerDirFile, "docker/Dockerfile", "Dockerfile");
writeOutScript(containerDirFile, "docker/.profile", ".profile");
writeOutScript(containerDirFile, "docker/java.policy", "java.policy");
File lib = new File(containerDir + libDirectoryName); lib.mkdirs();
File conf = new File(containerDir + confDirectoryName); conf.mkdirs();
for (ServiceEntry service : services){
String scriptsContainerDir = scriptsDir + service.getName() + "/";
new File(scriptsContainerDir).mkdirs();
new File(scriptsContainerDir + "logs").mkdirs();
File envFile = new File(scriptsContainerDir + service.getName() + ".env");
FileOutputStream fOutEnvFile = new FileOutputStream(envFile);
fOutEnvFile.write(("SERVICE_CLASS="+service.getStartClass()+"\n").getBytes());
fOutEnvFile.write(("SERVICE_PORT="+service.getRmiPort()+"\n").getBytes());
fOutEnvFile.write(("JVM_OPTIONS="+service.getJvmOptions()+"\n").getBytes());
fOutEnvFile.write(("GOOGLE_APPLICATION_CREDENTIALS_FILE=" + service.getGoogleApplicationCredentialsFile() + "\n").getBytes());
fOutEnvFile.close();
File startFile = new File(scriptsContainerDir + "start_container.sh");
FileOutputStream fOutStartFile = new FileOutputStream(startFile);
fOutStartFile.write("#!/bin/bash\n".getBytes());
fOutStartFile.write("if [ -z \"$1\" ] || [ \"$1\" == \"null\" ]; then\n".getBytes());
fOutStartFile.write(" tagName=\"latest\"\n".getBytes());
fOutStartFile.write("else\n".getBytes());
fOutStartFile.write(" tagName=\"$1\"\n".getBytes());
fOutStartFile.write("fi\n\n".getBytes());
fOutStartFile.write("source ../environment.sh\n".getBytes());
fOutStartFile.write(("docker run -d --env CONFIGUREME_ENVIRONMENT=$CONFIGUREME_ENVIRONMENT " +
" -v `pwd`/logs:/app/logs " +
" $DOCKER_CONTAINER_OPTS " +
" --cidfile "+service.getName()+".cid "+
" --env SERVICE_REGISTRATION_IP=$SERVICE_REGISTRATION_IP --env-file "+service.getName()+".env -p "+service.getRmiPort()+":"+service.getRmiPort()+
" --name "+service.getName()+" " + (StringUtils.isEmpty(dockerRepository) ? "" : (dockerRepository + "/")) + dockerImageName + ":$tagName"
+"\n").getBytes());
fOutStartFile.close();
startFile.setExecutable(true);
File stopFile = new File(scriptsContainerDir + "stop_container.sh");
FileOutputStream fOutStopFile = new FileOutputStream(stopFile);
fOutStopFile.write("#!/bin/bash\n".getBytes());
fOutStopFile.write(("CIDFILE=" + service.getName() + ".cid\n").getBytes());
fOutStopFile.write("echo stopping $CIDFILE - `cat $CIDFILE`\n".getBytes());
fOutStopFile.write("docker container stop `cat $CIDFILE`\n".getBytes());
fOutStopFile.write("docker container rm `cat $CIDFILE`\n".getBytes());
fOutStopFile.write(("rm " + service.getName() + ".cid\n").getBytes());
fOutStopFile.write(("echo stopped " + service.getName() + "\n").getBytes());
fOutStopFile.close();
stopFile.setExecutable(true);
}
createSymbolicLinkForEnvironment(scriptsDir);
writeOutGenericScripts(scriptsDirFile, "./start_container.sh", "./stop_container.sh");
}
public File getDefinitionsFile() {
return definitionsFile;
}
public void setDefinitionsFile(File definitionsFile) {
this.definitionsFile = definitionsFile;
}
protected void generateCommonPart() throws IOException{
//common part for all services scripts
File bin = new File("target/"+outputDirectory+"/" + binDirectoryName); bin.mkdirs();
File lib = new File("target/"+outputDirectory+"/" + libDirectoryName); lib.mkdirs();
File conf = new File("target/"+outputDirectory+"/" + confDirectoryName); conf.mkdirs();
createSymbolicLinkForEnvironment("target/"+outputDirectory+"/");
writeOutScript(bin, "start.sh");
writeOutScript(bin, "stop.sh");
writeOutGenericScripts(bin, "bin/start_service.sh", "bin/stop_service.sh");
}
private void createSymbolicLinkForEnvironment(String targetDir) throws IOException {
Path envLinkTarget = Paths.get(pathToEnvironmentSh);
Path envLinksource = Paths.get(targetDir + "environment.sh");
try {
Files.createSymbolicLink(envLinksource, envLinkTarget);
}catch(FileAlreadyExistsException toignore){
getLog().info("symlink "+envLinksource+" already exists, skipping");
}
}
protected void generateService(ServiceEntry entry) throws IOException{
//add service to the corresponding profile service list.
List serviceProfiles = entry.getProfiles();
for (String p : serviceProfiles){
List servicesForProfile = knownProfiles.get(p);
if (serviceProfiles == null)
throw new RuntimeException("Can't find profile '"+p+"' for service '"+entry.getName()+"'");
servicesForProfile.add(entry.getName());
}
String target = "target/"+outputDirectory+"/"+entry.getName()+"/";
String common = "../";
File log = new File(target + logDirectoryName); log.mkdirs();
File localLib = new File(target + locallibDirectoryName); localLib.mkdirs();
File localConf = new File(target + localconfDirectoryName); localConf.mkdirs();
File bin = new File(target + binDirectoryName); bin.mkdirs();
Path libLinkTarget = Paths.get(common+libDirectoryName);
Path libLinksource = Paths.get(target+libDirectoryName);
try{
Files.createSymbolicLink( libLinksource, libLinkTarget);
}catch(FileAlreadyExistsException toignore){
getLog().info("symlink "+libLinksource+" already exists, skipping");
}
Path confLinkTarget = Paths.get(common+confDirectoryName);
Path confLinksource = Paths.get(target+confDirectoryName);
try{
Files.createSymbolicLink( confLinksource, confLinkTarget);
}catch(FileAlreadyExistsException toignore){
getLog().info("symlink "+confLinksource+" already exists, skipping");
}
//generate service specific scripts
generateServiceStartScripts(bin, entry);
}
protected void generateServiceStartScripts(File targetDirectory, ServiceEntry serviceEntry) throws IOException{
//first write out the service definition file.
FileOutputStream serviceDefinitionFile = new FileOutputStream(targetDirectory+"/service.sh");
writeLine(serviceDefinitionFile, "#This is service definition file, it is sourced from the start script.");
writeLine(serviceDefinitionFile,"#This service definition is created from services.json with entry: "+serviceEntry+".");
writeLine(serviceDefinitionFile,"export SERVICE_NAME="+serviceEntry.getName());
writeLine(serviceDefinitionFile,"export TARGET_PID="+serviceEntry.getName()+".pid");
writeLine(serviceDefinitionFile,"export TARGET_CLASS="+serviceEntry.getStartClass());
writeLine(serviceDefinitionFile,"export RMI_PORT="+serviceEntry.getRmiPort());
writeLine(serviceDefinitionFile,"export JVM_OPTIONS=\""+(serviceEntry.getJvmOptions()!=null ? serviceEntry.getJvmOptions() : "none")+"\"");
writeLine(serviceDefinitionFile,"## profiles for this service are: "+serviceEntry.getProfiles());
//export LOCAL_RMI_PORT=9405
serviceDefinitionFile.close();
writeOutScript(targetDirectory, "start_service.sh");
writeOutScript(targetDirectory, "stop_service.sh");
}
protected void writeOutGenericScripts(File targetDirectory, String startAction, String stopAction) throws IOException{
File startAllFile = new File(targetDirectory.getAbsolutePath()+"/"+"start_all.sh");
FileOutputStream startAll = new FileOutputStream(startAllFile);
writeLine(startAll, "#!/usr/bin/env bash");
writeLine(startAll ,"source environment.sh");
writeLine(startAll ,"echo current profile: $DISTRIBUTEME_PROFILE");
writeLine(startAll ,"profile_found=\"false\"");
//generate service definition for every profile.
for (Map.Entry> entries : knownProfiles.entrySet()){
String serviceListForProfile = "";
for (String s : entries.getValue()){
serviceListForProfile += s + " ";
}
String profileNameForScript = "SERVICES_"+entries.getKey();
writeLine(startAll, profileNameForScript+"=\""+serviceListForProfile+"\"");
}
writeLine(startAll, "");
//generate profile name check for every profile.
for (Map.Entry> entries : knownProfiles.entrySet()){
String profileNameForScript = "SERVICES_"+entries.getKey();
writeLine(startAll, "if [ \""+entries.getKey()+"\" = \"$DISTRIBUTEME_PROFILE\" ]; then");
writeLine(startAll, " profile_found=\"true\"");
writeLine(startAll, " SERVICES=$"+profileNameForScript);
writeLine(startAll, "fi");
}
writeLine(startAll, "");
writeLine(startAll, "if [ $profile_found = \"false\" ]; then");
writeLine(startAll, " echo profile $DISTRIBUTEME_PROFILE not found!");
writeLine(startAll, "else");
writeLine(startAll, " echo starting services $SERVICES");
writeLine(startAll, "fi");
writeLine(startAll, "");
writeLine(startAll, "if [ -z \"$1\" ] || [ \"$1\" == \"null\" ]; then");
writeLine(startAll, " tagName=\"latest\"");
writeLine(startAll,"else");
writeLine(startAll," tagName=\"$1\"");
writeLine(startAll,"fi");
writeLine(startAll, "");
writeLine(startAll, "for i in $SERVICES; do");
writeLine(startAll, "\techo starting service $i");
writeLine(startAll, "\tcd $i");
writeLine(startAll, "\t" + startAction + " $tagName");
writeLine(startAll, "\tcd ..");
writeLine(startAll, "done");
startAll.close();
startAllFile.setExecutable(true);
File stopAllFile = new File(targetDirectory.getAbsolutePath()+"/"+"stop_all.sh");
FileOutputStream stopAll = new FileOutputStream(stopAllFile);
writeLine(stopAll,"#!/usr/bin/env bash");
writeLine(stopAll ,"source environment.sh");
writeLine(stopAll ,"echo current profile: $DISTRIBUTEME_PROFILE");
writeLine(stopAll ,"profile_found=\"false\"");
//generate service definition for every profile.
for (Map.Entry> entries : knownProfiles.entrySet()){
String serviceListForProfile = "";
for (String s : entries.getValue()){
serviceListForProfile += s + " ";
}
String profileNameForScript = "SERVICES_"+entries.getKey();
writeLine(stopAll, profileNameForScript+"=\""+serviceListForProfile+"\"");
}
writeLine(stopAll, "");
//generate profile name check for every profile.
for (Map.Entry> entries : knownProfiles.entrySet()){
String profileNameForScript = "SERVICES_"+entries.getKey();
writeLine(stopAll, "if [ \""+entries.getKey()+"\" = \"$DISTRIBUTEME_PROFILE\" ]; then");
writeLine(stopAll, " profile_found=\"true\"");
writeLine(stopAll, " SERVICES=$"+profileNameForScript);
writeLine(stopAll, "fi");
}
writeLine(stopAll, "");
writeLine(stopAll, "if [ $profile_found = \"false\" ]; then");
writeLine(stopAll, " echo profile $DISTRIBUTEME_PROFILE not found!");
writeLine(stopAll, "else");
writeLine(stopAll, " echo stoping services $SERVICES");
writeLine(stopAll, "fi");
writeLine(stopAll,"for i in $SERVICES; do");
writeLine(stopAll,"\techo stoping service $i");
writeLine(stopAll,"\tcd $i");
writeLine(stopAll,"\t" + stopAction);
writeLine(stopAll,"\tcd ..");
writeLine(stopAll,"done");
stopAll.close();
stopAllFile.setExecutable(true);
}
private void writeLine(FileOutputStream fOut, String line) throws IOException{
fOut.write( (line+"\n").getBytes());
}
protected void writeOutScript(File targetDirectory, String filename) throws IOException{
writeOutScript(targetDirectory, filename, filename);
}
protected void writeOutScript(File targetDirectory, String filename, String outputFileName) throws IOException{
InputStream fIn = ServiceMojo.class.getResourceAsStream("/"+filename);
File file = new File(targetDirectory.getAbsolutePath()+"/"+outputFileName);
FileOutputStream fOut = new FileOutputStream(file);
int c = -1;
while ( (c = fIn.read()) != -1 )
fOut.write(c);
fOut.close();
file.setExecutable(true);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy