import { StorageAccount } from "@azure/arm-storage/esm/models" ; import commander from "commander" ; import fs from "fs" ; import yaml from "js-yaml" ; import { Config , defaultConfigFile , readYaml } from "../../config" ; import { createStorageAccount , createTableIfNotExists , getStorageAccountKey , isStorageAccountExist , } from "../../lib/azure/storage" ; import { build as buildCmd , exit as exitCmd , populateInheritValueFromConfig , validateForRequiredValues , } from "../../lib/commandBuilder" ; import { build as buildError , log as logError } from "../../lib/errorBuilder" ; import { errorStatusCode } from "../../lib/errorStatusCode" ; import { logger } from "../../logger" ; import { AzureAccessOpts , ConfigYaml } from "../../types" ; import decorator from "./onboard.decorator.json" ; import { validateStorageAccountNameThrowable , validateStorageTableNameThrowable , } from "../../lib/validator" ; export interface CommandOptions { storageAccountName : string | undefined ; storageTableName : string | undefined ; storageLocation : string | undefined ; storageResourceGroupName : string | undefined ; servicePrincipalId : string | undefined ; servicePrincipalPassword : string | undefined ; tenantId : string | undefined ; subscriptionId : string | undefined ; } export interface OnBoardConfig { storageResourceGroupName : string ; storageAccountName : string ; storageTableName : string ; servicePrincipalId : string ; servicePrincipalPassword : string ; subscriptionId : string ; tenantId : string ; storageLocation ? : string ; } param opts export const populateValues = ( opts ) : CommandOptions => { populateInheritValueFromConfig ( decorator , Config ( ) , opts ) ; return opts ; } ; param opts export const validateValues = ( opts ) : OnBoardConfig => { validateForRequiredValues ( decorator , opts , true ) ; validateStorageAccountNameThrowable ( opts . storageAccountName ! ) ; validateStorageTableNameThrowable ( opts . storageTableName ! ) ; return { storageResourceGroupName : opts . storageResourceGroupName || "" , storageAccountName : opts . storageAccountName || "" , storageTableName : opts . storageTableName || "" , servicePrincipalId : opts . servicePrincipalId || "" , servicePrincipalPassword : opts . servicePrincipalPassword || "" , subscriptionId : opts . subscriptionId || "" , tenantId : opts . tenantId || "" , storageLocation : opts . storageLocation , } ; } ; param storageAccountName param storageTableName export const setConfiguration = ( storageAccountName , storageTableName ) : boolean => { try { const data = readYaml < ConfigYaml > ( defaultConfigFile ( ) ) ; if ( ! data . introspection ) { data . introspection = { } ; } data . introspection . azure = data . introspection . azure || { } ; data . introspection . azure . account_name = storageAccountName ; data . introspection . azure . table_name = storageTableName ; const jsonData = yaml . safeDump ( data ) ; logger . verbose ( jsonData ) ; fs . writeFileSync ( defaultConfigFile ( ) , jsonData ) ; return true ; } catch ( err ) { logger . error ( `Unable to set storage account and table names in configuration file. \n ${ err }` ) ; return false ; } } ; param values param accessOpts export const validateAndCreateStorageAccount = async ( values , accessOpts ) : Promise < StorageAccount | undefined > => { const isExist = await isStorageAccountExist ( values . storageResourceGroupName , values . storageAccountName , accessOpts ) ; if ( isExist === false ) { if ( ! values . storageLocation ) { throw buildError ( errorStatusCode . VALIDATION_ERR , "introspect-onboard-cmd-location-missing" ) ; } const storageAccount = await createStorageAccount ( values . storageResourceGroupName , values . storageAccountName , values . storageLocation , accessOpts ) ; logger . debug ( `Storage Account: ${ JSON . stringify ( storageAccount , null , 2 ) }` ) ; return storageAccount ; } return undefined ; } ; param values param accessOpts throws export const getStorageAccessKey = async ( values , accessOpts ) : Promise < string > => { const accessKey = await getStorageAccountKey ( values . storageResourceGroupName , values . storageAccountName , accessOpts ) ; if ( accessKey === undefined ) { throw buildError ( errorStatusCode . ENV_SETTING_ERR , { errorKey : "introspect-onboard-cmd-get-storage-access-key-err" , values : [ values . storageAccountName , values . storageResourceGroupName ] , } ) ; } return accessKey ; } ; param values export const onboard = async ( values ) : Promise < StorageAccount | undefined > => { logger . debug ( `onboard called with ${ values . storageAccountName }, ${ values . storageTableName },
    ${ values . storageResourceGroupName } and ${ values . storageLocation }` ) ; const accessOpts = { servicePrincipalId : values . servicePrincipalId , servicePrincipalPassword : values . servicePrincipalPassword , subscriptionId : values . subscriptionId , tenantId : values . tenantId , } ; const storageAccount = await validateAndCreateStorageAccount ( values , accessOpts ) ; const accessKey = await getStorageAccessKey ( values , accessOpts ) ; const tableCreated = await createTableIfNotExists ( values . storageAccountName , values . storageTableName , accessKey ) ; if ( tableCreated ) { if ( storageAccount !== undefined ) { logger . info ( `Storage account ${ values . storageAccountName } and
        table ${ values . storageTableName } are created.` ) ; } else { logger . info ( `Table ${ values . storageTableName } is created in
        existing storage account ${ values . storageAccountName }.` ) ; } } else if ( storageAccount !== undefined ) { logger . info ( `Both storage account ${ values . storageAccountName } and
      table ${ values . storageTableName } exist.` ) ; } setConfiguration ( values . storageAccountName , values . storageTableName ) ; return storageAccount ; } ; param opts param exitFn export const execute = async ( opts , exitFn ) : Promise < void > => { try { populateValues ( opts ) ; const values = validateValues ( opts ) ; const storageAccount = await onboard ( values ) ; logger . debug ( `Service introspection deployment onboarding is complete. \n ${ JSON . stringify ( storageAccount ) }` ) ; await exitFn ( 0 ) ; } catch ( err ) { logError ( buildError ( errorStatusCode . CMD_EXE_ERR , "introspect-onboard-cmd-failed" , err ) ) ; await exitFn ( 1 ) ; } } ; param command export const commandDecorator = ( command ) : void => { buildCmd ( command , decorator ) . action ( async ( opts ) => { await execute ( opts , async ( status ) => { await exitCmd ( logger , process . exit , status ) ; } ) ; } ) ; } ;