import type { ApplicationInsightsManagementClient } from '@azure/arm-appinsights' ; import type { ResourceManagementClient , ResourceManagementModels } from '@azure/arm-resources' ; import type { HttpOperationResponse , ServiceClient } from '@azure/ms-rest-js' ; import { MessageItem , Progress } from 'vscode' ; import { AzExtLocation , AzureWizardExecuteStep , createGenericClient , IActionContext , IParsedError , LocationListStep , parseError } from 'vscode-azureextensionui' ; import { ext } from '../extensionVariables' ; import { localize } from '../localize' ; import { createAppInsightsClient , createResourceClient } from '../utils/azureClients' ; import { areLocationNamesEqual } from '../utils/azureUtils' ; import { nonNullProp } from '../utils/nonNull' ; import { AppInsightsListStep } from './AppInsightsListStep' ; import { IAppServiceWizardContext } from './IAppServiceWizardContext' ; export class AppInsightsCreateStep extends AzureWizardExecuteStep < IAppServiceWizardContext > { public priority : number = 135 ; public async execute ( context , progress ) { const resourceLocation = await LocationListStep . getLocation ( context ) ; const verifyingAppInsightsAvailable = localize ( 'verifyingAppInsightsAvailable' , 'Verifying that Application Insights is available for this location...' ) ; ext . outputChannel . appendLog ( verifyingAppInsightsAvailable ) ; const appInsightsLocation = await this . getSupportedLocation ( context , resourceLocation ) ; if ( appInsightsLocation ) { const client = await createAppInsightsClient ( context ) ; const rg = nonNullProp ( context , 'resourceGroup' ) ; const rgName = nonNullProp ( rg , 'name' ) ; const aiName = nonNullProp ( context , 'newAppInsightsName' ) ; try { context . appInsightsComponent = await client . components . get ( rgName , aiName ) ; ext . outputChannel . appendLog ( localize ( 'existingNewAppInsights' , 'Using existing Application Insights resource "{0}".' , aiName ) ) ; } catch ( error ) { const pError = parseError ( error ) ; if ( pError . errorType === 'ResourceNotFound' ) { const creatingNewAppInsights = localize ( 'creatingNewAppInsightsInsights' , 'Creating Application Insights resource "{0}"...' , aiName ) ; ext . outputChannel . appendLog ( creatingNewAppInsights ) ; progress . report ( { message : creatingNewAppInsights } ) ; context . appInsightsComponent = await client . components . createOrUpdate ( rgName , aiName , { kind : 'web' , applicationType : 'web' , location : appInsightsLocation } ) ; const createdNewAppInsights = localize ( 'createdNewAppInsights' , 'Successfully created Application Insights resource "{0}".' , aiName ) ; ext . outputChannel . appendLog ( createdNewAppInsights ) ; } else if ( pError . errorType === 'AuthorizationFailed' ) { if ( ! context . advancedCreation ) { const appInsightsNotAuthorized = localize ( 'appInsightsNotAuthorized' , 'Skipping Application Insights resource because you do not have permission to create one in this subscription.' ) ; ext . outputChannel . appendLog ( appInsightsNotAuthorized ) ; } else { await this . selectExistingPrompt ( context ) ; } } else { throw error ; } } } else { const appInsightsNotAvailable = localize ( 'appInsightsNotAvailable' , 'Skipping Application Insights resource because it isn\'t compatible with this location.' ) ; ext . outputChannel . appendLog ( appInsightsNotAvailable ) ; } } public async selectExistingPrompt ( context ) { const message = localize ( 'aiForbidden' , 'You do not have permission to create an app insights resource in subscription "{0}".' , context . subscriptionDisplayName ) ; const selectExisting = { title : localize ( 'selectExisting' , 'Select Existing' ) } ; const skipForNow = { title : localize ( 'skipForNow' , 'Skip for Now' ) } ; const result = await context . ui . showWarningMessage ( message , { modal : true , stepName : 'AppInsightsNoPermissions' } , selectExisting , skipForNow ) ; if ( result === skipForNow ) { context . telemetry . properties . aiSkipForNow = 'true' ; context . appInsightsSkip = true ; context . telemetry . properties . forbiddenResponse = 'SkipAppInsights' ; } else { context . telemetry . properties . forbiddenResponse = 'SelectExistingAppInsights' ; const step = new AppInsightsListStep ( true ) ; await step . prompt ( context ) ; } } public shouldExecute ( context ) { return ! context . appInsightsComponent && ! ! context . newAppInsightsName ; } private async getSupportedLocation ( context , location ) { const locations = await this . getLocations ( context ) || [ ] ; const locationName = nonNullProp ( location , 'name' ) ; if ( locations . some ( ( loc ) => areLocationNamesEqual ( loc , location . name ) ) ) { context . telemetry . properties . aiLocationSupported = 'true' ; return locationName ; } else { const pairedRegions = await this . getPairedRegions ( context , locationName ) ; if ( pairedRegions . length > 0 ) { context . telemetry . properties . aiLocationSupported = 'pairedRegion' ; return pairedRegions [ 0 ] ; } context . telemetry . properties . aiLocationSupported = 'false' ; return undefined ; } } private async getPairedRegions ( context , locationName ) { try { const client = await createGenericClient ( context , undefined ) ; const response = await client . sendRequest ( { method : 'GET' , url : 'https://appinsights.azureedge.net/portal/regionMapping.json' } ) ; const regionMappingJson = < RegionMappingJsonResponse > response . parsedBody ; if ( regionMappingJson . regions [ locationName ] ) { return regionMappingJson . regions [ locationName ] . pairedRegions ; } } catch ( error ) { } return [ ] ; } private async getLocations ( context ) { const resourceClient = await createResourceClient ( context ) ; const supportedRegions = await resourceClient . providers . get ( 'microsoft.insights' ) ; const componentsResourceType = supportedRegions . resourceTypes && supportedRegions . resourceTypes . find ( aiRt => aiRt . resourceType === 'components' ) ; if ( ! ! componentsResourceType && ! ! componentsResourceType . locations ) { return componentsResourceType . locations ; } else { return undefined ; } } } type RegionMappingJsonResponse = { regions : { [ key ] : RegionMap ; } ; } ; type RegionMap = { geo : string ; pairedRegions : string [ ] ; } ;