<commit_before>import { IPromise, module } from 'angular';
import { chain, flatten, intersection, xor, cloneDeep } from 'lodash';
import { $q } from 'ngimport';
import { Subject } from 'rxjs';

import {
  AccountService,
  Application,
  IServerGroupCommand,
  IServerGroupCommandViewState,
  IDeploymentStrategy,
  IServerGroupCommandBackingData,
  CacheInitializerService,
  CACHE_INITIALIZER_SERVICE,
  LoadBalancerReader,
  LOAD_BALANCER_READ_SERVICE,
  ICluster,
  IAccountDetails,
  SECURITY_GROUP_READER,
  SecurityGroupReader,
  IVpc,
  ISecurityGroup,
  NameUtils,
  setMatchingResourceSummary,
} from '@spinnaker/core';
import {
  IAmazonApplicationLoadBalancer,
  IAmazonLoadBalancer,
  IAmazonServerGroupCommandDirty,
  VpcReader,
} from '@spinnaker/amazon';

import { IJobDisruptionBudget, ITitusResources } from 'titus/domain';
import { ITitusServiceJobProcesses } from 'titus/domain/ITitusServiceJobProcesses';

export interface ITitusServerGroupCommandBackingData extends IServerGroupCommandBackingData {
  accounts: string[];
  vpcs: IVpc[];
}

export interface ITitusServerGroupCommandViewState extends IServerGroupCommandViewState {
  accountChangedStream: Subject<{}>;
  regionChangedStream: Subject<{}>;
  groupsRemovedStream: Subject<{}>;
  dirty: IAmazonServerGroupCommandDirty;
  defaultIamProfile: string;
}

export const defaultJobDisruptionBudget: IJobDisruptionBudget = {
  availabilityPercentageLimit: {
    percentageOfHealthyContainers: 95,
  },
  ratePercentagePerInterval: {
    intervalMs: 600000,
    percentageLimitPerInterval: 5,
  },
  containerHealthProviders: [{ name: 'eureka' }],
  timeWindows: [
    {
      days: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
      hourlyTimeWindows: [{ startHour: 10, endHour: 16 }],
      timeZone: 'PST',
    },
  ],
};

export const getDefaultJobDisruptionBudgetForApp = (application: Application): IJobDisruptionBudget => {
  const budget = cloneDeep(defaultJobDisruptionBudget);
  if (application.attributes && application.attributes.platformHealthOnly) {
    budget.containerHealthProviders = [];
  }
  return budget;
};

export interface ITitusServerGroupCommand extends IServerGroupCommand {
  cluster?: ICluster;
  disruptionBudget?: IJobDisruptionBudget;
  deferredInitialization?: boolean;
  registry: string;
  imageId: string;
  organization: string;
  repository: string;
  tag?: string;
  digest?: string;
  image: string;
  inService: boolean;
  resources: ITitusResources;
  efs: {
    efsId: string;
    mountPoint: string;
    mountPerm: string;
    efsRelativeMountPoint: string;
  };
  viewState: ITitusServerGroupCommandViewState;
  targetGroups: string[];
  removedTargetGroups: string[];
  backingData: ITitusServerGroupCommandBackingData;
  labels: { [key: string]: string };
  containerAttributes: { [key: string]: string };
  env: { [key: string]: string };
  iamProfile: string;
  migrationPolicy: {
    type: string;
  };
  constraints: {
    hard: { [key: string]: string };
    soft: { [key: string]: string };
  };
  serviceJobProcesses: ITitusServiceJobProcesses;
}

export class TitusServerGroupConfigurationService {
  public static $inject = ['cacheInitializer', 'loadBalancerReader', 'securityGroupReader'];
  constructor(
    private cacheInitializer: CacheInitializerService,
    private loadBalancerReader: LoadBalancerReader,
    private securityGroupReader: SecurityGroupReader,
  ) {}

  public configureZones(command: ITitusServerGroupCommand) {
    command.backingData.filtered.regions = command.backingData.credentialsKeyedByAccount[command.credentials].regions;
  }

