2022-06-15 00:52:42 -05:00
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2022, The pgAdmin Development Team
// 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' ;
2022-08-05 03:39:09 -05:00
import { makeStyles } from '@material-ui/core/styles' ;
const useStyles = makeStyles ( ( ) =>
( {
formClass : {
overflow : 'auto' ,
}
} ) ,
) ;
2022-06-15 00:52:42 -05:00
// Azure credentials
export function AzureCredentials ( props ) {
const [ cloudDBCredInstance , setCloudDBCredInstance ] = React . useState ( ) ;
var _eventBus = React . useContext ( CloudWizardEventsContext ) ;
React . useMemo ( ( ) => {
const azureCloudDBCredSchema = new AzureCredSchema ( {
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 } ` ) ] ) ;
2022-06-15 00:52:42 -05:00
reject ( false ) ;
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 ) ;
window . open ( res . data . data . verification _uri , 'azure_authentication' ) ;
resolve ( res ) ;
}
} )
. catch ( ( error ) => {
clearInterval ( interval ) ;
reject ( error ) ;
} ) ;
} , 1000 ) ;
} ) ;
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 = {
nodeInfo : PropTypes . object ,
nodeData : PropTypes . object ,
cloudProvider : PropTypes . string ,
setAzureCredData : PropTypes . func
} ;
// Azure Instance
export function AzureInstanceDetails ( props ) {
const [ azureInstanceSchema , setAzureInstanceSchema ] = React . useState ( ) ;
2022-08-05 05:34:15 -05:00
const classes = useStyles ( ) ;
2022-06-15 00:52:42 -05:00
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 ) ;
} }
2022-08-05 03:39:09 -05:00
formClassName = { classes . formClass }
2022-06-15 00:52:42 -05:00
/ > ;
}
AzureInstanceDetails . propTypes = {
nodeInfo : PropTypes . object ,
nodeData : PropTypes . object ,
cloudProvider : PropTypes . string ,
setAzureInstanceData : PropTypes . func ,
hostIP : PropTypes . string ,
subscriptions : PropTypes . array ,
azureInstanceData : PropTypes . object
} ;
// Azure Database Details
export function AzureDatabaseDetails ( props ) {
const [ azureDBInstance , setAzureDBInstance ] = React . useState ( ) ;
2022-08-05 05:34:15 -05:00
const classes = useStyles ( ) ;
2022-06-15 00:52:42 -05:00
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 ) ;
} }
2022-08-05 03:39:09 -05:00
formClassName = { classes . formClass }
2022-06-15 00:52:42 -05:00
/ > ;
}
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 ;
}
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 ) => {
reject ( gettext ( ` Error while checking server name availability with Microsoft Azure: ${ error . response . data . errormsg } ` ) ) ;
} ) ;
} ) ;
}
// 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 = [
createData ( 'Cloud' , cloud ) ,
createData ( 'Subscription' , cloudInstanceDetails . subscription ) ,
createData ( 'Resource group' , cloudInstanceDetails . resource _group ) ,
createData ( 'Region' , cloudInstanceDetails . region ) ,
createData ( 'Availability zone' , cloudInstanceDetails . availability _zone ) ,
] ;
const rows2 = [
createData ( 'PostgreSQL version' , cloudInstanceDetails . db _version ) ,
createData ( 'Instance type' , cloudInstanceDetails . instance _type ) ,
] ;
const rows3 = [
createData ( 'Allocated storage' , cloudInstanceDetails . storage _size + ' GiB' ) ,
] ;
const rows4 = [
createData ( 'Username' , cloudDBDetails . db _username ) ,
createData ( 'Password' , 'xxxxxxx' ) ,
] ;
const rows5 = [
createData ( 'Public IP' , cloudInstanceDetails . public _ips ) ,
] ;
const rows6 = [
createData ( 'High availability' , cloudInstanceDetails . high _availability ) ,
] ;
return [ rows1 , rows2 , rows3 , rows4 , rows5 , rows6 ] ;
}