diff --git a/index.js b/index.js old mode 100755 new mode 100644 index 60ed342..a867c85 --- a/index.js +++ b/index.js @@ -817,6 +817,199 @@ async function registerCommand(options) { } } +// Command to install Fleetbase via Docker +async function installFleetbaseCommand(options) { + const crypto = require('crypto'); + const os = require('os'); + + console.log('\nšŸš€ Fleetbase Installation\n'); + + try { + // Collect installation parameters + const answers = await prompt([ + { + type: 'input', + name: 'host', + message: 'Enter host or IP address to bind to:', + initial: options.host || 'localhost', + validate: (value) => { + if (!value) { + return 'Host is required'; + } + return true; + } + }, + { + type: 'select', + name: 'environment', + message: 'Choose environment:', + initial: options.environment === 'production' ? 1 : 0, + choices: [ + { title: 'Development', value: 'development' }, + { title: 'Production', value: 'production' } + ] + }, + { + type: 'input', + name: 'directory', + message: 'Installation directory:', + initial: options.directory || process.cwd(), + validate: (value) => { + if (!value) { + return 'Directory is required'; + } + return true; + } + } + ]); + + const host = options.host || answers.host; + const environment = options.environment || answers.environment; + const directory = options.directory || answers.directory; + + // Determine configuration based on environment + const useHttps = environment === 'production'; + const appDebug = environment === 'development'; + const scSecure = environment === 'production'; + const schemeApi = useHttps ? 'https' : 'http'; + const schemeConsole = useHttps ? 'https' : 'http'; + + console.log(`\nšŸ“‹ Configuration:`); + console.log(` Host: ${host}`); + console.log(` Environment: ${environment}`); + console.log(` Directory: ${directory}`); + console.log(` HTTPS: ${useHttps}`); + + // Check if directory exists and has Fleetbase files + if (!await fs.pathExists(directory)) { + console.error(`\nāœ– Directory does not exist: ${directory}`); + console.log('\nā„¹ļø Please clone the Fleetbase repository first:'); + console.log(' git clone https://github.com/fleetbase/fleetbase.git'); + process.exit(1); + } + + const dockerComposePath = path.join(directory, 'docker-compose.yml'); + if (!await fs.pathExists(dockerComposePath)) { + console.error(`\nāœ– docker-compose.yml not found in ${directory}`); + console.log('\nā„¹ļø Please ensure you are in the Fleetbase root directory.'); + process.exit(1); + } + + // Generate APP_KEY + console.log('\nā³ Generating APP_KEY...'); + const appKey = 'base64:' + crypto.randomBytes(32).toString('base64'); + console.log('āœ” APP_KEY generated'); + + // Create docker-compose.override.yml + console.log('ā³ Creating docker-compose.override.yml...'); + const overrideContent = `services: + application: + environment: + APP_KEY: "${appKey}" + CONSOLE_HOST: "${schemeConsole}://${host}:4200" + ENVIRONMENT: "${environment}" + APP_DEBUG: "${appDebug}" +`; + const overridePath = path.join(directory, 'docker-compose.override.yml'); + await fs.writeFile(overridePath, overrideContent); + console.log('āœ” docker-compose.override.yml created'); + + // Create console/fleetbase.config.json (for development runtime config) + console.log('ā³ Creating console/fleetbase.config.json...'); + const configDir = path.join(directory, 'console'); + await fs.ensureDir(configDir); + const configContent = { + API_HOST: `${schemeApi}://${host}:8000`, + SOCKETCLUSTER_HOST: host, + SOCKETCLUSTER_PORT: '38000', + SOCKETCLUSTER_SECURE: scSecure + }; + const configPath = path.join(configDir, 'fleetbase.config.json'); + await fs.writeJson(configPath, configContent, { spaces: 2 }); + console.log('āœ” console/fleetbase.config.json created'); + + // Update console environment files (.env.development and .env.production) + console.log('ā³ Updating console environment files...'); + const environmentsDir = path.join(configDir, 'environments'); + + // Update .env.development + const envDevelopmentContent = `API_HOST=http://${host}:8000 +API_NAMESPACE=int/v1 +SOCKETCLUSTER_PATH=/socketcluster/ +SOCKETCLUSTER_HOST=${host} +SOCKETCLUSTER_SECURE=false +SOCKETCLUSTER_PORT=38000 +OSRM_HOST=https://router.project-osrm.org +`; + const envDevelopmentPath = path.join(environmentsDir, '.env.development'); + await fs.writeFile(envDevelopmentPath, envDevelopmentContent); + + // Update .env.production + const envProductionContent = `API_HOST=https://${host}:8000 +API_NAMESPACE=int/v1 +API_SECURE=true +SOCKETCLUSTER_PATH=/socketcluster/ +SOCKETCLUSTER_HOST=${host} +SOCKETCLUSTER_SECURE=true +SOCKETCLUSTER_PORT=38000 +OSRM_HOST=https://router.project-osrm.org +`; + const envProductionPath = path.join(environmentsDir, '.env.production'); + await fs.writeFile(envProductionPath, envProductionContent); + + console.log('āœ” Console environment files updated'); + + // Start Docker containers + console.log('\nā³ Starting Fleetbase containers...'); + console.log(' This may take a few minutes on first run...\n'); + + exec('docker compose up -d', { cwd: directory, maxBuffer: maxBuffer }, async (error, stdout, stderr) => { + if (error) { + console.error(`\nāœ– Error starting containers: ${error.message}`); + if (stderr) console.error(stderr); + process.exit(1); + } + + console.log(stdout); + console.log('āœ” Containers started'); + + // Wait for database + console.log('\nā³ Waiting for database to be ready...'); + await new Promise(resolve => setTimeout(resolve, 15000)); // Wait 15 seconds + console.log('āœ” Database should be ready'); + + // Run deploy script + console.log('\nā³ Running deployment script...'); + exec('docker compose exec -T application bash -c "./deploy.sh"', { cwd: directory, maxBuffer: maxBuffer }, (deployError, deployStdout, deployStderr) => { + if (deployError) { + console.error(`\nāœ– Error during deployment: ${deployError.message}`); + if (deployStderr) console.error(deployStderr); + console.log('\nā„¹ļø You may need to run the deployment manually:'); + console.log(' docker compose exec application bash -c "./deploy.sh"'); + } else { + console.log(deployStdout); + console.log('āœ” Deployment complete'); + } + + // Restart containers to ensure all changes are applied + exec('docker compose up -d', { cwd: directory }, () => { + console.log('\nšŸ Fleetbase is up!'); + console.log(` API → ${schemeApi}://${host}:8000`); + console.log(` Console → ${schemeConsole}://${host}:4200\n`); + console.log('ā„¹ļø Default credentials:'); + console.log(' Email: admin@fleetbase.io'); + console.log(' Password: password\n'); + }); + }); + }); + } catch (error) { + console.error('\nāœ– Installation failed:', error.message); + process.exit(1); + } +} + + + function loginCommand (options) { const npmLogin = require('npm-cli-login'); const username = options.username; @@ -979,6 +1172,14 @@ program .option('-n, --name ', 'Your full name (optional)') .action(registerCommand); +program + .command('install-fleetbase') + .description('Install Fleetbase using Docker') + .option('--host ', 'Host or IP address to bind to (default: localhost)') + .option('--environment ', 'Environment: development or production (default: development)') + .option('--directory ', 'Installation directory (default: current directory)') + .action(installFleetbaseCommand); + program .command('login') .description('Log in to the Fleetbase registry')