2023-03-13 04:26:16 -05:00
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2023, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import React from 'react' ;
import { GoogleCredSchema , GoogleClusterSchema , GoogleDatabaseSchema } from './google_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' ;
import { makeStyles } from '@material-ui/core/styles' ;
const useStyles = makeStyles ( ( ) =>
( {
formClass : {
overflow : 'auto' ,
}
} ) ,
) ;
export function GoogleCredentials ( props ) {
const [ cloudDBCredInstance , setCloudDBCredInstance ] = React . useState ( ) ;
let _eventBus = React . useContext ( CloudWizardEventsContext ) ;
let child = null ;
React . useMemo ( ( ) => {
const googleCredSchema = new GoogleCredSchema ( {
authenticateGoogle : ( client _secret _file ) => {
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 , 'Google authentication process is in progress..<img src="' + loading _icon _url + '" alt="' + gettext ( 'Loading...' ) + '">' ] ) ;
let _url = url _for ( 'google.verify_credentials' ) ;
const post _data = {
cloud : 'google' ,
secret : { 'client_secret_file' : client _secret _file }
} ;
return new Promise ( ( resolve , reject ) => { axiosApi . post ( _url , post _data )
. then ( ( res ) => {
if ( res . data && res . data . success == 1 ) {
_eventBus . fireEvent ( 'SET_CRED_VERIFICATION_INITIATED' , true ) ;
let params = 'scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no, width=550,height=650,left=600,top=150' ;
child = window . open ( res . data . data . auth _url , 'google_authentication' , params ) ;
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 ) => {
_eventBus . fireEvent ( 'SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD' , [ MESSAGE _TYPE . ERROR , gettext ( ` Error while authentication: ${ error } ` ) ] ) ;
reject ( false ) ;
} ) ;
} ) ;
} ,
verification _ack : ( ) => {
let auth _url = url _for ( 'google.verification_ack' ) ;
let countdown = 90 ;
const axiosApi = getApiInstance ( ) ;
return new Promise ( ( resolve , reject ) => {
const interval = setInterval ( ( ) => {
axiosApi . get ( auth _url )
. then ( ( res ) => {
if ( res . data . success && 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.' ) ] ) ;
clearInterval ( interval ) ;
if ( child ) {
// close authentication window
child . close ( ) ;
}
resolve ( ) ;
2023-03-20 07:52:16 -05:00
} else if ( res . data && res . data . success == 0 && res . data . errormsg ) {
2023-03-13 04:26:16 -05:00
_eventBus . fireEvent ( 'SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD' , [ MESSAGE _TYPE . ERROR , res . data . errormsg ] ) ;
_eventBus . fireEvent ( 'SET_CRED_VERIFICATION_INITIATED' , false ) ;
clearInterval ( interval ) ;
resolve ( false ) ;
} else if ( child && child . closed || countdown <= 0 ) {
_eventBus . fireEvent ( 'SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD' , [ MESSAGE _TYPE . ERROR , 'Authentication is aborted.' ] ) ;
_eventBus . fireEvent ( 'SET_CRED_VERIFICATION_INITIATED' , false ) ;
clearInterval ( interval ) ;
}
} )
. catch ( ( error ) => {
clearInterval ( interval ) ;
reject ( error ) ;
} ) ;
countdown = countdown - 1 ;
} , 1000 ) ;
} ) ;
}
} , { } , _eventBus ) ;
setCloudDBCredInstance ( googleCredSchema ) ;
} , [ props . cloudProvider ] ) ;
return < SchemaView
formType = { 'dialog' }
getInitData = { ( ) => { /*This is intentional (SonarQube)*/ } }
viewHelperProps = { { mode : 'create' } }
schema = { cloudDBCredInstance }
showFooter = { false }
isTabView = { false }
onDataChange = { ( isChanged , changedData ) => {
props . setGoogleCredData ( changedData ) ;
} }
/ > ;
}
GoogleCredentials . propTypes = {
nodeInfo : PropTypes . object ,
nodeData : PropTypes . object ,
cloudProvider : PropTypes . string ,
setGoogleCredData : PropTypes . func
} ;
// Google Instance
export function GoogleInstanceDetails ( props ) {
const [ googleInstanceSchema , setGoogleInstanceSchema ] = React . useState ( ) ;
const classes = useStyles ( ) ;
React . useMemo ( ( ) => {
const GoogleClusterSchemaObj = new GoogleClusterSchema ( {
projects : ( ) => getNodeAjaxOptions ( 'get_projects' , { } , { } , { } , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'google.projects' ) ;
}
} ) ,
regions : ( project ) => getNodeAjaxOptions ( 'get_regions' , pgAdmin . Browser . Nodes [ 'server' ] , props . nodeInfo , props . nodeData , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'google.regions' , { 'project_id' : project } ) ;
}
} ) ,
availabilityZones : ( region ) => getNodeAjaxOptions ( 'get_availability_zones' , pgAdmin . Browser . Nodes [ 'server' ] , props . nodeInfo , props . nodeData , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'google.availability_zones' , { 'region' : region } ) ;
}
} ) ,
dbVersions : ( ) => getNodeAjaxOptions ( 'get_db_versions' , pgAdmin . Browser . Nodes [ 'server' ] , props . nodeInfo , props . nodeData , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'google.database_versions' ) ;
}
} ) ,
instanceTypes : ( project , region , instanceClass ) => {
if ( isEmptyString ( project ) || isEmptyString ( region ) || isEmptyString ( instanceClass ) ) return [ ] ;
return getNodeAjaxOptions ( 'get_instance_types' , pgAdmin . Browser . Nodes [ 'server' ] , props . nodeInfo , props . nodeData , {
useCache : false ,
cacheNode : 'server' ,
customGenerateUrl : ( ) => {
return url _for ( 'google.instance_types' , { 'project_id' : project , 'region' : region , 'instance_class' : instanceClass } ) ;
}
} ) ; } ,
} , {
nodeInfo : props . nodeInfo ,
nodeData : props . nodeData ,
hostIP : props . hostIP ,
... props . googleInstanceData
} ) ;
setGoogleInstanceSchema ( GoogleClusterSchemaObj ) ;
} , [ props . cloudProvider ] ) ;
return < SchemaView
formType = { 'dialog' }
getInitData = { ( ) => { /*This is intentional (SonarQube)*/ } }
viewHelperProps = { { mode : 'create' } }
schema = { googleInstanceSchema }
showFooter = { false }
isTabView = { false }
onDataChange = { ( isChanged , changedData ) => {
props . setGoogleInstanceData ( changedData ) ;
} }
formClassName = { classes . formClass }
/ > ;
}
GoogleInstanceDetails . propTypes = {
nodeInfo : PropTypes . object ,
nodeData : PropTypes . object ,
cloudProvider : PropTypes . string ,
setGoogleInstanceData : PropTypes . func ,
hostIP : PropTypes . string ,
subscriptions : PropTypes . array ,
googleInstanceData : PropTypes . object
} ;
// Google Database Details
export function GoogleDatabaseDetails ( props ) {
const [ gooeleDBInstance , setGoogleDBInstance ] = React . useState ( ) ;
const classes = useStyles ( ) ;
React . useMemo ( ( ) => {
const googleDBSchema = new GoogleDatabaseSchema ( {
server _groups : ( ) => getNodeListById ( pgAdmin . Browser . Nodes [ 'server_group' ] , props . nodeInfo , props . nodeData ) ,
} ,
{
gid : props . nodeInfo [ 'server_group' ] . _id ,
}
) ;
setGoogleDBInstance ( googleDBSchema ) ;
} , [ props . cloudProvider ] ) ;
return < SchemaView
formType = { 'dialog' }
getInitData = { ( ) => { /*This is intentional (SonarQube)*/ } }
viewHelperProps = { { mode : 'create' } }
schema = { gooeleDBInstance }
showFooter = { false }
isTabView = { false }
onDataChange = { ( isChanged , changedData ) => {
props . setGoogleDatabaseData ( changedData ) ;
} }
formClassName = { classes . formClass }
/ > ;
}
GoogleDatabaseDetails . propTypes = {
nodeInfo : PropTypes . object ,
nodeData : PropTypes . object ,
cloudProvider : PropTypes . string ,
setGoogleDatabaseData : PropTypes . func ,
} ;
// Validation functions
export function validateGoogleStep2 ( cloudInstanceDetails ) {
let isError = false ;
2023-03-20 07:52:16 -05:00
if ( ( isEmptyString ( cloudInstanceDetails . name ) || isEmptyString ( cloudInstanceDetails . project ) ||
isEmptyString ( cloudInstanceDetails . region ) || isEmptyString ( cloudInstanceDetails . availability _zone ) ||
isEmptyString ( cloudInstanceDetails . db _version ) || isEmptyString ( cloudInstanceDetails . instance _type ) ||
isEmptyString ( cloudInstanceDetails . instance _class ) || isEmptyString ( cloudInstanceDetails . storage _type ) ||
isEmptyString ( cloudInstanceDetails . storage _size ) || isEmptyString ( cloudInstanceDetails . public _ips ) ) ||
( cloudInstanceDetails . high _availability && isEmptyString ( cloudInstanceDetails . secondary _availability _zone ) ) ) {
2023-03-13 04:26:16 -05:00
isError = true ;
}
return isError ;
}
export function validateGoogleStep3 ( cloudDBDetails , nodeInfo ) {
let isError = false ;
if ( isEmptyString ( cloudDBDetails . db _username ) || isEmptyString ( cloudDBDetails . db _password ) ) {
isError = true ;
}
if ( cloudDBDetails . db _password != cloudDBDetails . db _confirm _password ) {
isError = true ;
}
if ( isEmptyString ( cloudDBDetails . gid ) ) cloudDBDetails . gid = nodeInfo [ 'server_group' ] . _id ;
return isError ;
}
// Summary creation
function createData ( name , value ) {
if ( typeof ( value ) == 'boolean' ) {
value = ( value === true ) ? 'True' : 'False' ;
}
return { name , value } ;
}
// Summary section
export function getGoogleSummary ( cloud , cloudInstanceDetails , cloudDBDetails ) {
2023-03-20 07:52:16 -05:00
let db _version = cloudInstanceDetails . db _version ;
db _version = db _version . charAt ( 0 ) + db _version . slice ( 1 , 7 ) . toLowerCase ( ) + 'SQL ' + db _version . split ( '_' ) [ 1 ] ;
2023-03-13 04:26:16 -05:00
let storageType = cloudInstanceDetails . storage _type . split ( '_' ) [ 1 ] ;
2023-03-20 07:52:16 -05:00
let instance _class = cloudInstanceDetails . instance _class . charAt ( 0 ) . toUpperCase ( ) + cloudInstanceDetails . instance _class . slice ( 1 ) ;
let instance _type = cloudInstanceDetails . instance _type ;
if ( instance _class == 'Standard' || instance _class == 'Highmem' ) {
instance _type = instance _type . split ( '-' ) [ 2 ] + ' vCPU ' + Math . round ( ( parseInt ( instance _type . split ( '-' ) [ 3 ] ) ) / 1024 ) + ' GB' ;
} else {
const instance _type _mapping = { 'db-f1-micro' : '1 vCPU, 0.6 GB' , 'db-g1-small' : '1 vCPU, 1.7 GB' } ;
instance _type = instance _type _mapping [ instance _type ] ;
}
2023-03-13 04:26:16 -05:00
const rows1 = [
createData ( gettext ( 'Cloud' ) , cloud ) ,
createData ( gettext ( 'Instance name' ) , cloudInstanceDetails . name ) ,
createData ( gettext ( 'Project' ) , cloudInstanceDetails . project ) ,
createData ( gettext ( 'Region' ) , cloudInstanceDetails . region ) ,
createData ( gettext ( 'Availability zone' ) , cloudInstanceDetails . availability _zone ) ,
] ;
const rows2 = [
2023-03-20 07:52:16 -05:00
createData ( gettext ( 'PostgreSQL version' ) , db _version ) ,
createData ( gettext ( 'Instance class' ) , instance _class ) ,
createData ( gettext ( 'Instance type' ) , instance _type ) ,
2023-03-13 04:26:16 -05:00
] ;
const rows3 = [
createData ( gettext ( 'Storage type' ) , storageType ) ,
createData ( gettext ( 'Allocated storage' ) , cloudInstanceDetails . storage _size + ' GB' ) ,
] ;
const rows4 = [
createData ( gettext ( 'Username' ) , cloudDBDetails . db _username ) ,
createData ( gettext ( 'Password' ) , 'xxxxxxx' ) ,
] ;
const rows5 = [
createData ( gettext ( 'Public IP' ) , cloudInstanceDetails . public _ips ) ,
] ;
const rows6 = [
createData ( gettext ( 'High availability' ) , cloudInstanceDetails . high _availability ) ,
createData ( gettext ( 'Secondary availability zone' ) , cloudInstanceDetails . secondary _availability _zone ) ,
] ;
return [ rows1 , rows2 , rows3 , rows4 , rows5 , rows6 ] ;
}