  private attachEventHandlers(cmd: ITitusServerGroupCommand) {
    cmd.credentialsChanged = (command: ITitusServerGroupCommand) => {
      const result = { dirty: {} };
      const backingData = command.backingData;
      this.configureZones(command);
      if (command.credentials) {
        command.registry = (backingData.credentialsKeyedByAccount[command.credentials] as any).registry;
        backingData.filtered.regions = backingData.credentialsKeyedByAccount[command.credentials].regions;
        if (!backingData.filtered.regions.some((r) => r.name === command.region)) {
          command.region = null;
          command.regionChanged(command);
        }
      } else {
        command.region = null;
      }
      command.viewState.dirty = { ...(command.viewState.dirty || {}), ...result.dirty };
      this.configureLoadBalancerOptions(command);
      this.configureSecurityGroupOptions(command);
      setMatchingResourceSummary(command);
      return result;
    };

    cmd.regionChanged = (command: ITitusServerGroupCommand) => {
      this.configureLoadBalancerOptions(command);
      this.configureSecurityGroupOptions(command);
      setMatchingResourceSummary(command);
      return {};
    };

    cmd.clusterChanged = (command: ITitusServerGroupCommand): void => {
      command.moniker = NameUtils.getMoniker(command.application, command.stack, command.freeFormDetails);
      setMatchingResourceSummary(command);
    };
  }

  public configureCommand(cmd: ITitusServerGroupCommand) {
    cmd.viewState.accountChangedStream = new Subject();
    cmd.viewState.regionChangedStream = new Subject();
    cmd.viewState.groupsRemovedStream = new Subject();
    cmd.viewState.dirty = {};
    cmd.onStrategyChange = (command: ITitusServerGroupCommand, strategy: IDeploymentStrategy) => {
      // Any strategy other than None or Custom should force traffic to be enabled
      if (strategy.key !== '' && strategy.key !== 'custom') {
        command.inService = true;
      }
    };
    cmd.image = cmd.viewState.imageId;
    return $q
      .all({
        credentialsKeyedByAccount: AccountService.getCredentialsKeyedByAccount('titus'),
        securityGroups: this.securityGroupReader.getAllSecurityGroups(),
        vpcs: VpcReader.listVpcs(),
        images: [],
      })
      .then((backingData: any) => {
        backingData.accounts = Object.keys(backingData.credentialsKeyedByAccount);
        backingData.filtered = {};
        if (cmd.credentials.includes('${')) {
          // If our dependency is an expression, the only thing we can really do is to just preserve current selections
          backingData.filtered.regions = [{ name: cmd.region }];
        } else {
          backingData.filtered.regions = (backingData.credentialsKeyedByAccount[cmd.credentials] || []).regions || [];
        }
        cmd.backingData = backingData;
        backingData.filtered.securityGroups = this.getRegionalSecurityGroups(cmd);
        let securityGroupRefresher = $q.when();
        if (cmd.securityGroups && cmd.securityGroups.length) {
          const regionalSecurityGroupIds = backingData.filtered.securityGroups.map((g: ISecurityGroup) => g.id);
          if (intersection(cmd.securityGroups, regionalSecurityGroupIds).length < cmd.securityGroups.length) {
            securityGroupRefresher = this.refreshSecurityGroups(cmd, false);
          }
        }

        return $q.all([this.refreshLoadBalancers(cmd), securityGroupRefresher]).then(() => {
          this.attachEventHandlers(cmd);
        });
      });
  }

