This repository has been archived on 2025-12-25. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
qmi-cloud/qmi-cloud-common/azurecli.js
Manuel Romero c14d9efa44 new email
2025-03-04 00:10:28 +01:00

329 lines
12 KiB
JavaScript

const computeManagementClient = require("@azure/arm-compute").ComputeManagementClient;
const dnsManagementClient = require("@azure/arm-dns").DnsManagementClient;
const ManagedIdentityCredential = require("@azure/identity").ManagedIdentityCredential;
const storageManagementClient = require("@azure/arm-storage").StorageManagementClient;
const db = require("./mongo");
const utils = require("./utils");
const SUBSCRIPTION_ID = "62ebff8f-c40b-41be-9239-252d6c0c8ad9";
function _getRgName(provision) {
let rgName = provision.scenario.toUpperCase();
rgName = rgName.replace(/AZQMI/g, 'QMI');
rgName = rgName + "-" + provision._id.toString();
return rgName;
}
async function _getStorageAccountClient(scenarioName) {
var id = SUBSCRIPTION_ID;
if (scenarioName){
var scenario = await db.scenario.getOne({"name": scenarioName});
id = scenario.subscription? scenario.subscription.subsId : SUBSCRIPTION_ID;
}
const credential = new ManagedIdentityCredential();
//console.log("AzureCLI# authenticated", credential, id);
return new storageManagementClient(credential, id);
}
async function _getClient(scenarioName) {
var id = SUBSCRIPTION_ID;
if (scenarioName){
var scenario = await db.scenario.getOne({"name": scenarioName});
id = scenario.subscription? scenario.subscription.subsId : SUBSCRIPTION_ID;
}
const credential = new ManagedIdentityCredential();
//console.log("AzureCLI# authenticated", credential, id);
return new computeManagementClient(credential, id);
}
async function _getDNSClient(scenarioName) {
var id = SUBSCRIPTION_ID;
if (scenarioName){
var scenario = await db.scenario.getOne({"name": scenarioName});
id = scenario.subscription? scenario.subscription.subsId : SUBSCRIPTION_ID;
}
const credential = new ManagedIdentityCredential();
//console.log("AzureCLI# authenticated", credential, id);
return new dnsManagementClient(credentials, id);
}
async function deallocate(provision, triggerUserId, isSendEmailAfter ) {
let rgName = _getRgName(provision);
console.log("AzureCLI# Deallocating VMs for resource group: "+rgName);
try {
var computeClient = await _getClient(provision.scenario);
let finalResult = await computeClient.virtualMachines.list(rgName);
db.provision.update(provision._id, {"statusVms": "Stopping"});
for await (const vm of finalResult) {
await computeClient.virtualMachines.beginDeallocateAndWait(rgName, vm.name);
}
await utils.afterStopVms(provision, triggerUserId, isSendEmailAfter);
console.log("AzureCLI# All VMs DEALLOCATED for resource group: "+rgName);
} catch ( error ) {
console.log("AzureCLI# ERROR stopping VMs: "+rgName, error);
await db.provision.update(provision._id.toString(), {"statusVms": "Running" });
}
}
async function start(provision, triggerUserId){
let rgName = _getRgName(provision);
console.log("AzureCLI# Starting VMs for resource group: "+rgName);
try {
var computeClient = await _getClient(provision.scenario);
let finalResult = await computeClient.virtualMachines.list(rgName);
db.provision.update(provision._id, {"statusVms": "Starting"});
for await (const vm of finalResult) {
await computeClient.virtualMachines.beginStartAndWait(rgName, vm.name);
}
await utils.afterStartVms( provision, triggerUserId );
console.log("AzureCLI# All VMs RUNNING for resource group: "+rgName);
} catch ( error ) {
console.log("AzureCLI# ERROR starting VMs: "+rgName, error);
await db.provision.update(provision._id.toString(), {"statusVms": "Stopped" });
}
}
async function getResourceGroupVms(rgName){
let computeClient = await _getClient();
return await computeClient.virtualMachines.list(rgName);
}
async function getAllVms(){
let computeClient = await _getClient();
console.log("AzureCLI# Retrieving all VMS from subscription");
return await computeClient.virtualMachines.listAll();
}
async function getAllVmsNext(nextLink){
let computeClient = await _getClient();
console.log("AzureCLI# Retrieving all VMS from subscription (next): " +nextLink);
return await computeClient.virtualMachines.listAllNext(nextLink)
}
async function updateVmsTags(provId, tagsEdit) {
if ( !tagsEdit ){ return {} ; }
let provision = await db.provision.getById(provId);
if ( !provision ){ return };
let rgName = _getRgName(provision);
console.log("AzureCLI# Updating TAGS in VMs for resource group: "+rgName);
var computeClient;
var finalResult;
try {
computeClient = await _getClient(provision.scenario);
finalResult = await computeClient.virtualMachines.list(rgName);
} catch (e2) {
console.log(`AzureCLI# ERROR: Resource group '${rgName}' could not be found`, e2);
return {};
}
//if (finalResult && finalResult.length > 0) {
var toDelete = [];
var toAdd = [];
for(let tag in tagsEdit ) {
if ( !tagsEdit[tag] ) {
toDelete.push(tag);
} else {
toAdd.push({"key": tag, "value": tagsEdit[tag]});
}
}
var result = {};
if ( toDelete.length > 0 || toAdd.length > 0 ) {
for await (const vm of finalResult) {
var vmActualTags = JSON.stringify(vm.tags);
var tags = vm.tags;
toDelete.forEach(t=>{
delete tags[t];
});
toAdd.forEach(t=>{
tags[t.key] = t.value;
});
tags["ProvId"] = provision._id.toString();
result[vm.name] = tags;
if ( JSON.stringify(tags) !== vmActualTags ) {
try {
console.log(`AzureCLI# setting new tags to VM ${vm.name} (${rgName})`);
await computeClient.virtualMachines.beginUpdateAndWait(rgName, vm.name, {"tags": tags} );
} catch (e1) {
console.log(`AzureCLI# ERROR setting tags to VM ${vm.name} (${rgName})`, e1);
}
} else {
console.log(`AzureCLI# Same tags, no need to update tags for VM ${vm.name} (${rgName})`);
}
}
}
//db.event.add({ user: provision.user._id, provision: provision._id, type: 'provision.vms-tags-update' });
return result;
//} else {
// return {}
//}
};
/**
* DNS Records
*/
const DNS_RESOURCE_GROUP = "QMI-Infra-DNS";
const DNS_ZONE_NAME = "qmi.qlik-poc.com";
async function getDNSRecords(type = "CNAME") {
let dnsClient = await _getDNSClient();
console.log(`AzureCLI# Retrieving '${type}' DNS records`);
return await dnsClient.recordSets.listByType(DNS_RESOURCE_GROUP, DNS_ZONE_NAME, type);
}
async function createDNSRecord(provision, cname, type = "CNAME"){
if ( !provision ) return;
let rgName = _getRgName(provision).toLowerCase();
let dnsClient = await _getDNSClient();
console.log(`AzureCLI# Creating '${type}' DNS record: ${rgName}.${DNS_ZONE_NAME} --> ${cname}`);
let parameters = {
"cnameRecord": {
"cname": cname
},
"tTL": 60
};
return await dnsClient.recordSets.createOrUpdate(DNS_RESOURCE_GROUP, DNS_ZONE_NAME, rgName, type, parameters );
}
async function deleteDNSRecord(provision, type = "CNAME"){
if ( !provision ) return;
let rgName = _getRgName(provision).toLowerCase();
let dnsClient = await _getDNSClient();
console.log(`AzureCLI# Deleting '${type}' DNS record: ${rgName}.${DNS_ZONE_NAME}`);
return await dnsClient.recordSets.deleteMethod(DNS_RESOURCE_GROUP, DNS_ZONE_NAME, rgName, type );
}
async function createSnapshots(provId, targetRg = "QMI-Machines", userId) {
const provision = await db.provision.getById(provId);
const computeClient = await _getClient(provision.scenario);
const resourceGroupName = _getRgName(provision);
console.log(`AzureCLI# Start creating snapshot for RG: ${resourceGroupName}`);
const disks = await computeClient.disks.listByResourceGroup(resourceGroupName);
const now = Date.now();
//console.log("AzureCLI# DISKS", disks);
try {
var out = [];
const disks = computeClient.disks.listByResourceGroup(resourceGroupName);
for await (const disk of disks) {
//await processItems(disks, async function(disk){
console.log(`AzureCLI# Start creating snapshot for disk: ${disk.name}: ${disk.id}`);
// Define snapshot parameters
let snapshotParams = {
location: disk.location, // Example: "eastus"
creationData: {
createOption: "Copy", // Creates a snapshot from an existing disk
sourceResourceId: `/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${resourceGroupName}/providers/Microsoft.Compute/disks/${disk.name}`
}
};
let snapshotName = `Snap_${disk.name}_${provision._id}_${now}`
console.log(`AzureCLI# creating.... ${snapshotName}`);
let snapshot = await computeClient.snapshots.beginCreateOrUpdateAndWait(
targetRg,
snapshotName,
snapshotParams
);
await db.snapshot.add({"resourceID": snapshot.id, "provision": provision._id, "owner": userId, targetRg: targetRg, name: snapshotName });
out.push(snapshot);
console.log(`AzureCLI# snapshot: ${snapshotName} is DONE!`);
};
return out;
} catch (error) {
console.log("AzureCLI# Error creating snapshot:", error);
return null;
}
}
async function rotateStorageAccountKey(provision, keyName = "key1") {
if ( !provision || !provision.outputs) {
console.log("AzureCLI# rotateStorageAccountKey - No Proviosn or no outputs");
return null;
}
if (provision.outputs["StorageAccount-Name"] && provision.outputs["StorageAccount-AccessKey"]){
const storageAccountName = provision.outputs["StorageAccount-Name"];
try {
const client = await _getStorageAccountClient(provision.scenario);
const resourceGroupName = _getRgName(provision);
console.log(`AzureCLI# rotateStorageAccountKey - Regenerating ${keyName} for ${storageAccountName}...`);
const result = await client.storageAccounts.regenerateKey(resourceGroupName, storageAccountName, {
keyName: keyName
});
let newKey = result.keys.find(k => k.keyName === keyName).value;
console.log("AzureCLI# rotateStorageAccountKey - New Key:", storageAccountName, newKey);
let outputs = provision.outputs;
outputs["StorageAccount-AccessKey"] = newKey;
outputs["StorageAccount-ConnectionString"] = `DefaultEndpointsProtocol=https;AccountName=${storageAccountName};AccountKey=${newKey};EndpointSuffix=core.windows.net`;
const upProv = await db.provision.update(provision._id, {"outputs": outputs});
console.log(`AzureCLI# Done rotateStorageAccountKey!! - ${keyName} for ${storageAccountName}...`);
return upProv;
} catch (error) {
console.log("AzureCLI# Error rotateStorageAccountKey:", error);
return null;
}
} else {
console.log(`AzureCLI# rotateStorageAccountKey -Provision (${provision._id}) Outputs does not contain a storage account`);
return null;
}
}
module.exports.start = start;
module.exports.deallocate = deallocate;
module.exports.getResourceGroupVms = getResourceGroupVms;
module.exports.getAllVms = getAllVms;
module.exports.getAllVmsNext = getAllVmsNext;
module.exports.updateVmsTags = updateVmsTags;
module.exports.getDNSRecords = getDNSRecords;
module.exports.createDNSRecord = createDNSRecord;
module.exports.deleteDNSRecord = deleteDNSRecord;
module.exports.createSnapshots = createSnapshots;
module.exports.rotateStorageAccountKey = rotateStorageAccountKey;