///////////////////////////////////////////////////////////// // // pgAdmin 4 - PostgreSQL Tools // // Copyright (C) 2013 - 2022, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // ////////////////////////////////////////////////////////////// import gettext from 'sources/gettext'; import url_for from 'sources/url_for'; import React from 'react'; import { Box, Paper } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; import Wizard from '../../../../static/js/helpers/wizard/Wizard'; import WizardStep from '../../../../static/js/helpers/wizard/WizardStep'; import {FormFooterMessage, MESSAGE_TYPE } from '../../../../static/js/components/FormComponents'; import getApiInstance from '../../../../static/js/api_instance'; import Alertify from 'pgadmin.alertifyjs'; import PropTypes from 'prop-types'; import pgAdmin from 'sources/pgadmin'; import {ToggleButtons, FinalSummary} from './cloud_components'; import { PrimaryButton } from '../../../../static/js/components/Buttons'; import {AwsCredentials, AwsInstanceDetails, AwsDatabaseDetails, validateCloudStep1, validateCloudStep2, validateCloudStep3} from './aws'; import {BigAnimalInstance, BigAnimalDatabase, validateBigAnimal, validateBigAnimalStep2, validateBigAnimalStep3} from './biganimal'; import { isEmptyString } from 'sources/validators'; import { AWSIcon, BigAnimalIcon } from '../../../../static/js/components/ExternalIcon'; const useStyles = makeStyles(() => ({ messageBox: { marginBottom: '1em', display: 'flex', }, messagePadding: { paddingTop: '10px', flex: 2.5, }, buttonMarginEDB: { position: 'relative', top: '20%', }, toggleButton: { height: '100px', }, summaryContainer: { flexGrow: 1, minHeight: 0, overflow: 'auto', }, boxText: { paddingBottom: '5px' }, }), ); export default function CloudWizard({ nodeInfo, nodeData }) { const classes = useStyles(); var steps = [gettext('Cloud Provider'), gettext('Credentials'), gettext('Instance Specification'), gettext('Database Details'), gettext('Review')]; const [currentStep, setCurrentStep] = React.useState(''); const [selectionVal, setCloudSelection] = React.useState(''); const [errMsg, setErrMsg] = React.useState(''); const [cloudInstanceDetails, setCloudInstanceDetails] = React.useState({}); const [cloudDBCred, setCloudDBCred] = React.useState({}); const [cloudDBDetails, setCloudDBDetails] = React.useState({}); const [callRDSAPI, setCallRDSAPI] = React.useState({}); const [hostIP, setHostIP] = React.useState('127.0.0.1/32'); const [cloudProvider, setCloudProvider] = React.useState(''); const [verificationIntiated, setVerificationIntiated] = React.useState(false); const [bigAnimalInstanceData, setBigAnimalInstanceData] = React.useState({}); const [bigAnimalDatabaseData, setBigAnimalDatabaseData] = React.useState({}); const axiosApi = getApiInstance(); const [verificationURI, setVerificationURI] = React.useState(''); const [verificationCode, setVerificationCode] = React.useState(''); React.useEffect(() => { let _url = url_for('cloud.get_host_ip') ; axiosApi.get(_url) .then((res) => { if (res.data.data) { setHostIP(res.data.data); } }) .catch((error) => { Alertify.error(gettext(`Error while getting the host ip: ${error.response.data.errormsg}`)); }); }, [cloudProvider]); const wizardStepChange = (data) => { setCurrentStep(data.currentStep); }; const onSave = () => { var _url = url_for('cloud.deploy_on_cloud'), post_data = {}; if (cloudProvider == 'rds') { post_data = { gid: nodeInfo.server_group._id, cloud: cloudProvider, secret: cloudDBCred, instance_details:cloudInstanceDetails, db_details: cloudDBDetails }; } else { post_data = { gid: nodeInfo.server_group._id, cloud: cloudProvider, instance_details:bigAnimalInstanceData, db_details: bigAnimalDatabaseData }; } axiosApi.post(_url, post_data) .then((res) => { pgAdmin.Browser.Events.trigger('pgadmin:browser:tree:add', res.data.data.node, {'server_group': nodeInfo['server_group']}); pgAdmin.Browser.Events.trigger('pgadmin-bgprocess:created', Alertify.cloudWizardDialog()); Alertify.cloudWizardDialog().close(); }) .catch((error) => { Alertify.error(gettext(`Error while saving cloud wizard data: ${error.response.data.errormsg}`)); }); }; const disableNextCheck = () => { setCallRDSAPI(currentStep); let isError = (cloudProvider == ''); switch(cloudProvider) { case 'rds': switch (currentStep) { case 0: setCloudSelection('rds'); break; case 1: isError = validateCloudStep1(cloudDBCred); break; case 2: isError = validateCloudStep2(cloudInstanceDetails, hostIP); break; case 3: isError = validateCloudStep3(cloudDBDetails, nodeInfo); break; default: break; } break; case 'biganimal': switch (currentStep) { case 0: setCloudSelection('biganimal'); break; case 1: isError = !verificationIntiated; break; case 2: isError = validateBigAnimalStep2(bigAnimalInstanceData); break; case 3: isError = validateBigAnimalStep3(bigAnimalDatabaseData, nodeInfo); break; default: break; } break; } return isError; }; const onBeforeNext = (activeStep) => { return new Promise((resolve, reject)=>{ if(activeStep == 1 && cloudProvider == 'rds') { setErrMsg([MESSAGE_TYPE.INFO, 'Validating credentials...']); var _url = url_for('rds.verify_credentials'); const post_data = { cloud: selectionVal, secret: cloudDBCred, }; axiosApi.post(_url, post_data) .then((res) => { if(!res.data.success) { setErrMsg([MESSAGE_TYPE.ERROR, res.data.info]); reject(); } else { setErrMsg(['', '']); resolve(); } }) .catch(() => { setErrMsg([MESSAGE_TYPE.ERROR, 'Error while checking cloud credentials']); reject(); }); } else if(activeStep == 0 && cloudProvider == 'biganimal') { if (!isEmptyString(verificationURI)) { resolve(); return; } setErrMsg([MESSAGE_TYPE.INFO, 'Getting EDB BigAnimal verification URL...']); validateBigAnimal() .then((res) => { setVerificationURI(res); setVerificationCode(res.substring(res.indexOf('=')+1)); setErrMsg(['', '']); resolve(); }) .catch((error) => { setErrMsg([MESSAGE_TYPE.ERROR, gettext(error)]); reject(); }); } else { resolve(); } }); }; const authenticateBigAnimal = () => { var loading_icon_url = url_for( 'static', { 'filename': 'img/loading.gif'} ); setErrMsg([MESSAGE_TYPE.INFO, 'EDB BigAnimal authentication process is in progress...' + gettext('Loading...') + '']); window.open(verificationURI, 'edb_biganimal_authentication'); let _url = url_for('biganimal.verification_ack') ; const myInterval = setInterval(() => { axiosApi.get(_url) .then((res) => { if (res.data && res.data.success == 1 ) { setErrMsg([MESSAGE_TYPE.SUCCESS, gettext('Authentication completed successfully. Click the Next button to proceed.')]); setVerificationIntiated(true); clearInterval(myInterval); } else if (res.data && res.data.success == 0 && res.data.errormsg == 'access_denied') { setErrMsg([MESSAGE_TYPE.INFO, gettext('Verification failed. Access Denied...')]); setVerificationIntiated(false); clearInterval(myInterval); } else if (res.data && res.data.success == 0 && res.data.errormsg == 'forbidden') { setErrMsg([MESSAGE_TYPE.INFO, gettext('Authentication completed successfully but you do not have permission to create the cluster.')]); setVerificationIntiated(false); clearInterval(myInterval); } }) .catch((error) => { setErrMsg([MESSAGE_TYPE.ERROR, gettext(`Error while verification EDB BigAnimal: ${error.response.data.errormsg}`)]); }); }, 1000); }; const onDialogHelp = () => { window.open(url_for('help.static', { 'filename': 'cloud_deployment.html' }), 'pgadmin_help'); }; const onErrClose = React.useCallback(()=>{ setErrMsg([]); }); return ( <> {gettext('Select any option to deploy on cloud.')} }, {label: 'EDB BigAnimal', value: 'biganimal', icon: }]} > {gettext('More cloud providers are coming soon...')} {cloudProvider == 'biganimal' && {gettext('The verification code to authenticate the pgAdmin to EDB BigAnimal is: ')} {verificationCode}
{gettext('By clicking the below button, you will be redirected to the EDB BigAnimal authentication page in a new tab.')}
} {cloudProvider == 'biganimal' && {gettext('Click here to authenticate yourself to EDB BigAnimal')} } {cloudProvider == 'biganimal' && }
{cloudProvider == 'rds' && }
{cloudProvider == 'rds' && callRDSAPI == 2 && } {cloudProvider == 'biganimal' && callRDSAPI == 2 && } {cloudProvider == 'rds' && } {cloudProvider == 'biganimal' && callRDSAPI == 3 && } {gettext('Please review the details before creating the cloud instance.')} {cloudProvider == 'rds' && callRDSAPI == 4 && } {cloudProvider == 'biganimal' && callRDSAPI == 4 && }
); } CloudWizard.propTypes = { nodeInfo: PropTypes.object, nodeData: PropTypes.object, };