Fixed following issues related to cloud deployment:

1) The Mumbai region issue has been resolved
2) Display name of regions has been modified appropriately
3) The password field has been validated the same way as AWS
4) Added support for a list of IP addresses in the public IP address range field.
This commit is contained in:
Khushboo Vashi 2022-02-28 18:19:18 +05:30 committed by Akshay Joshi
parent dd4849070a
commit ffc1c6c3b7
7 changed files with 96 additions and 25 deletions

View File

@ -137,17 +137,18 @@ class RdsProvider(AbsProvider):
""" Create a new security group for the instance """
ec2 = self._get_aws_client('ec2', args)
ip = args.public_ip if args.public_ip else get_my_ip()
ip = ip.split(',')
# Deploy the security group
try:
name = 'pgacloud_{}_{}_{}'.format(args.name,
ip.replace('.', '-'),
ip[0].replace('.', '-'),
get_random_id())
debug(args, 'Creating security group: {}...'.format(name))
output({'Creating': 'Creating security group: {}...'.format(name)})
response = ec2.create_security_group(
Description='Inbound access for {} to RDS instance {}'.format(
ip, args.name),
ip[0], args.name),
GroupName=name
)
except Exception as e:
@ -158,9 +159,17 @@ class RdsProvider(AbsProvider):
def _add_ingress_rule(self, args, security_group):
""" Add a local -> PostgreSQL ingress rule to a security group """
ec2 = self._get_aws_client('ec2', args)
ip = args.public_ip if args.public_ip else '{}/32'.format(get_my_ip())
ip = args.public_ip if args.public_ip else\
'{}/32'.format(get_my_ip())
port = args.db_port or 5432
IpRanges = []
ip = ip.split(',')
for i in ip:
IpRanges.append({
'CidrIp': i,
'Description': 'pgcloud client {}'.format(i)
})
try:
output({'Adding': 'Adding ingress rule for: {}...'.format(ip)})
debug(args,
@ -172,12 +181,7 @@ class RdsProvider(AbsProvider):
'FromPort': port,
'ToPort': port,
'IpProtocol': 'tcp',
'IpRanges': [
{
'CidrIp': ip,
'Description': 'pgcloud client {}'.format(ip)
},
]
'IpRanges': IpRanges
},
]
)

View File

@ -25,6 +25,7 @@ from pgadmin.model import db, Server, Process
from pgadmin.misc.cloud.utils.rds import RDS, verify_aws_credentials,\
get_aws_db_instances, get_aws_db_versions, clear_aws_session,\
get_aws_regions
from pgadmin.misc.cloud.utils import get_my_ip
from config import root
@ -81,7 +82,8 @@ class CloudModule(PgAdminModule):
'cloud.get_aws_db_instances',
'cloud.update_cloud_server',
'cloud.update_cloud_process',
'cloud.get_aws_regions']
'cloud.get_aws_regions',
'cloud.get_host_ip']
# Create blueprint for CloudModule class
@ -108,6 +110,13 @@ def script():
return res
@blueprint.route('/get_host_ip/',
methods=['GET'], endpoint='get_host_ip')
@login_required
def get_host_ip():
return make_json_response(data=get_my_ip())
@blueprint.route('/verify_credentials/',
methods=['POST'], endpoint='verify_credentials')
@login_required
@ -285,7 +294,8 @@ def _create_server(data):
maintenance_db=data.get('db'),
username=data.get('username'),
ssl_mode='prefer',
cloud_status=data.get('cloud_status')
cloud_status=data.get('cloud_status'),
connect_timeout=30,
)
db.session.add(server)

View File

