PageRenderTime 42ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/jira-project/jira-components/jira-plugins/jira-ha-plugin/ha-container-api/src/main/java/com/atlassian/jira/plugins/ha/container/TomcatContainerSet.java

https://bitbucket.org/ahmed_bilal_360factors/jira7-core
Java | 241 lines | 203 code | 35 blank | 3 comment | 13 complexity | 3a5a2837c2346efcbd3478e82f6d1b84 MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.atlassian.jira.plugins.ha.container;
  2. import com.atlassian.jira.config.database.DatabaseConfig;
  3. import com.atlassian.jira.configurator.config.JiraHomeDatabaseConfigurationLoader;
  4. import com.atlassian.jira.functest.framework.backdoor.ZeroDowntimeControl;
  5. import com.atlassian.jira.plugins.ha.testapi.test.JiraCluster;
  6. import com.google.common.collect.ImmutableList;
  7. import com.google.common.collect.ImmutableMap;
  8. import org.ofbiz.core.entity.config.DatasourceInfo;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11. import java.io.BufferedReader;
  12. import java.io.FileNotFoundException;
  13. import java.io.IOException;
  14. import java.io.InputStreamReader;
  15. import java.net.URL;
  16. import java.nio.charset.StandardCharsets;
  17. import java.nio.file.Files;
  18. import java.nio.file.Path;
  19. import java.nio.file.StandardCopyOption;
  20. import java.sql.Connection;
  21. import java.sql.DriverManager;
  22. import java.sql.PreparedStatement;
  23. import java.sql.SQLException;
  24. import java.time.Duration;
  25. import java.time.Instant;
  26. import java.util.LinkedHashSet;
  27. import java.util.List;
  28. import java.util.Locale;
  29. import java.util.Map;
  30. import java.util.Set;
  31. import java.util.concurrent.TimeUnit;
  32. import java.util.function.Predicate;
  33. import java.util.function.Supplier;
  34. import java.util.stream.Stream;
  35. public class TomcatContainerSet implements ContainerSet<TomcatContainer> {
  36. private static final Logger log = LoggerFactory.getLogger(TomcatContainerSet.class);
  37. private final List<TomcatContainer> containers;
  38. private final Supplier<JiraCluster> clusterMaker;
  39. private final Path sharedHome;
  40. private final Path baseArtifactDirectory;
  41. private final Map<JiraType, ? extends Path> warArchiveMap;
  42. private final Path dbConfigFile;
  43. private JiraCluster cluster;
  44. TomcatContainerSet(List<? extends TomcatContainer> containers, Supplier<JiraCluster> clusterMaker,
  45. Path sharedHome, Path baseArtifactDirectory, Map<JiraType, ? extends Path> warArchiveMap,
  46. Path dbConfigFile) {
  47. this.containers = ImmutableList.copyOf(containers);
  48. this.clusterMaker = clusterMaker;
  49. this.sharedHome = sharedHome;
  50. this.baseArtifactDirectory = baseArtifactDirectory;
  51. this.warArchiveMap = ImmutableMap.copyOf(warArchiveMap);
  52. this.dbConfigFile = dbConfigFile;
  53. }
  54. @Override
  55. public List<? extends TomcatContainer> getContainers() {
  56. return containers;
  57. }
  58. @Override
  59. public void startAll() {
  60. getContainers().forEach(Container::start);
  61. }
  62. @Override
  63. public void stopAll() {
  64. getContainers().forEach(Container::stop);
  65. }
  66. @Override
  67. public synchronized JiraCluster cluster() {
  68. if (cluster == null) {
  69. cluster = clusterMaker.get();
  70. }
  71. return cluster;
  72. }
  73. @Override
  74. public void installJira(JiraType warType) {
  75. containers.forEach(c -> c.installJira(warType));
  76. }
  77. @Override
  78. public Path jiraWarFile(JiraType warType) {
  79. return warArchiveMap.get(warType);
  80. }
  81. @Override
  82. public void installWar(Path warFile, String context) {
  83. containers.forEach(c -> c.installWar(warFile, context));
  84. }
  85. private Path installedPluginsDirectory() {
  86. return sharedHome.resolve("plugins").resolve("installed-plugins");
  87. }
  88. public void removeAllSharedPlugins() {
  89. removeSharedPlugins(pluginFile -> true);
  90. }
  91. @Override
  92. public void installTestingPlugins(JiraType jiraType) {
  93. Path pluginsDir = baseArtifactDirectory.resolve("plugins-" + jiraType.name().toLowerCase(Locale.ROOT));
  94. try (Stream<Path> fileList = Files.list(pluginsDir)) {
  95. fileList.filter(file -> file.toString().endsWith(".jar")).forEach(this::installSharedPlugin);
  96. } catch (IOException e) {
  97. throw new RuntimeException("Failed to list files in plugins directory: " + e, e);
  98. }
  99. }
  100. @Override
  101. public void installSharedPlugin(Path pluginFile) {
  102. Path installedPluginsDirectory = installedPluginsDirectory();
  103. try {
  104. Files.createDirectories(installedPluginsDirectory);
  105. } catch (IOException e) {
  106. throw new RuntimeException("Failed to create installed-plugins directory under shared home: " + e, e);
  107. }
  108. Path targetPluginFile = installedPluginsDirectory.resolve(pluginFile.getFileName());
  109. try {
  110. Files.copy(pluginFile, targetPluginFile, StandardCopyOption.REPLACE_EXISTING);
  111. } catch (IOException e) {
  112. throw new RuntimeException("Failed to copy plugin to shared home: " + e, e);
  113. }
  114. }
  115. public void removeSharedPlugins(Predicate<? super Path> filter) {
  116. Path installedPluginsDirectory = installedPluginsDirectory();
  117. if (Files.notExists(installedPluginsDirectory))
  118. return;
  119. try (Stream<Path> fileList = Files.list(installedPluginsDirectory)) {
  120. fileList.filter(filter).forEach(file -> {
  121. try {
  122. Files.delete(file);
  123. } catch (IOException e) {
  124. throw new RuntimeException("Failed to delete plugin " + file.toString() + ": " + e, e);
  125. }
  126. });
  127. } catch (IOException e) {
  128. throw new RuntimeException("Failed to delete shared plugins: " + e, e);
  129. }
  130. }
  131. @Override
  132. public void resetDatabase() {
  133. //Use driver manager to read dbconfig.xml
  134. JiraHomeDatabaseConfigurationLoader loader = new JiraHomeDatabaseConfigurationLoader(dbConfigFile.getParent().toAbsolutePath().toString());
  135. DatabaseConfig dbConfig = loader.loadDatabaseConfiguration();
  136. DatasourceInfo datasourceInfo = dbConfig.getDatasourceInfo();
  137. String uri = datasourceInfo.getJdbcDatasource().getUri();
  138. String user = datasourceInfo.getJdbcDatasource().getUsername();
  139. String password = datasourceInfo.getJdbcDatasource().getPassword();
  140. try (Connection connection = DriverManager.getConnection(uri, user, password)) {
  141. runDbScript("reset-" + dbConfig.getDatabaseType(), connection);
  142. } catch (SQLException | IOException e) {
  143. throw new RuntimeException("Error restoring database dump: " + e, e);
  144. }
  145. }
  146. private static void runDbScript(String scriptName, Connection connection) throws SQLException, IOException {
  147. String resourceName = "/dbscript/" + scriptName + ".sql";
  148. URL scriptResource = TomcatContainerSet.class.getResource(resourceName);
  149. if (scriptResource == null) {
  150. throw new FileNotFoundException("Missing test resource: " + resourceName);
  151. }
  152. try (BufferedReader scriptReader = new BufferedReader(new InputStreamReader(scriptResource.openStream(), StandardCharsets.UTF_8))) {
  153. String line;
  154. do {
  155. line = scriptReader.readLine();
  156. if (line != null) {
  157. try (PreparedStatement stat = connection.prepareStatement(line)) {
  158. stat.executeUpdate();
  159. }
  160. }
  161. } while (line != null);
  162. }
  163. }
  164. @Override
  165. public Path getSharedHome() {
  166. return sharedHome;
  167. }
  168. @Override
  169. public void waitForUpgradeState(ZeroDowntimeControl.UpgradeState targetState, Duration timeout) {
  170. Instant timeoutTime = Instant.now().plus(timeout);
  171. Set<ZeroDowntimeControl.UpgradeState> statesObserved = new LinkedHashSet<>();
  172. try {
  173. do {
  174. ZeroDowntimeControl.ClusterState currentState = cluster.anyNode().backdoor().zdu().currentState();
  175. if (currentState.getState() == targetState) {
  176. return; //Got to our target
  177. }
  178. statesObserved.add(currentState.getState());
  179. Thread.sleep(200L);
  180. } while (Instant.now().isBefore(timeoutTime));
  181. } catch (InterruptedException e) {
  182. throw new RuntimeException("Interrupted waiting for target state " + targetState);
  183. }
  184. //If we get here we timed out waiting
  185. throw new RuntimeException("Timed out (" + timeout + ") waiting for target state " + targetState + ", observed " + statesObserved);
  186. }
  187. @Override
  188. public void waitForStartupOfActiveContainers(Duration timeout) {
  189. int startedContainers = Math.toIntExact(getContainers().stream()
  190. .map(container -> container.getCargoContainer().getState())
  191. .filter(state -> state.isStarted() || state.isStarting())
  192. .count());
  193. log.debug("Waiting for startup of " + startedContainers + " containers...");
  194. //Use first active node to perform replication operation - it doesn't actually matter which one we use
  195. getContainers().stream()
  196. .filter(container -> container.getCargoContainer().getState().isStarted())
  197. .findFirst()
  198. .orElseThrow(() -> new RuntimeException("No nodes have started up"))
  199. .replication().waitForClusterNodes(startedContainers, timeout.toMillis(), TimeUnit.MILLISECONDS);
  200. log.debug(startedContainers + " containers have now started up");
  201. }
  202. @Override
  203. public void waitForStartupOfActiveContainers() {
  204. waitForStartupOfActiveContainers(Duration.ofMinutes(5));
  205. }
  206. }