diff --git a/modules/mesos/pom.xml b/modules/mesos/pom.xml index fa38265e9003a..f2f1acdbcf18b 100644 --- a/modules/mesos/pom.xml +++ b/modules/mesos/pom.xml @@ -20,7 +20,8 @@ - + 4.0.0 @@ -36,6 +37,8 @@ 0.22.0 + http://ignite.run/download_ignite.php + https://archive.apache.org/dist/ignite/%s/apache-ignite-fabric-%s-bin.zip @@ -72,6 +75,44 @@ + + org.apache.maven.plugins + maven-antrun-plugin + 1.7 + + + update-versions + + run + + generate-sources + + + + + + + + + + + + + + + + + + + + + + + + + + + maven-assembly-plugin 2.4.1 diff --git a/modules/mesos/src/main/java/org/apache/ignite/mesos/ClusterProperties.java b/modules/mesos/src/main/java/org/apache/ignite/mesos/ClusterProperties.java index e249a25a2b0e4..747fbe95b147f 100644 --- a/modules/mesos/src/main/java/org/apache/ignite/mesos/ClusterProperties.java +++ b/modules/mesos/src/main/java/org/apache/ignite/mesos/ClusterProperties.java @@ -31,7 +31,11 @@ import java.util.regex.PatternSyntaxException; /** - * Cluster settings. + * The class defines cluster configuration. This configuration created from properties file + * that passed on startup or environment variables. + *

