dce-dev-wizard
Version: 
Wizard for managing development apps at Harvard DCE.
159 lines (138 loc) • 4.99 kB
text/typescript
import clear from 'clear';
// Import helpers
import showChooser from '../helpers/showChooser';
import getDeploymentConfig from '../operations/getDeploymentConfig';
import print from '../helpers/print';
import prompt from '../helpers/prompt';
import exec from '../helpers/exec';
import config from '../helpers/config';
// Import shared types
import Deployment from '../types/Deployment';
import ChooserOption from '../types/ChooserOption';
/**
 * Show and/or modify related cluster status
 * @author Gabe Abrams
 * @param deployment the currently selected deployment
 */
const relatedClusters = async (deployment: Deployment) => {
  while (true) {
    // Show loading indicator
    clear();
    console.log('Checking status of related instances...\n');
    // Get related clusters
    const { relatedClusters } = config;
    if (!relatedClusters || relatedClusters.length === 0) {
      clear();
      console.log('No related clusters. In your dceConfig.json file, add a "relatedClusters" array.');
      return;
    }
    // Get the status on related clusters
    const relatedClustersWithStatus: {
      name: string,
      cluster: string,
      isOnline: boolean,
    }[] = [];
    for (let i = 0; i < relatedClusters.length; i += 1) {
      const relatedCluster = relatedClusters[i];
      // Check if the related cluster is valid
      if (!relatedCluster.cluster || !relatedCluster.name) {
        console.log('Related clusters must be of form { name, cluster } where name is a human-readable name, cluster is the AWS cluster name.');
        process.exit(0);
      }
      // Execute status command via aws cli
      const statusOutput = exec(
        `aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[?contains(AutoScalingGroupName, '${relatedCluster.cluster}')] | [].Instances[] | length(@)"`,
        false,
      );
      // Check if the output is a number
      if (Number.isNaN(Number.parseInt(statusOutput, 10))) {
        console.log(`Error getting status of ${relatedCluster.name} (${relatedCluster.cluster})`);
        console.log(`Got output: ${statusOutput} but expected a number.`);
        process.exit(0);
      }
      const isOnline = Number.parseInt(statusOutput, 10) >= 2;
      // Write to related cluster list
      relatedClustersWithStatus.push({
        ...relatedCluster,
        isOnline,
      });
    }
    // Show status
    clear();
    const options: ChooserOption[] = relatedClustersWithStatus.map((cluster) => {
      return {
        description: `${cluster.name} (${cluster.isOnline ? 'ONLINE' : 'Offline'})`,
      };
    });
    // Option to refresh
    options.push({
      description: '[Refresh Status]',
      tag: 'R',
    });
    // Option to go back to main menu
    options.push({
      description: '[Back to Main Menu]',
      tag: 'B',
    });
    // Show chooser
    const option = showChooser({
      question: 'Choose a cluster to turn on/off:',
      options,
    });
    if (option.tag === 'B') {
      // Back to main menu
      return;
    }
    if (option.tag === 'R') {
      // Refresh status
      continue;
    }
    const cluster = relatedClustersWithStatus[option.index];
    // Re-check status
    const statusOutput = exec(
      `aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[?contains(AutoScalingGroupName, '${cluster.cluster}')] | [].Instances[] | length(@)"`,
      false,
    );
    const nowIsOnline = Number.parseInt(statusOutput, 10) >= 2;
    if (nowIsOnline !== cluster.isOnline) {
      console.log('Status is out of date. Please continue to refresh.');
      await print.enterToContinue();
      continue;
    }
    // Ready to toggle!
    const newStatus = (cluster.isOnline ? 'off' : 'on');
    const script = `
      ON_OR_OFF="${newStatus}"
      CLUSTER_NAME="${cluster.cluster}"
      if ! command -v -- "aws" >/dev/null 2>&1; then
        echo "AWS CLI is not installed. Please install it first."
        exit 1
      fi
      desiredCapacity=$([ "$ON_OR_OFF" == "on" ] && echo 1 || echo 0)
      asgs=$(
        aws autoscaling describe-auto-scaling-groups \
          --query "AutoScalingGroups[?contains(AutoScalingGroupName, '$CLUSTER_NAME')].AutoScalingGroupName" \
          --output text
      )
      for asg in $asgs; do
        echo "Turning $ON_OR_OFF auto scaling group $asg"
        aws autoscaling set-desired-capacity \
          --auto-scaling-group-name $asg \
          --desired-capacity $desiredCapacity \
          --no-honor-cooldown
      done
    `;
    clear();
    print.title(`Turning ${newStatus}`);
    console.log(`\nTurning ${newStatus} ${cluster.name}...\n`);
    await exec(script, true);
    await new Promise((r) => {
      setTimeout(r, 3000);
    });
    clear();
    print.title('Cluster Updated');
    console.log(`\n${cluster.name} is ${cluster.isOnline ? 'turning off' : 'turning on'}. This will take up to 15min.\n`);
    print.enterToContinue();
  }
};
export default relatedClusters;