Last active
September 11, 2020 13:17
-
-
Save rosinghal/198d96d1f12254a9a26d14c68b74b413 to your computer and use it in GitHub Desktop.
NodeJS script to clone or delete app from CloudWays
This file contains hidden or 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
const Axios = require("axios"); | |
const readline = require("readline"); | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}); | |
const axiosInstance = Axios.create({ | |
baseURL: "https://api.cloudways.com/api/v1" | |
}); | |
const getAccessToken = (email, api_key) => { | |
return axiosInstance.post("/oauth/access_token", { | |
email, | |
api_key | |
}); | |
}; | |
const listServers = () => { | |
return axiosInstance.get(`/server`); | |
}; | |
const asyncForEach = async (array, callback) => { | |
for (let index = 0; index < array.length; index++) { | |
await callback(array[index], index, array); | |
} | |
}; | |
const sleep = s => { | |
// console.log(`Sleeping for ${s} second(s)`); | |
return new Promise(resolve => setTimeout(resolve, s * 1000)); | |
}; | |
const cloneAppToOtherServer = ( | |
server_id, | |
app_id, | |
destination_server_id, | |
app_label | |
) => { | |
return axiosInstance.post("/app/cloneToOtherServer", { | |
server_id, | |
app_id, | |
destination_server_id, | |
app_label | |
}); | |
}; | |
const updateApplicationLabel = (server_id, app_id, label) => { | |
return axiosInstance.put(`/app/${app_id}`, { | |
server_id, | |
label | |
}); | |
}; | |
const updateApplicationCname = (server_id, app_id, cname) => { | |
return axiosInstance.post("/app/manage/cname", { | |
server_id, | |
app_id, | |
cname | |
}); | |
}; | |
const installLetsencryptForApplication = ( | |
server_id, | |
app_id, | |
ssl_email, | |
wild_card, | |
ssl_domains | |
) => { | |
return axiosInstance.post("/security/lets_encrypt_install", { | |
server_id, | |
app_id, | |
ssl_email, | |
wild_card, | |
ssl_domains | |
}); | |
}; | |
const enforceHTTPSForApplication = (server_id, app_id, status) => { | |
return axiosInstance.post("/app/manage/enforce_https", { | |
server_id, | |
app_id, | |
status | |
}); | |
}; | |
const resetPermissionsForApplication = (server_id, app_id, ownership) => { | |
return axiosInstance.post("/app/manage/reset_permissions", { | |
server_id, | |
app_id, | |
ownership | |
}); | |
}; | |
const updateSymlinkForApplication = (server_id, app_id, symlink) => { | |
return axiosInstance.post("/app/manage/symlink", { | |
server_id, | |
app_id, | |
symlink | |
}); | |
}; | |
const setToken = async (email, token) => { | |
const { access_token } = (await getAccessToken(email, token)).data; | |
axiosInstance.defaults.headers.common[ | |
"Authorization" | |
] = `Bearer ${access_token}`; | |
}; | |
const getOperationStatus = async operation_id => { | |
return axiosInstance.get(`/operation/${operation_id}`); | |
}; | |
const deleteApp = async (server_id, app_id) => { | |
return axiosInstance.delete(`/app/${app_id}`, { | |
params: { | |
server_id | |
} | |
}); | |
}; | |
const cloneApps = async (source_server_id, destination_server_id) => { | |
console.log("Fetching apps list..."); | |
const { servers } = (await listServers()).data; | |
const source_server = servers.find(s => s.id === source_server_id); | |
let op = null; | |
await asyncForEach(source_server.apps, async source_app => { | |
await new Promise(resolve => { | |
rl.question( | |
`Do you want to clone ${source_app.label} [y/N]? `, | |
async answer => { | |
if (["y"].includes(answer.toLowerCase())) { | |
try { | |
console.log(`Cloning ${source_app.label}...`); | |
// Cloning | |
const cloned_app = ( | |
await cloneAppToOtherServer( | |
source_server_id, | |
source_app.id, | |
destination_server_id, | |
source_app.label | |
) | |
).data; | |
await onOperationComplete( | |
cloned_app.destination_op_id | |
); | |
console.log(`Cloned ${source_app.label}`); | |
// label | |
console.log( | |
`Updating label for ${source_app.label}...` | |
); | |
await updateApplicationLabel( | |
destination_server_id, | |
cloned_app.app_id, | |
source_app.label | |
); | |
console.log( | |
`Label updated for ${source_app.label}` | |
); | |
// CNAME | |
console.log( | |
`Updating CNAME for ${source_app.label}...` | |
); | |
op = await updateApplicationCname( | |
destination_server_id, | |
cloned_app.app_id, | |
source_app.cname | |
); | |
await onOperationComplete(op.data.operation_id); | |
console.log( | |
`CNAME updated for ${source_app.label}...` | |
); | |
// SSL | |
console.log( | |
`Installing Let's encrypt for ${source_app.label}...` | |
); | |
op = await installLetsencryptForApplication( | |
destination_server_id, | |
cloned_app.app_id, | |
source_app.lets_encrypt.ssl_email, | |
false, | |
source_app.lets_encrypt.ssl_domains | |
); | |
await onOperationComplete(op.data.operation_id); | |
console.log( | |
`Let's encrypt installed for ${source_app.label}` | |
); | |
// Force SSL | |
console.log( | |
`Enforcing HTTPS for ${source_app.label}...` | |
); | |
op = await enforceHTTPSForApplication( | |
destination_server_id, | |
cloned_app.app_id, | |
source_app.label.includes("demo") | |
? "disable" | |
: "enable" | |
); | |
await onOperationComplete(op.data.operation_id); | |
console.log( | |
`Enforced HTTPS for ${source_app.label}` | |
); | |
// Reset permissions | |
console.log( | |
`Resetting permissions for ${source_app.label}...` | |
); | |
op = await resetPermissionsForApplication( | |
destination_server_id, | |
cloned_app.app_id, | |
"master_user" | |
); | |
await onOperationComplete(op.data.operation_id); | |
console.log( | |
`Resetted permissions for ${source_app.label}` | |
); | |
// Symlink | |
console.log( | |
`Updating symlink for ${source_app.label}...` | |
); | |
await updateSymlinkForApplication( | |
destination_server_id, | |
cloned_app.app_id, | |
source_app.label.replace(/[^a-zA-Z0-9]/g, "_") | |
); | |
console.log( | |
`Symlink updated for ${source_app.label}` | |
); | |
console.log(`Finished for ${source_app.label}`); | |
} catch (error) { | |
console.error( | |
`Failed for ${source_app.label}`, | |
error.message, | |
error.response && error.response.data | |
? error.response.data | |
: "" | |
); | |
} | |
resolve(); | |
} else { | |
console.log(`Skipping ${source_app.label}`); | |
resolve(); | |
} | |
} | |
); | |
}); | |
}); | |
}; | |
const onOperationComplete = async operation_id => { | |
console.log(`Operation in progress #${operation_id}...`); | |
try { | |
const op_response = (await getOperationStatus(operation_id)).data; | |
if (op_response.operation.is_completed === "1") { | |
console.log(`Operation completed #${operation_id}`); | |
return op_response; | |
} else { | |
await sleep(10); | |
return onOperationComplete(operation_id); | |
} | |
} catch (error) { | |
console.error( | |
error.message, | |
error.response && | |
error.response.data && | |
typeof error.response.data === "object" | |
? error.response.data | |
: "" | |
); | |
await sleep(10); | |
return onOperationComplete(operation_id); | |
} | |
}; | |
const deleteApps = async source_server_id => { | |
const { servers } = (await listServers()).data; | |
const source_server = servers.find(s => s.id === source_server_id); | |
await asyncForEach(source_server.apps, async source_app => { | |
await new Promise(resolve => { | |
rl.question( | |
`Do you want to delete ${source_app.label} [y/N]? `, | |
async answer => { | |
if (["y"].includes(answer.toLowerCase())) { | |
console.log(`Deleting ${source_app.label}...`); | |
const delete_app_operation = ( | |
await deleteApp(source_server_id, source_app.id) | |
).data; | |
await onOperationComplete( | |
delete_app_operation.operation_id | |
); | |
resolve(); | |
} else { | |
console.log(`Skipping ${source_app.label}`); | |
resolve(); | |
} | |
} | |
); | |
}); | |
}); | |
}; | |
const init = async () => { | |
const cloudwaysAPIKey = await new Promise(resolve => { | |
rl.question(`Enter CloudWays API key: `, async res => { | |
resolve(res); | |
}); | |
}); | |
const cloudwaysEmail = await new Promise(resolve => { | |
rl.question(`Enter CloudWays email: `, async res => { | |
resolve(res); | |
}); | |
}); | |
const action = await new Promise(resolve => { | |
rl.question( | |
`Enter action that you want to perform [delete|clone]: `, | |
async res => { | |
resolve(res); | |
} | |
); | |
}); | |
setToken(cloudwaysEmail, cloudwaysAPIKey); | |
switch (action) { | |
case "delete": | |
const serverId = await new Promise(resolve => { | |
rl.question(`Enter server ID: `, async res => { | |
resolve(res); | |
}); | |
}); | |
await deleteApps(serverId); | |
break; | |
case "clone": | |
const sourceServerId = await new Promise(resolve => { | |
rl.question(`Enter source server ID: `, async res => { | |
resolve(res); | |
}); | |
}); | |
const destinationServerId = await new Promise(resolve => { | |
rl.question(`Enter destination server ID: `, async res => { | |
resolve(res); | |
}); | |
}); | |
await cloneApps(sourceServerId, destinationServerId); | |
break; | |
default: | |
break; | |
} | |
rl.close(); | |
}; | |
init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment