2022-06-15 00:52:42 -05:00
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
2024-01-01 02:43:48 -06:00
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
2022-06-15 00:52:42 -05:00
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import React from 'react' ;
import { AzureCredSchema , AzureClusterSchema , AzureDatabaseSchema } from './azure_schema.ui' ;
import pgAdmin from 'sources/pgadmin' ;
import { getNodeAjaxOptions , getNodeListById } from 'pgbrowser/node_ajax' ;
import SchemaView from '../../../../static/js/SchemaView' ;
import url _for from 'sources/url_for' ;
import { isEmptyString } from 'sources/validators' ;
import PropTypes from 'prop-types' ;
import getApiInstance from '../../../../static/js/api_instance' ;
import { CloudWizardEventsContext } from './CloudWizard' ;
import { MESSAGE _TYPE } from '../../../../static/js/components/FormComponents' ;
import gettext from 'sources/gettext' ;
// Azure credentials
export function AzureCredentials ( props ) {
const [ cloudDBCredInstance , setCloudDBCredInstance ] = React . useState ( ) ;
2022-09-08 07:38:58 -05:00
let _eventBus = React . useContext ( CloudWizardEventsContext ) ;
2022-06-15 00:52:42 -05:00
React . useMemo ( ( ) => {
2024-06-13 08:18:02 -05:00
const azureCloudDBCredSchema = new AzureCredSchema ( _eventBus , {
2022-06-15 00:52:42 -05:00
authenticateAzure : ( auth _type , azure _tenant _id ) => {
let loading _icon _url = url _for (
'static' , { 'filename' : 'img/loading.gif' }
) ;
const axiosApi = getApiInstance ( ) ;
_eventBus . fireEvent ( 'SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD' , [ MESSAGE _TYPE . INFO , 'Microsoft Azure authentication process is in progress..<img src="' + loading _icon _url + '" alt="' + gettext ( 'Loading...' ) + '">' ] ) ;
let _url = url _for ( 'azure.verify_credentials' ) ;
const post _data = {
cloud : 'azure' ,
secret : { 'auth_type' : auth _type , 'azure_tenant_id' : azure _tenant _id }
} ;
return new Promise ( ( resolve , reject ) => { axiosApi . post ( _url , post _data )
. then ( ( res ) => {
if ( res . data && res . data . success == 1 ) {
_eventBus . fireEvent ( 'SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD' , [ MESSAGE _TYPE . SUCCESS , gettext ( 'Authentication completed successfully. Click the Next button to proceed.' ) ] ) ;
_eventBus . fireEvent ( 'SET_CRED_VERIFICATION_INITIATED' , true ) ;
resolve ( true ) ;
}
else if ( res . data && res . data . success == 0 ) {
_eventBus . fireEvent ( 'SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD' , [ MESSAGE _TYPE . ERROR , res . data . errormsg ] ) ;
_eventBus . fireEvent ( 'SET_CRED_VERIFICATION_INITIATED' , false ) ;
resolve ( false ) ;
}
} )
. catch ( ( error ) => {
2022-08-17 06:47:13 -05:00
_eventBus . fireEvent ( 'SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD' , [ MESSAGE _TYPE . ERROR , gettext ( ` Error while verifying Microsoft Azure: ${ error } ` ) ] ) ;
2024-04-09 08:48:56 -05:00
reject ( new Error ( gettext ( error ) ) ) ;
2022-07-06 01:13:49 -05:00
} ) ;
} ) ;
} ,
getAuthCode : ( ) => {
let _url _get _azure _verification _codes = url _for ( 'azure.get_azure_verification_codes' ) ;
const axiosApi = getApiInstance ( ) ;
return new Promise ( ( resolve , reject ) => {
const interval = setInterval ( ( ) => {
axiosApi . get ( _url _get _azure _verification _codes )
. then ( ( res ) => {
if ( res . data . success ) {
clearInterval ( interval ) ;
2023-03-13 04:26:16 -05:00
let params = 'scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no, width=550,height=650,left=920,top=150' ;
window . open ( res . data . data . verification _uri , 'azure_authentication' , params ) ;
2022-07-06 01:13:49 -05:00
resolve ( res ) ;
}
} )
. catch ( ( error ) => {
clearInterval ( interval ) ;
2024-06-17 07:52:38 -05:00
reject ( error instanceof Error ? error : Error ( gettext ( 'Something went wrong' ) ) ) ;
2022-07-06 01:13:49 -05:00
} ) ;
} , 1000 ) ;
} ) ;
2022-06-15 00:52:42 -05:00
}
2024-06-13 08:18:02 -05:00
} , { } ) ;
2022-06-15 00:52:42 -05:00
setCloudDBCredInstance ( azureCloudDBCredSchema ) ;
} , [ props . cloudProvider ] ) ;
return < SchemaView
formType = { 'dialog' }
getInitData = { ( ) => { /*This is intentional (SonarQube)*/ } }
viewHelperProps = { { mode : 'create' } }
schema = { cloudDBCredInstance }
showFooter = { false }
isTabView = { false }
onDataChange = { ( isChanged , changedData ) => {
props . setAzureCredData ( changedData ) ;
} }
/ > ;
}
AzureCredentials . propTypes = {
cloudProvider : PropTypes . string ,
setAzureCredData : PropTypes . func
} ;
// Azure Instance
export function AzureInstanceDetails ( props ) {
const [ azureInstanceSchema , setAzureInstanceSchema ] = React . useState ( ) ;
React . useMemo ( ( ) => {
const AzureSchema = new AzureClusterSchema ( {
subscriptions : ( ) => getNodeAjaxOptions ( 'get_subscriptions' , { } , { } , { } , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'azure.subscriptions' ) ;
}
} ) ,
resourceGroups : ( subscription ) => getNodeAjaxOptions ( 'ge_resource_groups' , pgAdmin . Browser . Nodes [ 'server' ] , props . nodeInfo , props . nodeData , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'azure.resource_groups' , { 'subscription_id' : subscription } ) ;
}
} ) ,
regions : ( subscription ) => getNodeAjaxOptions ( 'get_regions' , pgAdmin . Browser . Nodes [ 'server' ] , props . nodeInfo , props . nodeData , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'azure.regions' , { 'subscription_id' : subscription } ) ;
}
} ) ,
availabilityZones : ( region ) => getNodeAjaxOptions ( 'get_availability_zones' , pgAdmin . Browser . Nodes [ 'server' ] , props . nodeInfo , props . nodeData , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'azure.availability_zones' , { 'region_name' : region } ) ;
}
} ) ,
versionOptions : ( availabilityZone ) => getNodeAjaxOptions ( 'get_db_versions' , pgAdmin . Browser . Nodes [ 'server' ] , props . nodeInfo , props . nodeData , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'azure.db_versions' , { 'availability_zone' : availabilityZone } ) ;
}
} ) ,
instanceOptions : ( dbVersion , availabilityZone ) => {
if ( isEmptyString ( dbVersion ) || isEmptyString ( availabilityZone ) ) return [ ] ;
return getNodeAjaxOptions ( 'get_instance_types' , pgAdmin . Browser . Nodes [ 'server' ] , props . nodeInfo , props . nodeData , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'azure.instance_types' , { 'availability_zone' : availabilityZone , 'db_version' : dbVersion } ) ;
}
} ) ; } ,
storageOptions : ( dbVersion , availabilityZone ) => {
if ( isEmptyString ( dbVersion ) || isEmptyString ( availabilityZone ) ) return [ ] ;
return getNodeAjaxOptions ( 'get_instance_types' , pgAdmin . Browser . Nodes [ 'server' ] , props . nodeInfo , props . nodeData , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'azure.storage_types' , { 'availability_zone' : availabilityZone , 'db_version' : dbVersion } ) ;
}
} ) ;
} ,
zoneRedundantHaSupported : ( region ) => getNodeAjaxOptions ( 'is_zone_redundant_ha_supported' , pgAdmin . Browser . Nodes [ 'server' ] , props . nodeInfo , props . nodeData , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'azure.zone_redundant_ha_supported' , { 'region_name' : region } ) ;
}
} ) ,
} , {
nodeInfo : props . nodeInfo ,
nodeData : props . nodeData ,
hostIP : props . hostIP ,
... props . azureInstanceData
} ) ;
setAzureInstanceSchema ( AzureSchema ) ;
} , [ props . cloudProvider ] ) ;
return < SchemaView
formType = { 'dialog' }
getInitData = { ( ) => { /*This is intentional (SonarQube)*/ } }
viewHelperProps = { { mode : 'create' } }
schema = { azureInstanceSchema }
showFooter = { false }
isTabView = { false }
onDataChange = { ( isChanged , changedData ) => {
props . setAzureInstanceData ( changedData ) ;
} }
/ > ;
}
AzureInstanceDetails . propTypes = {
nodeInfo : PropTypes . object ,
nodeData : PropTypes . object ,
cloudProvider : PropTypes . string ,
setAzureInstanceData : PropTypes . func ,
hostIP : PropTypes . string ,
azureInstanceData : PropTypes . object
} ;
// Azure Database Details
export function AzureDatabaseDetails ( props ) {
const [ azureDBInstance , setAzureDBInstance ] = React . useState ( ) ;
React . useMemo ( ( ) => {
const azureDBSchema = new AzureDatabaseSchema ( {
server _groups : ( ) => getNodeListById ( pgAdmin . Browser . Nodes [ 'server_group' ] , props . nodeInfo , props . nodeData ) ,
} ,
{
gid : props . nodeInfo [ 'server_group' ] . _id ,
}
) ;
setAzureDBInstance ( azureDBSchema ) ;
} , [ props . cloudProvider ] ) ;
return < SchemaView
formType = { 'dialog' }
getInitData = { ( ) => { /*This is intentional (SonarQube)*/ } }
viewHelperProps = { { mode : 'create' } }
schema = { azureDBInstance }
showFooter = { false }
isTabView = { false }
onDataChange = { ( isChanged , changedData ) => {
props . setAzureDatabaseData ( changedData ) ;
} }
/ > ;
}
AzureDatabaseDetails . propTypes = {
nodeInfo : PropTypes . object ,
nodeData : PropTypes . object ,
cloudProvider : PropTypes . string ,
setAzureDatabaseData : PropTypes . func ,
} ;
// Validation functions
export function validateAzureStep2 ( cloudInstanceDetails ) {
let isError = false ;
if ( isEmptyString ( cloudInstanceDetails . name ) ||
isEmptyString ( cloudInstanceDetails . db _version ) || isEmptyString ( cloudInstanceDetails . instance _type ) ||
isEmptyString ( cloudInstanceDetails . region ) || isEmptyString ( cloudInstanceDetails . storage _size ) || isEmptyString ( cloudInstanceDetails . public _ips ) ) {
isError = true ;
}
return isError ;
}
export function validateAzureStep3 ( cloudDBDetails , nodeInfo ) {
let isError = false ;
if ( isEmptyString ( cloudDBDetails . db _username ) || isEmptyString ( cloudDBDetails . db _password ) ) {
isError = true ;
}
2022-08-18 08:09:52 -05:00
if ( cloudDBDetails . db _password != cloudDBDetails . db _confirm _password || ! /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$@!%&*?])[A-Za-z\d#$@!%&*?]{8,128}$/ . test ( cloudDBDetails . db _confirm _password ) ) {
isError = true ;
}
2022-06-15 00:52:42 -05:00
if ( isEmptyString ( cloudDBDetails . gid ) ) cloudDBDetails . gid = nodeInfo [ 'server_group' ] . _id ;
return isError ;
}
// Check cluster name avaiablity
export function checkClusternameAvailbility ( clusterName ) {
return new Promise ( ( resolve , reject ) => {
let _url = url _for ( 'azure.check_cluster_name_availability' ) ;
const axiosApi = getApiInstance ( ) ;
axiosApi . get ( _url , {
params : {
'name' : clusterName ,
}
} ) . then ( ( res ) => {
if ( res . data ) {
resolve ( res . data ) ;
}
} ) . catch ( ( error ) => {
2024-06-12 07:39:06 -05:00
reject ( new Error ( gettext ( ` Error while checking server name availability with Microsoft Azure: ${ error . response . data . errormsg } ` ) ) ) ;
2022-06-15 00:52:42 -05:00
} ) ;
} ) ;
}
// Summary creation
function createData ( name , value ) {
if ( typeof ( value ) == 'boolean' ) {
value = ( value === true ) ? 'True' : 'False' ;
}
return { name , value } ;
}
// Summary section
export function getAzureSummary ( cloud , cloudInstanceDetails , cloudDBDetails ) {
const rows1 = [
2022-08-18 03:11:27 -05:00
createData ( gettext ( 'Cloud' ) , cloud ) ,
createData ( gettext ( 'Subscription' ) , cloudInstanceDetails . subscription ) ,
createData ( gettext ( 'Resource group' ) , cloudInstanceDetails . resource _group ) ,
createData ( gettext ( 'Region' ) , cloudInstanceDetails . region ) ,
createData ( gettext ( 'Availability zone' ) , cloudInstanceDetails . availability _zone ) ,
2022-06-15 00:52:42 -05:00
] ;
const rows2 = [
2022-08-18 03:11:27 -05:00
createData ( gettext ( 'PostgreSQL version' ) , cloudInstanceDetails . db _version ) ,
createData ( gettext ( 'Instance type' ) , cloudInstanceDetails . instance _type ) ,
2022-06-15 00:52:42 -05:00
] ;
const rows3 = [
2022-08-18 03:11:27 -05:00
createData ( gettext ( 'Allocated storage' ) , cloudInstanceDetails . storage _size + ' GiB' ) ,
2022-06-15 00:52:42 -05:00
] ;
const rows4 = [
2022-08-18 03:11:27 -05:00
createData ( gettext ( 'Username' ) , cloudDBDetails . db _username ) ,
createData ( gettext ( 'Password' ) , 'xxxxxxx' ) ,
2022-06-15 00:52:42 -05:00
] ;
const rows5 = [
2022-08-18 03:11:27 -05:00
createData ( gettext ( 'Public IP' ) , cloudInstanceDetails . public _ips ) ,
2022-06-15 00:52:42 -05:00
] ;
const rows6 = [
2022-08-18 03:11:27 -05:00
createData ( gettext ( 'High availability' ) , cloudInstanceDetails . high _availability ) ,
2022-06-15 00:52:42 -05:00
] ;
return [ rows1 , rows2 , rows3 , rows4 , rows5 , rows6 ] ;
}