-
-
Notifications
You must be signed in to change notification settings - Fork 314
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d0ed753
commit a809603
Showing
10 changed files
with
1,583 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
const fs = require('fs-extra'); | ||
const { spawn } = require('child_process'); | ||
const YAML = require('yamljs'); | ||
|
||
const { destDir, fileExistsSync, appDir, getSCCWorkerDeploymentDefPath, sanitizeYAML } = require('../lib'); | ||
|
||
const copyDirRecursive = (src, dest, opts) => { | ||
try { | ||
fs.copySync(src, dest); | ||
return true; | ||
} catch (e) { | ||
opts.errorLog( | ||
'Failed to create necessary files. Please check your permissions and try again.', | ||
); | ||
} | ||
return false; | ||
}; | ||
|
||
const createSuccess = (destinationDir, opts) => { | ||
console.log( | ||
'Installing app dependencies using npm. This could take a while...', | ||
); | ||
|
||
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'; | ||
const options = { | ||
cwd: destinationDir, | ||
maxBuffer: Infinity, | ||
}; | ||
|
||
const npmProcess = spawn(npmCommand, ['install'], options); | ||
|
||
npmProcess.stdout.on('data', (data) => { | ||
process.stdout.write(data); | ||
}); | ||
|
||
npmProcess.stderr.on('data', (data) => { | ||
process.stderr.write(data); | ||
}); | ||
|
||
npmProcess.on('close', (code) => { | ||
if (code) { | ||
opts.errorLog(`Failed to install npm dependencies. Exited with code ${code}.`); | ||
} else { | ||
try { | ||
fs.writeFileSync( | ||
clientFileDestPath, | ||
fs.readFileSync(clientFileSourcePath), | ||
); | ||
opts.successLog( | ||
`SocketCluster app "${destinationDir}" was setup successfully.`, | ||
); | ||
} catch (err) { | ||
opts.errorLog( | ||
`Failed to copy file from "${clientFileSourcePath}" to "${clientFileDestPath}" - Try copying it manually.`, | ||
code, | ||
); | ||
} | ||
} | ||
}); | ||
|
||
npmProcess.stdin.end(); | ||
}; | ||
|
||
const setupMessage = function () { | ||
console.log('Creating app structure...'); | ||
}; | ||
|
||
const confirmReplaceSetup = function (confirm, destinationDir, opts) { | ||
const rmdirRecursive = function (dirname) { | ||
try { | ||
fs.removeSync(dirname); | ||
return true; | ||
} catch (e) { | ||
opts.errorLog( | ||
`Failed to remove existing directory at ${dirPath}. This directory may be used by another program or you may not have the permission to remove it.`, | ||
); | ||
} | ||
return false; | ||
}; | ||
|
||
if (confirm) { | ||
setupMessage(); | ||
if ( | ||
rmdirRecursive(destinationDir) && | ||
copyDirRecursive(appDir, destinationDir, opts) | ||
) { | ||
createSuccess(); | ||
} else { | ||
this.errorLog(); | ||
} | ||
} else { | ||
this.errorLog('SocketCluster "create" action was aborted.'); | ||
} | ||
}; | ||
|
||
const create = async function (app) { | ||
const destinationDir = destDir(app); | ||
|
||
let transformK8sConfigs = function () { | ||
return new Promise((resolve, reject) => { | ||
let kubernetesTargetDir = destinationDir + '/kubernetes'; | ||
let kubeConfSCCWorker = getSCCWorkerDeploymentDefPath( | ||
kubernetesTargetDir, | ||
); | ||
try { | ||
let kubeConfContentSCCWorker = fs.readFileSync(kubeConfSCCWorker, { | ||
encoding: 'utf8', | ||
}); | ||
let deploymentConfSCCWorker = YAML.parse(kubeConfContentSCCWorker); | ||
|
||
deploymentConfSCCWorker.spec.template.spec.volumes = [ | ||
{ | ||
name: 'app-src-volume', | ||
emptyDir: {}, | ||
}, | ||
]; | ||
|
||
let containers = deploymentConfSCCWorker.spec.template.spec.containers; | ||
let templateSpec = deploymentConfSCCWorker.spec.template.spec; | ||
|
||
if (!templateSpec.initContainers) { | ||
templateSpec.initContainers = []; | ||
} | ||
let initContainers = templateSpec.initContainers; | ||
let appSrcContainerIndex; | ||
containers.forEach((value, index) => { | ||
if (value && value.name == 'scc-worker') { | ||
appSrcContainerIndex = index; | ||
return; | ||
} | ||
}); | ||
if (!containers[appSrcContainerIndex].volumeMounts) { | ||
containers[appSrcContainerIndex].volumeMounts = []; | ||
} | ||
containers[appSrcContainerIndex].volumeMounts.push({ | ||
mountPath: '/usr/src/app', | ||
name: 'app-src-volume', | ||
}); | ||
initContainers.push({ | ||
name: 'app-src-container', | ||
image: '', // image name will be generated during deployment | ||
volumeMounts: [ | ||
{ | ||
mountPath: '/usr/dest', | ||
name: 'app-src-volume', | ||
}, | ||
], | ||
command: ['cp', '-a', '/usr/src/.', '/usr/dest/'], | ||
}); | ||
let formattedYAMLString = sanitizeYAML( | ||
YAML.stringify(deploymentConfSCCWorker, Infinity, 2), | ||
); | ||
fs.writeFileSync(kubeConfSCCWorker, formattedYAMLString); | ||
} catch (err) { | ||
reject(err); | ||
} | ||
resolve(); | ||
}); | ||
}; | ||
|
||
if (app) { | ||
if (fileExistsSync(destinationDir)) { | ||
if (this.argv.force) { | ||
confirmReplaceSetup(true, destinationDir, this); | ||
} else { | ||
let message = `There is already a directory at ${destinationDir}. Do you want to overwrite it?`; | ||
if(await this.promptConfirm(message, { default: true }, confirmReplaceSetup)) { | ||
createSuccess(destinationDir, this) | ||
}; | ||
} | ||
} else { | ||
setupMessage(); | ||
if (copyDirRecursive(appDir, destinationDir, this)) { | ||
try { | ||
await transformK8sConfigs(); | ||
createSuccess(destinationDir); | ||
} catch (err) { | ||
this.errorLog( | ||
`Failed to format Kubernetes configs. Failed to create SocketCluster app. ${err}`, | ||
); | ||
} | ||
} else { | ||
this.errorLog('Failed to create SocketCluster app.'); | ||
} | ||
} | ||
} else { | ||
this.errorLog( | ||
'The "create" command requires a valid <appname> as argument.', | ||
); | ||
showCorrectUsage(); | ||
process.exit(); | ||
} | ||
}; | ||
|
||
module.exports = { create }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
const dockerStop = async function () { | ||
let appName = arg1; | ||
if (!appName) { | ||
let appPath = '.'; | ||
let pkg = parsePackageFile(appPath); | ||
appName = pkg.name; | ||
} | ||
try { | ||
execSync(`docker stop ${appName}`); | ||
execSync(`docker rm ${appName}`); | ||
this.successLog(`App '${appName}' was stopped.`); | ||
} catch (e) { | ||
this.errorLog(`Failed to stop app '${appName}'.`); | ||
} | ||
process.exit(); | ||
}; | ||
|
||
const dockerRestart = async function () { | ||
let appName = arg1; | ||
if (!appName) { | ||
let appPath = '.'; | ||
let pkg = parsePackageFile(appPath); | ||
appName = pkg.name; | ||
} | ||
try { | ||
execSync(`docker stop ${appName}`, { stdio: 'ignore' }); | ||
this.successLog(`App '${appName}' was stopped.`); | ||
} catch (e) {} | ||
try { | ||
execSync(`docker start ${appName}`); | ||
this.successLog(`App '${appName}' is running.`); | ||
} catch (e) { | ||
this.errorLog(`Failed to start app '${appName}'.`); | ||
} | ||
process.exit(); | ||
}; | ||
|
||
const dockerRun = async function () { | ||
let appPath = arg1 || '.'; | ||
let absoluteAppPath = path.resolve(appPath); | ||
let pkg = parsePackageFile(appPath); | ||
let appName = pkg.name; | ||
|
||
let portNumber = Number(argv.p) || 8000; | ||
let envVarList; | ||
if (argv.e === undefined) { | ||
envVarList = []; | ||
} else if (!Array.isArray(argv.e)) { | ||
envVarList = [argv.e]; | ||
} else { | ||
envVarList = argv.e; | ||
} | ||
let envFlagList = envVarList.map((value) => { | ||
return `-e "${value}"`; | ||
}); | ||
let envFlagString = envFlagList.join(' '); | ||
if (envFlagList.length > 0) { | ||
envFlagString += ' '; | ||
} | ||
|
||
try { | ||
execSync(`docker stop ${appName}`, { stdio: 'ignore' }); | ||
execSync(`docker rm ${appName}`, { stdio: 'ignore' }); | ||
} catch (e) {} | ||
|
||
let dockerCommand = | ||
`docker run -d -p ${portNumber}:8000 -v ${absoluteAppPath}:/usr/src/app/ ` + | ||
`${envFlagString}--name ${appName} socketcluster/socketcluster:v${scVersion} `; | ||
try { | ||
execSync(dockerCommand, { stdio: 'inherit' }); | ||
this.successLog( | ||
`App "${appName}" is running at http://localhost:${portNumber}`, | ||
); | ||
} catch (e) { | ||
this.errorLog(`Failed to start app "${appName}".`); | ||
} | ||
process.exit(); | ||
}; | ||
|
||
const dockerList = async function () { | ||
let command = exec(`docker ps${commandRawArgsString}`, (err) => { | ||
if (err) { | ||
this.errorLog(`Failed to list active containers. ` + err); | ||
} | ||
process.exit(); | ||
}); | ||
command.stdout.pipe(process.stdout); | ||
command.stderr.pipe(process.stderr); | ||
}; | ||
|
||
const dockerLogs = async function () { | ||
let appName = arg1; | ||
if (!appName) { | ||
let appPath = '.'; | ||
let pkg = parsePackageFile(appPath); | ||
appName = pkg.name; | ||
} | ||
let command = exec(`docker logs ${appName}${commandRawArgsString}`, (err) => { | ||
if (err) { | ||
this.errorLog(`Failed to get logs for '${appName}' app. ` + err); | ||
} | ||
process.exit(); | ||
}); | ||
command.stdout.pipe(process.stdout); | ||
command.stderr.pipe(process.stderr); | ||
}; | ||
|
||
module.exports = { | ||
dockerRestart, | ||
dockerRun, | ||
dockerStop, | ||
dockerList, | ||
dockerLogs, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const create = require('./create'); | ||
const docker = require('./docker'); | ||
const k8s = require('./k8s'); | ||
|
||
module.exports = { | ||
...create, | ||
...docker, | ||
...k8s, | ||
}; |
Oops, something went wrong.