@ -68,8 +68,22 @@ export default function CloudWizard({ nodeInfo, nodeData }) {
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 axiosApi = getApiInstance();
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}`));
});
}, []);
React.useEffect(() => {
if (callRDSAPI == 2) {
const cloudDBInstanceSchema = new CloudInstanceDetailsSchema({
@ -111,6 +125,7 @@ export default function CloudWizard({ nodeInfo, nodeData }) {
server_groups: ()=>getNodeListById(pgAdmin.Browser.Nodes['server_group'], nodeInfo, nodeData),
}, {
gid: nodeInfo['server_group']._id,
hostIP: hostIP,
});
setCloudInstanceDetailsInstance(cloudDBInstanceSchema);
}
@ -151,7 +166,7 @@ export default function CloudWizard({ nodeInfo, nodeData }) {
return isError;
};
const validateCloudStep2 = (cloudInstanceDetails) => {
const validateCloudStep2 = (cloudInstanceDetails, host_ip) => {
let isError = false;
if (isEmptyString(cloudInstanceDetails.aws_name) ||
isEmptyString(cloudInstanceDetails.aws_db_version) || isEmptyString(cloudInstanceDetails.aws_instance_type) ||
@ -162,7 +177,7 @@ export default function CloudWizard({ nodeInfo, nodeData }) {
if(cloudInstanceDetails.aws_storage_type == 'io1' && isEmptyString(cloudInstanceDetails.aws_storage_IOPS)) {
isError = true;
}
if (isEmptyString(cloudInstanceDetails.aws_public_ip)) cloudInstanceDetails.aws_public_ip = '127.0.0.1/32';
if (isEmptyString(cloudInstanceDetails.aws_public_ip)) cloudInstanceDetails.aws_public_ip = host_ip;
return isError;
};
@ -222,7 +237,7 @@ export default function CloudWizard({ nodeInfo, nodeData }) {
isError = validateCloudStep1(cloudDBCred);
break;
case 2:
isError = validateCloudStep2(cloudInstanceDetails);
isError = validateCloudStep2(cloudInstanceDetails, hostIP);
break;
case 3:
isError = validateCloudStep3(cloudDBDetails);

View File

@ -27,6 +27,7 @@ define('pgadmin.misc.cloud', [
return pgBrowser.Cloud;
}
// Create an Object Cloud of pgBrowser class
pgBrowser.Cloud = {
init: function() {

View File

@ -17,7 +17,7 @@ class CloudInstanceDetailsSchema extends BaseUISchema {
super({
oid: undefined,
aws_name: '',
aws_public_ip: '127.0.0.1/32',
aws_public_ip: initValues.hostIP,
...initValues
});
@ -39,7 +39,7 @@ class CloudInstanceDetailsSchema extends BaseUISchema {
}, {
id: 'aws_public_ip', label: gettext('Public IP range'), type: 'text',
mode: ['create'],
helpMessage: gettext('IP Address range for permitting the inbound traffic. Ex: 127.0.0.1/32'),
helpMessage: gettext('IP Address range for permitting the inbound traffic. Ex: 127.0.0.1/32, add multiple ip addresses/ranges by comma separated.'),
}, {
type: 'nested-fieldset', label: gettext('Version & Instance'),
mode: ['create'],
@ -127,9 +127,18 @@ class DatabaseSchema extends BaseUISchema {
&& data.aws_db_password != data.aws_db_confirm_password) {
setErrMsg('aws_db_confirm_password', gettext('Passwords do not match.'));
return true;
} else {
return false;
}
if (!isEmptyString(data.aws_db_confirm_password) && data.aws_db_confirm_password.length < 8) {
setErrMsg('aws_db_confirm_password', gettext('Password must be 8 characters or more.'));
return true;
}
if (data.aws_db_confirm_password.includes('\'') || data.aws_db_confirm_password.includes('"') ||
data.aws_db_confirm_password.includes('@') || data.aws_db_confirm_password.includes('/')) {
setErrMsg('aws_db_confirm_password', gettext('Invalid passowrd.'));
return true;
}
return false;
}
get idAttribute() {
@ -152,6 +161,7 @@ class DatabaseSchema extends BaseUISchema {
}, {
id: 'aws_db_password', label: gettext('Password'), type: 'password',
mode: ['create'], noEmpty: true,
helpMessage: gettext('At least 8 printable ASCII characters. Can not contain any of the following: / \(slash\), \'\(single quote\), "\(double quote\) and @ \(at sign\).')
}, {
id: 'aws_db_confirm_password', label: gettext('Confirm password'),
type: 'password',
@ -202,6 +212,7 @@ export class InstanceSchema extends BaseUISchema {
if (source[0] == 'aws_db_instance_class') {
return {reload_instances: false};
} else {
state.instanceData = [];
return {reload_instances: true};
}
},

View File

@ -0,0 +1,26 @@
# ##########################################################################
# #
# # pgAdmin 4 - PostgreSQL Tools
# #
# # Copyright (C) 2013 - 2022, The pgAdmin Development Team
# # This software is released under the PostgreSQL Licence
# #
# ##########################################################################
import urllib3
def get_my_ip():
""" Return the public IP of this host """
http = urllib3.PoolManager()
try:
external_ip = http.request.urlopen(
'https://ident.me').read().decode('utf8')
except Exception:
try:
external_ip = http.request.urlopen(
'https://ifconfig.me/ip').read().decode('utf8')
except Exception:
external_ip = '127.0.0.1'
return external_ip

View File

@ -13,24 +13,28 @@
AWS_REGIONS = {
'us-gov-east-1': 'AWS GovCloud (US-East)',
'us-gov-west-1': 'AWS GovCloud (US-West)',
'af-south-1': 'Africa (Cape Town)',
'ap-east-1': 'Asia Pacific (Hong Kong)',
'ap-south-': 'Asia Pacific (Mumbai)',
'ap-northeast-3': 'Asia Pacific (Osaka-Local)',
'ap-south-1': 'Asia Pacific (Mumbai)',
'ap-northeast-3': 'Asia Pacific (Osaka)',
'ap-northeast-2': 'Asia Pacific (Seoul)',
'ap-southeast-1': 'Asia Pacific (Singapore)',
'ap-southeast-2': 'Asia Pacific (Sydney)',
'ap-southeast-3': 'Asia Pacific (Jakarta)',
'ap-northeast-1': 'Asia Pacific (Tokyo)',
'ca-central-1': 'Canada (Central)',
'cn-north-1': 'China (Beijing)',
'cn-northwest-1': 'China (Ningxia)',
'eu-central-1': 'EU (Frankfurt)',
'eu-west-1': 'EU (Ireland)',
'eu-west-2': 'EU (London)',
'eu-west-3': 'EU (Paris)',
'eu-north-1': 'EU (Stockholm)',
'eu-central-1': 'Europe (Frankfurt)',
'eu-west-1': 'Europe (Ireland)',
'eu-west-2': 'Europe (London)',
'eu-west-3': 'Europe (Paris)',
'eu-north-1': 'Europe (Stockholm)',
'eu-south-1': 'Europe (Milan)',
'sa-east-1': 'South America (Sao Paulo)',
'us-east-1': 'US East (N. Virginia)',
'us-east-2': 'US East (Ohio)',
'us-west-1': 'US West (N. California)',
'us-west-2': 'US West (Oregon)',
'me-south-1': 'Middle East (Bahrain)',
}