From f25bd9d2d1152540023310ee21fa41d504323dfa Mon Sep 17 00:00:00 2001 From: Clebert Suconic Date: Fri, 7 Oct 2022 11:44:40 -0400 Subject: [PATCH] ARTEMIS-4081 Upgrade command This command will help updating the instance from a previous home --- .../apache/activemq/artemis/cli/Artemis.java | 3 +- .../activemq/artemis/cli/commands/Create.java | 222 ++++----------- .../artemis/cli/commands/InstallAbstract.java | 176 ++++++++++++ .../activemq/artemis/cli/commands/Run.java | 18 ++ .../artemis/cli/commands/Upgrade.java | 240 +++++++++++++++++ .../cli/commands/bin/artemis-service.xml | 4 +- .../artemis/cli/commands/etc/artemis.profile | 2 +- .../cli/commands/etc/artemis.profile.cmd | 2 +- .../artemis/maven/ArtemisUpgradePlugin.java | 120 +++++++++ docs/user-manual/en/upgrading.md | 28 +- docs/user-manual/en/versions.md | 2 + tests/smoke-tests/pom.xml | 39 +++ .../toUpgradeETC/artemis-roles.properties | 18 ++ .../toUpgradeETC/artemis-users.properties | 18 ++ .../servers/toUpgradeETC/artemis.profile | 65 +++++ .../servers/toUpgradeETC/bootstrap.xml | 39 +++ .../servers/toUpgradeETC/broker.xml | 254 ++++++++++++++++++ .../servers/toUpgradeETC/jolokia-access.xml | 35 +++ .../servers/toUpgradeETC/logging.properties | 90 +++++++ .../servers/toUpgradeETC/login.config | 29 ++ .../servers/toUpgradeETC/management.xml | 52 ++++ .../windowsETC/artemis-roles.properties | 18 ++ .../windowsETC/artemis-users.properties | 18 ++ .../servers/windowsETC/artemis.profile.cmd | 50 ++++ .../servers/windowsETC/bootstrap.xml | 39 +++ .../servers/windowsETC/broker.xml | 254 ++++++++++++++++++ .../servers/windowsETC/jolokia-access.xml | 35 +++ .../servers/windowsETC/logging.properties | 90 +++++++ .../servers/windowsETC/login.config | 29 ++ .../servers/windowsETC/management.xml | 52 ++++ .../smoke/upgradeTest/CompareUpgradeTest.java | 145 ++++++++++ .../tests/smoke/upgradeTest/UpgradeTest.java | 72 +++++ 32 files changed, 2082 insertions(+), 176 deletions(-) create mode 100644 artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/InstallAbstract.java create mode 100644 artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Upgrade.java create mode 100644 artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisUpgradePlugin.java create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis-roles.properties create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis-users.properties create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis.profile create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/bootstrap.xml create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/broker.xml create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/jolokia-access.xml create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/logging.properties create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/login.config create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/management.xml create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis-roles.properties create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis-users.properties create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis.profile.cmd create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/bootstrap.xml create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/broker.xml create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/jolokia-access.xml create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/logging.properties create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/login.config create mode 100644 tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/management.xml create mode 100644 tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/upgradeTest/CompareUpgradeTest.java create mode 100644 tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/upgradeTest/UpgradeTest.java diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java index f58e56dcf0e6..31bd72ffd6d3 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java @@ -32,6 +32,7 @@ import org.apache.activemq.artemis.cli.commands.Kill; import org.apache.activemq.artemis.cli.commands.Mask; import org.apache.activemq.artemis.cli.commands.PrintVersion; +import org.apache.activemq.artemis.cli.commands.Upgrade; import org.apache.activemq.artemis.cli.commands.activation.ActivationSequenceSet; import org.apache.activemq.artemis.cli.commands.check.HelpCheck; import org.apache.activemq.artemis.cli.commands.check.NodeCheck; @@ -243,7 +244,7 @@ private static Cli.CliBuilder builder(File artemisInstance) { } else { builder.withGroup("data").withDescription("data tools group (print|recover) (example ./artemis data print)"). withDefaultCommand(HelpData.class).withCommands(RecoverMessages.class, PrintData.class); - builder = builder.withCommand(Create.class); + builder = builder.withCommands(Create.class, Upgrade.class); } return builder; diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java index 7aa2d7a75fa6..50c4504e1dc0 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java @@ -17,29 +17,18 @@ package org.apache.activemq.artemis.cli.commands; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; -import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import io.airlift.airline.Arguments; import io.airlift.airline.Command; import io.airlift.airline.Option; import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; import org.apache.activemq.artemis.api.core.RoutingType; -import org.apache.activemq.artemis.cli.CLIException; import org.apache.activemq.artemis.cli.commands.util.HashUtil; import org.apache.activemq.artemis.cli.commands.util.SyncCalculation; import org.apache.activemq.artemis.core.server.JournalType; @@ -52,7 +41,7 @@ * CLI action that creates a broker instance directory. */ @Command(name = "create", description = "creates a new broker instance") -public class Create extends InputAbstract { +public class Create extends InstallAbstract { private static final Integer DEFAULT_PORT = 61616; @@ -73,13 +62,17 @@ public class Create extends InputAbstract { * This is to make sure maven or something else is not hiding these resources. * ********************************************************************************** */ - public static final String BIN_ARTEMIS_CMD = "bin/artemis.cmd"; + public static final String ARTEMIS_CMD = "artemis.cmd"; + public static final String BIN_ARTEMIS_CMD = "bin/" + ARTEMIS_CMD; public static final String BIN_ARTEMIS_SERVICE_EXE = "bin/artemis-service.exe"; public static final String BIN_ARTEMIS_SERVICE_EXE_CONFIG = "bin/artemis-service.exe.config"; - public static final String BIN_ARTEMIS_SERVICE_XML = "bin/artemis-service.xml"; + public static final String ARTEMIS_SERVICE_XML = "artemis-service.xml"; + public static final String BIN_ARTEMIS_SERVICE_XML = "bin/" + ARTEMIS_SERVICE_XML; public static final String ETC_ARTEMIS_PROFILE_CMD = "artemis.profile.cmd"; - public static final String BIN_ARTEMIS = "bin/artemis"; - public static final String BIN_ARTEMIS_SERVICE = "bin/artemis-service"; + public static final String ARTEMIS = "artemis"; + public static final String BIN_ARTEMIS = "bin/" + ARTEMIS; + public static final String ARTEMIS_SERVICE = "artemis-service"; + public static final String BIN_ARTEMIS_SERVICE = "bin/" + ARTEMIS_SERVICE; public static final String ETC_ARTEMIS_PROFILE = "artemis.profile"; public static final String ETC_LOG4J2_PROPERTIES = "log4j2.properties"; public static final String ETC_BOOTSTRAP_XML = "bootstrap.xml"; @@ -115,9 +108,6 @@ public class Create extends InputAbstract { public static final String ETC_PAGE_SYNC_SETTINGS = "etc/page-sync-settings.txt"; public static final String ETC_JOLOKIA_ACCESS_XML = "jolokia-access.xml"; - @Arguments(description = "The instance directory to hold the broker's configuration and data. Path must be writable.", required = true) - private File directory; - @Option(name = "--host", description = "The host name of the broker (Default: 0.0.0.0 or input if clustered)") private String host; @@ -160,15 +150,9 @@ public class Create extends InputAbstract { @Option(name = "--force", description = "Overwrite configuration at destination directory") private boolean force; - @Option(name = "--home", description = "Directory where ActiveMQ Artemis is installed") - private File home; - @Option(name = "--data", description = "Directory where ActiveMQ data are stored. Paths can be absolute or relative to artemis.instance directory ('data' by default)") private String data = "data"; - @Option(name = "--etc", description = "Directory where ActiveMQ configuration is located. Paths can be absolute or relative to artemis.instance directory ('etc' by default)") - private String etc = "etc"; - @Option(name = "--clustered", description = "Enable clustering") private boolean clustered = false; @@ -196,15 +180,6 @@ public class Create extends InputAbstract { @Option(name = "--cluster-password", description = "The cluster password to use for clustering. (Default: input)") private String clusterPassword = null; - @Option(name = "--encoding", description = "The encoding that text files should use") - private String encoding = "UTF-8"; - - @Option(name = "--java-options", description = "Extra java options to be passed to the profile") - private String javaOptions = ""; - - @Option(name = "--java-memory", description = "Define the -Xmx memory parameter for the broker. Default = '2G'") - private String javaMemory = "2G"; - @Option(name = "--allow-anonymous", description = "Enables anonymous configuration on security, opposite of --require-login (Default: input)") private Boolean allowAnonymous = null; @@ -345,9 +320,6 @@ public String[] getStaticNodes() { @Option(name = "--jdbc-lock-expiration", description = "Lock expiration") long jdbcLockExpiration = ActiveMQDefaultConfiguration.getDefaultJdbcLockExpirationMillis(); - private boolean IS_WINDOWS; - private boolean IS_CYGWIN; - private boolean isAutoCreate() { if (autoCreate == null) { if (noAutoCreate != null) { @@ -362,14 +334,6 @@ private boolean isAutoCreate() { return autoCreate; } - public File getInstance() { - return directory; - } - - public void setInstance(File directory) { - this.directory = directory; - } - public String getHost() { if (host == null) { host = "0.0.0.0"; @@ -397,13 +361,6 @@ public void setForce(boolean force) { this.force = force; } - public File getHome() { - if (home == null) { - home = new File(getBrokerHome()); - } - return home; - } - public void setHome(File home) { this.home = home; } @@ -420,14 +377,6 @@ public boolean isSharedStore() { return sharedStore; } - public String getEncoding() { - return encoding; - } - - public void setEncoding(String encoding) { - this.encoding = encoding; - } - public String getData() { return data; } @@ -553,13 +502,6 @@ public Object execute(ActionContext context) throws Exception { return run(context); } - /** - * This method is made public for the testsuite - */ - public InputStream openStream(String source) { - return this.getClass().getResourceAsStream(source); - } - /** * Checks that the directory provided either exists and is writable or doesn't exist but can be created. */ @@ -583,10 +525,9 @@ private File createDirectory(String name, File root) { return directory; } + @Override public Object run(ActionContext context) throws Exception { - - IS_WINDOWS = System.getProperty("os.name").toLowerCase().trim().startsWith("win"); - IS_CYGWIN = IS_WINDOWS && "cygwin".equals(System.getenv("OSTYPE")); + super.run(context); setupJournalType(); @@ -670,7 +611,6 @@ public Object run(ActionContext context) throws Exception { filters.put("${message-load-balancing}", messageLoadBalancing.toString()); filters.put("${user}", getUser()); filters.put("${password}", getPassword()); - filters.put("${role}", role); filters.put("${encoded.role}", role.replaceAll(" ", "\\\\ ")); @@ -749,30 +689,21 @@ public Object run(ActionContext context) throws Exception { if (home != null) { filters.put("${home}", path(home)); } - filters.put("${artemis.home}", path(getHome().toString())); - filters.put("${artemis.instance}", path(directory)); - filters.put("${artemis.instance.uri}", directory.toURI().toString()); - filters.put("${artemis.instance.uri.windows}", directory.toURI().toString().replaceAll("%", "%%")); - filters.put("${artemis.instance.name}", directory.getName()); - filters.put("${java.home}", path(System.getProperty("java.home"))); - + new File(directory, "bin").mkdirs(); File etcFolder = createDirectory(etc, directory); - filters.put("${artemis.instance.etc.uri}", etcFolder.toURI().toString()); - filters.put("${artemis.instance.etc.uri.windows}", etcFolder.toURI().toString().replaceAll("%", "%%")); - filters.put("${artemis.instance.etc}", path(etcFolder)); - File logFolder = createDirectory("log", directory); - File oomeDumpFile = new File(logFolder, "oom_dump.hprof"); - filters.put("${artemis.instance.oome.dump}", path(oomeDumpFile)); new File(directory, "tmp").mkdirs(); new File(directory, "lib").mkdirs(); File dataFolder = createDirectory(data, directory); - filters.put("${artemis.instance.data}", path(dataFolder)); + File logFolder = createDirectory("log", directory); + File oomeDumpFile = new File(logFolder, "oom_dump.hprof"); if (javaOptions == null || javaOptions.length() == 0) { javaOptions = ""; } + addScriptFilters(filters, getHome(), getInstance(), etcFolder, dataFolder, oomeDumpFile, javaMemory, javaOptions, role); + boolean allowAnonymous = isAllowAnonymous(); @@ -794,22 +725,21 @@ public Object run(ActionContext context) throws Exception { filters.put("${journal-retention}", retentionTag); - filters.put("${java-opts}", javaOptions); filters.put("${java-memory}", javaMemory); if (allowAnonymous) { - write(ETC_LOGIN_CONFIG_WITH_GUEST, new File(etcFolder, ETC_LOGIN_CONFIG), filters, false); + write(ETC_LOGIN_CONFIG_WITH_GUEST, new File(etcFolder, ETC_LOGIN_CONFIG), filters, false, force); } else { - write(ETC_LOGIN_CONFIG_WITHOUT_GUEST, new File(etcFolder, ETC_LOGIN_CONFIG), filters, false); + write(ETC_LOGIN_CONFIG_WITHOUT_GUEST, new File(etcFolder, ETC_LOGIN_CONFIG), filters, false, force); } writeEtc(ETC_ARTEMIS_ROLES_PROPERTIES, etcFolder, filters, false); if (IS_WINDOWS) { write(BIN_ARTEMIS_CMD, filters, false); - write(BIN_ARTEMIS_SERVICE_EXE); - write(BIN_ARTEMIS_SERVICE_EXE_CONFIG); + write(BIN_ARTEMIS_SERVICE_EXE, force); + write(BIN_ARTEMIS_SERVICE_EXE_CONFIG, force); write(BIN_ARTEMIS_SERVICE_XML, filters, false); writeEtc(ETC_ARTEMIS_PROFILE_CMD, etcFolder, filters, false); } @@ -881,7 +811,6 @@ public Object run(ActionContext context) throws Exception { writeEtc(ETC_ARTEMIS_USERS_PROPERTIES, etcFolder, filters, false); // we want this variable to remain unchanged so that it will use the value set in the profile - filters.remove("${artemis.instance}"); if (SecurityManagerType.getType(securityManager) == SecurityManagerType.BASIC) { filters.put("${security-manager-settings}", readTextFile(ETC_BASIC_SECURITY_MANAGER_TXT, filters)); } else { @@ -894,7 +823,7 @@ public Object run(ActionContext context) throws Exception { filters.put("${jolokia.options}", ""); } else { filters.put("${jolokia.options}", "\n" + - " "); + " "); } writeEtc(ETC_JOLOKIA_ACCESS_XML, etcFolder, filters, false); @@ -930,6 +859,34 @@ public Object run(ActionContext context) throws Exception { return null; } + protected static void addScriptFilters(HashMap filters, + File home, + File directory, + File etcFolder, + File dataFolder, + File oomeDumpFile, + String javaMemory, + String javaOptions, + String role) throws IOException { + filters.put("${artemis.home}", path(home)); + // I am using a different replacing pattern here, for cases where want an actual ${artemis.instance} in the output + // so that's just to make a distinction + filters.put("@artemis.instance@", path(directory)); + filters.put("${artemis.instance.uri}", directory.toURI().toString()); + filters.put("${artemis.instance.uri.windows}", directory.toURI().toString().replaceAll("%", "%%")); + filters.put("${artemis.instance.name}", directory.getName()); + filters.put("${java.home}", path(System.getProperty("java.home"))); + + filters.put("${artemis.instance.etc.uri}", etcFolder.toURI().toString()); + filters.put("${artemis.instance.etc.uri.windows}", etcFolder.toURI().toString().replaceAll("%", "%%")); + filters.put("${artemis.instance.etc}", path(etcFolder)); + filters.put("${artemis.instance.oome.dump}", path(oomeDumpFile)); + filters.put("${artemis.instance.data}", path(dataFolder)); + filters.put("${java-memory}", javaMemory); + filters.put("${java-opts}", javaOptions); + filters.put("${role}", role); + } + private String getConnectors(HashMap filters) throws IOException { if (staticNode != null) { StringWriter stringWriter = new StringWriter(); @@ -1069,7 +1026,7 @@ private void performAutoTune(HashMap filters, JournalType journa syncFilter.put("${maxaio}", journalType == JournalType.ASYNCIO ? "" + ActiveMQDefaultConfiguration.getDefaultJournalMaxIoAio() : "1"); getActionContext().out.println("done! Your system can make " + writesPerMillisecondStr + - " writes per millisecond, your journal-buffer-timeout will be " + nanoseconds); + " writes per millisecond, your journal-buffer-timeout will be " + nanoseconds); filters.put("${journal-buffer.settings}", readTextFile(ETC_JOURNAL_BUFFER_SETTINGS, syncFilter)); @@ -1140,89 +1097,20 @@ private String[] getAddressList() { } } - private String path(String value) throws IOException { + private static String path(String value) throws IOException { return path(new File(value)); } - private String path(File value) throws IOException { + private static String path(File value) throws IOException { return value.getCanonicalPath(); } private void write(String source, HashMap filters, boolean unixTarget) throws Exception { - write(source, new File(directory, source), filters, unixTarget); + write(source, new File(directory, source), filters, unixTarget, force); } private void writeEtc(String source, File etcFolder, HashMap filters, boolean unixTarget) throws Exception { - write("etc/" + source, new File(etcFolder, source), filters, unixTarget); - } - - private void write(String source, - File target, - HashMap filters, - boolean unixTarget) throws Exception { - if (target.exists() && !force) { - throw new CLIException(String.format("The file '%s' already exists. Use --force to overwrite.", target)); - } - - String content = readTextFile(source, filters); - - // and then writing out in the new target encoding.. Let's also replace \n with the values - // that is correct for the current platform. - String separator = unixTarget && IS_CYGWIN ? "\n" : System.getProperty("line.separator"); - content = content.replaceAll("\\r?\\n", Matcher.quoteReplacement(separator)); - ByteArrayInputStream in = new ByteArrayInputStream(content.getBytes(encoding)); - try (FileOutputStream fout = new FileOutputStream(target)) { - copy(in, fout); - } - } - - private String applyFilters(String content, Map filters) throws IOException { - - if (filters != null) { - for (Map.Entry entry : filters.entrySet()) { - try { - content = replace(content, entry.getKey(), entry.getValue()); - } catch (Throwable e) { - getActionContext().out.println("Error on " + entry.getKey()); - e.printStackTrace(); - System.exit(-1); - } - } - } - return content; - } - - private String readTextFile(String source, Map filters) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try (InputStream in = openStream(source)) { - copy(in, out); - } - return applyFilters(new String(out.toByteArray(), StandardCharsets.UTF_8), filters); - } - - private void write(String source) throws IOException { - File target = new File(directory, source); - if (target.exists() && !force) { - throw new RuntimeException(String.format("The file '%s' already exists. Use --force to overwrite.", target)); - } - try (FileOutputStream fout = new FileOutputStream(target)) { - try (InputStream in = openStream(source)) { - copy(in, fout); - } - } - } - - private String replace(String content, String key, String value) { - return content.replaceAll(Pattern.quote(key), Matcher.quoteReplacement(value)); - } - - private void copy(InputStream is, OutputStream os) throws IOException { - byte[] buffer = new byte[1024 * 4]; - int c = is.read(buffer); - while (c >= 0) { - os.write(buffer, 0, c); - c = is.read(buffer); - } + write("etc/" + source, new File(etcFolder, source), filters, unixTarget, force); } private enum SecurityManagerType { @@ -1240,4 +1128,4 @@ public static SecurityManagerType getType(String type) { } } } -} +} \ No newline at end of file diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/InstallAbstract.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/InstallAbstract.java new file mode 100644 index 000000000000..8b3ed5bd01c0 --- /dev/null +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/InstallAbstract.java @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.activemq.artemis.cli.commands; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.airlift.airline.Arguments; +import io.airlift.airline.Option; +import org.apache.activemq.artemis.cli.CLIException; + +public class InstallAbstract extends InputAbstract { + + @Arguments(description = "The instance directory to hold the broker's configuration and data. Path must be writable.", required = true) + protected File directory; + + @Option(name = "--etc", description = "Directory where ActiveMQ configuration is located. Paths can be absolute or relative to artemis.instance directory ('etc' by default)") + protected String etc = "etc"; + + @Option(name = "--home", description = "Directory where ActiveMQ Artemis is installed") + protected File home; + + @Option(name = "--encoding", description = "The encoding that text files should use. Default = UTF-8.") + protected String encoding = "UTF-8"; + + @Option(name = "--windows", description = "Force windows script creation. Default based on your actual system.") + protected boolean windows = false; + + @Option(name = "--cygwin", description = "Force cygwin script creation. Default based on your actual system.") + protected boolean cygwin = false; + + @Option(name = "--java-options", description = "Extra java options to be passed to the profile") + protected String javaOptions = ""; + + @Option(name = "--java-memory", description = "Define the -Xmx memory parameter for the broker. Default = '2G'") + protected String javaMemory = "2G"; + + + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public File getInstance() { + return directory; + } + + public void setInstance(File directory) { + this.directory = directory; + } + + public File getHome() { + if (home == null) { + home = new File(getBrokerHome()); + } + return home; + } + + protected boolean IS_WINDOWS; + protected boolean IS_CYGWIN; + + public Object run(ActionContext context) throws Exception { + IS_WINDOWS = windows | System.getProperty("os.name").toLowerCase().trim().startsWith("win"); + IS_CYGWIN = cygwin | IS_WINDOWS && "cygwin".equals(System.getenv("OSTYPE")); + + return null; + } + + protected String applyFilters(String content, Map filters) { + if (filters != null) { + for (Map.Entry entry : filters.entrySet()) { + content = replace(content, entry.getKey(), entry.getValue()); + } + } + return content; + } + + protected String replace(String content, String key, String value) { + return content.replaceAll(Pattern.quote(key), Matcher.quoteReplacement(value)); + } + + + protected void copy(InputStream is, OutputStream os) throws IOException { + byte[] buffer = new byte[1024 * 4]; + int c = is.read(buffer); + while (c >= 0) { + os.write(buffer, 0, c); + c = is.read(buffer); + } + } + + + protected void write(String source, + File target, + HashMap filters, + boolean unixTarget, boolean force) throws Exception { + if (target.exists() && !force) { + throw new CLIException(String.format("The file '%s' already exists. Use --force to overwrite.", target)); + } + + String content = readTextFile(source, filters); + + if (content == null) { + new Exception(source + " not found").printStackTrace(); + } + + // and then writing out in the new target encoding.. Let's also replace \n with the values + // that is correct for the current platform. + String separator = unixTarget && IS_CYGWIN ? "\n" : System.getProperty("line.separator"); + content = content.replaceAll("\\r?\\n", Matcher.quoteReplacement(separator)); + ByteArrayInputStream in = new ByteArrayInputStream(content.getBytes(encoding)); + try (FileOutputStream fout = new FileOutputStream(target)) { + copy(in, fout); + } + } + + protected String readTextFile(String source, Map filters) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try (InputStream in = openStream(source)) { + if (in == null) { + throw new IOException("could not find resource " + source); + } + copy(in, out); + } + return applyFilters(new String(out.toByteArray(), StandardCharsets.UTF_8), filters); + } + + protected void write(String source, boolean force) throws IOException { + File target = new File(directory, source); + if (target.exists() && !force) { + throw new RuntimeException(String.format("The file '%s' already exists. Use --force to overwrite.", target)); + } + try (FileOutputStream fout = new FileOutputStream(target)) { + try (InputStream in = openStream(source)) { + copy(in, fout); + } + } + } + + /** + * This method is made public for the testsuite + */ + public InputStream openStream(String source) { + return this.getClass().getResourceAsStream(source); + } + + +} diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java index 62dc89e855b0..6c2f7e50a50d 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java @@ -75,6 +75,8 @@ public static void setEmbedded(boolean embedded) { public Object execute(ActionContext context) throws Exception { super.execute(context); + verifyOlderLogging(new File(getBrokerEtc())); + AtomicReference serverActivationFailed = new AtomicReference<>(); try { BrokerDTO broker = getBrokerDTO(); @@ -225,4 +227,20 @@ protected void stop() { e.printStackTrace(); } } + + + public static final String OLD_LOG_NAME = "logging.properties"; + + public static void verifyOlderLogging(File etc) throws Exception { + File newLogging = new File(etc, Create.ETC_LOG4J2_PROPERTIES); + File oldLogging = new File(etc, OLD_LOG_NAME); + + if (oldLogging.exists() && !newLogging.exists()) { + System.out.println("******************************************************************************************************************************************************************************"); + System.out.println("Your system has the older logging file " + OLD_LOG_NAME + ", but not the new " + Create.ETC_LOG4J2_PROPERTIES); + System.out.println("It appears you did not complete the migration on this artemis instance properly. Please check all the settings or run the './artemis upgrade' command from the new artemis home"); + System.out.println("******************************************************************************************************************************************************************************"); + } + } + } diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Upgrade.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Upgrade.java new file mode 100644 index 000000000000..9215f9e66472 --- /dev/null +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Upgrade.java @@ -0,0 +1,240 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.activemq.artemis.cli.commands; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.HashMap; +import java.util.Iterator; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; + +import io.airlift.airline.Command; +import io.airlift.airline.Option; + +@Command(name = "upgrade", description = "Update an artemis instance to the current artemis.home, keeping all the data and broker.xml. Warning: backup your instance before using this command and compare the files.") +public class Upgrade extends InstallAbstract { + /** + * Checks that the directory provided either exists and is writable or doesn't exist but can be created. + */ + protected void checkDirectory() { + if (!directory.exists()) { + throw new RuntimeException(String.format("Could not find path '%s' to upgrade.", directory)); + } else if (!directory.canWrite()) { + throw new RuntimeException(String.format("The path '%s' is not writable.", directory)); + } + } + + + @Override + public Object execute(ActionContext context) throws Exception { + this.checkDirectory(); + super.execute(context); + + return run(context); + } + + + public Object run(ActionContext context) throws Exception { + super.run(context); + context.out.println("*******************************************************************************************************************************"); + context.out.println("Upgrading broker instance " + directory + " to use artemis.home=" + getBrokerHome()); + + File bkpFolder = findBackup(context); + File binBkp = new File(bkpFolder, "bin"); + File etcBkp = new File(bkpFolder, "etc"); + File tmp = new File(bkpFolder, "tmp"); + binBkp.mkdirs(); + etcBkp.mkdirs(); + tmp.mkdirs(); + + File bin = new File(directory, "bin"); + File etcFolder = new File (directory, etc); + + if (etc == null || etc.equals("etc")) { + if (IS_WINDOWS && !IS_CYGWIN) { + File cmd = new File(bin, Create.ARTEMIS_CMD); + String pattern = "set ARTEMIS_INSTANCE_ETC="; + etcFolder = getETC(context, etcFolder, cmd, pattern); + } else { + File cmd = new File(bin, Create.ARTEMIS); + String pattern = "ARTEMIS_INSTANCE_ETC="; + etcFolder = getETC(context, etcFolder, cmd, pattern); + } + } + + if (bin == null || !bin.exists()) { // it can't be null, just being cautious + throw new IOException(bin + " does not exist for binary"); + } + + if (etcFolder == null || !etcFolder.exists()) { // it can't be null, just being cautious + throw new IOException(etcFolder + " does not exist for etc"); + } + + HashMap filters = new HashMap<>(); + Create.addScriptFilters(filters, getHome(), getInstance(), etcFolder, new File(getInstance(), "notUsed"), new File(getInstance(), "om-not-used.dmp"), javaMemory, javaOptions, "NA"); + + if (IS_WINDOWS) { + write(Create.BIN_ARTEMIS_CMD, new File(tmp, Create.ARTEMIS_CMD), filters, false, false); + upgrade(new File(tmp, Create.ARTEMIS_CMD), new File(bin, Create.ARTEMIS_CMD), binBkp, "set ARTEMIS_INSTANCE_ETC="); + + write(Create.BIN_ARTEMIS_SERVICE_XML, new File(tmp, Create.ARTEMIS_SERVICE_XML), filters, false, false); + upgrade(new File(tmp, Create.ARTEMIS_SERVICE_XML), new File(bin, Create.ARTEMIS_SERVICE_XML), binBkp, + "", "-Xmx", "-Xmx"); + + write("etc/" + Create.ETC_ARTEMIS_PROFILE_CMD, new File(tmp, Create.ETC_ARTEMIS_PROFILE_CMD), filters, false, false); + upgrade(new File(tmp, Create.ETC_ARTEMIS_PROFILE_CMD), new File(etcFolder, Create.ETC_ARTEMIS_PROFILE_CMD), binBkp, + "set ARTEMIS_INSTANCE=\"", "set ARTEMIS_DATA_DIR=", "set ARTEMIS_ETC_DIR=", "set ARTEMIS_OOME_DUMP=", "set ARTEMIS_INSTANCE_URI=", "set ARTEMIS_INSTANCE_ETC_URI="); + } + + if (!IS_WINDOWS || IS_CYGWIN) { + write(Create.BIN_ARTEMIS, new File(tmp, Create.ARTEMIS), filters, false, false); + upgrade(new File(tmp, Create.ARTEMIS), new File(bin, Create.ARTEMIS), binBkp, "ARTEMIS_INSTANCE_ETC="); + + write(Create.BIN_ARTEMIS_SERVICE, new File(tmp, Create.ARTEMIS_SERVICE), filters, false, false); + upgrade(new File(tmp, Create.ARTEMIS_SERVICE), new File(bin, Create.ARTEMIS_SERVICE), binBkp); // we replace the whole thing + + write("etc/" + Create.ETC_ARTEMIS_PROFILE, new File(tmp, Create.ETC_ARTEMIS_PROFILE), filters, false, false); + upgrade(new File(tmp, Create.ETC_ARTEMIS_PROFILE), new File(etcFolder, Create.ETC_ARTEMIS_PROFILE), etcBkp, "ARTEMIS_INSTANCE=", + "ARTEMIS_DATA_DIR=", "ARTEMIS_ETC_DIR=", "ARTEMIS_OOME_DUMP=", "ARTEMIS_INSTANCE_URI=", "ARTEMIS_INSTANCE_ETC_URI=", "HAWTIO_ROLE="); + } + + upgradeLogging(context, etcBkp, etcFolder); + + context.out.println(); + context.out.println("*******************************************************************************************************************************"); + + return null; + } + + private File getETC(ActionContext context, File etcFolder, File cmd, String pattern) throws IOException { + String etcLine = getLine(cmd, pattern); + if (etcLine != null) { + etcLine = etcLine.trim(); + etcLine = etcLine.substring(pattern.length() + 1, etcLine.length() - 1); + etcFolder = new File(etcLine); + context.out.println("ETC found at " + etcFolder); + context.out.println("Substring = " + etcFolder); + } + return etcFolder; + } + + private String getLine(File cmd, String pattern) throws IOException { + Stream lines = Files.lines(cmd.toPath()); + Iterator iterator = lines.iterator(); + while (iterator.hasNext()) { + String line = iterator.next(); + if (line.trim().startsWith(pattern)) { + return line; + } + } + return null; + } + + private void upgrade(File tmpFile, File targetFile, File bkp, String... keepingPrefixes) throws Exception { + HashMap replaceMatrix = new HashMap<>(); + + doUpgrade(tmpFile, targetFile, bkp, + line -> { + for (String prefix : keepingPrefixes) { + if (line.trim().startsWith(prefix)) { + replaceMatrix.put(prefix, line); + } + } + }, line -> { + for (String prefix : keepingPrefixes) { + if (line.trim().startsWith(prefix)) { + String original = replaceMatrix.get(prefix); + return original; + } + } + return line; + }); + } + + private void doUpgrade(File tmpFile, File targetFile, File bkp, Consumer originalConsumer, Function targetFunction) throws Exception { + Files.copy(targetFile.toPath(), bkp.toPath(), StandardCopyOption.REPLACE_EXISTING); + + // we first scan the original lines on the originalConsumer, giving a chance to the caller to fill out the original matrix + Stream originalLines = Files.lines(targetFile.toPath()); + originalLines.forEach(line -> { + if (originalConsumer != null) { + originalConsumer.accept(line); + } + }); + + PrintStream streamOutput = new PrintStream(new FileOutputStream(targetFile)); + + // now we open the new file from the tmp, and we will give a chance for the targetFunction to replace lines from a matrix + try (Stream lines = Files.lines(tmpFile.toPath())) { + + Iterator linesIterator = lines.iterator(); + while (linesIterator.hasNext()) { + String line = linesIterator.next(); + line = targetFunction.apply(line); + if (line != null) { + streamOutput.println(line); + } + } + } + } + + private void upgradeLogging(ActionContext context, File bkpFolder, File etc) throws Exception { + File oldLogging = new File(etc, "logging.properties"); + + if (oldLogging.exists()) { + context.out.println("Moving " + oldLogging + " under " + bkpFolder); + File oldLoggingCopy = new File(bkpFolder, "logging.properties"); + context.out.println(oldLogging.toPath() + " copy as " + oldLoggingCopy.toPath()); + Files.copy(oldLogging.toPath(), bkpFolder.toPath(), StandardCopyOption.REPLACE_EXISTING); + oldLogging.delete(); + File newLogging = new File(etc, Create.ETC_LOG4J2_PROPERTIES); + + + if (!newLogging.exists()) { + context.out.println("Creating " + newLogging); + InputStream inputStream = getClass().getResourceAsStream("etc/" + Create.ETC_LOG4J2_PROPERTIES); + OutputStream outputStream = new FileOutputStream(newLogging); + outputStream.write(inputStream.readAllBytes()); + inputStream.close(); + } + } + } + + protected File findBackup(ActionContext context) { + for (int bkp = 0; bkp < 10; bkp++) { + File bkpFolder = new File(directory, "old-config-bkp." + bkp); + if (!bkpFolder.exists()) { + bkpFolder.mkdirs(); + context.out.println("Using " + bkpFolder.getAbsolutePath() + " as a backup folder for the modified files"); + return bkpFolder; + } + } + throw new RuntimeException("Too many backup folders in place already. Please remove some of the old-config-bkp.* folders"); + } + + +} diff --git a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/bin/artemis-service.xml b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/bin/artemis-service.xml index 0f7881b5e980..fc76661261e5 100644 --- a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/bin/artemis-service.xml +++ b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/bin/artemis-service.xml @@ -23,13 +23,13 @@ Apache ActiveMQ Artemis is a reliable messaging broker - + - ${artemis.instance}\log + @artemis.instance@\log roll %JAVA_HOME%\bin\java.exe diff --git a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis.profile b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis.profile index 56d8adf83e74..e0b857fa2694 100644 --- a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis.profile +++ b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis.profile @@ -16,7 +16,7 @@ # under the License. ARTEMIS_HOME='${artemis.home}' -ARTEMIS_INSTANCE='${artemis.instance}' +ARTEMIS_INSTANCE='@artemis.instance@' ARTEMIS_DATA_DIR='${artemis.instance.data}' ARTEMIS_ETC_DIR='${artemis.instance.etc}' ARTEMIS_OOME_DUMP='${artemis.instance.oome.dump}' diff --git a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis.profile.cmd b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis.profile.cmd index c4ebbff04ae4..0d7c1e5acb38 100644 --- a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis.profile.cmd +++ b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/artemis.profile.cmd @@ -17,7 +17,7 @@ rem specific language governing permissions and limitations rem under the License. set ARTEMIS_HOME="${artemis.home}" -set ARTEMIS_INSTANCE="${artemis.instance}" +set ARTEMIS_INSTANCE="@artemis.instance@" set ARTEMIS_DATA_DIR="${artemis.instance.data}" set ARTEMIS_ETC_DIR="${artemis.instance.etc}" set ARTEMIS_OOME_DUMP="${artemis.instance.oome.dump}" diff --git a/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisUpgradePlugin.java b/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisUpgradePlugin.java new file mode 100644 index 000000000000..1d21fee762a7 --- /dev/null +++ b/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisUpgradePlugin.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.activemq.artemis.maven; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.activemq.artemis.boot.Artemis; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.descriptor.PluginDescriptor; +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; + +@Mojo(name = "upgrade", defaultPhase = LifecyclePhase.TEST_COMPILE) +public class ArtemisUpgradePlugin extends ArtemisAbstractPlugin { + + @Parameter + String name; + + /** + * The plugin descriptor + */ + private PluginDescriptor descriptor; + + @Parameter(defaultValue = "${activemq.basedir}", required = true) + private File home; + + @Parameter(defaultValue = "${activemq.basedir}/artemis-distribution/target/apache-artemis-${project.version}-bin/apache-artemis-${project.version}/", required = true) + private File alternateHome; + + @Parameter(defaultValue = "${basedir}/target/server0", required = true) + private File instance; + + @Parameter + private String[] args; + + + @Override + protected boolean isIgnore() { + return false; + } + + @Parameter boolean useSystemOutput = getLog().isDebugEnabled(); + + private void add(List list, String... str) { + for (String s : str) { + list.add(s); + } + } + + @Override + protected void doExecute() throws MojoExecutionException, MojoFailureException { + getLog().debug("Local " + localRepository); + MavenProject project = (MavenProject) getPluginContext().get("project"); + + if (!isArtemisHome(home.toPath())) { + if (isArtemisHome(alternateHome.toPath())) { + home = alternateHome; + } else { + getLog().error("********************************************************************************************"); + getLog().error("Could not locate suitable Artemis.home on either " + home + " or " + alternateHome); + getLog().error("Use the binary distribution or build the distribution before running the examples"); + getLog().error("********************************************************************************************"); + + throw new MojoExecutionException("Couldn't find artemis.home"); + } + } + + Map properties = getPluginContext(); + + Set entries = properties.entrySet(); + + if (getLog().isDebugEnabled()) { + getLog().debug("Entries.size " + entries.size()); + for (Map.Entry entry : entries) { + getLog().debug("... key=" + entry.getKey() + " = " + entry.getValue()); + } + } + + ArrayList listCommands = new ArrayList<>(); + + add(listCommands, "upgrade"); + + add(listCommands, instance.getAbsolutePath()); + + if (args != null) { + for (String a : args) { + add(listCommands, a); + } + } + getLog().debug("***** Server upgrading at " + instance + " with home=" + home + " *****"); + + try { + Artemis.execute(home, null, null, useSystemOutput, listCommands); + } catch (Throwable e) { + getLog().error(e); + throw new MojoFailureException(e.getMessage()); + } + } +} diff --git a/docs/user-manual/en/upgrading.md b/docs/user-manual/en/upgrading.md index 4eddda3c768b..e82c2eb30ff7 100644 --- a/docs/user-manual/en/upgrading.md +++ b/docs/user-manual/en/upgrading.md @@ -16,18 +16,18 @@ Because of this separation it's very easy to upgrade Artemis in most cases. > **Note:** > -> It's recommended to choose a folder different than the on where Apache +> It's recommended to choose a folder different from where Apache > Artemis was downloaded. This separation allows you run multiple broker > instances with the same Artemis "home" for example. It also simplifies > updating to newer versions of Artemis. - + ## General Upgrade Procedure Upgrading may require some specific steps noted in the [versions](versions.md), but the general process is as follows: 1. Navigate to the `etc` folder of the broker instance that's being upgraded -1. Open `artemis.profile` (`artemis.profile.cmd` on Windows). It contains a +2. Open `artemis.profile` (`artemis.profile.cmd` on Windows). It contains a property which is relevant for the upgrade: ``` @@ -37,7 +37,7 @@ but the general process is as follows: If you run Artemis as a service on windows you have to do the following additional steps: 1. Navigate to the `bin` folder of the broker instance that's being upgraded -1. Open `artemis-service.xml`. It contains a property which is relevant for the upgrade: +2. Open `artemis-service.xml`. It contains a property which is relevant for the upgrade: ``` @@ -48,3 +48,23 @@ most cases_ the instance can be upgraded to a newer version simply by changing the value of this property to the location of the new broker home. Please refer to the aforementioned [versions](versions.md) document for additional upgrade steps (if required). + +It is also possible to do these steps automatically as it can be seen in the next section. + +## Upgrading tool + +An automatic approach can be used to upgrade the instance. You may simply call `./artemis upgrade `. + +```shell +cd $NEW_ARTEMIS_DOWNLOAD/bin/ +./artemis upgrade PATH_TO_UPGRADING_INSTANCE +``` + +artemis, artemis.profile will be updated to the new version. + +The tool will also update log4j2.properties (if you are migrating from a version previous to 2.27.0). + +> **Note:** +> +>Eventual customizations to your scripts will be lost, however the script will copy the older version at a created old-config-bkp folder. + diff --git a/docs/user-manual/en/versions.md b/docs/user-manual/en/versions.md index 65f134181d16..ba94c14714b8 100644 --- a/docs/user-manual/en/versions.md +++ b/docs/user-manual/en/versions.md @@ -9,8 +9,10 @@ This chapter provides the following information for each release: chapter in addition to any version-specific upgrade instructions outlined here. ## 2.27.0 +[Full release notes](https://issues.apache.org/jira/secure/ReleaseNote.jspa?version=12352246&projectId=12315920) Highlights: +- 2.27.0 Introduced a new upgrade tool to help migrating your instance to a newer version. Simply use `./artemis upgrade ` from the new downloaded broker. - The client and broker now use [SLF4J](https://www.slf4j.org/) for their logging API. - The broker distribution now uses [Log4J 2](https://logging.apache.org/log4j/2.x/manual/) as its logging implementation. diff --git a/tests/smoke-tests/pom.xml b/tests/smoke-tests/pom.xml index a2951950a622..1607bc60c7c9 100644 --- a/tests/smoke-tests/pom.xml +++ b/tests/smoke-tests/pom.xml @@ -191,6 +191,22 @@ + + + src/main/resources + false + + **/* + + + + src/main/filtered-resources + true + + **/* + + + maven-resources-plugin @@ -1212,6 +1228,29 @@ + + test-compile + upgrade + + upgrade + + + ${basedir}/target/classes/servers/toUpgradeTest + + + + test-compile + upgrade-windows + + upgrade + + + ${basedir}/target/classes/servers/windows + + --windows + + + diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis-roles.properties b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis-roles.properties new file mode 100644 index 000000000000..ee6feea7904f --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis-roles.properties @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF 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. +## --------------------------------------------------------------------------- + +amq = y \ No newline at end of file diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis-users.properties b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis-users.properties new file mode 100644 index 000000000000..47025bdaabb0 --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis-users.properties @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF 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. +## --------------------------------------------------------------------------- + +y = ENC(1024:4D83B7E5E85B4F43D65E31E9C7A69055D13BB165E54F57078F3E5D3DA188F3ED:3D71F9F4D6396B43255D37B47E859357DC244759B9BF5BCCA19DAD8C613E1A7302EF7A433BE2463B6AC4057B7227271C23659BF50CFE30ACE49F891C63F2A7D2) \ No newline at end of file diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis.profile b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis.profile new file mode 100644 index 000000000000..4f0539bae072 --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/artemis.profile @@ -0,0 +1,65 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF 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. + +ARTEMIS_HOME='must-change' +ARTEMIS_INSTANCE='${project.basedir}/target/classes/servers/toUpgradeTest' +ARTEMIS_DATA_DIR='${project.basedir}/target/classes/servers/toUpgradeTest/data' +ARTEMIS_ETC_DIR='${project.basedir}/target/classes/servers/toUpgradeETC' +ARTEMIS_OOME_DUMP='${project.basedir}/target/classes/servers/toUpgradeTest/log/oom_dump.hprof' + +# The logging config will need an URI +# this will be encoded in case you use spaces or special characters +# on your directory structure +ARTEMIS_INSTANCE_URI='file:${project.basedir}/target/classes/servers/toUpgradeTest' +ARTEMIS_INSTANCE_ETC_URI='file:${project.basedir}/target/classes/servers/toUpgradeETC' + +# Cluster Properties: Used to pass arguments to ActiveMQ Artemis which can be referenced in broker.xml +#ARTEMIS_CLUSTER_PROPS="-Dactivemq.remoting.default.port=61617 -Dactivemq.remoting.amqp.port=5673 -Dactivemq.remoting.stomp.port=61614 -Dactivemq.remoting.hornetq.port=5446" + +# Hawtio Properties +# HAWTIO_ROLE define the user role or roles required to be able to login to the console. Multiple roles to allow can +# be separated by a comma. Set to '*' or an empty value to disable role checking when Hawtio authenticates a user. +HAWTIO_ROLE='amq' + +# Java Opts +if [ -z "$JAVA_ARGS" ]; then + #### I am adding a customization to the JAVA-ARGS that would be replaced + #### If this line is seen on the upgrade it means that things are not working + JAVA_ARGS="-should-not-work -XX:+PrintClassHistogram -XX:+UseG1GC -XX:+UseStringDeduplication -Xms512M -Xmx2G -Dhawtio.disableProxy=true -Dhawtio.realm=activemq -Dhawtio.offline=true -Dhawtio.rolePrincipalClasses=org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal -Djolokia.policyLocation=${ARTEMIS_INSTANCE_ETC_URI}jolokia-access.xml " +fi + +# Uncomment to enable logging for Safepoint JVM pauses +# +# In addition to the traditional GC logs you could enable some JVM flags to know any meaningful and "hidden" pause +# that could affect the latencies of the services delivered by the broker, including those that are not reported by +# the classic GC logs and dependent by JVM background work (eg method deoptimizations, lock unbiasing, JNI, counted +# loops and obviously GC activity). +# +# Replace "all_pauses.log" with the file name you want to log to. +# JAVA_ARGS="$JAVA_ARGS -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:+LogVMOutput -XX:LogFile=all_pauses.log" + +# Uncomment to enable the dumping of the Java heap when a java.lang.OutOfMemoryError exception is thrown +# JAVA_ARGS="$JAVA_ARGS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${ARTEMIS_OOME_DUMP}" + +# Only enable debug options for the 'run' command +if [ "$1" = "run" ]; then : + # Uncomment to enable remote debugging + # DEBUG_ARGS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" + + # Uncomment for async profiler + # DEBUG_ARGS="-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints" +fi \ No newline at end of file diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/bootstrap.xml b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/bootstrap.xml new file mode 100644 index 000000000000..c16bcf9082ee --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/bootstrap.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/broker.xml b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/broker.xml new file mode 100644 index 000000000000..c88da8e62f71 --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/broker.xml @@ -0,0 +1,254 @@ + + + + + + + + 0.0.0.0 + + + true + + + NIO + + data/paging + + data/bindings + + data/journal + + data/large-messages + + + + + + + true + + 2 + + 10 + + 4096 + + 10M + + + + + + + + + + + + + + + + + + + + + 5000 + + + 90 + + + true + + 120000 + + 60000 + + HALT + + + + + + + -1 + + + + + + + + + + + + + + tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;amqpMinLargeMessageSize=102400;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300;amqpDuplicateDetection=true;supportAdvisory=false;suppressInternalManagementObjects=false + + + tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;amqpCredits=1000;amqpLowCredits=300;amqpMinLargeMessageSize=102400;amqpDuplicateDetection=true + + + tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true + + + tcp://0.0.0.0:5445?anycastPrefix=jms.queue.;multicastPrefix=jms.topic.;protocols=HORNETQ,STOMP;useEpoll=true + + + tcp://0.0.0.0:1883?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;useEpoll=true + + + + + + + + + + + + + + + + + + + + + + + + DLQ + ExpiryQueue + 0 + + -1 + 10 + PAGE + true + true + + + + DLQ + ExpiryQueue + 0 + + + + -1 + + + -1 + + + 10M + + + -1 + + + 20M + + 10 + PAGE + true + true + false + false + + + + +
+ + + +
+
+ + + +
+ +
+ + + + +
+
diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/jolokia-access.xml b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/jolokia-access.xml new file mode 100644 index 000000000000..679523f896e6 --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/jolokia-access.xml @@ -0,0 +1,35 @@ + + + + + + + + + *://localhost* + + + + + + + + \ No newline at end of file diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/logging.properties b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/logging.properties new file mode 100644 index 000000000000..97980b99c222 --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/logging.properties @@ -0,0 +1,90 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF 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. +# + +# Additional logger names to configure (root logger is always configured) +# Root logger option +loggers=org.eclipse.jetty,org.jboss.logging,org.apache.activemq.artemis.core.server,org.apache.activemq.artemis.utils,org.apache.activemq.artemis.utils.critical,org.apache.activemq.artemis.journal,org.apache.activemq.artemis.jms.server,org.apache.activemq.artemis.integration.bootstrap,org.apache.activemq.audit.base,org.apache.activemq.audit.message,org.apache.activemq.audit.resource,org.apache.curator,org.apache.zookeeper + +# Root logger level +logger.level=INFO +# ActiveMQ Artemis logger levels +logger.org.apache.activemq.artemis.core.server.level=INFO +logger.org.apache.activemq.artemis.journal.level=INFO +logger.org.apache.activemq.artemis.utils.level=INFO + +# if you have issues with CriticalAnalyzer, setting this as TRACE would give you extra troubleshooting information. +# but do not use it regularly as it would incur in some extra CPU usage for this diagnostic. +logger.org.apache.activemq.artemis.utils.critical.level=INFO + +logger.org.apache.activemq.artemis.jms.level=INFO +logger.org.apache.activemq.artemis.integration.bootstrap.level=INFO +logger.org.eclipse.jetty.level=WARN +# Root logger handlers +logger.handlers=FILE,CONSOLE + +# quorum logger levels +logger.org.apache.curator.level=WARN +logger.org.apache.zookeeper.level=ERROR + +# to enable audit change the level to INFO +logger.org.apache.activemq.audit.base.level=ERROR +logger.org.apache.activemq.audit.base.handlers=AUDIT_FILE +logger.org.apache.activemq.audit.base.useParentHandlers=false + +logger.org.apache.activemq.audit.resource.level=ERROR +logger.org.apache.activemq.audit.resource.handlers=AUDIT_FILE +logger.org.apache.activemq.audit.resource.useParentHandlers=false + +logger.org.apache.activemq.audit.message.level=ERROR +logger.org.apache.activemq.audit.message.handlers=AUDIT_FILE +logger.org.apache.activemq.audit.message.useParentHandlers=false + +# Console handler configuration +handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler +handler.CONSOLE.properties=autoFlush +handler.CONSOLE.level=DEBUG +handler.CONSOLE.autoFlush=true +handler.CONSOLE.formatter=PATTERN + +# File handler configuration +handler.FILE=org.jboss.logmanager.handlers.PeriodicRotatingFileHandler +handler.FILE.level=DEBUG +handler.FILE.properties=suffix,append,autoFlush,fileName +handler.FILE.suffix=.yyyy-MM-dd +handler.FILE.append=true +handler.FILE.autoFlush=true +handler.FILE.fileName=${artemis.instance}/log/artemis.log +handler.FILE.formatter=PATTERN + +# Formatter pattern configuration +formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter +formatter.PATTERN.properties=pattern +formatter.PATTERN.pattern=%d %-5p [%c] %s%E%n + +#Audit logger +handler.AUDIT_FILE=org.jboss.logmanager.handlers.PeriodicRotatingFileHandler +handler.AUDIT_FILE.level=INFO +handler.AUDIT_FILE.properties=suffix,append,autoFlush,fileName +handler.AUDIT_FILE.suffix=.yyyy-MM-dd +handler.AUDIT_FILE.append=true +handler.AUDIT_FILE.autoFlush=true +handler.AUDIT_FILE.fileName=${artemis.instance}/log/audit.log +handler.AUDIT_FILE.formatter=AUDIT_PATTERN + +formatter.AUDIT_PATTERN=org.jboss.logmanager.formatters.PatternFormatter +formatter.AUDIT_PATTERN.properties=pattern +formatter.AUDIT_PATTERN.pattern=%d [AUDIT](%t) %s%E%n diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/login.config b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/login.config new file mode 100644 index 000000000000..bcdf92893f9c --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/login.config @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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. + */ + +activemq { + org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule sufficient + debug=false + reload=true + org.apache.activemq.jaas.properties.user="artemis-users.properties" + org.apache.activemq.jaas.properties.role="artemis-roles.properties"; + + org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule sufficient + debug=false + org.apache.activemq.jaas.guest.user="y" + org.apache.activemq.jaas.guest.role="amq"; +}; \ No newline at end of file diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/management.xml b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/management.xml new file mode 100644 index 000000000000..002ee950501e --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/toUpgradeETC/management.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis-roles.properties b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis-roles.properties new file mode 100644 index 000000000000..ee6feea7904f --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis-roles.properties @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF 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. +## --------------------------------------------------------------------------- + +amq = y \ No newline at end of file diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis-users.properties b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis-users.properties new file mode 100644 index 000000000000..8d4122dc45e9 --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis-users.properties @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF 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. +## --------------------------------------------------------------------------- + +y = ENC(1024:F2B5A875934D0DA88F3E7416FA616418DB802AB1B0F8925B2C2A93BDC0AD57B4:A9A5D72B87731DA5CB02F8317028B526032240EC26C371B8DEF771CF0BC4805FB10DD5A9BBAEE9F984300EDB03C4A5018D7A4FE3680A98B4CCF57E79C347EF43) \ No newline at end of file diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis.profile.cmd b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis.profile.cmd new file mode 100644 index 000000000000..0ea79ca86c04 --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/artemis.profile.cmd @@ -0,0 +1,50 @@ +@echo off +rem Licensed to the Apache Software Foundation (ASF) under one +rem or more contributor license agreements. See the NOTICE file +rem distributed with this work for additional information +rem regarding copyright ownership. The ASF licenses this file +rem to you under the Apache License, Version 2.0 (the +rem "License"); you may not use this file except in compliance +rem with the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, +rem software distributed under the License is distributed on an +rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +rem KIND, either express or implied. See the License for the +rem specific language governing permissions and limitations +rem under the License. + +set ARTEMIS_HOME="must-change" +set ARTEMIS_INSTANCE="no-change" +set ARTEMIS_DATA_DIR="no-change" +set ARTEMIS_ETC_DIR="no-change" +set ARTEMIS_OOME_DUMP="no-change" + + +rem The logging config will need an URI +rem this will be encoded in case you use spaces or special characters +rem on your directory structure +set ARTEMIS_INSTANCE_URI="file:/no-change/" +set ARTEMIS_INSTANCE_ETC_URI="file:/no-change/" + +rem Cluster Properties: Used to pass arguments to ActiveMQ Artemis which can be referenced in broker.xml +rem set ARTEMIS_CLUSTER_PROPS=-Dactivemq.remoting.default.port=61617 -Dactivemq.remoting.amqp.port=5673 -Dactivemq.remoting.stomp.port=61614 -Dactivemq.remoting.hornetq.port=5446 + +rem Java Opts +IF "%JAVA_ARGS%"=="" (set JAVA_ARGS= -XX:AutoBoxCacheMax=20000 -XX:+PrintClassHistogram -XX:+UseG1GC -XX:+UseStringDeduplication -Xms512M -Xmx2G -Djava.security.auth.login.config=%ARTEMIS_ETC_DIR%\login.config -Dhawtio.disableProxy=true -Dhawtio.offline=true -Dhawtio.realm=activemq -Dhawtio.role=amq -Dhawtio.rolePrincipalClasses=org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal -Djolokia.policyLocation=%ARTEMIS_INSTANCE_ETC_URI%\jolokia-access.xml -Dartemis.instance=%ARTEMIS_INSTANCE%) + +rem Logs Safepoints JVM pauses: Uncomment to enable them +rem In addition to the traditional GC logs you could enable some JVM flags to know any meaningful and "hidden" pause that could +rem affect the latencies of the services delivered by the broker, including those that are not reported by the classic GC logs +rem and dependent by JVM background work (eg method deoptimizations, lock unbiasing, JNI, counted loops and obviously GC activity). +rem Replace "all_pauses.log" with the file name you want to log to. +rem set JAVA_ARGS=%JAVA_ARGS% -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:+LogVMOutput -XX:LogFile=all_pauses.log + +rem Enables the dumping of the java heap when a java.lang.OutOfMemoryError exception is thrown. +rem set JAVA_ARGS=%JAVA_ARGS% -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%ARTEMIS_OOME_DUMP% + +rem Only enable debug options for the 'run' command +rem Uncomment to enable remote debugging +rem if "%1"=="run" set DEBUG_ARGS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 \ No newline at end of file diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/bootstrap.xml b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/bootstrap.xml new file mode 100644 index 000000000000..9576de7c5592 --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/bootstrap.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/broker.xml b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/broker.xml new file mode 100644 index 000000000000..c88da8e62f71 --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/broker.xml @@ -0,0 +1,254 @@ + + + + + + + + 0.0.0.0 + + + true + + + NIO + + data/paging + + data/bindings + + data/journal + + data/large-messages + + + + + + + true + + 2 + + 10 + + 4096 + + 10M + + + + + + + + + + + + + + + + + + + + + 5000 + + + 90 + + + true + + 120000 + + 60000 + + HALT + + + + + + + -1 + + + + + + + + + + + + + + tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;amqpMinLargeMessageSize=102400;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300;amqpDuplicateDetection=true;supportAdvisory=false;suppressInternalManagementObjects=false + + + tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;amqpCredits=1000;amqpLowCredits=300;amqpMinLargeMessageSize=102400;amqpDuplicateDetection=true + + + tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true + + + tcp://0.0.0.0:5445?anycastPrefix=jms.queue.;multicastPrefix=jms.topic.;protocols=HORNETQ,STOMP;useEpoll=true + + + tcp://0.0.0.0:1883?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;useEpoll=true + + + + + + + + + + + + + + + + + + + + + + + + DLQ + ExpiryQueue + 0 + + -1 + 10 + PAGE + true + true + + + + DLQ + ExpiryQueue + 0 + + + + -1 + + + -1 + + + 10M + + + -1 + + + 20M + + 10 + PAGE + true + true + false + false + + + + +
+ + + +
+
+ + + +
+ +
+ + + + +
+
diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/jolokia-access.xml b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/jolokia-access.xml new file mode 100644 index 000000000000..679523f896e6 --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/jolokia-access.xml @@ -0,0 +1,35 @@ + + + + + + + + + *://localhost* + + + + + + + + \ No newline at end of file diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/logging.properties b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/logging.properties new file mode 100644 index 000000000000..97980b99c222 --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/logging.properties @@ -0,0 +1,90 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF 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. +# + +# Additional logger names to configure (root logger is always configured) +# Root logger option +loggers=org.eclipse.jetty,org.jboss.logging,org.apache.activemq.artemis.core.server,org.apache.activemq.artemis.utils,org.apache.activemq.artemis.utils.critical,org.apache.activemq.artemis.journal,org.apache.activemq.artemis.jms.server,org.apache.activemq.artemis.integration.bootstrap,org.apache.activemq.audit.base,org.apache.activemq.audit.message,org.apache.activemq.audit.resource,org.apache.curator,org.apache.zookeeper + +# Root logger level +logger.level=INFO +# ActiveMQ Artemis logger levels +logger.org.apache.activemq.artemis.core.server.level=INFO +logger.org.apache.activemq.artemis.journal.level=INFO +logger.org.apache.activemq.artemis.utils.level=INFO + +# if you have issues with CriticalAnalyzer, setting this as TRACE would give you extra troubleshooting information. +# but do not use it regularly as it would incur in some extra CPU usage for this diagnostic. +logger.org.apache.activemq.artemis.utils.critical.level=INFO + +logger.org.apache.activemq.artemis.jms.level=INFO +logger.org.apache.activemq.artemis.integration.bootstrap.level=INFO +logger.org.eclipse.jetty.level=WARN +# Root logger handlers +logger.handlers=FILE,CONSOLE + +# quorum logger levels +logger.org.apache.curator.level=WARN +logger.org.apache.zookeeper.level=ERROR + +# to enable audit change the level to INFO +logger.org.apache.activemq.audit.base.level=ERROR +logger.org.apache.activemq.audit.base.handlers=AUDIT_FILE +logger.org.apache.activemq.audit.base.useParentHandlers=false + +logger.org.apache.activemq.audit.resource.level=ERROR +logger.org.apache.activemq.audit.resource.handlers=AUDIT_FILE +logger.org.apache.activemq.audit.resource.useParentHandlers=false + +logger.org.apache.activemq.audit.message.level=ERROR +logger.org.apache.activemq.audit.message.handlers=AUDIT_FILE +logger.org.apache.activemq.audit.message.useParentHandlers=false + +# Console handler configuration +handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler +handler.CONSOLE.properties=autoFlush +handler.CONSOLE.level=DEBUG +handler.CONSOLE.autoFlush=true +handler.CONSOLE.formatter=PATTERN + +# File handler configuration +handler.FILE=org.jboss.logmanager.handlers.PeriodicRotatingFileHandler +handler.FILE.level=DEBUG +handler.FILE.properties=suffix,append,autoFlush,fileName +handler.FILE.suffix=.yyyy-MM-dd +handler.FILE.append=true +handler.FILE.autoFlush=true +handler.FILE.fileName=${artemis.instance}/log/artemis.log +handler.FILE.formatter=PATTERN + +# Formatter pattern configuration +formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter +formatter.PATTERN.properties=pattern +formatter.PATTERN.pattern=%d %-5p [%c] %s%E%n + +#Audit logger +handler.AUDIT_FILE=org.jboss.logmanager.handlers.PeriodicRotatingFileHandler +handler.AUDIT_FILE.level=INFO +handler.AUDIT_FILE.properties=suffix,append,autoFlush,fileName +handler.AUDIT_FILE.suffix=.yyyy-MM-dd +handler.AUDIT_FILE.append=true +handler.AUDIT_FILE.autoFlush=true +handler.AUDIT_FILE.fileName=${artemis.instance}/log/audit.log +handler.AUDIT_FILE.formatter=AUDIT_PATTERN + +formatter.AUDIT_PATTERN=org.jboss.logmanager.formatters.PatternFormatter +formatter.AUDIT_PATTERN.properties=pattern +formatter.AUDIT_PATTERN.pattern=%d [AUDIT](%t) %s%E%n diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/login.config b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/login.config new file mode 100644 index 000000000000..bcdf92893f9c --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/login.config @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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. + */ + +activemq { + org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule sufficient + debug=false + reload=true + org.apache.activemq.jaas.properties.user="artemis-users.properties" + org.apache.activemq.jaas.properties.role="artemis-roles.properties"; + + org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule sufficient + debug=false + org.apache.activemq.jaas.guest.user="y" + org.apache.activemq.jaas.guest.role="amq"; +}; \ No newline at end of file diff --git a/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/management.xml b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/management.xml new file mode 100644 index 000000000000..002ee950501e --- /dev/null +++ b/tests/smoke-tests/src/main/filtered-resources/servers/windowsETC/management.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/upgradeTest/CompareUpgradeTest.java b/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/upgradeTest/CompareUpgradeTest.java new file mode 100644 index 000000000000..80d00dbd44a5 --- /dev/null +++ b/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/upgradeTest/CompareUpgradeTest.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.activemq.artemis.tests.smoke.upgradeTest; + +import java.io.File; +import java.lang.invoke.MethodHandles; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** This test will compare expected values at the upgraded servers. */ +public class CompareUpgradeTest { + + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + public static final String basedir = System.getProperty("basedir"); + + @Test + public void testWindows() throws Exception { + String windowsBin = basedir + "/target/classes/servers/windows/bin"; + String windowsETC = basedir + "/target/classes/servers/windowsETC"; + + checkExpectedValues(windowsBin + "/artemis.cmd", "set ARTEMIS_INSTANCE_ETC=", "\"" + windowsETC + "\""); + Map result = checkExpectedValues(windowsBin + "/artemis-service.xml", + "", + "", + "", + "" + ); + + String home = result.get(""); + + File oldLogging = new File(windowsETC + "/logging.properties"); + File newLogging = new File(windowsETC + "/log4j2.properties"); + + Assert.assertFalse("Old logging must be removed by upgrade", oldLogging.exists()); + Assert.assertTrue("New Logging must be installed by upgrade", newLogging.exists()); + } + + + @Test + public void testLinux() throws Exception { + + String instanceDir = basedir + "/target/classes/servers/toUpgradeTest"; + String bin = instanceDir + "/bin"; + String etc = basedir + "/target/classes/servers/toUpgradeETC"; + + checkExpectedValues(bin + "/artemis", "ARTEMIS_INSTANCE_ETC=", "'" + etc + "'"); + + Map result = checkExpectedValues(etc + "/artemis.profile", + "ARTEMIS_HOME=", null, // no expected value, will check on result + "ARTEMIS_INSTANCE=", "'" + instanceDir + "'", + "ARTEMIS_DATA_DIR=", "'" + instanceDir + "/data'", + "ARTEMIS_ETC_DIR=", "'" + etc + "'", + "ARTEMIS_OOME_DUMP=", "'" + instanceDir + "/log/oom_dump.hprof'", + "ARTEMIS_INSTANCE_URI=", "'file:" + instanceDir + "'", + "ARTEMIS_INSTANCE_ETC_URI=", "'file:" + etc + "'"); + + String home = result.get("ARTEMIS_HOME="); + Assert.assertNotNull(home); + Assert.assertNotEquals("'must-change'", home); + + File oldLogging = new File(etc + "/logging.properties"); + File newLogging = new File(etc + "/log4j2.properties"); + + Assert.assertFalse("Old logging must be removed by upgrade", oldLogging.exists()); + Assert.assertTrue("New Logging must be installed by upgrade", newLogging.exists()); + } + + + private Map checkExpectedValues(String fileName, String... expectedPairs) throws Exception { + Assert.assertTrue("You must pass a pair of expected values", expectedPairs.length > 0 && expectedPairs.length % 2 == 0); + HashMap expectedValues = new HashMap<>(); + HashMap matchingValues = new HashMap<>(); + + for (int i = 0; i < expectedPairs.length; i += 2) { + Assert.assertFalse("Value duplicated on pairs ::" + expectedPairs[i], expectedValues.containsKey(expectedPairs[i])); + expectedValues.put(expectedPairs[i], expectedPairs[i + 1]); + } + + File file = new File(fileName); + Stream lines = Files.lines(file.toPath()); + lines.forEach(line -> { + String trimmedLine = line.trim(); + expectedValues.forEach((key, value) -> { + if (trimmedLine.startsWith(key)) { + String actualValue = trimmedLine.substring(key.length()); + logger.debug("match = {}", line); + matchingValues.put(key, actualValue); + + if (value == null) { + logger.debug("no expected value was defined for {}, we will just fill out the matchingValues for further evaluation", key); + } else { + logger.debug("prefix={}, expecting={}, actualValue={}", key, value, actualValue); + Assert.assertEquals(key + " did not match", value, actualValue); + } + } + }); + }); + + Assert.assertEquals("Some elements were not found in the output of " + fileName, matchingValues.size(), expectedValues.size()); + + return matchingValues; + } +} diff --git a/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/upgradeTest/UpgradeTest.java b/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/upgradeTest/UpgradeTest.java new file mode 100644 index 000000000000..75501318ef5d --- /dev/null +++ b/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/upgradeTest/UpgradeTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.activemq.artemis.tests.smoke.upgradeTest; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import java.io.File; + +import org.apache.activemq.artemis.tests.smoke.common.SmokeTestBase; +import org.apache.activemq.artemis.tests.util.CFUtil; +import org.apache.activemq.artemis.util.ServerUtil; +import org.apache.activemq.artemis.utils.RandomUtil; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** This test is making sure the upgrade command would be able to upgrade a test I created with artemis 2.25.0 */ +public class UpgradeTest extends SmokeTestBase { + + File upgradedServer; + + Process processServer; + + @Before + public void beforeTest() throws Exception { + upgradedServer = new File(basedir + "/target/classes/servers/toUpgradeTest"); + deleteDirectory(new File(upgradedServer, "data")); + deleteDirectory(new File(upgradedServer, "log")); + + processServer = ServerUtil.startServer(upgradedServer.getAbsolutePath(), "upgradedServer", 0, 5000); + addProcess(processServer); + } + + @Test + public void testSimpleSendReceive() throws Throwable { + + ConnectionFactory factory = CFUtil.createConnectionFactory("core", "tcp://localhost:61616"); + + try (Connection connection = factory.createConnection()) { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(session.createQueue(getName())); + MessageProducer producer = session.createProducer(session.createQueue(getName())); + String randomString = "Hello " + RandomUtil.randomString(); + producer.send(session.createTextMessage(randomString)); + TextMessage message = (TextMessage)consumer.receive(5000); + Assert.assertNotNull(message); + Assert.assertEquals(randomString, message.getText()); + } + + } + +}