  private getVpcId(command: ITitusServerGroupCommand): string {
    const credentials = this.getCredentials(command);
    const match = command.backingData.vpcs.find(
      (vpc) =>
        vpc.name === credentials.awsVpc &&
        vpc.account === credentials.awsAccount &&
        vpc.region === this.getRegion(command) &&
        vpc.cloudProvider === 'aws',
    );
    return match ? match.id : null;
  }<commit_msg>chore(amazon/serverGroup): Migrate from $q.all({}) to $q.all([])<commit_after>import { IPromise, module } from 'angular';
import { chain, flatten, intersection, xor, cloneDeep } from 'lodash';
import { $q } from 'ngimport';
import { Subject } from 'rxjs';

import {
  AccountService,
  Application,
  IServerGroupCommand,
  IServerGroupCommandViewState,
  IDeploymentStrategy,
  IServerGroupCommandBackingData,
  CacheInitializerService,
  CACHE_INITIALIZER_SERVICE,
  LoadBalancerReader,
  LOAD_BALANCER_READ_SERVICE,
  ICluster,
  IAccountDetails,
  SECURITY_GROUP_READER,
  SecurityGroupReader,
  IVpc,
  ISecurityGroup,
  NameUtils,
  setMatchingResourceSummary,
} from '@spinnaker/core';
import {
  IAmazonApplicationLoadBalancer,
  IAmazonLoadBalancer,
  IAmazonServerGroupCommandDirty,
  VpcReader,
} from '@spinnaker/amazon';

import { IJobDisruptionBudget, ITitusResources } from 'titus/domain';
import { ITitusServiceJobProcesses } from 'titus/domain/ITitusServiceJobProcesses';

export interface ITitusServerGroupCommandBackingData extends IServerGroupCommandBackingData {
  accounts: string[];
  vpcs: IVpc[];
}

export interface ITitusServerGroupCommandViewState extends IServerGroupCommandViewState {
  accountChangedStream: Subject<{}>;
  regionChangedStream: Subject<{}>;
  groupsRemovedStream: Subject<{}>;
  dirty: IAmazonServerGroupCommandDirty;
  defaultIamProfile: string;
}

export const defaultJobDisruptionBudget: IJobDisruptionBudget = {
  availabilityPercentageLimit: {
    percentageOfHealthyContainers: 95,
  },
  ratePercentagePerInterval: {
    intervalMs: 600000,
    percentageLimitPerInterval: 5,
  },
  containerHealthProviders: [{ name: 'eureka' }],
  timeWindows: [
    {
      days: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
      hourlyTimeWindows: [{ startHour: 10, endHour: 16 }],
      timeZone: 'PST',
    },
  ],
};

export const getDefaultJobDisruptionBudgetForApp = (application: Application): IJobDisruptionBudget => {
  const budget = cloneDeep(defaultJobDisruptionBudget);
  if (application.attributes && application.attributes.platformHealthOnly) {
    budget.containerHealthProviders = [];
  }
  return budget;
};

export interface ITitusServerGroupCommand extends IServerGroupCommand {
  cluster?: ICluster;
  disruptionBudget?: IJobDisruptionBudget;
  deferredInitialization?: boolean;
  registry: string;
  imageId: string;
  organization: string;
  repository: string;
  tag?: string;
  digest?: string;
  image: string;
  inService: boolean;
  resources: ITitusResources;
  efs: {
    efsId: string;
    mountPoint: string;
    mountPerm: string;
    efsRelativeMountPoint: string;
  };
  viewState: ITitusServerGroupCommandViewState;
  targetGroups: string[];
  removedTargetGroups: string[];
  backingData: ITitusServerGroupCommandBackingData;
  labels: { [key: string]: string };
  containerAttributes: { [key: string]: string };
  env: { [key: string]: string };
  iamProfile: string;
  migrationPolicy: {
    type: string;
  };
  constraints: {
    hard: { [key: string]: string };
    soft: { [key: string]: string };
  };
  serviceJobProcesses: ITitusServiceJobProcesses;
}

export class TitusServerGroupConfigurationService {
  public static $inject = ['cacheInitializer', 'loadBalancerReader', 'securityGroupReader'];
  constructor(
    private cacheInitializer: CacheInitializerService,
    private loadBalancerReader: LoadBalancerReader,
    private securityGroupReader: SecurityGroupReader,
  ) {}

  public configureZones(command: ITitusServerGroupCommand) {
    command.backingData.filtered.regions = command.backingData.credentialsKeyedByAccount[command.credentials].regions;
  }

