mongodb-migration-web 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #!/bin/bash
  2. # MongoDB Migration Web Interface
  3. # Serves migration progress at ROOT_URL/migration-progress using Node.js
  4. # Source settings
  5. source $SNAP/bin/wekan-read-settings
  6. # Set up Node.js environment like wekan-control
  7. export NODE_PATH=$SNAP/bin
  8. # Configuration
  9. MIGRATION_STATUS="${SNAP_COMMON}/mongodb-migration-status.json"
  10. MIGRATION_LOG="${SNAP_COMMON}/mongodb-migration-log.txt"
  11. MIGRATION_PROGRESS="${SNAP_COMMON}/mongodb-migration-progress.html"
  12. # Use same PORT as wekan-control, but add 1 to avoid conflicts
  13. MIGRATION_PORT=$((PORT + 1))
  14. # Create Node.js HTTP server script
  15. create_node_server() {
  16. cat > "${SNAP_COMMON}/migration-web-server.js" << 'EOF'
  17. const http = require('http');
  18. const fs = require('fs');
  19. const path = require('path');
  20. const PORT = process.env.MIGRATION_PORT || 8081;
  21. const SNAP_COMMON = process.env.SNAP_COMMON;
  22. const ROOT_URL = process.env.ROOT_URL || 'http://127.0.0.1';
  23. const MIGRATION_STATUS = path.join(SNAP_COMMON, 'mongodb-migration-status.json');
  24. const MIGRATION_LOG = path.join(SNAP_COMMON, 'mongodb-migration-log.txt');
  25. function readFileSafe(filePath) {
  26. try {
  27. return fs.readFileSync(filePath, 'utf8');
  28. } catch (error) {
  29. return null;
  30. }
  31. }
  32. function getMigrationStatus() {
  33. const statusContent = readFileSafe(MIGRATION_STATUS);
  34. if (!statusContent) {
  35. return null;
  36. }
  37. try {
  38. return JSON.parse(statusContent);
  39. } catch (error) {
  40. return null;
  41. }
  42. }
  43. function getMigrationLog() {
  44. const logContent = readFileSafe(MIGRATION_LOG);
  45. if (!logContent) {
  46. return 'No log available';
  47. }
  48. const lines = logContent.split('\n');
  49. return lines.slice(-20).join('\n');
  50. }
  51. function generateHTML(status) {
  52. if (!status) {
  53. return `<!DOCTYPE html>
  54. <html>
  55. <head>
  56. <title>MongoDB Migration Progress</title>
  57. <meta http-equiv="refresh" content="5">
  58. <style>
  59. body { font-family: Arial, sans-serif; margin: 40px; }
  60. .container { max-width: 800px; margin: 0 auto; text-align: center; }
  61. </style>
  62. </head>
  63. <body>
  64. <div class="container">
  65. <h1>MongoDB Migration</h1>
  66. <p>No migration in progress.</p>
  67. <p><em>This page will refresh automatically every 5 seconds.</em></p>
  68. </div>
  69. </body>
  70. </html>`;
  71. }
  72. const { status: statusValue, step, total_steps, percentage, description, timestamp } = status;
  73. const logContent = getMigrationLog();
  74. return `<!DOCTYPE html>
  75. <html>
  76. <head>
  77. <title>MongoDB Migration Progress</title>
  78. <meta http-equiv="refresh" content="5">
  79. <style>
  80. body {
  81. font-family: Arial, sans-serif;
  82. margin: 40px;
  83. background-color: #f5f5f5;
  84. }
  85. .container {
  86. max-width: 800px;
  87. margin: 0 auto;
  88. background: white;
  89. padding: 30px;
  90. border-radius: 10px;
  91. box-shadow: 0 2px 10px rgba(0,0,0,0.1);
  92. }
  93. .progress-bar {
  94. width: 100%;
  95. background-color: #e0e0e0;
  96. border-radius: 10px;
  97. overflow: hidden;
  98. margin: 20px 0;
  99. }
  100. .progress-fill {
  101. height: 40px;
  102. background: linear-gradient(90deg, #4CAF50, #45a049);
  103. border-radius: 10px;
  104. width: ${percentage}%;
  105. transition: width 0.3s ease;
  106. display: flex;
  107. align-items: center;
  108. justify-content: center;
  109. color: white;
  110. font-weight: bold;
  111. }
  112. .status {
  113. margin: 20px 0;
  114. padding: 20px;
  115. background-color: #f9f9f9;
  116. border-radius: 5px;
  117. }
  118. .error { color: #d32f2f; }
  119. .success { color: #388e3c; }
  120. .warning { color: #f57c00; }
  121. .info { color: #1976d2; }
  122. .log-container {
  123. margin-top: 30px;
  124. max-height: 300px;
  125. overflow-y: auto;
  126. background-color: #f5f5f5;
  127. padding: 15px;
  128. border-radius: 5px;
  129. font-family: monospace;
  130. font-size: 12px;
  131. }
  132. .header {
  133. text-align: center;
  134. margin-bottom: 30px;
  135. }
  136. .status-indicator {
  137. display: inline-block;
  138. width: 12px;
  139. height: 12px;
  140. border-radius: 50%;
  141. margin-right: 8px;
  142. }
  143. .status-running { background-color: #ff9800; }
  144. .status-completed { background-color: #4caf50; }
  145. .status-error { background-color: #f44336; }
  146. .status-unknown { background-color: #9e9e9e; }
  147. </style>
  148. </head>
  149. <body>
  150. <div class="container">
  151. <div class="header">
  152. <h1>MongoDB Migration Progress</h1>
  153. <p>Migrating from MongoDB 3 to MongoDB 7</p>
  154. </div>
  155. <div class="progress-bar">
  156. <div class="progress-fill">${percentage}%</div>
  157. </div>
  158. <div class="status">
  159. <p><span class="status-indicator status-${statusValue}"></span><strong>Status:</strong> ${statusValue}</p>
  160. <p><strong>Progress:</strong> ${step} of ${total_steps} steps</p>
  161. <p><strong>Current Step:</strong> ${description}</p>
  162. <p><strong>Last Updated:</strong> ${timestamp}</p>
  163. </div>
  164. <div class="log-container">
  165. <h3>Migration Log (Last 20 lines):</h3>
  166. <pre>${logContent}</pre>
  167. </div>
  168. <p style="text-align: center; margin-top: 30px; color: #666;">
  169. <em>This page will refresh automatically every 5 seconds.</em><br>
  170. <em>Migration URL: ${ROOT_URL}/migration-progress</em>
  171. </p>
  172. </div>
  173. </body>
  174. </html>`;
  175. }
  176. const server = http.createServer((req, res) => {
  177. if (req.url === '/migration-progress' || req.url === '/') {
  178. const status = getMigrationStatus();
  179. const html = generateHTML(status);
  180. res.writeHead(200, {
  181. 'Content-Type': 'text/html; charset=utf-8',
  182. 'Cache-Control': 'no-cache',
  183. 'Connection': 'close'
  184. });
  185. res.end(html);
  186. } else {
  187. res.writeHead(404, { 'Content-Type': 'text/plain' });
  188. res.end('Not Found');
  189. }
  190. });
  191. server.listen(PORT, () => {
  192. console.log(`MongoDB Migration Web Server running on port ${PORT}`);
  193. });
  194. // Handle graceful shutdown
  195. process.on('SIGTERM', () => {
  196. console.log('Received SIGTERM, shutting down gracefully');
  197. server.close(() => {
  198. process.exit(0);
  199. });
  200. });
  201. process.on('SIGINT', () => {
  202. console.log('Received SIGINT, shutting down gracefully');
  203. server.close(() => {
  204. process.exit(0);
  205. });
  206. });
  207. EOF
  208. }
  209. # Start the Node.js web server
  210. start_node_server() {
  211. echo "Starting MongoDB migration web server using Node.js..."
  212. echo "Migration server will be available at: ${ROOT_URL}/migration-progress"
  213. echo "Migration server port: ${MIGRATION_PORT}"
  214. # Create the Node.js server script
  215. create_node_server
  216. # Export environment variables for the Node.js process
  217. export MIGRATION_PORT
  218. export ROOT_URL
  219. # Start the server using Node.js from SNAP/bin
  220. $NODE_PATH/node "${SNAP_COMMON}/migration-web-server.js"
  221. }
  222. # Start the web server
  223. start_node_server