+ * If Mesos cluster working in Intranet or behind NAT then an access to local resources can be set + * by {@link #ignitePackagePath()} or {@link #ignitePackageUrl()} which should be available from nodes. */ public class ClusterProperties { /** */ @@ -68,7 +72,7 @@ public class ClusterProperties { public static final String IGNITE_HTTP_SERVER_HOST = "IGNITE_HTTP_SERVER_HOST"; /** Http server host. */ - private String httpServerHost = null; + private String httpSrvHost = null; /** */ public static final String IGNITE_HTTP_SERVER_PORT = "IGNITE_HTTP_SERVER_PORT"; @@ -77,7 +81,7 @@ public class ClusterProperties { public static final String DEFAULT_HTTP_SERVER_PORT = "48610"; /** Http server host. */ - private int httpServerPort = Integer.valueOf(DEFAULT_HTTP_SERVER_PORT); + private int httpSrvPort = Integer.valueOf(DEFAULT_HTTP_SERVER_PORT); /** */ public static final String IGNITE_TOTAL_CPU = "IGNITE_TOTAL_CPU"; @@ -152,7 +156,13 @@ public class ClusterProperties { public static final String IGNITE_PACKAGE_URL = "IGNITE_PACKAGE_URL"; /** Ignite package url. */ - private String ignitePackageUrl = null; + private String ignitePkgUrl; + + /** */ + public static final String IGNITE_PACKAGE_PATH = "IGNITE_PACKAGE_PATH"; + + /** Ignite package path. */ + private String ignitePkgPath; /** */ public static final String IGNITE_WORK_DIR = "IGNITE_WORK_DIR"; @@ -318,10 +328,10 @@ public void minMemoryPerNode(double minMemory) { /** * Sets hostname constraint. * - * @param pattern Hostname pattern. + * @param ptrn Hostname pattern. */ - public void hostnameConstraint(Pattern pattern) { - this.hostnameConstraint = pattern; + public void hostnameConstraint(Pattern ptrn) { + this.hostnameConstraint = ptrn; } /** @@ -379,21 +389,34 @@ public String masterUrl() { * @return Http server host. */ public String httpServerHost() { - return httpServerHost; + return httpSrvHost; } /** * @return Http server port. */ public int httpServerPort() { - return httpServerPort; + return httpSrvPort; } /** + * URL to ignite package. The URL should to point at valid apache ignite archive. + * This property can be useful if using own apache ignite build. + * * @return Url to ignite package. */ public String ignitePackageUrl() { - return ignitePackageUrl; + return ignitePkgUrl; + } + + /** + * Path on local file system to ignite archive. That can be useful when + * Mesos working in Intranet or behind NAT. + * + * @return Path on local host to ignite package. + */ + public String ignitePackagePath() { + return ignitePkgPath; } /** @@ -425,37 +448,38 @@ public Pattern hostnameConstraint() { } /** - * @param config path to config file. + * @param cfg path to config file. * @return Cluster configuration. */ - public static ClusterProperties from(String config) { + public static ClusterProperties from(String cfg) { try { Properties props = null; - if (config != null) { + if (cfg != null) { props = new Properties(); - props.load(new FileInputStream(config)); + props.load(new FileInputStream(cfg)); } ClusterProperties prop = new ClusterProperties(); prop.mesosUrl = getStringProperty(MESOS_MASTER_URL, props, DEFAULT_MESOS_MASTER_URL); - prop.httpServerHost = getStringProperty(IGNITE_HTTP_SERVER_HOST, props, getNonLoopbackAddress()); + prop.httpSrvHost = getStringProperty(IGNITE_HTTP_SERVER_HOST, props, getNonLoopbackAddress()); String port = System.getProperty("PORT0"); if (port != null && !port.isEmpty()) - prop.httpServerPort = Integer.valueOf(port); + prop.httpSrvPort = Integer.valueOf(port); else - prop.httpServerPort = Integer.valueOf(getStringProperty(IGNITE_HTTP_SERVER_PORT, props, + prop.httpSrvPort = Integer.valueOf(getStringProperty(IGNITE_HTTP_SERVER_PORT, props, DEFAULT_HTTP_SERVER_PORT)); prop.clusterName = getStringProperty(IGNITE_CLUSTER_NAME, props, DEFAULT_CLUSTER_NAME); prop.userLibsUrl = getStringProperty(IGNITE_USERS_LIBS_URL, props, null); - prop.ignitePackageUrl = getStringProperty(IGNITE_PACKAGE_URL, props, null); + prop.ignitePkgUrl = getStringProperty(IGNITE_PACKAGE_URL, props, null); + prop.ignitePkgPath = getStringProperty(IGNITE_PACKAGE_PATH, props, null); prop.licenceUrl = getStringProperty(LICENCE_URL, props, null); prop.igniteCfgUrl = getStringProperty(IGNITE_CONFIG_XML_URL, props, null); @@ -476,11 +500,11 @@ public static ClusterProperties from(String config) { prop.igniteCfg = getStringProperty(IGNITE_CONFIG_XML, props, null); prop.userLibs = getStringProperty(IGNITE_USERS_LIBS, props, null); - String pattern = getStringProperty(IGNITE_HOSTNAME_CONSTRAINT, props, null); + String ptrn = getStringProperty(IGNITE_HOSTNAME_CONSTRAINT, props, null); - if (pattern != null) { + if (ptrn != null) { try { - prop.hostnameConstraint = Pattern.compile(pattern); + prop.hostnameConstraint = Pattern.compile(ptrn); } catch (PatternSyntaxException e) { log.log(Level.WARNING, "IGNITE_HOSTNAME_CONSTRAINT has invalid pattern. It will be ignore.", e); @@ -499,16 +523,16 @@ public static ClusterProperties from(String config) { * @param fileProps Property file. * @return Property value. */ - private static double getDoubleProperty(String name, Properties fileProps, Double defaultVal) { + private static double getDoubleProperty(String name, Properties fileProps, Double dfltVal) { if (fileProps != null && fileProps.containsKey(name)) return Double.valueOf(fileProps.getProperty(name)); - String property = System.getProperty(name); + String prop = System.getProperty(name); - if (property == null) - property = System.getenv(name); + if (prop == null) + prop = System.getenv(name); - return property == null ? defaultVal : Double.valueOf(property); + return prop == null ? dfltVal : Double.valueOf(prop); } /** @@ -516,16 +540,16 @@ private static double getDoubleProperty(String name, Properties fileProps, Doubl * @param fileProps Property file. * @return Property value. */ - private static String getStringProperty(String name, Properties fileProps, String defaultVal) { + private static String getStringProperty(String name, Properties fileProps, String dfltVal) { if (fileProps != null && fileProps.containsKey(name)) return fileProps.getProperty(name); - String property = System.getProperty(name); + String prop = System.getProperty(name); - if (property == null) - property = System.getenv(name); + if (prop == null) + prop = System.getenv(name); - return property == null ? defaultVal : property; + return prop == null ? dfltVal : prop; } /** @@ -540,16 +564,16 @@ public static String getNonLoopbackAddress() throws SocketException { while (ifaces.hasMoreElements()) { NetworkInterface iface = ifaces.nextElement(); - Enumeration addresses = iface.getInetAddresses(); + Enumeration addrs = iface.getInetAddresses(); - while (addresses.hasMoreElements()) { - InetAddress addr = addresses.nextElement(); + while (addrs.hasMoreElements()) { + InetAddress addr = addrs.nextElement(); if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) return addr.getHostAddress(); } } - throw new RuntimeException("Failed. Couldn't find non-loopback address"); + throw new RuntimeException("Failed. Could not find non-loopback address"); } } \ No newline at end of file diff --git a/modules/mesos/src/main/java/org/apache/ignite/mesos/IgniteFramework.java b/modules/mesos/src/main/java/org/apache/ignite/mesos/IgniteFramework.java index 9f33f9a053d5b..0cd9efb636400 100644 --- a/modules/mesos/src/main/java/org/apache/ignite/mesos/IgniteFramework.java +++ b/modules/mesos/src/main/java/org/apache/ignite/mesos/IgniteFramework.java @@ -19,6 +19,7 @@ import com.google.protobuf.ByteString; import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.ignite.mesos.resource.IgniteProvider; @@ -43,6 +44,7 @@ public class IgniteFramework { * Main methods has only one optional parameter - path to properties files. * * @param args Args. + * @throws Exception If failed. */ public static void main(String[] args) throws Exception { final int frameworkFailoverTimeout = 0; @@ -63,9 +65,9 @@ public static void main(String[] args) throws Exception { String baseUrl = String.format("http://%s:%d", clusterProps.httpServerHost(), clusterProps.httpServerPort()); - JettyServer httpServer = new JettyServer(); + JettyServer httpSrv = new JettyServer(); - httpServer.start( + httpSrv.start( new InetSocketAddress(clusterProps.httpServerHost(), clusterProps.httpServerPort()), new ResourceHandler(clusterProps.userLibs(), clusterProps.igniteCfg(), clusterProps.igniteWorkDir()) ); @@ -79,8 +81,9 @@ public static void main(String[] args) throws Exception { // Create the scheduler. Scheduler scheduler = new IgniteScheduler(clusterProps, provider); - // create the driver + // Create the driver. MesosSchedulerDriver driver; + if (System.getenv("MESOS_AUTHENTICATE") != null) { log.info("Enabling authentication for the framework"); @@ -96,7 +99,7 @@ public static void main(String[] args) throws Exception { System.exit(1); } - Protos.Credential credential = Protos.Credential.newBuilder() + Protos.Credential cred = Protos.Credential.newBuilder() .setPrincipal(System.getenv("DEFAULT_PRINCIPAL")) .setSecret(ByteString.copyFrom(System.getenv("DEFAULT_SECRET").getBytes())) .build(); @@ -104,7 +107,7 @@ public static void main(String[] args) throws Exception { frameworkBuilder.setPrincipal(System.getenv("DEFAULT_PRINCIPAL")); driver = new MesosSchedulerDriver(scheduler, frameworkBuilder.build(), clusterProps.masterUrl(), - credential); + cred); } else { frameworkBuilder.setPrincipal("ignite-framework-java"); @@ -114,7 +117,7 @@ public static void main(String[] args) throws Exception { int status = driver.run() == Protos.Status.DRIVER_STOPPED ? 0 : 1; - httpServer.stop(); + httpSrv.stop(); // Ensure that the driver process terminates. driver.stop(); diff --git a/modules/mesos/src/main/java/org/apache/ignite/mesos/resource/IgniteProvider.java b/modules/mesos/src/main/java/org/apache/ignite/mesos/resource/IgniteProvider.java index 75101109b231a..3d794db273013 100644 --- a/modules/mesos/src/main/java/org/apache/ignite/mesos/resource/IgniteProvider.java +++ b/modules/mesos/src/main/java/org/apache/ignite/mesos/resource/IgniteProvider.java @@ -23,27 +23,26 @@ import java.net.HttpURLConnection; import java.net.URL; import java.nio.channels.Channels; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import org.apache.ignite.mesos.ClusterProperties; /** * Class downloads and stores Ignite. */ public class IgniteProvider { + // This constants are set by maven-ant-plugin. /** */ - public static final String DOWNLOAD_LINK = "http://tiny.cc/updater/download_community.php"; + private static final String DOWNLOAD_LINK = "http://ignite.run/download_ignite.php"; /** */ - public static final String DIRECT_DOWNLOAD_LINK = "http://www.gridgain.com/media/gridgain-community-fabric-"; + private static final String DOWNLOAD_URL_PATTERN = "https://archive.apache.org/dist/ignite/%s/apache-ignite-fabric-%s-bin.zip"; /** */ private String downloadFolder; - /** */ - private String latestVersion = null; - /** * @param downloadFolder Folder with ignite. */ @@ -52,158 +51,116 @@ public IgniteProvider(String downloadFolder) { } /** - * @return Latest ignite version. + * @param ver Ignite version. + * @throws IOException If downloading failed. + * @return Path to latest ignite. */ - public String getIgnite() { - File folder = checkDownloadFolder(); - - if (latestVersion == null) { - List files = findIgnites(folder); - - if (!files.isEmpty()) { - if (files.size() == 1) - latestVersion = parseVersion(files.get(0)); - else - latestVersion = parseVersion(Collections.max(files, new Comparator() { - @Override public int compare(String f1, String f2) { - if (f1.equals(f2)) - return 0; - - String[] ver1 = parseVersion(f1).split("\\."); - String[] ver2 = parseVersion(f2).split("\\."); - - if (Integer.valueOf(ver1[0]) >= Integer.valueOf(ver2[0]) - && Integer.valueOf(ver1[1]) >= Integer.valueOf(ver2[1]) - && Integer.valueOf(ver1[2]) >= Integer.valueOf(ver2[2])) - - return 1; - else - return -1; - } - })); - } - } - - latestVersion = updateIgnite(latestVersion); - - return "gridgain-community-fabric-" + latestVersion + ".zip"; + public String getIgnite(String ver) throws IOException { + return downloadIgnite(ver); } /** - * @param folder Folder. - * @return Ignite archives. + * @param ver Ignite version which will be downloaded. If {@code null} will download the latest ignite version. + * @throws IOException If downloading failed. + * @return Ignite archive. */ - private List findIgnites(File folder) { - String[] files = folder.list(); + public String downloadIgnite(String ver) throws IOException { + assert ver != null; - List ignites = new ArrayList<>(); + URL url; - if (files != null) { - for (String fileName : files) { - if (fileName.contains("gridgain-community-fabric-") && fileName.endsWith(".zip")) - ignites.add(fileName); - } - } + if (ver.equals(ClusterProperties.DEFAULT_IGNITE_VERSION)) { + URL updateUrl = new URL(DOWNLOAD_LINK); - return ignites; - } + HttpURLConnection conn = (HttpURLConnection)updateUrl.openConnection(); - /** - * @param version Ignite version. - * @return Ignite. - */ - public String getIgnite(String version) { - File folder = checkDownloadFolder(); - - String[] ignites = folder.list(); - - String ignite = null; + int code = conn.getResponseCode(); - if (ignites != null) { - for (String fileName : ignites) { - if (fileName.equals("gridgain-community-fabric-" + version + ".zip")) - ignite = fileName; - } + if (code == 200) + url = conn.getURL(); + else + throw new RuntimeException("Failed to download ignite distributive. Maybe set incorrect version? " + + "[resCode:" + code + ", ver: " + ver + "]"); } + else + url = new URL(String.format(DOWNLOAD_URL_PATTERN, ver.replace("-incubating", ""), ver)); - if (ignite != null) - return ignite; - - return downloadIgnite(version); + return downloadIgnite(url); } /** - * @param currentVersion The current latest version. - * @return Current version if the current version is latest; new ignite version otherwise. + * Downloads ignite by URL if this version wasn't downloaded before. + * + * @param url URL to Ignite. + * @return File name. */ - private String updateIgnite(String currentVersion) { - try { - URL url; - - if (currentVersion == null) - url = new URL(DOWNLOAD_LINK); - else - url = new URL(DOWNLOAD_LINK + "?version=" + currentVersion); + private String downloadIgnite(URL url) { + assert url != null; + try { HttpURLConnection conn = (HttpURLConnection)url.openConnection(); int code = conn.getResponseCode(); if (code == 200) { - String redirectUrl = conn.getURL().toString(); - checkDownloadFolder(); - FileOutputStream outFile = new FileOutputStream(downloadFolder + "/" + fileName(redirectUrl)); + String fileName = fileName(url.toString()); + + if (fileExist(fileName)) + return fileName; + + FileOutputStream outFile = new FileOutputStream(downloadFolder + fileName); outFile.getChannel().transferFrom(Channels.newChannel(conn.getInputStream()), 0, Long.MAX_VALUE); outFile.close(); - return parseVersion(redirectUrl); + return fileName; } - else if (code == 304) - // This version is latest. - return currentVersion; else throw new RuntimeException("Got unexpected response code. Response code: " + code); } catch (IOException e) { - throw new RuntimeException("Failed update ignite.", e); + throw new RuntimeException("Failed to download Ignite.", e); } } /** - * @param version The current latest version. - * @return Ignite archive. + * Checks that file exists. + * + * @param fileName File name. + * @return {@code True} if file exist otherwise {@code false}. */ - public String downloadIgnite(String version) { - try { - URL url = new URL(DIRECT_DOWNLOAD_LINK + version + ".zip"); - - HttpURLConnection conn = (HttpURLConnection)url.openConnection(); + private boolean fileExist(String fileName) { + String pathToIgnite = downloadFolder + (downloadFolder.endsWith("/") ? "" : '/') + fileName; - int code = conn.getResponseCode(); + return new File(pathToIgnite).exists(); + } - if (code == 200) { - checkDownloadFolder(); + /** + * Copy file to working directory. + * + * @param filePath File path. + * @return File name. + * @throws IOException If coping failed. + */ + String copyToWorkDir(String filePath) throws IOException { + Path srcFile = Paths.get(filePath); - String fileName = fileName(url.toString()); + if (Files.exists(srcFile)) { + checkDownloadFolder(); - FileOutputStream outFile = new FileOutputStream(downloadFolder + fileName); + Path newDir = Paths.get(downloadFolder); - outFile.getChannel().transferFrom(Channels.newChannel(conn.getInputStream()), 0, Long.MAX_VALUE); + Path fileName = srcFile.getFileName(); - outFile.close(); + Files.copy(srcFile, newDir.resolve(fileName), StandardCopyOption.REPLACE_EXISTING); - return fileName; - } - else - throw new RuntimeException("Got unexpected response code. Response code: " + code); - } - catch (IOException e) { - throw new RuntimeException("Failed update ignite.", e); + return fileName.toString(); } + + return null; } /** @@ -215,17 +172,10 @@ private File checkDownloadFolder() { if (!file.exists()) file.mkdirs(); - return file; - } - - /** - * @param url URL. - * @return Ignite version. - */ - public static String parseVersion(String url) { - String[] split = url.split("-"); + if (!file.exists()) + throw new IllegalArgumentException("Failed to create working directory: " + downloadFolder); - return split[split.length - 1].replaceAll(".zip", ""); + return file; } /** diff --git a/modules/mesos/src/main/java/org/apache/ignite/mesos/resource/ResourceProvider.java b/modules/mesos/src/main/java/org/apache/ignite/mesos/resource/ResourceProvider.java index 23945e1fc81e5..1aa8863bcfef1 100644 --- a/modules/mesos/src/main/java/org/apache/ignite/mesos/resource/ResourceProvider.java +++ b/modules/mesos/src/main/java/org/apache/ignite/mesos/resource/ResourceProvider.java @@ -18,9 +18,15 @@ package org.apache.ignite.mesos.resource; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.ignite.mesos.ClusterProperties; import static org.apache.ignite.mesos.resource.ResourceHandler.CONFIG_PREFIX; @@ -32,6 +38,9 @@ * Provides path to user's libs and config file. */ public class ResourceProvider { + /** */ + private static final Logger log = Logger.getLogger(ResourceProvider.class.getSimpleName()); + /** Ignite url. */ private String igniteUrl; @@ -39,26 +48,57 @@ public class ResourceProvider { private Collection libsUris; /** Url config. */ - private String configUrl; + private String cfgUrl; /** Config name. */ - private String configName; + private String cfgName; /** - * @param properties Cluster properties. + * @param props Cluster properties. * @param provider Ignite provider. * @param baseUrl Base url. */ - public void init(ClusterProperties properties, IgniteProvider provider, String baseUrl) { - // Downloading ignite. - if (properties.igniteVer().equals(ClusterProperties.DEFAULT_IGNITE_VERSION)) - igniteUrl = baseUrl + IGNITE_PREFIX + provider.getIgnite(); - else - igniteUrl = baseUrl + IGNITE_PREFIX + provider.getIgnite(properties.igniteVer()); + public void init(ClusterProperties props, IgniteProvider provider, String baseUrl) throws IOException { + if (props.ignitePackageUrl() == null && props.ignitePackagePath() == null) { + // Downloading ignite. + try { + igniteUrl = baseUrl + IGNITE_PREFIX + provider.getIgnite(props.igniteVer()); + } + catch (Exception e) { + log.log(Level.SEVERE, "Failed to download Ignite [err={0}, ver={1}].\n" + + "If application working behind NAT or Intranet and does not have access to external resources " + + "then you can use IGNITE_PACKAGE_URL or IGNITE_PACKAGE_PATH property that allow to use local " + + "resources.", + new Object[]{e, props.igniteVer()}); + } + } + + if (props.ignitePackagePath() != null) { + Path ignitePackPath = Paths.get(props.ignitePackagePath()); + + if (Files.exists(ignitePackPath) && !Files.isDirectory(ignitePackPath)) { + try { + String fileName = provider.copyToWorkDir(props.ignitePackagePath()); + + assert fileName != null; + + igniteUrl = baseUrl + IGNITE_PREFIX + fileName; + } + catch (Exception e) { + log.log(Level.SEVERE, "Failed to copy Ignite to working directory [err={0}, path={1}].", + new Object[] {e, props.ignitePackagePath()}); + + throw e; + } + } + else + throw new IllegalArgumentException("Failed to find a ignite archive by path: " + + props.ignitePackagePath()); + } // Find all jar files into user folder. - if (properties.userLibs() != null && !properties.userLibs().isEmpty()) { - File libsDir = new File(properties.userLibs()); + if (props.userLibs() != null && !props.userLibs().isEmpty()) { + File libsDir = new File(props.userLibs()); List libs = new ArrayList<>(); @@ -78,19 +118,19 @@ public void init(ClusterProperties properties, IgniteProvider provider, String b } // Set configuration url. - if (properties.igniteCfg() != null) { - File cfg = new File(properties.igniteCfg()); + if (props.igniteCfg() != null) { + File cfg = new File(props.igniteCfg()); if (cfg.isFile() && cfg.canRead()) { - configUrl = baseUrl + CONFIG_PREFIX + cfg.getName(); + cfgUrl = baseUrl + CONFIG_PREFIX + cfg.getName(); - configName = cfg.getName(); + cfgName = cfg.getName(); } } else { - configName = "ignite-default-config.xml"; + cfgName = "ignite-default-config.xml"; - configUrl = baseUrl + DEFAULT_CONFIG + configName; + cfgUrl = baseUrl + DEFAULT_CONFIG + cfgName; } } @@ -98,7 +138,7 @@ public void init(ClusterProperties properties, IgniteProvider provider, String b * @return Config name. */ public String configName() { - return configName; + return cfgName; } /** @@ -119,6 +159,6 @@ public Collection resourceUrl() { * @return Url to config file. */ public String igniteConfigUrl() { - return configUrl; + return cfgUrl; } } \ No newline at end of file