  private attachEventHandlers(cmd: ITitusServerGroupCommand) {
    cmd.credentialsChanged = (command: ITitusServerGroupCommand) => {
      const result = { dirty: {} };
      const backingData = command.backingData;
      this.configureZones(command);
      if (command.credentials) {
        command.registry = (backingData.credentialsKeyedByAccount[command.credentials] as any).registry;
        backingData.filtered.regions = backingData.credentialsKeyedByAccount[command.credentials].regions;
        if (!backingData.filtered.regions.some((r) => r.name === command.region)) {
          command.region = null;
          command.regionChanged(command);
        }
      } else {
        command.region = null;
      }
      command.viewState.dirty = { ...(command.viewState.dirty || {}), ...result.dirty };
      this.configureLoadBalancerOptions(command);
      this.configureSecurityGroupOptions(command);
      setMatchingResourceSummary(command);
      return result;
    };

    cmd.regionChanged = (command: ITitusServerGroupCommand) => {
      this.configureLoadBalancerOptions(command);
      this.configureSecurityGroupOptions(command);
      setMatchingResourceSummary(command);
      return {};
    };

    cmd.clusterChanged = (command: ITitusServerGroupCommand): void => {
      command.moniker = NameUtils.getMoniker(command.application, command.stack, command.freeFormDetails);
      setMatchingResourceSummary(command);
    };
  }

  public configureCommand(cmd: ITitusServerGroupCommand) {
    cmd.viewState.accountChangedStream = new Subject();
    cmd.viewState.regionChangedStream = new Subject();
    cmd.viewState.groupsRemovedStream = new Subject();
    cmd.viewState.dirty = {};
    cmd.onStrategyChange = (command: ITitusServerGroupCommand, strategy: IDeploymentStrategy) => {
      // Any strategy other than None or Custom should force traffic to be enabled
      if (strategy.key !== '' && strategy.key !== 'custom') {
        command.inService = true;
      }
    };
    cmd.image = cmd.viewState.imageId;
    return $q
      .all([
        AccountService.getCredentialsKeyedByAccount('titus'),
        this.securityGroupReader.getAllSecurityGroups(),
        VpcReader.listVpcs(),
      ])
      .then(([credentialsKeyedByAccount, securityGroups, vpcs]) => {
        const backingData: any = {
          credentialsKeyedByAccount,
          securityGroups,
          vpcs,
        };
        backingData.images = [];
        backingData.accounts = Object.keys(credentialsKeyedByAccount);
        backingData.filtered = {};
        if (cmd.credentials.includes('${')) {
          // If our dependency is an expression, the only thing we can really do is to just preserve current selections
          backingData.filtered.regions = [{ name: cmd.region }];
        } else {
          backingData.filtered.regions = (credentialsKeyedByAccount[cmd.credentials] || []).regions || [];
        }
        backingData.filtered.securityGroups = this.getRegionalSecurityGroups(cmd);
        cmd.backingData = backingData;

        let securityGroupRefresher = $q.when();
        if (cmd.securityGroups && cmd.securityGroups.length) {
          const regionalSecurityGroupIds = backingData.filtered.securityGroups.map((g: ISecurityGroup) => g.id);
          if (intersection(cmd.securityGroups, regionalSecurityGroupIds).length < cmd.securityGroups.length) {
            securityGroupRefresher = this.refreshSecurityGroups(cmd, false);
          }
        }

        return $q.all([this.refreshLoadBalancers(cmd), securityGroupRefresher]).then(() => {
          this.attachEventHandlers(cmd);
        });
      });
  }

  private getVpcId(command: ITitusServerGroupCommand): string {
    const credentials = this.getCredentials(command);
    const match = command.backingData.vpcs.find(
      (vpc) =>
        vpc.name === credentials.awsVpc &&
        vpc.account === credentials.awsAccount &&
        vpc.region === this.getRegion(command) &&
        vpc.cloudProvider === 'aws',
    );
    return match ? match.id : null;
  }
{'fraction_non_alphanumeric': 0.10963476894881528, 'fraction_numerical': 0.0017017934284592224, 'mean_word_length': 3.9655508612284693, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2409219', 'n_tokens_mistral': 4452, 'n_tokens_neox': 4345, 'n_words': 829}