From 9181003be7185d5f6294acf60a01b53a5d986e09 Mon Sep 17 00:00:00 2001 From: Naia Scott Date: Wed, 25 Feb 2026 12:48:54 -0500 Subject: [PATCH 01/10] Init --- .../command_modules/postgresql/_db_context.py | 41 + .../postgresql/flexible_server_custom.py | 798 ++++++++++++++++++ .../flexible_server_custom_postgres.py | 57 +- .../flexible_server_microsoft_entra.py | 15 + ..._network.py => flexible_server_network.py} | 185 +--- ...gres_flexible_commands_private_dns_zone.py | 2 +- .../test_postgres_flexible_commands_vnet.py | 1 - 7 files changed, 903 insertions(+), 196 deletions(-) create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/_db_context.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_microsoft_entra.py rename src/azure-cli/azure/cli/command_modules/postgresql/{flexible_server_virtual_network.py => flexible_server_network.py} (72%) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/_db_context.py b/src/azure-cli/azure/cli/command_modules/postgresql/_db_context.py new file mode 100644 index 00000000000..9f805eea23c --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/_db_context.py @@ -0,0 +1,41 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + + +class DbContext: + """Database context class for PostgreSQL flexible server operations. + + This class serves as a context container for various database-related configurations, + factory functions, and clients used throughout PostgreSQL command operations. + """ + + def __init__(self, cmd=None, azure_sdk=None, logging_name=None, cf_firewall=None, cf_db=None, + cf_availability=None, cf_private_dns_zone_suffix=None, + command_group=None, server_client=None, location=None): + """ + Initialize DbContext with configuration and factory parameters. + + Args: + cmd: Azure CLI command context + azure_sdk: Azure SDK module (e.g., postgresqlflexibleservers) + logging_name: Name to use for logging (e.g., 'PostgreSQL') + cf_firewall: Client factory for firewall rules + cf_db: Client factory for databases + cf_availability: Client factory for resource availability checks + cf_private_dns_zone_suffix: Client factory for private DNS zone suffixes + command_group: The command group name (e.g., 'postgres') + server_client: The server management client + location: Azure region location + """ + self.cmd = cmd + self.azure_sdk = azure_sdk + self.cf_firewall = cf_firewall + self.cf_availability = cf_availability + self.cf_private_dns_zone_suffix = cf_private_dns_zone_suffix + self.logging_name = logging_name + self.cf_db = cf_db + self.command_group = command_group + self.server_client = server_client + self.location = location diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py new file mode 100644 index 00000000000..514ab2adb2e --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py @@ -0,0 +1,798 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from .flexible_server_custom_common import create_firewall_rule +from .flexible_server_microsoft_entra import _create_admin +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + + +# region create without args +# pylint: disable=too-many-locals +# pylint: disable=too-many-statements +# pylint: disable=raise-missing-from, unbalanced-tuple-unpacking +def flexible_server_create(cmd, client, + resource_group_name=None, server_name=None, + location=None, backup_retention=None, + sku_name=None, tier=None, + storage_gb=None, version=None, microsoft_entra_auth=None, + admin_name=None, admin_id=None, admin_type=None, + password_auth=None, administrator_login=None, administrator_login_password=None, + tags=None, subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, + private_dns_zone_arguments=None, public_access=None, + high_availability=None, zonal_resiliency=None, allow_same_zone=False, + zone=None, standby_availability_zone=None, + geo_redundant_backup=None, byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, + auto_grow=None, performance_tier=None, + storage_type=None, iops=None, throughput=None, create_cluster=None, cluster_size=None, database_name=None, yes=False): + + if not check_resource_group(resource_group_name): + resource_group_name = None + + # Generate missing parameters + location, resource_group_name, server_name = generate_missing_parameters(cmd, location, resource_group_name, + server_name, 'postgres') + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + server_name = server_name.lower() + high_availability_mode = high_availability + + if (sku_name is None) or (version is None) or \ + (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): + list_location_capability_info = get_postgres_location_capability_info(cmd, location) + + # set sku_name from capability API + if sku_name is None: + tiers = [item.lower() for item in get_postgres_tiers(list_location_capability_info['sku_info'])] + try: + sku_info = list_location_capability_info['sku_info'] + skus = list(get_postgres_skus(sku_info, tier.lower())) + skus = sorted(skus, key=cmp_to_key(compare_sku_names)) + sku_name = skus[0] + except: + raise CLIError('Incorrect value for --tier. Allowed values : {}'.format(tiers)) + # default to the latest version + if version is None: + supported_server_versions = sorted(list_location_capability_info['supported_server_versions']) + version = supported_server_versions[-1] + # set high availability from capability API + if (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): + single_az = list_location_capability_info['single_az'] + high_availability_mode = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' + + pg_arguments_validator(db_context, + server_name=server_name, + location=location, + tier=tier, sku_name=sku_name, + storage_gb=storage_gb, + auto_grow=auto_grow, + storage_type=storage_type, + iops=iops, throughput=throughput, + high_availability=high_availability, + zonal_resiliency=zonal_resiliency, + allow_same_zone=allow_same_zone, + standby_availability_zone=standby_availability_zone, + zone=zone, + subnet=subnet, + public_access=public_access, + version=version, + geo_redundant_backup=geo_redundant_backup, + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key, + performance_tier=performance_tier, + create_cluster=create_cluster, + password_auth=password_auth, microsoft_entra_auth=microsoft_entra_auth, + admin_name=admin_name, admin_id=admin_id, admin_type=admin_type,) + + cluster = None + if create_cluster == 'ElasticCluster': + cluster_size = cluster_size if cluster_size else 2 + cluster = postgresql_flexibleservers.models.Cluster(cluster_size=cluster_size, default_database_name=database_name if database_name else POSTGRES_DB_NAME) + + server_result = firewall_id = None + + network, start_ip, end_ip = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access=public_access, + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + + storage = postgresql_flexibleservers.models.Storage(storage_size_gb=storage_gb, auto_grow=auto_grow, tier=performance_tier, type=storage_type, iops=iops, throughput=throughput) + + backup = postgresql_flexibleservers.models.Backup(backup_retention_days=backup_retention, + geo_redundant_backup=geo_redundant_backup) + + sku = postgresql_flexibleservers.models.Sku(name=sku_name, tier=tier) + + high_availability = postgresql_flexibleservers.models.HighAvailability(mode=high_availability_mode, + standby_availability_zone=standby_availability_zone) + + is_password_auth_enabled = bool(password_auth is not None and password_auth.lower() == 'enabled') + is_microsoft_entra_auth_enabled = bool(microsoft_entra_auth is not None and microsoft_entra_auth.lower() == 'enabled') + if is_password_auth_enabled: + administrator_login_password = generate_password(administrator_login_password) + + identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + auth_config = postgresql_flexibleservers.models.AuthConfig(active_directory_auth='Enabled' if is_microsoft_entra_auth_enabled else 'Disabled', + password_auth=password_auth) + + # Create postgresql + # Note : passing public_access has no effect as the accepted values are 'Enabled' and 'Disabled'. So the value ends up being ignored. + server_result = _create_server(db_context, cmd, resource_group_name, server_name, + tags=tags, + location=location, + sku=sku, + administrator_login=administrator_login, + administrator_login_password=administrator_login_password, + storage=storage, + backup=backup, + network=network, + version=version, + high_availability=high_availability, + availability_zone=zone, + identity=identity, + data_encryption=data_encryption, + auth_config=auth_config, + cluster=cluster) + + # Add Microsoft Entra Admin + if is_microsoft_entra_auth_enabled and admin_name is not None or admin_id is not None: + server_admin_client = cf_postgres_flexible_admin(cmd.cli_ctx, '_') + logger.warning("Add Microsoft Entra Admin '%s'.", admin_name) + _create_admin(server_admin_client, resource_group_name, server_name, admin_name, admin_id, admin_type) + + # Adding firewall rule + if start_ip != -1 and end_ip != -1: + firewall_id = create_firewall_rule(db_context, cmd, resource_group_name, server_name, start_ip, end_ip) + + user = server_result.administrator_login if is_password_auth_enabled else '' + password = administrator_login_password if is_password_auth_enabled else '' + admin = quote(admin_name) if admin_name else '' + server_id = server_result.id + loc = server_result.location + version = server_result.version + sku = server_result.sku.name + host = server_result.fully_qualified_domain_name + subnet_id = None if network is None else network.delegated_subnet_resource_id + + if is_password_auth_enabled: + logger.warning('Make a note of your password. If you forget, you would have to ' + 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', + server_name, resource_group_name) + logger.warning('Try using \'az postgres flexible-server connect\' command to test out connection.') + + _update_local_contexts(cmd, server_name, resource_group_name, location, user) + + return _form_response(user, sku, loc, server_id, host, version, password, + firewall_id, subnet_id, is_password_auth_enabled, is_microsoft_entra_auth_enabled, admin_name) + + +def _create_server(db_context, cmd, resource_group_name, server_name, tags, location, sku, administrator_login, administrator_login_password, + storage, backup, network, version, high_availability, availability_zone, identity, data_encryption, auth_config, cluster): + validate_resource_group(resource_group_name) + + logging_name, server_client = db_context.logging_name, db_context.server_client + logger.warning('Creating %s Server \'%s\' in group \'%s\'...', logging_name, server_name, resource_group_name) + + logger.warning('Your server \'%s\' is using sku \'%s\' (Paid Tier). ' + 'Please refer to https://aka.ms/postgres-pricing for pricing details', server_name, sku.name) + + # Note : passing public-network-access has no effect as the accepted values are 'Enabled' and 'Disabled'. + # So when you pass an IP here(from the CLI args of public_access), it ends up being ignored. + parameters = postgresql_flexibleservers.models.Server( + tags=tags, + location=location, + sku=sku, + administrator_login=administrator_login, + administrator_login_password=administrator_login_password, + storage=storage, + backup=backup, + network=network, + version=version, + high_availability=high_availability, + availability_zone=availability_zone, + identity=identity, + data_encryption=data_encryption, + auth_config=auth_config, + cluster=cluster, + create_mode="Create") + + return resolve_poller( + server_client.begin_create_or_update(resource_group_name, server_name, parameters), cmd.cli_ctx, + '{} Server Create'.format(logging_name)) + + +def _update_local_contexts(cmd, server_name, resource_group_name, location, user): + validate_resource_group(resource_group_name) + + if cmd.cli_ctx.local_context.is_on: + cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'server_name', + server_name) # Setting the server name in the local context + cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'administrator_login', + user) # Setting the server name in the local context + cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'database_name', + POSTGRES_DB_NAME) # Setting the server name in the local context + cmd.cli_ctx.local_context.set([ALL], 'location', + location) # Setting the location in the local context + cmd.cli_ctx.local_context.set([ALL], 'resource_group_name', resource_group_name) + + +def _form_response(username, sku, location, server_id, host, version, password, firewall_id=None, + subnet_id=None, is_password_auth=True, is_microsoft_entra_auth_enabled=False, microsoft_admin=None): + + connection_kwargs = { + 'user': username if username is not None else '{user}', + 'host': host, + 'password': password if password is not None else '{password}', + 'database': POSTGRES_DB_NAME, + } + output = { + 'host': host, + 'username': username if is_password_auth else None, + 'password': password if is_password_auth else None, + 'skuname': sku, + 'location': location, + 'id': server_id, + 'version': version, + 'databaseName': POSTGRES_DB_NAME, + 'connectionString': 'postgresql://{user}:{password}@{host}/{database}?sslmode=require'.format(**connection_kwargs) + } + if is_microsoft_entra_auth_enabled: + user = quote(microsoft_admin) if microsoft_admin else '' + connection_kwargs = { + 'user': user, + 'host': host, + 'database': POSTGRES_DB_NAME, + } + output['admin'] = microsoft_admin + output['connectionStringMicrosoftEntra'] = 'postgresql://{user}:@{host}/{database}?sslmode=require'.format(**connection_kwargs) + if firewall_id is not None: + output['firewallName'] = firewall_id + if subnet_id is not None: + output['subnetId'] = subnet_id + return output + + +def flexible_server_restore(cmd, client, + resource_group_name, server_name, + source_server, restore_point_in_time=None, zone=None, no_wait=False, + subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, + private_dns_zone_arguments=None, geo_redundant_backup=None, + byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, storage_type=None, yes=False): + + server_name = server_name.lower() + + validate_resource_group(resource_group_name) + + if not is_valid_resource_id(source_server): + if len(source_server.split('/')) == 1: + source_server_id = resource_id( + subscription=get_subscription_id(cmd.cli_ctx), + resource_group=resource_group_name, + namespace=RESOURCE_PROVIDER, + type='flexibleServers', + name=source_server) + else: + raise ValueError('The provided source server {} is invalid.'.format(source_server)) + else: + source_server_id = source_server + + restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) + + try: + id_parts = parse_resource_id(source_server_id) + source_subscription_id = id_parts['subscription'] + postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) + source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) + + location = ''.join(source_server_object.location.lower().split()) + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') + + pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) + + pg_restore_validator(source_server_object.sku.tier, storage_type=storage_type) + storage = postgresql_flexibleservers.models.Storage(type=storage_type if source_server_object.storage.type != "PremiumV2_LRS" else None) + + parameters = postgresql_flexibleservers.models.Server( + location=location, + point_in_time_utc=restore_point_in_time, + source_server_resource_id=source_server_id, # this should be the source server name, not id + create_mode="PointInTimeRestore", + availability_zone=zone, + storage=storage + ) + + if source_server_object.network.public_network_access == 'Disabled' and any((vnet, subnet)): + parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access='Disabled', + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + else: + parameters.network = source_server_object.network + + parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) + + parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + except Exception as e: + raise ResourceNotFoundError(e) + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) + + +# pylint: disable=too-many-branches +def flexible_server_update_custom_func(cmd, client, instance, + sku_name=None, tier=None, + storage_gb=None, + backup_retention=None, + administrator_login_password=None, + high_availability=None, + zonal_resiliency=None, + allow_same_zone=False, + standby_availability_zone=None, + maintenance_window=None, + byok_identity=None, byok_key=None, + backup_byok_identity=None, backup_byok_key=None, + microsoft_entra_auth=None, password_auth=None, + private_dns_zone_arguments=None, + public_access=None, + tags=None, + auto_grow=None, + performance_tier=None, + iops=None, throughput=None, + cluster_size=None, yes=False): + + # validator + location = ''.join(instance.location.lower().split()) + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + pg_arguments_validator(db_context, + location=location, + tier=tier, + sku_name=sku_name, + storage_gb=storage_gb, + auto_grow=auto_grow, + iops=iops, + throughput=throughput, + high_availability=high_availability, + zonal_resiliency=zonal_resiliency, + allow_same_zone=allow_same_zone, + zone=instance.availability_zone, + standby_availability_zone=standby_availability_zone, + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key, + performance_tier=performance_tier, + cluster_size=cluster_size, instance=instance) + + server_module_path = instance.__module__ + module = import_module(server_module_path) + ServerForPatch = getattr(module, 'ServerForPatch') + + server_id_parts = parse_resource_id(instance.id) + resource_group_name = server_id_parts['resource_group'] + server_name = server_id_parts['name'] + + if public_access: + instance.network.public_network_access = public_access + + if private_dns_zone_arguments: + private_dns_zone_id = prepare_private_dns_zone(db_context, + resource_group_name, + server_name, + private_dns_zone=private_dns_zone_arguments, + subnet_id=instance.network.delegated_subnet_resource_id, + location=location, + yes=yes) + instance.network.private_dns_zone_arm_resource_id = private_dns_zone_id + + _confirm_restart_server(instance, sku_name, storage_gb, yes) + + if sku_name: + instance.sku.name = sku_name + + if tier: + instance.sku.tier = tier + + if storage_gb: + instance.storage.storage_size_gb = storage_gb + + if auto_grow: + instance.storage.auto_grow = auto_grow + + instance.storage.tier = performance_tier if performance_tier else None + + if instance.storage.type == "PremiumV2_LRS": + instance.storage.tier = None + + if sku_name or storage_gb: + logger.warning("You are changing the compute and/or storage size of the server. " + "The server will be restarted for this operation and you will see a short downtime.") + + if iops: + instance.storage.iops = iops + + if throughput: + instance.storage.throughput = throughput + else: + instance.storage.type = None + instance.storage.iops = None + instance.storage.throughput = None + + if backup_retention: + instance.backup.backup_retention_days = backup_retention + + if maintenance_window: + if maintenance_window.lower() == "disabled": + # if disabled is pass in reset to default values + day_of_week = start_hour = start_minute = 0 + custom_window = "Disabled" + else: + day_of_week, start_hour, start_minute = parse_maintenance_window(maintenance_window) + custom_window = "Enabled" + + # set values - if maintenance_window when is None when created then create a new object + instance.maintenance_window.day_of_week = day_of_week + instance.maintenance_window.start_hour = start_hour + instance.maintenance_window.start_minute = start_minute + instance.maintenance_window.custom_window = custom_window + + identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key, + instance=instance) + + auth_config = instance.auth_config + administrator_login = instance.administrator_login if instance.administrator_login else None + if microsoft_entra_auth: + auth_config.active_directory_auth = microsoft_entra_auth + if password_auth: + administrator_login, administrator_login_password = _update_login(server_name, resource_group_name, auth_config, + password_auth, administrator_login, administrator_login_password) + auth_config.password_auth = password_auth + + if cluster_size: + instance.cluster.cluster_size = cluster_size + + params = ServerForPatch(sku=instance.sku, + storage=instance.storage, + backup=instance.backup, + administrator_login=administrator_login, + administrator_login_password=administrator_login_password, + availability_zone=instance.availability_zone, + maintenance_window=instance.maintenance_window, + network=instance.network, + identity=identity, + data_encryption=data_encryption, + auth_config=auth_config, + cluster=instance.cluster, + tags=tags) + + # High availability can't be updated with existing properties + high_availability_param = postgresql_flexibleservers.models.HighAvailability() + if zonal_resiliency is not None: + if zonal_resiliency.lower() == 'disabled': + high_availability = 'Disabled' + else: + list_capability_info = get_postgres_server_capability_info(cmd, resource_group_name, server_name) + single_az = list_capability_info['single_az'] + high_availability = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' + if high_availability: + high_availability_param.mode = high_availability + + if high_availability.lower() != "disabled" and standby_availability_zone: + high_availability_param.standby_availability_zone = standby_availability_zone + + # PG 11 and 12 will never receive fabric mirroring support. Ignite 2025 Fabric mirroring supported on 17. Skip this check for servers of these versions + if high_availability.lower() != "disabled" and str(instance.version) not in ["11", "12", "17", "18"]: + config_client = cf_postgres_flexible_config(cmd.cli_ctx, '_') + fabric_mirror_status = config_client.get(resource_group_name, server_name, 'azure.fabric_mirror_enabled') + if (fabric_mirror_status and fabric_mirror_status.value.lower() == 'on'): + raise CLIError("High availability cannot be enabled while Fabric mirroring is Active. Please disable Fabric mirroring to enable high availability.") + + params.high_availability = high_availability_param + + return params + + +def _update_login(server_name, resource_group_name, auth_config, password_auth, administrator_login, administrator_login_password): + if auth_config.password_auth.lower() == 'disabled' and password_auth.lower() == 'enabled': + administrator_login = administrator_login if administrator_login else prompt('Please enter administrator username for the server. Once set, it cannot be changed: ') + if not administrator_login: + raise CLIError('Administrator username is required for enabling password authentication.') + if not administrator_login_password: + administrator_login_password = generate_password(administrator_login_password) + logger.warning('Make a note of password "%s". You can ' + 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', + administrator_login_password, server_name, resource_group_name) + + return administrator_login, administrator_login_password + + +# pylint: disable=chained-comparison +def _confirm_restart_server(instance, sku_name, storage_gb, yes): + show_confirmation = False + + # check if sku_name is changed + if sku_name and sku_name != instance.sku.name: + show_confirmation = True + + # check if requested storage growth is crossing the 4096 threshold + if storage_gb and storage_gb > 4096 and instance.storage.storage_size_gb <= 4096 and instance.storage.type == "": + show_confirmation = True + + # check if storage_gb changed for PremiumV2_LRS + if storage_gb and instance.storage.type == "PremiumV2_LRS" and instance.storage.storage_size_gb != storage_gb: + show_confirmation = True + + if not yes and show_confirmation: + user_confirmation("You are trying to change the compute or the size of storage assigned to your server in a way that \ + requires a server restart. During the restart, you'll experience some downtime of the server. Do you want to proceed?", yes=yes) + + +def flexible_server_delete(cmd, client, resource_group_name, server_name, yes=False): + validate_resource_group(resource_group_name) + result = None + if not yes: + user_confirmation( + "Are you sure you want to delete the server '{0}' in resource group '{1}'".format(server_name, + resource_group_name), yes=yes) + try: + result = client.begin_delete(resource_group_name, server_name) + if cmd.cli_ctx.local_context.is_on: + local_context_file = cmd.cli_ctx.local_context._get_local_context_file() # pylint: disable=protected-access + local_context_file.remove_option('postgres flexible-server', 'server_name') + local_context_file.remove_option('postgres flexible-server', 'administrator_login') + local_context_file.remove_option('postgres flexible-server', 'database_name') + except Exception as ex: # pylint: disable=broad-except + logger.error(ex) + raise CLIError(ex) + return result + + +def flexible_server_postgresql_get(cmd, resource_group_name, server_name): + validate_resource_group(resource_group_name) + client = get_postgresql_flexible_management_client(cmd.cli_ctx) + return client.servers.get(resource_group_name, server_name) + + +def flexible_list_skus(cmd, client, location): + result = client.list(location) + logger.warning('For prices please refer to https://aka.ms/postgres-pricing') + return result + + +def flexible_server_georestore(cmd, client, resource_group_name, server_name, source_server, location, zone=None, + vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, + private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, + byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, restore_point_in_time=None): + validate_resource_group(resource_group_name) + + server_name = server_name.lower() + + if not is_valid_resource_id(source_server): + if _is_resource_name(source_server): + source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), + resource_group=resource_group_name, + namespace='Microsoft.DBforPostgreSQL', + type='flexibleServers', + name=source_server) + else: + raise CLIError('The provided source-server {} is invalid.'.format(source_server)) + else: + source_server_id = source_server + + restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) + + try: + id_parts = parse_resource_id(source_server_id) + validate_citus_cluster(cmd, id_parts['resource_group'], id_parts['name']) + source_subscription_id = id_parts['subscription'] + postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) + source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) + except Exception as e: + raise ResourceNotFoundError(e) + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') + if source_server_object.network.delegated_subnet_resource_id is not None: + validate_georestore_network(source_server_object, None, vnet, subnet, 'postgres') + + pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) + + storage = postgresql_flexibleservers.models.Storage(type=None) + + parameters = postgresql_flexibleservers.models.Server( + point_in_time_utc=restore_point_in_time, + location=location, + source_server_resource_id=source_server_id, + create_mode="GeoRestore", + availability_zone=zone, + storage=storage + ) + + if source_server_object.network.public_network_access == 'Disabled': + parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access='Disabled', + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + + parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) + + parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) + + +def flexible_server_revivedropped(cmd, client, resource_group_name, server_name, source_server, location, zone=None, + vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, + private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, + byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None): + validate_resource_group(resource_group_name) + + server_name = server_name.lower() + + if not is_valid_resource_id(source_server): + if _is_resource_name(source_server): + source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), + resource_group=resource_group_name, + namespace='Microsoft.DBforPostgreSQL', + type='flexibleServers', + name=source_server) + else: + raise CLIError('The provided source-server {} is invalid.'.format(source_server)) + else: + source_server_id = source_server + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') + + pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) + + storage = postgresql_flexibleservers.models.Storage(type=None) + + parameters = postgresql_flexibleservers.models.Server( + point_in_time_utc=get_current_time(), + location=location, + source_server_resource_id=source_server_id, + create_mode="ReviveDropped", + availability_zone=zone, + storage=storage + ) + + if vnet is not None or vnet_address_prefix is not None or subnet is not None or \ + subnet_address_prefix is not None or private_dns_zone_arguments is not None: + parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access='Disabled', + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + + parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) + + parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) \ No newline at end of file diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py index ca6d63def6a..60f00989a47 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py @@ -37,8 +37,9 @@ get_postgres_tiers, get_postgres_skus from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext from .flexible_server_custom_common import create_firewall_rule -from .flexible_server_virtual_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ @@ -1174,45 +1175,6 @@ def flexible_server_microsoft_entra_admin_show(client, resource_group_name, serv object_id=sid) -def flexible_server_provision_network_resource(cmd, resource_group_name, server_name, - location, db_context, private_dns_zone_arguments=None, public_access=None, - vnet=None, subnet=None, vnet_address_prefix=None, subnet_address_prefix=None, yes=False): - validate_resource_group(resource_group_name) - - start_ip = -1 - end_ip = -1 - network = postgresql_flexibleservers.models.Network() - - if subnet is not None or vnet is not None: - subnet_id = prepare_private_network(cmd, - resource_group_name, - server_name, - vnet=vnet, - subnet=subnet, - location=location, - delegation_service_name=DELEGATION_SERVICE_NAME, - vnet_address_pref=vnet_address_prefix, - subnet_address_pref=subnet_address_prefix, - yes=yes) - private_dns_zone_id = prepare_private_dns_zone(db_context, - resource_group_name, - server_name, - private_dns_zone=private_dns_zone_arguments, - subnet_id=subnet_id, - location=location, - yes=yes) - network.delegated_subnet_resource_id = subnet_id - network.private_dns_zone_arm_resource_id = private_dns_zone_id - elif subnet is None and vnet is None and private_dns_zone_arguments is not None: - raise RequiredArgumentMissingError("Private DNS zone can only be used with private access setting. Use vnet or/and subnet parameters.") - else: - start_ip, end_ip = prepare_public_network(public_access, yes=yes) - if public_access is not None and str(public_access).lower() in ['disabled', 'none']: - network.public_network_access = 'Disabled' - else: - network.public_network_access = 'Enabled' - - return network, start_ip, end_ip def flexible_server_threat_protection_get( @@ -2066,17 +2028,4 @@ def _confirm_restart_server(instance, sku_name, storage_gb, yes): # pylint: disable=too-many-instance-attributes, too-few-public-methods -class DbContext: - def __init__(self, cmd=None, azure_sdk=None, logging_name=None, cf_firewall=None, cf_db=None, - cf_availability=None, cf_private_dns_zone_suffix=None, - command_group=None, server_client=None, location=None): - self.cmd = cmd - self.azure_sdk = azure_sdk - self.cf_firewall = cf_firewall - self.cf_availability = cf_availability - self.cf_private_dns_zone_suffix = cf_private_dns_zone_suffix - self.logging_name = logging_name - self.cf_db = cf_db - self.command_group = command_group - self.server_client = server_client - self.location = location + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_microsoft_entra.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_microsoft_entra.py new file mode 100644 index 00000000000..017071480c3 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_microsoft_entra.py @@ -0,0 +1,15 @@ +from azure.cli.core.util import sdk_no_wait +from ._flexible_server_util import get_tenant_id + + +# Create Microsoft Entra admin +def _create_admin(client, resource_group_name, server_name, principal_name, sid, principal_type=None, no_wait=False): + parameters = { + 'properties': { + 'principalName': principal_name, + 'tenantId': get_tenant_id(), + 'principalType': principal_type + } + } + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, sid, parameters) \ No newline at end of file diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_virtual_network.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_network.py similarity index 72% rename from src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_virtual_network.py rename to src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_network.py index df4ff4052ea..e0fac858385 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_virtual_network.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_network.py @@ -10,94 +10,26 @@ from azure.cli.core.commands import LongRunningOperation from azure.cli.core.commands.client_factory import get_subscription_id from azure.cli.core.util import CLIError, user_confirmation -from azure.cli.core.azclierror import ValidationError +from azure.cli.core.azclierror import ValidationError, RequiredArgumentMissingError from azure.mgmt.privatedns.models import PrivateZone from azure.mgmt.privatedns.models import SubResource from azure.mgmt.privatedns.models import VirtualNetworkLink +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers from ._client_factory import resource_client_factory, private_dns_client_factory, private_dns_link_client_factory from ._config_reader import get_cloud_cluster from ._flexible_server_util import get_id_components, check_existence, _is_resource_name, parse_public_access_input, get_user_confirmation, _check_resource_group_existence -from .validators import validate_private_dns_zone, validate_vnet_location +from .validators import validate_private_dns_zone, validate_vnet_location, validate_resource_group from .aaz.latest.network.vnet import Create as VNetCreate, Show as VNetShow, Update as _VNetUpdate from .aaz.latest.network.vnet.subnet import Create as SubnetCreate, Show as SubnetShow, Update as SubnetUpdate logger = get_logger(__name__) +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" DEFAULT_VNET_ADDRESS_PREFIX = '10.0.0.0/16' DEFAULT_SUBNET_ADDRESS_PREFIX = '10.0.0.0/24' IP_ADDRESS_CHECKER = 'https://api.ipify.org' -def prepare_mysql_exist_private_network(cmd, resource_group, server_name, vnet, subnet, location, delegation_service_name): - nw_subscription = get_subscription_id(cmd.cli_ctx) - resource_client = resource_client_factory(cmd.cli_ctx) - if subnet is not None and vnet is None: - if not is_valid_resource_id(subnet): - raise ValidationError("Incorrectly formed Subnet ID. If you are providing only --subnet (not --vnet), the Subnet parameter should be in resource ID format.") - if 'child_name_1' not in parse_resource_id(subnet): - raise ValidationError("Incorrectly formed Subnet ID. Check if the Subnet ID is in the right format.") - - id_subscription, id_resource_group, id_vnet, id_subnet = get_id_components(subnet) - nw_subscription, resource_client = _change_client_with_different_subscription(cmd, id_subscription, nw_subscription, resource_client) - - if id_subnet is None: - id_subnet = 'Subnet' + server_name - - subnet_result = _create_mysql_exist_vnet_subnet_delegation(cmd, nw_subscription, resource_client, delegation_service_name, id_resource_group, id_vnet, id_subnet, location) - elif subnet is None and vnet is not None: - raise ValidationError("Missing Subnet. If you want to use private access, --subnet is requried.") - elif subnet is not None and vnet is not None: - if _is_resource_name(vnet) and _is_resource_name(subnet): - subnet_result = _create_mysql_exist_vnet_subnet_delegation(cmd, nw_subscription, resource_client, delegation_service_name, resource_group, vnet, subnet, location) - else: - raise ValidationError("If you pass both --vnet and --subnet, consider passing names instead of IDs. If you want to use an existing subnet, please provide the subnet Id only (not vnet Id).") - - return subnet_result["id"] - - -def _create_mysql_exist_vnet_subnet_delegation(cmd, nw_subscription, resource_client, delegation_service_name, resource_group, vnet_name, subnet_name, location): - if not check_existence(resource_client, vnet_name, resource_group, 'Microsoft.Network', 'virtualNetworks'): - raise ValidationError("Invalid Vnet. The vnet id of the subnet id your provided was not found.") - - if not check_existence(resource_client, subnet_name, resource_group, 'Microsoft.Network', 'subnets', parent_name=vnet_name, parent_type='virtualNetworks'): - raise ValidationError("Invalid Subnet. The subnet id your provided was not found.") - - logger.warning('Using existing Vnet "%s" in resource group "%s"', vnet_name, resource_group) - vnet = VNetShow(cli_ctx=cmd.cli_ctx)(command_args={ - "name": vnet_name, - "subscription": nw_subscription, - "resource_group": resource_group - }) - validate_vnet_location(vnet, location) - - delegation = {"name": delegation_service_name, "service_name": delegation_service_name} - logger.warning('Using existing Subnet "%s" in resource group "%s"', subnet_name, resource_group) - subnet = SubnetShow(cli_ctx=cmd.cli_ctx)(command_args={ - "name": subnet_name, - "vnet_name": vnet_name, - "subscription": nw_subscription, - "resource_group": resource_group - }) - - # Add Delegation if not delegated already - if not subnet.get("delegations", None): - logger.warning('Adding "%s" delegation to the existing subnet %s.', delegation_service_name, subnet_name) - poller = SubnetUpdate(cli_ctx=cmd.cli_ctx)(command_args={ - "name": subnet_name, - "vnet_name": vnet_name, - "subscription": nw_subscription, - "resource_group": resource_group, - "delegated_services": [delegation] - }) - subnet = LongRunningOperation(cmd.cli_ctx)(poller) - else: - for delgtn in subnet["delegations"]: - if delgtn["serviceName"] != delegation_service_name: - raise CLIError("Can not use subnet with existing delegations other than {}".format(delegation_service_name)) - - return subnet - - # pylint: disable=too-many-locals, too-many-statements, too-many-branches, import-outside-toplevel def prepare_private_network(cmd, resource_group_name, server_name, vnet, subnet, location, delegation_service_name, vnet_address_pref, subnet_address_pref, yes): @@ -274,72 +206,6 @@ def _create_subnet_delegation(cmd, nw_subscription, resource_client, delegation_ return subnet -def prepare_mysql_exist_private_dns_zone(cmd, resource_group, private_dns_zone, subnet_id): - # Get Vnet Components - vnet_subscription, vnet_rg, vnet_name, _ = get_id_components(subnet_id) - vnet_id = resource_id(subscription=vnet_subscription, - resource_group=vnet_rg, - namespace='Microsoft.Network', - type='virtualNetworks', - name=vnet_name) - vnet = VNetShow(cli_ctx=cmd.cli_ctx)(command_args={ - "name": vnet_name, - "subscription": vnet_subscription, - "resource_group": vnet_rg - }) - - dns_rg = None - dns_subscription = vnet_subscription - if not _is_resource_name(private_dns_zone) and is_valid_resource_id(private_dns_zone): - dns_subscription, dns_rg, private_dns_zone, _ = get_id_components(private_dns_zone) - - server_sub_resource_client = resource_client_factory(cmd.cli_ctx, subscription_id=get_subscription_id(cmd.cli_ctx)) - vnet_sub_resource_client = resource_client_factory(cmd.cli_ctx, subscription_id=vnet_subscription) - dns_sub_resource_client = resource_client_factory(cmd.cli_ctx, subscription_id=dns_subscription) - - zone_exist_flag = False - if dns_rg is not None and check_existence(dns_sub_resource_client, private_dns_zone, dns_rg, 'Microsoft.Network', 'privateDnsZones'): - zone_exist_flag = True - elif dns_rg is None and check_existence(server_sub_resource_client, private_dns_zone, resource_group, 'Microsoft.Network', 'privateDnsZones'): - zone_exist_flag = True - dns_rg = resource_group - dns_subscription = get_subscription_id(cmd.cli_ctx) - elif dns_rg is None and check_existence(vnet_sub_resource_client, private_dns_zone, vnet_rg, 'Microsoft.Network', 'privateDnsZones'): - zone_exist_flag = True - dns_subscription = vnet_subscription - dns_rg = vnet_rg - elif dns_rg is None: - zone_exist_flag = False - dns_subscription = vnet_subscription - dns_rg = vnet_rg - - if not zone_exist_flag: - raise ValidationError("Invalid Private DNS Zone. --private-dns-zone your provided was not found.") - - private_dns_client = private_dns_client_factory(cmd.cli_ctx, subscription_id=dns_subscription) - private_dns_link_client = private_dns_link_client_factory(cmd.cli_ctx, subscription_id=dns_subscription) - link = VirtualNetworkLink(location='global', virtual_network=SubResource(id=vnet["id"])) - link.registration_enabled = False - - logger.warning('Using existing private dns zone %s in resource group "%s"', private_dns_zone, dns_rg) - - private_zone = private_dns_client.get(resource_group_name=dns_rg, private_zone_name=private_dns_zone) - virtual_links = private_dns_link_client.list(resource_group_name=dns_rg, private_zone_name=private_dns_zone) - - link_exist_flag = False - for virtual_link in virtual_links: - if virtual_link.virtual_network.id == vnet_id: - link_exist_flag = True - break - - if not link_exist_flag: - private_dns_link_client.begin_create_or_update(resource_group_name=dns_rg, - private_zone_name=private_dns_zone, - virtual_network_link_name=vnet_name + '-link', - parameters=link, if_none_match='*').result() - return private_zone.id - - def prepare_private_dns_zone(db_context, resource_group, server_name, private_dns_zone, subnet_id, location, yes): cmd = db_context.cmd @@ -363,8 +229,6 @@ def prepare_private_dns_zone(db_context, resource_group, server_name, private_dn else: dns_suffix_client = db_context.cf_private_dns_zone_suffix(cmd.cli_ctx, '_') private_dns_zone_suffix = dns_suffix_client.get() - if db_context.command_group == 'mysql': - private_dns_zone_suffix = private_dns_zone_suffix.private_dns_zone_suffix # suffix should start with . if private_dns_zone_suffix[0] != '.': @@ -482,3 +346,44 @@ def prepare_public_network(public_access, yes): start_ip, end_ip = parse_public_access_input(public_access) return start_ip, end_ip + + +def flexible_server_provision_network_resource(cmd, resource_group_name, server_name, + location, db_context, private_dns_zone_arguments=None, public_access=None, + vnet=None, subnet=None, vnet_address_prefix=None, subnet_address_prefix=None, yes=False): + validate_resource_group(resource_group_name) + + start_ip = -1 + end_ip = -1 + network = postgresql_flexibleservers.models.Network() + + if subnet is not None or vnet is not None: + subnet_id = prepare_private_network(cmd, + resource_group_name, + server_name, + vnet=vnet, + subnet=subnet, + location=location, + delegation_service_name=DELEGATION_SERVICE_NAME, + vnet_address_pref=vnet_address_prefix, + subnet_address_pref=subnet_address_prefix, + yes=yes) + private_dns_zone_id = prepare_private_dns_zone(db_context, + resource_group_name, + server_name, + private_dns_zone=private_dns_zone_arguments, + subnet_id=subnet_id, + location=location, + yes=yes) + network.delegated_subnet_resource_id = subnet_id + network.private_dns_zone_arm_resource_id = private_dns_zone_id + elif subnet is None and vnet is None and private_dns_zone_arguments is not None: + raise RequiredArgumentMissingError("Private DNS zone can only be used with private access setting. Use vnet or/and subnet parameters.") + else: + start_ip, end_ip = prepare_public_network(public_access, yes=yes) + if public_access is not None and str(public_access).lower() in ['disabled', 'none']: + network.public_network_access = 'Disabled' + else: + network.public_network_access = 'Enabled' + + return network, start_ip, end_ip diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_private_dns_zone.py b/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_private_dns_zone.py index 217e917e9b9..e828d3a9b91 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_private_dns_zone.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_private_dns_zone.py @@ -12,7 +12,7 @@ ScenarioTest, StringContainCheck) from ..._client_factory import cf_postgres_flexible_private_dns_zone_suffix_operations -from ...flexible_server_virtual_network import prepare_private_dns_zone +from ...flexible_server_network import prepare_private_dns_zone from ...flexible_server_custom_postgres import DbContext as PostgresDbContext from .constants import DEFAULT_LOCATION, SERVER_NAME_PREFIX, SERVER_NAME_MAX_LENGTH diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_vnet.py b/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_vnet.py index 8d2c0197af7..faced018730 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_vnet.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_vnet.py @@ -9,7 +9,6 @@ NoneCheck, ResourceGroupPreparer, ScenarioTest) -from ...flexible_server_virtual_network import prepare_private_network, DEFAULT_VNET_ADDRESS_PREFIX, DEFAULT_SUBNET_ADDRESS_PREFIX from .constants import DEFAULT_LOCATION, SERVER_NAME_PREFIX, SERVER_NAME_MAX_LENGTH From c8a0285937264c8837a870588ed8c8911de295c4 Mon Sep 17 00:00:00 2001 From: Naia Scott Date: Wed, 25 Feb 2026 18:10:38 -0500 Subject: [PATCH 02/10] Init part 2 --- ...flexible_server_network.py => _network.py} | 0 .../postgresql/autonomous_tuning_commands.py | 232 +++ ...le_server_custom.py => custom_commands.py} | 13 + .../flexible_server_custom_postgres.py | 1547 ----------------- .../flexible_server_microsoft_entra.py | 15 - .../postgresql/identity_commands.py | 221 +++ .../postgresql/microsoft_entra_commands.py | 101 ++ .../postgresql/migration_commands.py | 190 ++ .../postgresql/parameter_commands.py | 91 + .../postgresql/power_commands.py | 84 + .../postgresql/replica_commands.py | 90 + .../postgresql/server_logs_commands.py | 90 + .../postgresql/threat_protection_commands.py | 120 ++ .../postgresql/virtual_endpoint_commands.py | 124 ++ 14 files changed, 1356 insertions(+), 1562 deletions(-) rename src/azure-cli/azure/cli/command_modules/postgresql/{flexible_server_network.py => _network.py} (100%) create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py rename src/azure-cli/azure/cli/command_modules/postgresql/{flexible_server_custom.py => custom_commands.py} (99%) delete mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_microsoft_entra.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_network.py b/src/azure-cli/azure/cli/command_modules/postgresql/_network.py similarity index 100% rename from src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_network.py rename to src/azure-cli/azure/cli/command_modules/postgresql/_network.py diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py new file mode 100644 index 00000000000..29f93a8e00f --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py @@ -0,0 +1,232 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from .flexible_server_custom_common import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .parameter_commands import flexible_parameter_update, _update_parameters +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + +def index_tuning_update(cmd, client, resource_group_name, server_name, index_tuning_enabled): + validate_resource_group(resource_group_name) + source = "user-override" + + if index_tuning_enabled == "True": + list_capability_info = get_postgres_server_capability_info(cmd, resource_group_name, server_name, is_offer_restriction_check_required=True) + autonomous_tuning_supported = list_capability_info['autonomous_tuning_supported'] + if not autonomous_tuning_supported: + raise CLIError("Index tuning is not supported for the server.") + + logger.warning("Enabling index tuning for the server.") + configuration_name = "index_tuning.mode" + value = "report" + _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) + configuration_name = "pg_qs.query_capture_mode" + query_capture_mode_configuration = client.get(resource_group_name, server_name, configuration_name) + + if query_capture_mode_configuration.value.lower() == "none": + value = "all" + _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) + logger.warning("Index tuning is enabled for the server.") + else: + logger.warning("Disabling index tuning for the server.") + configuration_name = "index_tuning.mode" + value = "off" + _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) + logger.warning("Index tuning is disabled for the server.") + + +def index_tuning_show(client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + index_tuning_configuration = client.get(resource_group_name, server_name, "index_tuning.mode") + query_capture_mode_configuration = client.get(resource_group_name, server_name, "pg_qs.query_capture_mode") + + if index_tuning_configuration.value.lower() == "report" and query_capture_mode_configuration.value.lower() != "none": + logger.warning("Index tuning is enabled for the server.") + else: + logger.warning("Index tuning is disabled for the server.") + + +def index_tuning_settings_list(cmd, client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + index_tuning_configurations_map_values = get_autonomous_tuning_settings_map().values() + configurations_list = client.list_by_server(resource_group_name, server_name) + + # Filter the list based on the values in the dictionary + index_tuning_settings = [setting for setting in configurations_list if setting.name in index_tuning_configurations_map_values] + + return index_tuning_settings + + +def index_tuning_settings_get(cmd, client, resource_group_name, server_name, setting_name): + validate_resource_group(resource_group_name) + index_tuning_configurations_map = get_autonomous_tuning_settings_map() + index_tuning_configuration_name = index_tuning_configurations_map[setting_name] + + return client.get( + resource_group_name=resource_group_name, + server_name=server_name, + configuration_name=index_tuning_configuration_name) + + +def index_tuning_settings_set(client, resource_group_name, server_name, setting_name, value=None): + source = "user-override" if value else None + tuning_settings = get_autonomous_tuning_settings_map() + configuration_name = tuning_settings[setting_name] + return flexible_parameter_update(client, server_name, configuration_name, resource_group_name, source, value) + + +def index_tuning_recommendations_list(cmd, resource_group_name, server_name, recommendation_type=None): + validate_resource_group(resource_group_name) + tuning_options_client = cf_postgres_flexible_tuning_options(cmd.cli_ctx, None) + + return tuning_options_client.list_recommendations( + resource_group_name=resource_group_name, + server_name=server_name, + tuning_option="index", + recommendation_type=recommendation_type + ) + + +def autonomous_tuning_update(cmd, client, resource_group_name, server_name, autonomous_tuning_enabled): + validate_resource_group(resource_group_name) + source = "user-override" + + if autonomous_tuning_enabled == "True": + subscription = get_subscription_id(cmd.cli_ctx) + postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, subscription) + source_server_object = postgres_source_client.servers.get(resource_group_name, server_name) + location = ''.join(source_server_object.location.lower().split()) + list_location_capability_info = get_postgres_location_capability_info(cmd, location, is_offer_restriction_check_required=True) + autonomous_tuning_supported = list_location_capability_info['autonomous_tuning_supported'] + if not autonomous_tuning_supported: + raise CLIError("Autonomous tuning is not supported for the server.") + + logger.warning("Enabling autonomous tuning for the server.") + configuration_name = "index_tuning.mode" + value = "report" + _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) + configuration_name = "pg_qs.query_capture_mode" + query_capture_mode_configuration = client.get(resource_group_name, server_name, configuration_name) + + if query_capture_mode_configuration.value.lower() == "none": + value = "all" + _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) + logger.warning("Autonomous tuning is enabled for the server.") + else: + logger.warning("Disabling autonomous tuning for the server.") + configuration_name = "index_tuning.mode" + value = "off" + _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) + logger.warning("Autonomous tuning is disabled for the server.") + + +def autonomous_tuning_show(client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + autonomous_tuning_configuration = client.get(resource_group_name, server_name, "index_tuning.mode") + query_capture_mode_configuration = client.get(resource_group_name, server_name, "pg_qs.query_capture_mode") + + if autonomous_tuning_configuration.value.lower() == "report" and query_capture_mode_configuration.value.lower() != "none": + logger.warning("Autonomous tuning is enabled for the server.") + else: + logger.warning("Autonomous tuning is disabled for the server.") + + +def autonomous_tuning_settings_list(cmd, client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + autonomous_tuning_configurations_map_values = get_autonomous_tuning_settings_map().values() + configurations_list = client.list_by_server(resource_group_name, server_name) + + # Filter the list based on the values in the dictionary + autonomous_tuning_settings = [setting for setting in configurations_list if setting.name in autonomous_tuning_configurations_map_values] + + return autonomous_tuning_settings + + +def autonomous_tuning_settings_get(cmd, client, resource_group_name, server_name, setting_name): + validate_resource_group(resource_group_name) + autonomous_tuning_configurations_map = get_autonomous_tuning_settings_map() + autonomous_tuning_configuration_name = autonomous_tuning_configurations_map[setting_name] + + return client.get( + resource_group_name=resource_group_name, + server_name=server_name, + configuration_name=autonomous_tuning_configuration_name) + + +def autonomous_tuning_settings_set(client, resource_group_name, server_name, setting_name, value=None): + source = "user-override" if value else None + tuning_settings = get_autonomous_tuning_settings_map() + configuration_name = tuning_settings[setting_name] + return flexible_parameter_update(client, server_name, configuration_name, resource_group_name, source, value) + + +def autonomous_tuning_index_recommendations_list(cmd, resource_group_name, server_name, recommendation_type=None): + validate_resource_group(resource_group_name) + tuning_options_client = cf_postgres_flexible_tuning_options(cmd.cli_ctx, None) + + return tuning_options_client.list_recommendations( + resource_group_name=resource_group_name, + server_name=server_name, + tuning_option="index", + recommendation_type=recommendation_type + ) + + +def autonomous_tuning_table_recommendations_list(cmd, resource_group_name, server_name, recommendation_type=None): + validate_resource_group(resource_group_name) + tuning_options_client = cf_postgres_flexible_tuning_options(cmd.cli_ctx, None) + + return tuning_options_client.list_recommendations( + resource_group_name=resource_group_name, + server_name=server_name, + tuning_option="table", + recommendation_type=recommendation_type + ) + + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py b/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py similarity index 99% rename from src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py rename to src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py index 514ab2adb2e..123cfad84ea 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py @@ -585,6 +585,19 @@ def flexible_server_update_custom_func(cmd, client, instance, return params +# Common functions used by other providers +def flexible_server_update_get(client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + + return client.get(resource_group_name, server_name) + + +def flexible_server_update_set(client, resource_group_name, server_name, parameters): + validate_resource_group(resource_group_name) + + return client.begin_update(resource_group_name, server_name, parameters) + + def _update_login(server_name, resource_group_name, auth_config, password_auth, administrator_login, administrator_login_password): if auth_config.password_auth.lower() == 'disabled' and password_auth.lower() == 'enabled': administrator_login = administrator_login if administrator_login else prompt('Please enter administrator username for the server. Once set, it cannot be changed: ') diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py index 60f00989a47..8ff7842307f 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py @@ -52,859 +52,6 @@ RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' -# region create without args -# pylint: disable=too-many-locals -# pylint: disable=too-many-statements -# pylint: disable=raise-missing-from, unbalanced-tuple-unpacking -def flexible_server_create(cmd, client, - resource_group_name=None, server_name=None, - location=None, backup_retention=None, - sku_name=None, tier=None, - storage_gb=None, version=None, microsoft_entra_auth=None, - admin_name=None, admin_id=None, admin_type=None, - password_auth=None, administrator_login=None, administrator_login_password=None, - tags=None, subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, - private_dns_zone_arguments=None, public_access=None, - high_availability=None, zonal_resiliency=None, allow_same_zone=False, - zone=None, standby_availability_zone=None, - geo_redundant_backup=None, byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, - auto_grow=None, performance_tier=None, - storage_type=None, iops=None, throughput=None, create_cluster=None, cluster_size=None, database_name=None, yes=False): - - if not check_resource_group(resource_group_name): - resource_group_name = None - - # Generate missing parameters - location, resource_group_name, server_name = generate_missing_parameters(cmd, location, resource_group_name, - server_name, 'postgres') - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - server_name = server_name.lower() - high_availability_mode = high_availability - - if (sku_name is None) or (version is None) or \ - (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): - list_location_capability_info = get_postgres_location_capability_info(cmd, location) - - # set sku_name from capability API - if sku_name is None: - tiers = [item.lower() for item in get_postgres_tiers(list_location_capability_info['sku_info'])] - try: - sku_info = list_location_capability_info['sku_info'] - skus = list(get_postgres_skus(sku_info, tier.lower())) - skus = sorted(skus, key=cmp_to_key(compare_sku_names)) - sku_name = skus[0] - except: - raise CLIError('Incorrect value for --tier. Allowed values : {}'.format(tiers)) - # default to the latest version - if version is None: - supported_server_versions = sorted(list_location_capability_info['supported_server_versions']) - version = supported_server_versions[-1] - # set high availability from capability API - if (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): - single_az = list_location_capability_info['single_az'] - high_availability_mode = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' - - pg_arguments_validator(db_context, - server_name=server_name, - location=location, - tier=tier, sku_name=sku_name, - storage_gb=storage_gb, - auto_grow=auto_grow, - storage_type=storage_type, - iops=iops, throughput=throughput, - high_availability=high_availability, - zonal_resiliency=zonal_resiliency, - allow_same_zone=allow_same_zone, - standby_availability_zone=standby_availability_zone, - zone=zone, - subnet=subnet, - public_access=public_access, - version=version, - geo_redundant_backup=geo_redundant_backup, - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key, - performance_tier=performance_tier, - create_cluster=create_cluster, - password_auth=password_auth, microsoft_entra_auth=microsoft_entra_auth, - admin_name=admin_name, admin_id=admin_id, admin_type=admin_type,) - - cluster = None - if create_cluster == 'ElasticCluster': - cluster_size = cluster_size if cluster_size else 2 - cluster = postgresql_flexibleservers.models.Cluster(cluster_size=cluster_size, default_database_name=database_name if database_name else POSTGRES_DB_NAME) - - server_result = firewall_id = None - - network, start_ip, end_ip = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access=public_access, - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - - storage = postgresql_flexibleservers.models.Storage(storage_size_gb=storage_gb, auto_grow=auto_grow, tier=performance_tier, type=storage_type, iops=iops, throughput=throughput) - - backup = postgresql_flexibleservers.models.Backup(backup_retention_days=backup_retention, - geo_redundant_backup=geo_redundant_backup) - - sku = postgresql_flexibleservers.models.Sku(name=sku_name, tier=tier) - - high_availability = postgresql_flexibleservers.models.HighAvailability(mode=high_availability_mode, - standby_availability_zone=standby_availability_zone) - - is_password_auth_enabled = bool(password_auth is not None and password_auth.lower() == 'enabled') - is_microsoft_entra_auth_enabled = bool(microsoft_entra_auth is not None and microsoft_entra_auth.lower() == 'enabled') - if is_password_auth_enabled: - administrator_login_password = generate_password(administrator_login_password) - - identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - auth_config = postgresql_flexibleservers.models.AuthConfig(active_directory_auth='Enabled' if is_microsoft_entra_auth_enabled else 'Disabled', - password_auth=password_auth) - - # Create postgresql - # Note : passing public_access has no effect as the accepted values are 'Enabled' and 'Disabled'. So the value ends up being ignored. - server_result = _create_server(db_context, cmd, resource_group_name, server_name, - tags=tags, - location=location, - sku=sku, - administrator_login=administrator_login, - administrator_login_password=administrator_login_password, - storage=storage, - backup=backup, - network=network, - version=version, - high_availability=high_availability, - availability_zone=zone, - identity=identity, - data_encryption=data_encryption, - auth_config=auth_config, - cluster=cluster) - - # Add Microsoft Entra Admin - if is_microsoft_entra_auth_enabled and admin_name is not None or admin_id is not None: - server_admin_client = cf_postgres_flexible_admin(cmd.cli_ctx, '_') - logger.warning("Add Microsoft Entra Admin '%s'.", admin_name) - _create_admin(server_admin_client, resource_group_name, server_name, admin_name, admin_id, admin_type) - - # Adding firewall rule - if start_ip != -1 and end_ip != -1: - firewall_id = create_firewall_rule(db_context, cmd, resource_group_name, server_name, start_ip, end_ip) - - user = server_result.administrator_login if is_password_auth_enabled else '' - password = administrator_login_password if is_password_auth_enabled else '' - admin = quote(admin_name) if admin_name else '' - server_id = server_result.id - loc = server_result.location - version = server_result.version - sku = server_result.sku.name - host = server_result.fully_qualified_domain_name - subnet_id = None if network is None else network.delegated_subnet_resource_id - - if is_password_auth_enabled: - logger.warning('Make a note of your password. If you forget, you would have to ' - 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', - server_name, resource_group_name) - logger.warning('Try using \'az postgres flexible-server connect\' command to test out connection.') - - _update_local_contexts(cmd, server_name, resource_group_name, location, user) - - return _form_response(user, sku, loc, server_id, host, version, password, - _create_postgresql_connection_string(host, user, password), - firewall_id, subnet_id, is_password_auth_enabled, is_microsoft_entra_auth_enabled, admin_name, - _create_microsoft_entra_connection_string(host, POSTGRES_DB_NAME, admin)) -# endregion create without args - - -def flexible_server_restore(cmd, client, - resource_group_name, server_name, - source_server, restore_point_in_time=None, zone=None, no_wait=False, - subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, - private_dns_zone_arguments=None, geo_redundant_backup=None, - byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, storage_type=None, yes=False): - - server_name = server_name.lower() - - validate_resource_group(resource_group_name) - - if not is_valid_resource_id(source_server): - if len(source_server.split('/')) == 1: - source_server_id = resource_id( - subscription=get_subscription_id(cmd.cli_ctx), - resource_group=resource_group_name, - namespace=RESOURCE_PROVIDER, - type='flexibleServers', - name=source_server) - else: - raise ValueError('The provided source server {} is invalid.'.format(source_server)) - else: - source_server_id = source_server - - restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) - - try: - id_parts = parse_resource_id(source_server_id) - source_subscription_id = id_parts['subscription'] - postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) - source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) - - location = ''.join(source_server_object.location.lower().split()) - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') - - pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) - - pg_restore_validator(source_server_object.sku.tier, storage_type=storage_type) - storage = postgresql_flexibleservers.models.Storage(type=storage_type if source_server_object.storage.type != "PremiumV2_LRS" else None) - - parameters = postgresql_flexibleservers.models.Server( - location=location, - point_in_time_utc=restore_point_in_time, - source_server_resource_id=source_server_id, # this should be the source server name, not id - create_mode="PointInTimeRestore", - availability_zone=zone, - storage=storage - ) - - if source_server_object.network.public_network_access == 'Disabled' and any((vnet, subnet)): - parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access='Disabled', - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - else: - parameters.network = source_server_object.network - - parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) - - parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - except Exception as e: - raise ResourceNotFoundError(e) - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) - - -# pylint: disable=too-many-branches -def flexible_server_update_custom_func(cmd, client, instance, - sku_name=None, tier=None, - storage_gb=None, - backup_retention=None, - administrator_login_password=None, - high_availability=None, - zonal_resiliency=None, - allow_same_zone=False, - standby_availability_zone=None, - maintenance_window=None, - byok_identity=None, byok_key=None, - backup_byok_identity=None, backup_byok_key=None, - microsoft_entra_auth=None, password_auth=None, - private_dns_zone_arguments=None, - public_access=None, - tags=None, - auto_grow=None, - performance_tier=None, - iops=None, throughput=None, - cluster_size=None, yes=False): - - # validator - location = ''.join(instance.location.lower().split()) - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - pg_arguments_validator(db_context, - location=location, - tier=tier, - sku_name=sku_name, - storage_gb=storage_gb, - auto_grow=auto_grow, - iops=iops, - throughput=throughput, - high_availability=high_availability, - zonal_resiliency=zonal_resiliency, - allow_same_zone=allow_same_zone, - zone=instance.availability_zone, - standby_availability_zone=standby_availability_zone, - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key, - performance_tier=performance_tier, - cluster_size=cluster_size, instance=instance) - - server_module_path = instance.__module__ - module = import_module(server_module_path) - ServerForPatch = getattr(module, 'ServerForPatch') - - server_id_parts = parse_resource_id(instance.id) - resource_group_name = server_id_parts['resource_group'] - server_name = server_id_parts['name'] - - if public_access: - instance.network.public_network_access = public_access - - if private_dns_zone_arguments: - private_dns_zone_id = prepare_private_dns_zone(db_context, - resource_group_name, - server_name, - private_dns_zone=private_dns_zone_arguments, - subnet_id=instance.network.delegated_subnet_resource_id, - location=location, - yes=yes) - instance.network.private_dns_zone_arm_resource_id = private_dns_zone_id - - _confirm_restart_server(instance, sku_name, storage_gb, yes) - - if sku_name: - instance.sku.name = sku_name - - if tier: - instance.sku.tier = tier - - if storage_gb: - instance.storage.storage_size_gb = storage_gb - - if auto_grow: - instance.storage.auto_grow = auto_grow - - instance.storage.tier = performance_tier if performance_tier else None - - if instance.storage.type == "PremiumV2_LRS": - instance.storage.tier = None - - if sku_name or storage_gb: - logger.warning("You are changing the compute and/or storage size of the server. " - "The server will be restarted for this operation and you will see a short downtime.") - - if iops: - instance.storage.iops = iops - - if throughput: - instance.storage.throughput = throughput - else: - instance.storage.type = None - instance.storage.iops = None - instance.storage.throughput = None - - if backup_retention: - instance.backup.backup_retention_days = backup_retention - - if maintenance_window: - if maintenance_window.lower() == "disabled": - # if disabled is pass in reset to default values - day_of_week = start_hour = start_minute = 0 - custom_window = "Disabled" - else: - day_of_week, start_hour, start_minute = parse_maintenance_window(maintenance_window) - custom_window = "Enabled" - - # set values - if maintenance_window when is None when created then create a new object - instance.maintenance_window.day_of_week = day_of_week - instance.maintenance_window.start_hour = start_hour - instance.maintenance_window.start_minute = start_minute - instance.maintenance_window.custom_window = custom_window - - identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key, - instance=instance) - - auth_config = instance.auth_config - administrator_login = instance.administrator_login if instance.administrator_login else None - if microsoft_entra_auth: - auth_config.active_directory_auth = microsoft_entra_auth - if password_auth: - administrator_login, administrator_login_password = _update_login(server_name, resource_group_name, auth_config, - password_auth, administrator_login, administrator_login_password) - auth_config.password_auth = password_auth - - if cluster_size: - instance.cluster.cluster_size = cluster_size - - params = ServerForPatch(sku=instance.sku, - storage=instance.storage, - backup=instance.backup, - administrator_login=administrator_login, - administrator_login_password=administrator_login_password, - availability_zone=instance.availability_zone, - maintenance_window=instance.maintenance_window, - network=instance.network, - identity=identity, - data_encryption=data_encryption, - auth_config=auth_config, - cluster=instance.cluster, - tags=tags) - - # High availability can't be updated with existing properties - high_availability_param = postgresql_flexibleservers.models.HighAvailability() - if zonal_resiliency is not None: - if zonal_resiliency.lower() == 'disabled': - high_availability = 'Disabled' - else: - list_capability_info = get_postgres_server_capability_info(cmd, resource_group_name, server_name) - single_az = list_capability_info['single_az'] - high_availability = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' - if high_availability: - high_availability_param.mode = high_availability - - if high_availability.lower() != "disabled" and standby_availability_zone: - high_availability_param.standby_availability_zone = standby_availability_zone - - # PG 11 and 12 will never receive fabric mirroring support. Ignite 2025 Fabric mirroring supported on 17. Skip this check for servers of these versions - if high_availability.lower() != "disabled" and str(instance.version) not in ["11", "12", "17", "18"]: - config_client = cf_postgres_flexible_config(cmd.cli_ctx, '_') - fabric_mirror_status = config_client.get(resource_group_name, server_name, 'azure.fabric_mirror_enabled') - if (fabric_mirror_status and fabric_mirror_status.value.lower() == 'on'): - raise CLIError("High availability cannot be enabled while Fabric mirroring is Active. Please disable Fabric mirroring to enable high availability.") - - params.high_availability = high_availability_param - - return params - - -def flexible_server_restart(cmd, client, resource_group_name, server_name, fail_over=None): - validate_resource_group(resource_group_name) - instance = client.get(resource_group_name, server_name) - if fail_over is not None and instance.high_availability.mode not in ("ZoneRedundant", "SameZone"): - raise ArgumentUsageError("Failing over can only be triggered for zone redundant or same zone servers.") - - if fail_over is not None: - validate_citus_cluster(cmd, resource_group_name, server_name) - if fail_over.lower() not in ['planned', 'forced']: - raise InvalidArgumentValueError("Allowed failover parameters are 'Planned' and 'Forced'.") - if fail_over.lower() == 'planned': - fail_over = 'plannedFailover' - elif fail_over.lower() == 'forced': - fail_over = 'forcedFailover' - parameters = postgresql_flexibleservers.models.RestartParameter(restart_with_failover=True, - failover_mode=fail_over) - else: - parameters = postgresql_flexibleservers.models.RestartParameter(restart_with_failover=False) - - return resolve_poller( - client.begin_restart(resource_group_name, server_name, parameters), cmd.cli_ctx, 'PostgreSQL Server Restart') - - -def flexible_server_delete(cmd, client, resource_group_name, server_name, yes=False): - validate_resource_group(resource_group_name) - result = None - if not yes: - user_confirmation( - "Are you sure you want to delete the server '{0}' in resource group '{1}'".format(server_name, - resource_group_name), yes=yes) - try: - result = client.begin_delete(resource_group_name, server_name) - if cmd.cli_ctx.local_context.is_on: - local_context_file = cmd.cli_ctx.local_context._get_local_context_file() # pylint: disable=protected-access - local_context_file.remove_option('postgres flexible-server', 'server_name') - local_context_file.remove_option('postgres flexible-server', 'administrator_login') - local_context_file.remove_option('postgres flexible-server', 'database_name') - except Exception as ex: # pylint: disable=broad-except - logger.error(ex) - raise CLIError(ex) - return result - - -def flexible_server_postgresql_get(cmd, resource_group_name, server_name): - validate_resource_group(resource_group_name) - client = get_postgresql_flexible_management_client(cmd.cli_ctx) - return client.servers.get(resource_group_name, server_name) - - -def flexible_parameter_update(client, server_name, configuration_name, resource_group_name, source=None, value=None): - validate_resource_group(resource_group_name) - parameter_value = value - parameter_source = source - try: - # validate configuration name - parameter = client.get(resource_group_name, server_name, configuration_name) - - # update the command with system default - if parameter_value is None and parameter_source is None: - parameter_value = parameter.default_value # reset value to default - - # this should be 'system-default' but there is currently a bug in PG - # this will reset source to be 'system-default' anyway - parameter_source = "user-override" - elif parameter_source is None: - parameter_source = "user-override" - except HttpResponseError as e: - if parameter_value is None and parameter_source is None: - raise CLIError('Unable to get default parameter value: {}.'.format(str(e))) - raise CLIError(str(e)) - - parameters = postgresql_flexibleservers.models.Configuration( - value=parameter_value, - source=parameter_source - ) - - return client.begin_update(resource_group_name, server_name, configuration_name, parameters) - - -def flexible_list_skus(cmd, client, location): - result = client.list(location) - logger.warning('For prices please refer to https://aka.ms/postgres-pricing') - return result - - -def flexible_replica_list_by_server(cmd, client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - return client.list_by_server(resource_group_name, server_name) - - -def flexible_replica_create(cmd, client, resource_group_name, source_server, replica_name=None, name=None, zone=None, - location=None, vnet=None, vnet_address_prefix=None, subnet=None, - subnet_address_prefix=None, private_dns_zone_arguments=None, no_wait=False, - byok_identity=None, byok_key=None, - sku_name=None, tier=None, - storage_gb=None, performance_tier=None, yes=False, tags=None): - validate_resource_group(resource_group_name) - - if replica_name is None and name is None: - raise RequiredArgumentMissingError('the following arguments are required: --name') - if replica_name is not None and name is not None: - raise MutuallyExclusiveArgumentError('usage error: --name and --replica-name cannot be used together. Please use --name.') - replica_name = replica_name.lower() if name is None else name.lower() - - if not is_valid_resource_id(source_server): - if _is_resource_name(source_server): - source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), - resource_group=resource_group_name, - namespace='Microsoft.DBforPostgreSQL', - type='flexibleServers', - name=source_server) - else: - raise CLIError('The provided source-server {} is invalid.'.format(source_server)) - else: - source_server_id = source_server - - source_server_id_parts = parse_resource_id(source_server_id) - try: - source_server_object = client.get(source_server_id_parts['resource_group'], source_server_id_parts['name']) - except Exception as e: - raise ResourceNotFoundError(e) - - if not location: - location = source_server_object.location - location = ''.join(location.lower().split()) - - list_location_capability_info = get_postgres_location_capability_info(cmd, location) - - if tier is None and source_server_object is not None: - tier = source_server_object.sku.tier - if sku_name is None and source_server_object is not None: - sku_name = source_server_object.sku.name - if storage_gb is None and source_server_object is not None: - storage_gb = source_server_object.storage.storage_size_gb - validate_postgres_replica(cmd, tier, location, source_server_object, - sku_name, storage_gb, performance_tier, list_location_capability_info) - - if not zone: - zone = _get_pg_replica_zone(list_location_capability_info['zones'], - source_server_object.availability_zone, - zone) - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - validate_server_name(db_context, replica_name, 'Microsoft.DBforPostgreSQL/flexibleServers') - - pg_byok_validator(byok_identity, byok_key) - - parameters = postgresql_flexibleservers.models.Server( - tags=tags, - source_server_resource_id=source_server_id, - location=location, - availability_zone=zone, - create_mode="Replica") - - if source_server_object.network.public_network_access == 'Disabled' and any((vnet, subnet)): - parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=replica_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access='Disabled', - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - else: - parameters.network = source_server_object.network - - parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key) - - parameters.sku = postgresql_flexibleservers.models.Sku(name=sku_name, tier=tier) - - parameters.storage = postgresql_flexibleservers.models.Storage(storage_size_gb=storage_gb, auto_grow=source_server_object.storage.auto_grow, tier=performance_tier) - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, replica_name, parameters) - - -def flexible_server_georestore(cmd, client, resource_group_name, server_name, source_server, location, zone=None, - vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, - private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, - byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, restore_point_in_time=None): - validate_resource_group(resource_group_name) - - server_name = server_name.lower() - - if not is_valid_resource_id(source_server): - if _is_resource_name(source_server): - source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), - resource_group=resource_group_name, - namespace='Microsoft.DBforPostgreSQL', - type='flexibleServers', - name=source_server) - else: - raise CLIError('The provided source-server {} is invalid.'.format(source_server)) - else: - source_server_id = source_server - - restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) - - try: - id_parts = parse_resource_id(source_server_id) - validate_citus_cluster(cmd, id_parts['resource_group'], id_parts['name']) - source_subscription_id = id_parts['subscription'] - postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) - source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) - except Exception as e: - raise ResourceNotFoundError(e) - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') - if source_server_object.network.delegated_subnet_resource_id is not None: - validate_georestore_network(source_server_object, None, vnet, subnet, 'postgres') - - pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) - - storage = postgresql_flexibleservers.models.Storage(type=None) - - parameters = postgresql_flexibleservers.models.Server( - point_in_time_utc=restore_point_in_time, - location=location, - source_server_resource_id=source_server_id, - create_mode="GeoRestore", - availability_zone=zone, - storage=storage - ) - - if source_server_object.network.public_network_access == 'Disabled': - parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access='Disabled', - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - - parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) - - parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) - - -def flexible_server_revivedropped(cmd, client, resource_group_name, server_name, source_server, location, zone=None, - vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, - private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, - byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None): - validate_resource_group(resource_group_name) - - server_name = server_name.lower() - - if not is_valid_resource_id(source_server): - if _is_resource_name(source_server): - source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), - resource_group=resource_group_name, - namespace='Microsoft.DBforPostgreSQL', - type='flexibleServers', - name=source_server) - else: - raise CLIError('The provided source-server {} is invalid.'.format(source_server)) - else: - source_server_id = source_server - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') - - pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) - - storage = postgresql_flexibleservers.models.Storage(type=None) - - parameters = postgresql_flexibleservers.models.Server( - point_in_time_utc=get_current_time(), - location=location, - source_server_resource_id=source_server_id, - create_mode="ReviveDropped", - availability_zone=zone, - storage=storage - ) - - if vnet is not None or vnet_address_prefix is not None or subnet is not None or \ - subnet_address_prefix is not None or private_dns_zone_arguments is not None: - parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access='Disabled', - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - - parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) - - parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) - - -def flexible_replica_promote(cmd, client, resource_group_name, replica_name, promote_mode='standalone', promote_option='planned'): - validate_resource_group(resource_group_name) - if is_citus_cluster(cmd, resource_group_name, replica_name): - # some settings validation - if promote_mode.lower() == 'standalone': - raise ValidationError("Standalone replica promotion on elastic cluster isn't currently supported. Please use 'switchover' instead.") - if promote_option.lower() == 'planned': - raise ValidationError("Planned replica promotion on elastic cluster isn't currently supported. Please use 'forced' instead.") - - try: - server_object = client.get(resource_group_name, replica_name) - except Exception as e: - raise ResourceNotFoundError(e) - - if server_object.replica.role is not None and "replica" not in server_object.replica.role.lower(): - raise CLIError('Server {} is not a replica server.'.format(replica_name)) - - if promote_mode == "standalone": - params = postgresql_flexibleservers.models.ServerForPatch( - replica=postgresql_flexibleservers.models.Replica( - role='None', - promote_mode=promote_mode, - promote_option=promote_option - ) - ) - else: - params = postgresql_flexibleservers.models.ServerForPatch( - replica=postgresql_flexibleservers.models.Replica( - role='Primary', - promote_mode=promote_mode, - promote_option=promote_option - ) - ) - - return client.begin_update(resource_group_name, replica_name, params) - - -def _create_server(db_context, cmd, resource_group_name, server_name, tags, location, sku, administrator_login, administrator_login_password, - storage, backup, network, version, high_availability, availability_zone, identity, data_encryption, auth_config, cluster): - validate_resource_group(resource_group_name) - - logging_name, server_client = db_context.logging_name, db_context.server_client - logger.warning('Creating %s Server \'%s\' in group \'%s\'...', logging_name, server_name, resource_group_name) - - logger.warning('Your server \'%s\' is using sku \'%s\' (Paid Tier). ' - 'Please refer to https://aka.ms/postgres-pricing for pricing details', server_name, sku.name) - - # Note : passing public-network-access has no effect as the accepted values are 'Enabled' and 'Disabled'. - # So when you pass an IP here(from the CLI args of public_access), it ends up being ignored. - parameters = postgresql_flexibleservers.models.Server( - tags=tags, - location=location, - sku=sku, - administrator_login=administrator_login, - administrator_login_password=administrator_login_password, - storage=storage, - backup=backup, - network=network, - version=version, - high_availability=high_availability, - availability_zone=availability_zone, - identity=identity, - data_encryption=data_encryption, - auth_config=auth_config, - cluster=cluster, - create_mode="Create") - - return resolve_poller( - server_client.begin_create_or_update(resource_group_name, server_name, parameters), cmd.cli_ctx, - '{} Server Create'.format(logging_name)) - - def database_create_func(cmd, client, resource_group_name, server_name, database_name=None, charset=None, collation=None): validate_database_name(database_name) validate_resource_group(resource_group_name) @@ -930,523 +77,7 @@ def database_create_func(cmd, client, resource_group_name, server_name, database parameters) -def flexible_server_connection_string( - server_name='{server}', - database_name='{database}', - administrator_login='{login}', - administrator_login_password='{password}', - show_pg_bouncer=False): - host = '{}.postgres.database.azure.com'.format(server_name) - port = 5432 - if show_pg_bouncer is True: - port = 6432 - - return { - 'connectionStrings': _create_postgresql_connection_strings(host, administrator_login, - administrator_login_password, database_name, port) - } - - -# Custom functions for identity -def flexible_server_identity_update(cmd, client, resource_group_name, server_name, system_assigned): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - server = client.get(resource_group_name, server_name) - identity_type = server.identity.type if (server and server.identity and server.identity.type) else 'None' - - if system_assigned.lower() == 'enabled': - # user wants to enable system-assigned identity - if identity_type == 'None': - # if user-assigned identity is not enabled, then enable system-assigned identity - identity_type = 'SystemAssigned' - elif identity_type == 'UserAssigned': - # if user-assigned identity is enabled, then enable both system-assigned and user-assigned identity - identity_type = 'SystemAssigned,UserAssigned' - else: - # check if fabric is enabled - config_client = cf_postgres_flexible_config(cmd.cli_ctx, '_') - fabric_mirror_status = config_client.get(resource_group_name, server_name, 'azure.fabric_mirror_enabled') - if (fabric_mirror_status and fabric_mirror_status.value.lower() == 'on'): - raise CLIError("On servers for which Fabric mirroring is enabled, system assigned managed identity cannot be disabled.") - if server.data_encryption.type == 'AzureKeyVault': - # if data encryption is enabled, then system-assigned identity cannot be disabled - raise CLIError("On servers for which data encryption is based on customer managed key, system assigned managed identity cannot be disabled.") - if identity_type == 'SystemAssigned,UserAssigned': - # if both system-assigned and user-assigned identity is enabled, then disable system-assigned identity - identity_type = 'UserAssigned' - elif identity_type == 'SystemAssigned': - # if only system-assigned identity is enabled, then disable system-assigned identity - identity_type = 'None' - - if identity_type == 'UserAssigned' or identity_type == 'SystemAssigned,UserAssigned': - identities_map = {} - for identity in server.identity.user_assigned_identities: - identities_map[identity] = {} - parameters = { - 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( - user_assigned_identities=identities_map, - type=identity_type)} - else: - parameters = { - 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( - type=identity_type)} - - result = resolve_poller( - client.begin_update( - resource_group_name=resource_group_name, - server_name=server_name, - parameters=parameters), - cmd.cli_ctx, 'Updating user assigned identity type for server {}'.format(server_name) - ) - - return result.identity - - -def flexible_server_identity_assign(cmd, client, resource_group_name, server_name, identities): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - server = client.get(resource_group_name, server_name) - identity_type = server.identity.type if (server and server.identity and server.identity.type) else 'None' - - if identity_type == 'SystemAssigned': - # if system-assigned identity is enabled, then enable both system - identity_type = 'SystemAssigned,UserAssigned' - elif identity_type == 'None': - # if system-assigned identity is not enabled, then enable user-assigned identity - identity_type = 'UserAssigned' - - identities_map = {} - for identity in identities: - identities_map[identity] = {} - - parameters = { - 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( - user_assigned_identities=identities_map, - type=identity_type)} - - result = resolve_poller( - client.begin_update( - resource_group_name=resource_group_name, - server_name=server_name, - parameters=parameters), - cmd.cli_ctx, 'Adding identities to server {}'.format(server_name) - ) - - return result.identity - - -def flexible_server_identity_remove(cmd, client, resource_group_name, server_name, identities): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - instance = client.get(resource_group_name, server_name) - - if instance.data_encryption: - primary_id = instance.data_encryption.primary_user_assigned_identity_id - - if primary_id and primary_id.lower() in [identity.lower() for identity in identities]: - raise CLIError("Cannot remove identity {} because it's used for data encryption.".format(primary_id)) - - geo_backup_id = instance.data_encryption.geo_backup_user_assigned_identity_id - - if geo_backup_id and geo_backup_id.lower() in [identity.lower() for identity in identities]: - raise CLIError("Cannot remove identity {} because it's used for geo backup data encryption.".format(geo_backup_id)) - - identities_map = {} - for identity in identities: - identities_map[identity] = None - - system_assigned_identity = instance.identity and instance.identity.principal_id is not None - - # if there are no user-assigned identities or all user-assigned identities are already removed - if not (instance.identity and instance.identity.user_assigned_identities) or \ - all(key.lower() in [identity.lower() for identity in identities] for key in instance.identity.user_assigned_identities.keys()): - if system_assigned_identity: - # if there is system assigned identity, then set identity type to SystemAssigned - parameters = { - 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( - type="SystemAssigned")} - else: - # no system assigned identity, set identity type to None - parameters = { - 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( - type="None")} - # if there are user-assigned identities and system assigned identity, then set identity type to SystemAssigned,UserAssigned - elif system_assigned_identity: - parameters = { - 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( - user_assigned_identities=identities_map, - type="SystemAssigned,UserAssigned")} - # there is no system assigned identity, but there are user-assigned identities, then set identity type to UserAssigned - else: - parameters = { - 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( - user_assigned_identities=identities_map, - type="UserAssigned")} - - result = resolve_poller( - client.begin_update( - resource_group_name=resource_group_name, - server_name=server_name, - parameters=parameters), - cmd.cli_ctx, 'Removing identities from server {}'.format(server_name) - ) - - return result.identity or postgresql_flexibleservers.models.UserAssignedIdentity(type="SystemAssigned") - - -def flexible_server_identity_list(cmd, client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - server = client.get(resource_group_name, server_name) - return server.identity or postgresql_flexibleservers.models.UserAssignedIdentity(type="SystemAssigned") - - -def flexible_server_identity_show(cmd, client, resource_group_name, server_name, identity): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - server = client.get(resource_group_name, server_name) - - for key, value in server.identity.user_assigned_identities.items(): - if key.lower() == identity.lower(): - return value - - raise CLIError("Identity '{}' does not exist in server {}.".format(identity, server_name)) - - -# Custom functions for ad-admin -def flexible_server_microsoft_entra_admin_set(cmd, client, resource_group_name, server_name, login, sid, principal_type=None, no_wait=False): - validate_resource_group(resource_group_name) - - server_operations_client = cf_postgres_flexible_servers(cmd.cli_ctx, '_') - - instance = server_operations_client.get(resource_group_name, server_name) - - if 'replica' in instance.replication_role.lower(): - raise CLIError("Cannot create a Microsoft Entra admin on a server with replication role. Use the primary server instead.") - - return _create_admin(client, resource_group_name, server_name, login, sid, principal_type, no_wait) - - -# Create Microsoft Entra admin -def _create_admin(client, resource_group_name, server_name, principal_name, sid, principal_type=None, no_wait=False): - parameters = { - 'properties': { - 'principalName': principal_name, - 'tenantId': get_tenant_id(), - 'principalType': principal_type - } - } - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, sid, parameters) - - -def flexible_server_microsoft_entra_admin_delete(cmd, client, resource_group_name, server_name, sid, no_wait=False): - validate_resource_group(resource_group_name) - - server_operations_client = cf_postgres_flexible_servers(cmd.cli_ctx, '_') - - instance = server_operations_client.get(resource_group_name, server_name) - - if 'replica' in instance.replication_role.lower(): - raise CLIError("Cannot delete an Microsoft Entra admin on a server with replication role. Use the primary server instead.") - - return sdk_no_wait(no_wait, client.begin_delete, resource_group_name, server_name, sid) - - -def flexible_server_microsoft_entra_admin_list(client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - - return client.list_by_server( - resource_group_name=resource_group_name, - server_name=server_name) - - -def flexible_server_microsoft_entra_admin_show(client, resource_group_name, server_name, sid): - validate_resource_group(resource_group_name) - - return client.get( - resource_group_name=resource_group_name, - server_name=server_name, - object_id=sid) - - - - -def flexible_server_threat_protection_get( - client, - resource_group_name, - server_name): - ''' - Gets an advanced threat protection setting. - ''' - - validate_resource_group(resource_group_name) - - return client.get( - resource_group_name=resource_group_name, - server_name=server_name, - threat_protection_name="Default") - - -def flexible_server_threat_protection_update( - cmd, - client, resource_group_name, server_name, - state=None): - # pylint: disable=unused-argument - ''' - Updates an advanced threat protection setting. Custom update function to apply parameters to instance. - ''' - - validate_resource_group(resource_group_name) - - try: - parameters = { - 'properties': { - 'state': state - } - } - return resolve_poller( - client.begin_create_or_update( - resource_group_name=resource_group_name, - server_name=server_name, - threat_protection_name="Default", - parameters=parameters), - cmd.cli_ctx, - 'PostgreSQL Flexible Server Advanced Threat Protection Setting Update') - except HttpResponseError as ex: - if "Operation returned an invalid status 'Accepted'" in ex.message: - # TODO: Once the swagger is updated, this won't be needed. - pass - else: - raise ex - - -def flexible_server_threat_protection_set( - cmd, - client, - resource_group_name, - server_name, - parameters): - validate_resource_group(resource_group_name) - - return resolve_poller( - client.begin_create_or_update( - resource_group_name=resource_group_name, - server_name=server_name, - threat_protection_name="Default", - parameters=parameters), - cmd.cli_ctx, - 'PostgreSQL Flexible Server Advanced Threat Protection Setting Update') - - # Custom functions for server logs -def flexible_server_download_log_files(client, resource_group_name, server_name, file_name): - validate_resource_group(resource_group_name) - - # list all files - files = client.list_by_server(resource_group_name, server_name) - - for f in files: - if f.name in file_name: - urlretrieve(f.url, f.name.replace("/", "_")) - - -def flexible_server_list_log_files_with_filter(client, resource_group_name, server_name, filename_contains=None, - file_last_written=None, max_file_size=None): - validate_resource_group(resource_group_name) - - # list all files - all_files = client.list_by_server(resource_group_name, server_name) - files = [] - - if file_last_written is None: - file_last_written = 72 - time_line = datetime.utcnow().replace(tzinfo=tzutc()) - timedelta(hours=file_last_written) - - for f in all_files: - if f.last_modified_time < time_line: - continue - if filename_contains is not None and re.search(filename_contains, f.name) is None: - continue - if max_file_size is not None and f.size_in_kb > max_file_size: - continue - - del f.created_time - files.append(f) - - return files - - -def migration_create_func(cmd, client, resource_group_name, server_name, properties, migration_mode="offline", - migration_name=None, migration_option=None, tags=None, location=None): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - logging_name = 'PostgreSQL' - subscription_id = get_subscription_id(cmd.cli_ctx) - properties_filepath = os.path.join(os.path.abspath(os.getcwd()), properties) - # Generate missing parameters - location, resource_group_name, server_name = generate_missing_parameters(cmd, location, resource_group_name, - server_name, 'postgres') - - # Get the properties for migration from the json file at the specific properties file path - if not os.path.exists(properties_filepath): - raise FileOperationError("Properties file does not exist in the given location") - with open(properties_filepath, "r") as f: - try: - request_payload = json.load(f) - migration_parameters = request_payload.get("properties") - except ValueError as err: - logger.error(err) - raise BadRequestError("Invalid json file. Make sure that the json file content is properly formatted.") - - if migration_name is None: - # Convert a UUID to a string of hex digits in standard form - migration_name = str(uuid.uuid4()) - - if migration_option is None: - # Use default migration_option as 'ValidateAndMigrate' - migration_option = "ValidateAndMigrate" - - return _create_migration(cmd, logging_name, client, subscription_id, resource_group_name, server_name, migration_name, - migration_mode, migration_option, migration_parameters, tags, location) - - -def migration_show_func(cmd, client, resource_group_name, server_name, migration_name): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - return client.get(resource_group_name, server_name, migration_name) - - -def migration_list_func(cmd, client, resource_group_name, server_name, migration_filter="Active"): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - return client.list_by_target_server(resource_group_name, server_name, migration_list_filter=migration_filter) - - -def migration_delete_func(cmd, client, resource_group_name, server_name, migration_name): - validate_resource_group(resource_group_name) - - return client.cancel(resource_group_name, server_name, migration_name) - - -def migration_update_func(cmd, client, resource_group_name, server_name, migration_name, setup_logical_replication=None, cutover=None, cancel=None): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - operationSpecified = False - if setup_logical_replication is True: - operationSpecified = True - parameters = postgresql_flexibleservers.models.MigrationResourceForPatch(setup_logical_replication_on_source_db_if_needed=True) - - if cutover is not None: - if operationSpecified is True: - raise MutuallyExclusiveArgumentError("Incorrect Usage: Can only specify one update operation.") - operationSpecified = True - migration_resource = migration_show_func(cmd, client, resource_group_name, server_name, migration_name) - if migration_resource.migration_mode == "Offline": - raise BadRequestError("Cutover is not possible for migration {} if the migration_mode set to offline. The migration will cutover automatically".format(migration_name)) - parameters = postgresql_flexibleservers.models.MigrationResourceForPatch(trigger_cutover="True", dbs_to_trigger_cutover_migration_on=migration_resource.dbs_to_migrate) - - if cancel is not None: - if operationSpecified is True: - raise MutuallyExclusiveArgumentError("Incorrect Usage: Can only specify one update operation.") - operationSpecified = True - migration_resource = migration_show_func(cmd, client, resource_group_name, server_name, migration_name) - parameters = postgresql_flexibleservers.models.MigrationResourceForPatch(cancel="True", dbs_to_cancel_migration_on=migration_resource.dbs_to_migrate) - - if operationSpecified is False: - raise RequiredArgumentMissingError("Incorrect Usage: At least one update operation needs to be specified.") - - return client.update(resource_group_name, server_name, migration_name, parameters) - - -def migration_check_name_availability(cmd, client, resource_group_name, server_name, migration_name): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - migration_name_availability_parammeters = {"name": "%s" % migration_name, "type": "Microsoft.DBforPostgreSQL/flexibleServers/migrations"} - return client.check_name_availability(resource_group_name, server_name, migration_name_availability_parammeters) - - -def virtual_endpoint_create_func(cmd, client, resource_group_name, server_name, virtual_endpoint_name, endpoint_type, members): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - validate_virtual_endpoint_name_availability(cmd, virtual_endpoint_name) - - parameters = { - 'properties': { - 'endpointType': endpoint_type, - 'members': [members] - } - } - - return client.begin_create( - resource_group_name, - server_name, - virtual_endpoint_name, - parameters) - - -def virtual_endpoint_show_func(cmd, client, resource_group_name, server_name, virtual_endpoint_name): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - return client.get( - resource_group_name, - server_name, - virtual_endpoint_name) - - -def virtual_endpoint_list_func(cmd, client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - return client.list_by_server( - resource_group_name, - server_name) - - -def virtual_endpoint_delete_func(cmd, client, resource_group_name, server_name, virtual_endpoint_name, yes=False): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - if not yes: - user_confirmation( - "Are you sure you want to delete the virtual endpoint '{0}' in resource group '{1}'".format(virtual_endpoint_name, - resource_group_name), yes=yes) - - return client.begin_delete( - resource_group_name, - server_name, - virtual_endpoint_name) - - -def virtual_endpoint_update_func(cmd, client, resource_group_name, server_name, virtual_endpoint_name, endpoint_type, members): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - parameters = { - 'properties': { - 'endpointType': endpoint_type, - 'members': [members] - } - } - - return client.begin_update( - resource_group_name, - server_name, - virtual_endpoint_name, - parameters) - - def backup_create_func(client, resource_group_name, server_name, backup_name): validate_resource_group(resource_group_name) validate_backup_name(backup_name) @@ -1619,184 +250,6 @@ def _update_parameters(cmd, client, server_name, configuration_name, resource_gr client.begin_update(resource_group_name, server_name, configuration_name, parameters), cmd.cli_ctx, 'PostgreSQL Parameter update') -def index_tuning_update(cmd, client, resource_group_name, server_name, index_tuning_enabled): - validate_resource_group(resource_group_name) - source = "user-override" - - if index_tuning_enabled == "True": - list_capability_info = get_postgres_server_capability_info(cmd, resource_group_name, server_name, is_offer_restriction_check_required=True) - autonomous_tuning_supported = list_capability_info['autonomous_tuning_supported'] - if not autonomous_tuning_supported: - raise CLIError("Index tuning is not supported for the server.") - - logger.warning("Enabling index tuning for the server.") - configuration_name = "index_tuning.mode" - value = "report" - _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) - configuration_name = "pg_qs.query_capture_mode" - query_capture_mode_configuration = client.get(resource_group_name, server_name, configuration_name) - - if query_capture_mode_configuration.value.lower() == "none": - value = "all" - _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) - logger.warning("Index tuning is enabled for the server.") - else: - logger.warning("Disabling index tuning for the server.") - configuration_name = "index_tuning.mode" - value = "off" - _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) - logger.warning("Index tuning is disabled for the server.") - - -def index_tuning_show(client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - index_tuning_configuration = client.get(resource_group_name, server_name, "index_tuning.mode") - query_capture_mode_configuration = client.get(resource_group_name, server_name, "pg_qs.query_capture_mode") - - if index_tuning_configuration.value.lower() == "report" and query_capture_mode_configuration.value.lower() != "none": - logger.warning("Index tuning is enabled for the server.") - else: - logger.warning("Index tuning is disabled for the server.") - - -def index_tuning_settings_list(cmd, client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - index_tuning_configurations_map_values = get_autonomous_tuning_settings_map().values() - configurations_list = client.list_by_server(resource_group_name, server_name) - - # Filter the list based on the values in the dictionary - index_tuning_settings = [setting for setting in configurations_list if setting.name in index_tuning_configurations_map_values] - - return index_tuning_settings - - -def index_tuning_settings_get(cmd, client, resource_group_name, server_name, setting_name): - validate_resource_group(resource_group_name) - index_tuning_configurations_map = get_autonomous_tuning_settings_map() - index_tuning_configuration_name = index_tuning_configurations_map[setting_name] - - return client.get( - resource_group_name=resource_group_name, - server_name=server_name, - configuration_name=index_tuning_configuration_name) - - -def index_tuning_settings_set(client, resource_group_name, server_name, setting_name, value=None): - source = "user-override" if value else None - tuning_settings = get_autonomous_tuning_settings_map() - configuration_name = tuning_settings[setting_name] - return flexible_parameter_update(client, server_name, configuration_name, resource_group_name, source, value) - - -def index_tuning_recommendations_list(cmd, resource_group_name, server_name, recommendation_type=None): - validate_resource_group(resource_group_name) - tuning_options_client = cf_postgres_flexible_tuning_options(cmd.cli_ctx, None) - - return tuning_options_client.list_recommendations( - resource_group_name=resource_group_name, - server_name=server_name, - tuning_option="index", - recommendation_type=recommendation_type - ) - - -def autonomous_tuning_update(cmd, client, resource_group_name, server_name, autonomous_tuning_enabled): - validate_resource_group(resource_group_name) - source = "user-override" - - if autonomous_tuning_enabled == "True": - subscription = get_subscription_id(cmd.cli_ctx) - postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, subscription) - source_server_object = postgres_source_client.servers.get(resource_group_name, server_name) - location = ''.join(source_server_object.location.lower().split()) - list_location_capability_info = get_postgres_location_capability_info(cmd, location, is_offer_restriction_check_required=True) - autonomous_tuning_supported = list_location_capability_info['autonomous_tuning_supported'] - if not autonomous_tuning_supported: - raise CLIError("Autonomous tuning is not supported for the server.") - - logger.warning("Enabling autonomous tuning for the server.") - configuration_name = "index_tuning.mode" - value = "report" - _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) - configuration_name = "pg_qs.query_capture_mode" - query_capture_mode_configuration = client.get(resource_group_name, server_name, configuration_name) - - if query_capture_mode_configuration.value.lower() == "none": - value = "all" - _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) - logger.warning("Autonomous tuning is enabled for the server.") - else: - logger.warning("Disabling autonomous tuning for the server.") - configuration_name = "index_tuning.mode" - value = "off" - _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) - logger.warning("Autonomous tuning is disabled for the server.") - - -def autonomous_tuning_show(client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - autonomous_tuning_configuration = client.get(resource_group_name, server_name, "index_tuning.mode") - query_capture_mode_configuration = client.get(resource_group_name, server_name, "pg_qs.query_capture_mode") - - if autonomous_tuning_configuration.value.lower() == "report" and query_capture_mode_configuration.value.lower() != "none": - logger.warning("Autonomous tuning is enabled for the server.") - else: - logger.warning("Autonomous tuning is disabled for the server.") - - -def autonomous_tuning_settings_list(cmd, client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - autonomous_tuning_configurations_map_values = get_autonomous_tuning_settings_map().values() - configurations_list = client.list_by_server(resource_group_name, server_name) - - # Filter the list based on the values in the dictionary - autonomous_tuning_settings = [setting for setting in configurations_list if setting.name in autonomous_tuning_configurations_map_values] - - return autonomous_tuning_settings - - -def autonomous_tuning_settings_get(cmd, client, resource_group_name, server_name, setting_name): - validate_resource_group(resource_group_name) - autonomous_tuning_configurations_map = get_autonomous_tuning_settings_map() - autonomous_tuning_configuration_name = autonomous_tuning_configurations_map[setting_name] - - return client.get( - resource_group_name=resource_group_name, - server_name=server_name, - configuration_name=autonomous_tuning_configuration_name) - - -def autonomous_tuning_settings_set(client, resource_group_name, server_name, setting_name, value=None): - source = "user-override" if value else None - tuning_settings = get_autonomous_tuning_settings_map() - configuration_name = tuning_settings[setting_name] - return flexible_parameter_update(client, server_name, configuration_name, resource_group_name, source, value) - - -def autonomous_tuning_index_recommendations_list(cmd, resource_group_name, server_name, recommendation_type=None): - validate_resource_group(resource_group_name) - tuning_options_client = cf_postgres_flexible_tuning_options(cmd.cli_ctx, None) - - return tuning_options_client.list_recommendations( - resource_group_name=resource_group_name, - server_name=server_name, - tuning_option="index", - recommendation_type=recommendation_type - ) - - -def autonomous_tuning_table_recommendations_list(cmd, resource_group_name, server_name, recommendation_type=None): - validate_resource_group(resource_group_name) - tuning_options_client = cf_postgres_flexible_tuning_options(cmd.cli_ctx, None) - - return tuning_options_client.list_recommendations( - resource_group_name=resource_group_name, - server_name=server_name, - tuning_option="table", - recommendation_type=recommendation_type - ) - - def flexible_server_migrate_network(client, resource_group_name, server_name, no_wait=False): validate_resource_group(resource_group_name) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_microsoft_entra.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_microsoft_entra.py deleted file mode 100644 index 017071480c3..00000000000 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_microsoft_entra.py +++ /dev/null @@ -1,15 +0,0 @@ -from azure.cli.core.util import sdk_no_wait -from ._flexible_server_util import get_tenant_id - - -# Create Microsoft Entra admin -def _create_admin(client, resource_group_name, server_name, principal_name, sid, principal_type=None, no_wait=False): - parameters = { - 'properties': { - 'principalName': principal_name, - 'tenantId': get_tenant_id(), - 'principalType': principal_type - } - } - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, sid, parameters) \ No newline at end of file diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py new file mode 100644 index 00000000000..c05d954c4a1 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py @@ -0,0 +1,221 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from .flexible_server_custom_common import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + +def flexible_server_identity_update(cmd, client, resource_group_name, server_name, system_assigned): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + server = client.get(resource_group_name, server_name) + identity_type = server.identity.type if (server and server.identity and server.identity.type) else 'None' + + if system_assigned.lower() == 'enabled': + # user wants to enable system-assigned identity + if identity_type == 'None': + # if user-assigned identity is not enabled, then enable system-assigned identity + identity_type = 'SystemAssigned' + elif identity_type == 'UserAssigned': + # if user-assigned identity is enabled, then enable both system-assigned and user-assigned identity + identity_type = 'SystemAssigned,UserAssigned' + else: + # check if fabric is enabled + config_client = cf_postgres_flexible_config(cmd.cli_ctx, '_') + fabric_mirror_status = config_client.get(resource_group_name, server_name, 'azure.fabric_mirror_enabled') + if (fabric_mirror_status and fabric_mirror_status.value.lower() == 'on'): + raise CLIError("On servers for which Fabric mirroring is enabled, system assigned managed identity cannot be disabled.") + if server.data_encryption.type == 'AzureKeyVault': + # if data encryption is enabled, then system-assigned identity cannot be disabled + raise CLIError("On servers for which data encryption is based on customer managed key, system assigned managed identity cannot be disabled.") + if identity_type == 'SystemAssigned,UserAssigned': + # if both system-assigned and user-assigned identity is enabled, then disable system-assigned identity + identity_type = 'UserAssigned' + elif identity_type == 'SystemAssigned': + # if only system-assigned identity is enabled, then disable system-assigned identity + identity_type = 'None' + + if identity_type == 'UserAssigned' or identity_type == 'SystemAssigned,UserAssigned': + identities_map = {} + for identity in server.identity.user_assigned_identities: + identities_map[identity] = {} + parameters = { + 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( + user_assigned_identities=identities_map, + type=identity_type)} + else: + parameters = { + 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( + type=identity_type)} + + result = resolve_poller( + client.begin_update( + resource_group_name=resource_group_name, + server_name=server_name, + parameters=parameters), + cmd.cli_ctx, 'Updating user assigned identity type for server {}'.format(server_name) + ) + + return result.identity + + +def flexible_server_identity_assign(cmd, client, resource_group_name, server_name, identities): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + server = client.get(resource_group_name, server_name) + identity_type = server.identity.type if (server and server.identity and server.identity.type) else 'None' + + if identity_type == 'SystemAssigned': + # if system-assigned identity is enabled, then enable both system + identity_type = 'SystemAssigned,UserAssigned' + elif identity_type == 'None': + # if system-assigned identity is not enabled, then enable user-assigned identity + identity_type = 'UserAssigned' + + identities_map = {} + for identity in identities: + identities_map[identity] = {} + + parameters = { + 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( + user_assigned_identities=identities_map, + type=identity_type)} + + result = resolve_poller( + client.begin_update( + resource_group_name=resource_group_name, + server_name=server_name, + parameters=parameters), + cmd.cli_ctx, 'Adding identities to server {}'.format(server_name) + ) + + return result.identity + + +def flexible_server_identity_remove(cmd, client, resource_group_name, server_name, identities): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + instance = client.get(resource_group_name, server_name) + + if instance.data_encryption: + primary_id = instance.data_encryption.primary_user_assigned_identity_id + + if primary_id and primary_id.lower() in [identity.lower() for identity in identities]: + raise CLIError("Cannot remove identity {} because it's used for data encryption.".format(primary_id)) + + geo_backup_id = instance.data_encryption.geo_backup_user_assigned_identity_id + + if geo_backup_id and geo_backup_id.lower() in [identity.lower() for identity in identities]: + raise CLIError("Cannot remove identity {} because it's used for geo backup data encryption.".format(geo_backup_id)) + + identities_map = {} + for identity in identities: + identities_map[identity] = None + + system_assigned_identity = instance.identity and instance.identity.principal_id is not None + + # if there are no user-assigned identities or all user-assigned identities are already removed + if not (instance.identity and instance.identity.user_assigned_identities) or \ + all(key.lower() in [identity.lower() for identity in identities] for key in instance.identity.user_assigned_identities.keys()): + if system_assigned_identity: + # if there is system assigned identity, then set identity type to SystemAssigned + parameters = { + 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( + type="SystemAssigned")} + else: + # no system assigned identity, set identity type to None + parameters = { + 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( + type="None")} + # if there are user-assigned identities and system assigned identity, then set identity type to SystemAssigned,UserAssigned + elif system_assigned_identity: + parameters = { + 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( + user_assigned_identities=identities_map, + type="SystemAssigned,UserAssigned")} + # there is no system assigned identity, but there are user-assigned identities, then set identity type to UserAssigned + else: + parameters = { + 'identity': postgresql_flexibleservers.models.UserAssignedIdentity( + user_assigned_identities=identities_map, + type="UserAssigned")} + + result = resolve_poller( + client.begin_update( + resource_group_name=resource_group_name, + server_name=server_name, + parameters=parameters), + cmd.cli_ctx, 'Removing identities from server {}'.format(server_name) + ) + + return result.identity or postgresql_flexibleservers.models.UserAssignedIdentity(type="SystemAssigned") + + +def flexible_server_identity_list(cmd, client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + server = client.get(resource_group_name, server_name) + return server.identity or postgresql_flexibleservers.models.UserAssignedIdentity(type="SystemAssigned") + + +def flexible_server_identity_show(cmd, client, resource_group_name, server_name, identity): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + server = client.get(resource_group_name, server_name) + + for key, value in server.identity.user_assigned_identities.items(): + if key.lower() == identity.lower(): + return value + + raise CLIError("Identity '{}' does not exist in server {}.".format(identity, server_name)) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py new file mode 100644 index 00000000000..0c79495e47f --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py @@ -0,0 +1,101 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from .flexible_server_custom_common import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + + +def flexible_server_microsoft_entra_admin_set(cmd, client, resource_group_name, server_name, login, sid, principal_type=None, no_wait=False): + validate_resource_group(resource_group_name) + + server_operations_client = cf_postgres_flexible_servers(cmd.cli_ctx, '_') + + instance = server_operations_client.get(resource_group_name, server_name) + + if 'replica' in instance.replication_role.lower(): + raise CLIError("Cannot create a Microsoft Entra admin on a server with replication role. Use the primary server instead.") + + return _create_admin(client, resource_group_name, server_name, login, sid, principal_type, no_wait) + + +def _create_admin(client, resource_group_name, server_name, principal_name, sid, principal_type=None, no_wait=False): + parameters = { + 'properties': { + 'principalName': principal_name, + 'tenantId': get_tenant_id(), + 'principalType': principal_type + } + } + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, sid, parameters) + + +def flexible_server_microsoft_entra_admin_delete(cmd, client, resource_group_name, server_name, sid, no_wait=False): + validate_resource_group(resource_group_name) + + server_operations_client = cf_postgres_flexible_servers(cmd.cli_ctx, '_') + + instance = server_operations_client.get(resource_group_name, server_name) + + if 'replica' in instance.replication_role.lower(): + raise CLIError("Cannot delete an Microsoft Entra admin on a server with replication role. Use the primary server instead.") + + return sdk_no_wait(no_wait, client.begin_delete, resource_group_name, server_name, sid) + + +def flexible_server_microsoft_entra_admin_list(client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + + return client.list_by_server( + resource_group_name=resource_group_name, + server_name=server_name) + + +def flexible_server_microsoft_entra_admin_show(client, resource_group_name, server_name, sid): + validate_resource_group(resource_group_name) + + return client.get( + resource_group_name=resource_group_name, + server_name=server_name, + object_id=sid) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py new file mode 100644 index 00000000000..16c3d76b29c --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py @@ -0,0 +1,190 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from .flexible_server_custom_common import create_firewall_rule +from ._network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + +def migration_create_func(cmd, client, resource_group_name, server_name, properties, migration_mode="offline", + migration_name=None, migration_option=None, tags=None, location=None): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + logging_name = 'PostgreSQL' + subscription_id = get_subscription_id(cmd.cli_ctx) + properties_filepath = os.path.join(os.path.abspath(os.getcwd()), properties) + # Generate missing parameters + location, resource_group_name, server_name = generate_missing_parameters(cmd, location, resource_group_name, + server_name, 'postgres') + + # Get the properties for migration from the json file at the specific properties file path + if not os.path.exists(properties_filepath): + raise FileOperationError("Properties file does not exist in the given location") + with open(properties_filepath, "r") as f: + try: + request_payload = json.load(f) + migration_parameters = request_payload.get("properties") + except ValueError as err: + logger.error(err) + raise BadRequestError("Invalid json file. Make sure that the json file content is properly formatted.") + + if migration_name is None: + # Convert a UUID to a string of hex digits in standard form + migration_name = str(uuid.uuid4()) + + if migration_option is None: + # Use default migration_option as 'ValidateAndMigrate' + migration_option = "ValidateAndMigrate" + + return _create_migration(cmd, logging_name, client, subscription_id, resource_group_name, server_name, migration_name, + migration_mode, migration_option, migration_parameters, tags, location) + + +def _create_migration(cmd, logging_name, client, subscription_id, resource_group_name, target_db_server_name, + migration_name, migration_mode, migration_option, parameters, tags, location): + validate_resource_group(resource_group_name) + + parameter_keys = list(parameters.keys()) + migrationInstanceResourceId = get_case_insensitive_key_value("MigrationRuntimeResourceId", parameter_keys, parameters) + if migrationInstanceResourceId is not None: + validate_migration_runtime_server(cmd, migrationInstanceResourceId, resource_group_name, target_db_server_name) + + logger.warning('Creating %s Migration for server \'%s\' in group \'%s\' and subscription \'%s\'...', logging_name, target_db_server_name, resource_group_name, subscription_id) + secret_parameter_dictionary = get_case_insensitive_key_value("SecretParameters", parameter_keys, parameters) + secret_parameter_keys = list(secret_parameter_dictionary.keys()) + admin_credentials_dictionary = get_case_insensitive_key_value("AdminCredentials", secret_parameter_keys, secret_parameter_dictionary) + admin_credentials_keys = list(admin_credentials_dictionary.keys()) + source_type = get_case_insensitive_key_value("SourceType", parameter_keys, parameters) + ssl_mode = get_case_insensitive_key_value("SslMode", parameter_keys, parameters) + + admin_credentials = postgresql_flexibleservers.models.AdminCredentials( + source_server_password=get_case_insensitive_key_value("SourceServerPassword", admin_credentials_keys, admin_credentials_dictionary), + target_server_password=get_case_insensitive_key_value("TargetServerPassword", admin_credentials_keys, admin_credentials_dictionary)) + secret_parameters = postgresql_flexibleservers.models.MigrationSecretParameters( + admin_credentials=admin_credentials, + source_server_username=get_case_insensitive_key_value("SourceServerUsername", secret_parameter_keys, secret_parameter_dictionary), + target_server_username=get_case_insensitive_key_value("TargetServerUsername", secret_parameter_keys, secret_parameter_dictionary)) + migration_parameters = postgresql_flexibleservers.models.Migration( + tags=tags, + location=location, + migration_mode=migration_mode, + source_db_server_resource_id=get_case_insensitive_key_value("SourceDbServerResourceId", parameter_keys, parameters), + secret_parameters=secret_parameters, + source_db_server_fully_qualified_domain_name=get_case_insensitive_key_value("SourceDbServerFullyQualifiedDomainName", parameter_keys, parameters), + target_db_server_fully_qualified_domain_name=get_case_insensitive_key_value("TargetDbServerFullyQualifiedDomainName", parameter_keys, parameters), + dbs_to_migrate=get_case_insensitive_key_value("DbsToMigrate", parameter_keys, parameters), + setup_logical_replication_on_source_db_if_needed=get_enum_value_true_false(get_case_insensitive_key_value("SetupLogicalReplicationOnSourceDbIfNeeded", parameter_keys, parameters), "SetupLogicalReplicationOnSourceDbIfNeeded"), + overwrite_dbs_in_target=get_enum_value_true_false(get_case_insensitive_key_value("OverwriteDbsInTarget", parameter_keys, parameters), "OverwriteDbsInTarget"), + source_type=source_type, + migration_option=migration_option, + ssl_mode=ssl_mode, + migration_instance_resource_id=migrationInstanceResourceId) + + return client.create(resource_group_name, server_name=target_db_server_name, migration_name=migration_name, parameters=migration_parameters) + + +def migration_show_func(cmd, client, resource_group_name, server_name, migration_name): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + return client.get(resource_group_name, server_name, migration_name) + + +def migration_list_func(cmd, client, resource_group_name, server_name, migration_filter="Active"): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + return client.list_by_target_server(resource_group_name, server_name, migration_list_filter=migration_filter) + + +def migration_delete_func(cmd, client, resource_group_name, server_name, migration_name): + validate_resource_group(resource_group_name) + + return client.cancel(resource_group_name, server_name, migration_name) + + +def migration_update_func(cmd, client, resource_group_name, server_name, migration_name, setup_logical_replication=None, cutover=None, cancel=None): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + operationSpecified = False + if setup_logical_replication is True: + operationSpecified = True + parameters = postgresql_flexibleservers.models.MigrationResourceForPatch(setup_logical_replication_on_source_db_if_needed=True) + + if cutover is not None: + if operationSpecified is True: + raise MutuallyExclusiveArgumentError("Incorrect Usage: Can only specify one update operation.") + operationSpecified = True + migration_resource = migration_show_func(cmd, client, resource_group_name, server_name, migration_name) + if migration_resource.migration_mode == "Offline": + raise BadRequestError("Cutover is not possible for migration {} if the migration_mode set to offline. The migration will cutover automatically".format(migration_name)) + parameters = postgresql_flexibleservers.models.MigrationResourceForPatch(trigger_cutover="True", dbs_to_trigger_cutover_migration_on=migration_resource.dbs_to_migrate) + + if cancel is not None: + if operationSpecified is True: + raise MutuallyExclusiveArgumentError("Incorrect Usage: Can only specify one update operation.") + operationSpecified = True + migration_resource = migration_show_func(cmd, client, resource_group_name, server_name, migration_name) + parameters = postgresql_flexibleservers.models.MigrationResourceForPatch(cancel="True", dbs_to_cancel_migration_on=migration_resource.dbs_to_migrate) + + if operationSpecified is False: + raise RequiredArgumentMissingError("Incorrect Usage: At least one update operation needs to be specified.") + + return client.update(resource_group_name, server_name, migration_name, parameters) + + +def migration_check_name_availability(cmd, client, resource_group_name, server_name, migration_name): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + migration_name_availability_parammeters = {"name": "%s" % migration_name, "type": "Microsoft.DBforPostgreSQL/flexibleServers/migrations"} + return client.check_name_availability(resource_group_name, server_name, migration_name_availability_parammeters) + + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py new file mode 100644 index 00000000000..890522c3c14 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py @@ -0,0 +1,91 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from .flexible_server_custom_common import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + + +def flexible_parameter_update(client, server_name, configuration_name, resource_group_name, source=None, value=None): + validate_resource_group(resource_group_name) + parameter_value = value + parameter_source = source + try: + # validate configuration name + parameter = client.get(resource_group_name, server_name, configuration_name) + + # update the command with system default + if parameter_value is None and parameter_source is None: + parameter_value = parameter.default_value # reset value to default + + # this should be 'system-default' but there is currently a bug in PG + # this will reset source to be 'system-default' anyway + parameter_source = "user-override" + elif parameter_source is None: + parameter_source = "user-override" + except HttpResponseError as e: + if parameter_value is None and parameter_source is None: + raise CLIError('Unable to get default parameter value: {}.'.format(str(e))) + raise CLIError(str(e)) + + parameters = postgresql_flexibleservers.models.Configuration( + value=parameter_value, + source=parameter_source + ) + + return client.begin_update(resource_group_name, server_name, configuration_name, parameters) + +def _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value): + parameters = postgresql_flexibleservers.models.Configuration( + value=value, + source=source + ) + + return resolve_poller( + client.begin_update(resource_group_name, server_name, configuration_name, parameters), cmd.cli_ctx, 'PostgreSQL Parameter update') diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py new file mode 100644 index 00000000000..9960c55415a --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py @@ -0,0 +1,84 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from .flexible_server_custom_common import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + +def flexible_server_restart(cmd, client, resource_group_name, server_name, fail_over=None): + validate_resource_group(resource_group_name) + instance = client.get(resource_group_name, server_name) + if fail_over is not None and instance.high_availability.mode not in ("ZoneRedundant", "SameZone"): + raise ArgumentUsageError("Failing over can only be triggered for zone redundant or same zone servers.") + + if fail_over is not None: + validate_citus_cluster(cmd, resource_group_name, server_name) + if fail_over.lower() not in ['planned', 'forced']: + raise InvalidArgumentValueError("Allowed failover parameters are 'Planned' and 'Forced'.") + if fail_over.lower() == 'planned': + fail_over = 'plannedFailover' + elif fail_over.lower() == 'forced': + fail_over = 'forcedFailover' + parameters = postgresql_flexibleservers.models.RestartParameter(restart_with_failover=True, + failover_mode=fail_over) + else: + parameters = postgresql_flexibleservers.models.RestartParameter(restart_with_failover=False) + + return resolve_poller( + client.begin_restart(resource_group_name, server_name, parameters), cmd.cli_ctx, 'PostgreSQL Server Restart') + + +def flexible_server_stop(client, resource_group_name=None, server_name=None, no_wait=False): + if not check_resource_group(resource_group_name): + resource_group_name = None + + days = 7 + logger.warning("Server will be automatically started after %d days " + "if you do not perform a manual start operation", days) + return sdk_no_wait(no_wait, client.begin_stop, resource_group_name, server_name) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py new file mode 100644 index 00000000000..7e984f8aa52 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py @@ -0,0 +1,90 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from .flexible_server_custom_common import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + +def flexible_replica_promote(cmd, client, resource_group_name, replica_name, promote_mode='standalone', promote_option='planned'): + validate_resource_group(resource_group_name) + if is_citus_cluster(cmd, resource_group_name, replica_name): + # some settings validation + if promote_mode.lower() == 'standalone': + raise ValidationError("Standalone replica promotion on elastic cluster isn't currently supported. Please use 'switchover' instead.") + if promote_option.lower() == 'planned': + raise ValidationError("Planned replica promotion on elastic cluster isn't currently supported. Please use 'forced' instead.") + + try: + server_object = client.get(resource_group_name, replica_name) + except Exception as e: + raise ResourceNotFoundError(e) + + if server_object.replica.role is not None and "replica" not in server_object.replica.role.lower(): + raise CLIError('Server {} is not a replica server.'.format(replica_name)) + + if promote_mode == "standalone": + params = postgresql_flexibleservers.models.ServerForPatch( + replica=postgresql_flexibleservers.models.Replica( + role='None', + promote_mode=promote_mode, + promote_option=promote_option + ) + ) + else: + params = postgresql_flexibleservers.models.ServerForPatch( + replica=postgresql_flexibleservers.models.Replica( + role='Primary', + promote_mode=promote_mode, + promote_option=promote_option + ) + ) + + return client.begin_update(resource_group_name, replica_name, params) + + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py new file mode 100644 index 00000000000..3da338881c0 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py @@ -0,0 +1,90 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from .flexible_server_custom_common import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + +def flexible_server_download_log_files(client, resource_group_name, server_name, file_name): + validate_resource_group(resource_group_name) + + # list all files + files = client.list_by_server(resource_group_name, server_name) + + for f in files: + if f.name in file_name: + urlretrieve(f.url, f.name.replace("/", "_")) + + +def flexible_server_list_log_files_with_filter(client, resource_group_name, server_name, filename_contains=None, + file_last_written=None, max_file_size=None): + validate_resource_group(resource_group_name) + + # list all files + all_files = client.list_by_server(resource_group_name, server_name) + files = [] + + if file_last_written is None: + file_last_written = 72 + time_line = datetime.utcnow().replace(tzinfo=tzutc()) - timedelta(hours=file_last_written) + + for f in all_files: + if f.last_modified_time < time_line: + continue + if filename_contains is not None and re.search(filename_contains, f.name) is None: + continue + if max_file_size is not None and f.size_in_kb > max_file_size: + continue + + del f.created_time + files.append(f) + + return files + + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py new file mode 100644 index 00000000000..b31dd1aaa81 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py @@ -0,0 +1,120 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from .flexible_server_custom_common import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + +def flexible_server_threat_protection_get( + client, + resource_group_name, + server_name): + ''' + Gets an advanced threat protection setting. + ''' + + validate_resource_group(resource_group_name) + + return client.get( + resource_group_name=resource_group_name, + server_name=server_name, + threat_protection_name="Default") + + +def flexible_server_threat_protection_update( + cmd, + client, resource_group_name, server_name, + state=None): + # pylint: disable=unused-argument + ''' + Updates an advanced threat protection setting. Custom update function to apply parameters to instance. + ''' + + validate_resource_group(resource_group_name) + + try: + parameters = { + 'properties': { + 'state': state + } + } + return resolve_poller( + client.begin_create_or_update( + resource_group_name=resource_group_name, + server_name=server_name, + threat_protection_name="Default", + parameters=parameters), + cmd.cli_ctx, + 'PostgreSQL Flexible Server Advanced Threat Protection Setting Update') + except HttpResponseError as ex: + if "Operation returned an invalid status 'Accepted'" in ex.message: + # TODO: Once the swagger is updated, this won't be needed. + pass + else: + raise ex + + +def flexible_server_threat_protection_set( + cmd, + client, + resource_group_name, + server_name, + parameters): + validate_resource_group(resource_group_name) + + return resolve_poller( + client.begin_create_or_update( + resource_group_name=resource_group_name, + server_name=server_name, + threat_protection_name="Default", + parameters=parameters), + cmd.cli_ctx, + 'PostgreSQL Flexible Server Advanced Threat Protection Setting Update') + + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py new file mode 100644 index 00000000000..ee93c8ffec9 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py @@ -0,0 +1,124 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from .flexible_server_custom_common import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + +def virtual_endpoint_create_func(cmd, client, resource_group_name, server_name, virtual_endpoint_name, endpoint_type, members): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + validate_virtual_endpoint_name_availability(cmd, virtual_endpoint_name) + + parameters = { + 'properties': { + 'endpointType': endpoint_type, + 'members': [members] + } + } + + return client.begin_create( + resource_group_name, + server_name, + virtual_endpoint_name, + parameters) + + +def virtual_endpoint_show_func(cmd, client, resource_group_name, server_name, virtual_endpoint_name): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + return client.get( + resource_group_name, + server_name, + virtual_endpoint_name) + + +def virtual_endpoint_list_func(cmd, client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + return client.list_by_server( + resource_group_name, + server_name) + + +def virtual_endpoint_delete_func(cmd, client, resource_group_name, server_name, virtual_endpoint_name, yes=False): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + if not yes: + user_confirmation( + "Are you sure you want to delete the virtual endpoint '{0}' in resource group '{1}'".format(virtual_endpoint_name, + resource_group_name), yes=yes) + + return client.begin_delete( + resource_group_name, + server_name, + virtual_endpoint_name) + + +def virtual_endpoint_update_func(cmd, client, resource_group_name, server_name, virtual_endpoint_name, endpoint_type, members): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + parameters = { + 'properties': { + 'endpointType': endpoint_type, + 'members': [members] + } + } + + return client.begin_update( + resource_group_name, + server_name, + virtual_endpoint_name, + parameters) + + From 0e41884b1cae088841408d5f2be83b62ecb54850 Mon Sep 17 00:00:00 2001 From: Naia Scott Date: Thu, 26 Feb 2026 16:00:34 -0500 Subject: [PATCH 03/10] init 3 --- .../cli/command_modules/postgresql/_github.py | 77 ++ .../postgresql/autonomous_tuning_commands.py | 2 +- .../postgresql/backup_commands.py | 105 +++ .../postgresql/custom_commands.py | 19 +- .../postgresql/database_commands.py | 102 +++ .../postgresql/fabric_mirroring_commands.py | 128 +++ .../postgresql/firewall_rule_commands.py | 139 +++ .../postgresql/flexible_server_custom.py | 811 ++++++++++++++++++ .../flexible_server_custom_common.py | 346 -------- .../flexible_server_custom_postgres.py | 195 +---- .../postgresql/flexible_server_power.py | 84 ++ .../postgresql/flexible_server_replica.py | 90 ++ .../postgresql/identity_commands.py | 2 +- .../postgresql/microsoft_entra_commands.py | 2 +- .../postgresql/migration_commands.py | 4 +- .../{_network.py => network_commands.py} | 8 +- .../postgresql/parameter_commands.py | 2 +- .../postgresql/power_commands.py | 2 +- .../postgresql/private_endpoint_commands.py | 112 +++ .../postgresql/replica_commands.py | 2 +- .../postgresql/server_logs_commands.py | 84 +- .../postgresql/threat_protection_commands.py | 2 +- .../postgresql/upgrade_commands.py | 80 ++ .../postgresql/virtual_endpoint_commands.py | 2 +- 24 files changed, 1846 insertions(+), 554 deletions(-) create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/_github.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/backup_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/database_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/fabric_mirroring_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/firewall_rule_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py delete mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_common.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_power.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_replica.py rename src/azure-cli/azure/cli/command_modules/postgresql/{_network.py => network_commands.py} (98%) create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/private_endpoint_commands.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/upgrade_commands.py diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/_github.py b/src/azure-cli/azure/cli/command_modules/postgresql/_github.py new file mode 100644 index 00000000000..99a7b9401ee --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/_github.py @@ -0,0 +1,77 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long + +import re +from datetime import datetime, timedelta +from dateutil.tz import tzutc +from knack.log import get_logger +from knack.util import CLIError +from urllib.request import urlretrieve +from azure.cli.core.util import sdk_no_wait, user_confirmation, run_cmd +from azure.cli.core.azclierror import ClientRequestError, RequiredArgumentMissingError +from ._client_factory import cf_postgres_flexible_replica +from ._flexible_server_util import run_subprocess, \ + fill_action_template, get_git_root_dir, resolve_poller, GITHUB_ACTION_PATH +from ._flexible_server_location_capabilities_util import get_postgres_server_capability_info +from .validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster + +logger = get_logger(__name__) +# pylint: disable=raise-missing-from + + +# Common functions used by other providers +def github_actions_setup(cmd, client, resource_group_name, server_name, database_name, administrator_login, administrator_login_password, sql_file_path, repository, action_name=None, branch=None, allow_push=None): + validate_resource_group(resource_group_name) + + server = client.get(resource_group_name, server_name) + if server.network.public_network_access == 'Disabled': + raise ClientRequestError("This command only works with public access enabled server.") + if allow_push and not branch: + raise RequiredArgumentMissingError("Provide remote branch name to allow pushing the action file to your remote branch.") + if action_name is None: + action_name = server.name + '_' + database_name + "_deploy" + gitcli_check_and_login() + + database_engine = 'postgresql' + + fill_action_template(cmd, + database_engine=database_engine, + server=server, + database_name=database_name, + administrator_login=administrator_login, + administrator_login_password=administrator_login_password, + file_name=sql_file_path, + repository=repository, + action_name=action_name) + + action_path = get_git_root_dir() + GITHUB_ACTION_PATH + action_name + '.yml' + logger.warning("Making git commit for file %s", action_path) + run_subprocess("git add {}".format(action_path)) + run_subprocess("git commit -m \"Add github action file\"") + + if allow_push: + logger.warning("Pushing the created action file to origin %s branch", branch) + run_subprocess("git push origin {}".format(branch)) + else: + logger.warning('You did not set --allow-push parameter. Please push the prepared file %s to your remote repo and run "deploy run" command to activate the workflow.', action_path) + + +def github_actions_run(action_name, branch): + + gitcli_check_and_login() + logger.warning("Created an event for %s.yml in branch %s", action_name, branch) + run_subprocess("gh workflow run {}.yml --ref {}".format(action_name, branch)) + + +def gitcli_check_and_login(): + output = run_cmd(["gh"], capture_output=True) + if output.returncode: + raise ClientRequestError('Please install "Github CLI" to run this command.') + + output = run_cmd(["gh", "auth", "status"], capture_output=True) + if output.returncode: + run_subprocess("gh auth login", stdout_show=True) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py index 29f93a8e00f..0357b9e0715 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule +from ._github import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .parameter_commands import flexible_parameter_update, _update_parameters from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/backup_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/backup_commands.py new file mode 100644 index 00000000000..8d3dc4ea56d --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/backup_commands.py @@ -0,0 +1,105 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from ._github import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + + +def backup_create_func(client, resource_group_name, server_name, backup_name): + validate_resource_group(resource_group_name) + validate_backup_name(backup_name) + + return client.begin_create( + resource_group_name, + server_name, + backup_name) + + +def ltr_precheck_func(client, resource_group_name, server_name, backup_name): + validate_resource_group(resource_group_name) + + return client.check_prerequisites( + resource_group_name=resource_group_name, + server_name=server_name, + parameters={"backupSettings": {"backupName": backup_name}} + ) + + +def ltr_start_func(client, resource_group_name, server_name, backup_name, sas_url): + validate_resource_group(resource_group_name) + + parameters = { + "backupSettings": { + "backupName": backup_name + }, + "targetDetails": { + "sasUriList": [sas_url] + } + } + + return client.begin_start( + resource_group_name=resource_group_name, + server_name=server_name, + parameters=parameters + ) + + +def backup_delete_func(client, resource_group_name, server_name, backup_name, yes=False): + validate_resource_group(resource_group_name) + + if not yes: + user_confirmation( + "Are you sure you want to delete the backup '{0}' in server '{1}'".format(backup_name, server_name), yes=yes) + + return client.begin_delete( + resource_group_name, + server_name, + backup_name) + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py index 123cfad84ea..3e80109804d 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule +from ._github import create_firewall_rule from .flexible_server_microsoft_entra import _create_admin from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ @@ -659,6 +659,23 @@ def flexible_server_postgresql_get(cmd, resource_group_name, server_name): return client.servers.get(resource_group_name, server_name) +def server_list_custom_func(client, resource_group_name=None, show_cluster=None): + if not check_resource_group(resource_group_name): + resource_group_name = None + + servers = client.list_by_subscription() + + if resource_group_name: + servers = client.list_by_resource_group(resource_group_name) + + if show_cluster: + servers = [s for s in servers if s.cluster is not None] + else: + servers = [s for s in servers if s.cluster is None] + + return servers + + def flexible_list_skus(cmd, client, location): result = client.list(location) logger.warning('For prices please refer to https://aka.ms/postgres-pricing') diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/database_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/database_commands.py new file mode 100644 index 00000000000..129f9667b96 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/database_commands.py @@ -0,0 +1,102 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from ._github import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + + +def database_create_func(cmd, client, resource_group_name, server_name, database_name=None, charset=None, collation=None): + validate_database_name(database_name) + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + if charset is None and collation is None: + charset = 'utf8' + collation = 'en_US.utf8' + logger.warning("Creating database with utf8 charset and en_US.utf8 collation") + elif (not charset and collation) or (charset and not collation): + raise RequiredArgumentMissingError("charset and collation have to be input together.") + + parameters = { + 'name': database_name, + 'charset': charset, + 'collation': collation + } + + return client.begin_create( + resource_group_name, + server_name, + database_name, + parameters) + + +def database_delete_func(cmd, client, resource_group_name=None, server_name=None, database_name=None, yes=None): + if not check_resource_group(resource_group_name): + resource_group_name = None + + result = None + if resource_group_name is None or server_name is None or database_name is None: + raise CLIError("Incorrect Usage : Deleting a database needs resource-group, server-name and database-name. " + "If your parameter persistence is turned ON, make sure these three parameters exist in " + "persistent parameters using \'az config param-persist show\'. " + "If your parameter persistence is turned OFF, consider passing them explicitly.") + if not yes: + user_confirmation( + "Are you sure you want to delete the database '{0}' of server '{1}'".format(database_name, + server_name), yes=yes) + + validate_citus_cluster(cmd, resource_group_name, server_name) + try: + result = client.begin_delete(resource_group_name, server_name, database_name) + except Exception as ex: # pylint: disable=broad-except + logger.error(ex) + return result + + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/fabric_mirroring_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/fabric_mirroring_commands.py new file mode 100644 index 00000000000..a3f4ba1e97b --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/fabric_mirroring_commands.py @@ -0,0 +1,128 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from ._github import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + + +def flexible_server_fabric_mirroring_start(cmd, client, resource_group_name, server_name, database_names, yes=False): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + flexible_servers_client = cf_postgres_flexible_servers(cmd.cli_ctx, '_') + server = flexible_servers_client.get(resource_group_name, server_name) + + if server.high_availability.mode != "Disabled" and server.version not in ["17", "18"]: + # disable fabric mirroring on HA server + raise CLIError("Fabric mirroring is not supported on servers with high availability enabled.") + + databases = ','.join(database_names) + user_confirmation("Are you sure you want to prepare and enable your server" + + " '{0}' in resource group '{1}' for mirroring of databases '{2}'.".format(server_name, resource_group_name, databases) + + " This requires restart.", yes=yes) + + if (server.identity is None or 'SystemAssigned' not in server.identity.type): + logger.warning('Enabling system assigned managed identity on the server.') + flexible_server_identity_update(cmd, flexible_servers_client, resource_group_name, server_name, 'Enabled') + + logger.warning('Updating necessary server parameters.') + source = "user-override" + configuration_name = "azure.fabric_mirror_enabled" + value = "on" + _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) + configuration_name = "azure.mirror_databases" + value = databases + return _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) + + +def flexible_server_fabric_mirroring_stop(cmd, client, resource_group_name, server_name, yes=False): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + flexible_servers_client = cf_postgres_flexible_servers(cmd.cli_ctx, '_') + server = flexible_servers_client.get(resource_group_name, server_name) + + if server.high_availability.mode != "Disabled" and server.version not in ["17", "18"]: + # disable fabric mirroring on HA server + raise CLIError("Fabric mirroring is not supported on servers with high availability enabled.") + + user_confirmation("Are you sure you want to disable mirroring for server '{0}' in resource group '{1}'".format(server_name, resource_group_name), yes=yes) + + configuration_name = "azure.fabric_mirror_enabled" + parameters = postgresql_flexibleservers.models.Configuration( + value="off", + source="user-override" + ) + + return client.begin_update(resource_group_name, server_name, configuration_name, parameters) + + +def flexible_server_fabric_mirroring_update_databases(cmd, client, resource_group_name, server_name, database_names, yes=False): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + flexible_servers_client = cf_postgres_flexible_servers(cmd.cli_ctx, '_') + server = flexible_servers_client.get(resource_group_name, server_name) + + if server.high_availability.mode != "Disabled" and server.version not in ["17", "18"]: + # disable fabric mirroring on HA server + raise CLIError("Fabric mirroring is not supported on servers with high availability enabled.") + + databases = ','.join(database_names) + user_confirmation("Are you sure for server '{0}' in resource group '{1}' you want to update the databases being mirrored to be '{2}'" + .format(server_name, resource_group_name, databases), yes=yes) + + configuration_name = "azure.mirror_databases" + parameters = postgresql_flexibleservers.models.Configuration( + value=databases, + source="user-override" + ) + + return client.begin_update(resource_group_name, server_name, configuration_name, parameters) + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/firewall_rule_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/firewall_rule_commands.py new file mode 100644 index 00000000000..31c06d99ee4 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/firewall_rule_commands.py @@ -0,0 +1,139 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long + +import re +from datetime import datetime, timedelta +from dateutil.tz import tzutc +from knack.log import get_logger +from knack.util import CLIError +from urllib.request import urlretrieve +from azure.cli.core.util import sdk_no_wait, user_confirmation, run_cmd +from azure.cli.core.azclierror import ClientRequestError, RequiredArgumentMissingError +from ._client_factory import cf_postgres_flexible_replica +from ._flexible_server_util import run_subprocess, \ + fill_action_template, get_git_root_dir, resolve_poller, GITHUB_ACTION_PATH +from ._flexible_server_location_capabilities_util import get_postgres_server_capability_info +from .validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster + +logger = get_logger(__name__) +# pylint: disable=raise-missing-from + + +def firewall_rule_delete_func(cmd, client, resource_group_name, server_name, firewall_rule_name, yes=None): + validate_resource_group(resource_group_name) + validate_public_access_server(cmd, resource_group_name, server_name) + + result = None + if not yes: + user_confirmation( + "Are you sure you want to delete the firewall-rule '{0}' in server '{1}', resource group '{2}'".format( + firewall_rule_name, server_name, resource_group_name)) + try: + result = client.begin_delete(resource_group_name, server_name, firewall_rule_name) + except Exception as ex: # pylint: disable=broad-except + logger.error(ex) + return result + + +def firewall_rule_create_func(cmd, client, resource_group_name, server_name, firewall_rule_name=None, start_ip_address=None, end_ip_address=None): + validate_resource_group(resource_group_name) + validate_public_access_server(cmd, resource_group_name, server_name) + + if end_ip_address is None and start_ip_address is not None: + end_ip_address = start_ip_address + elif start_ip_address is None and end_ip_address is not None: + start_ip_address = end_ip_address + elif start_ip_address is None and end_ip_address is None: + raise CLIError("Incorrect Usage : Need to pass in value for either \'--start-ip-address\' or \'--end-ip-address\'.") + + if firewall_rule_name is None: + now = datetime.now() + firewall_rule_name = 'FirewallIPAddress_{}-{}-{}_{}-{}-{}'.format(now.year, now.month, now.day, now.hour, now.minute, + now.second) + if start_ip_address == '0.0.0.0' and end_ip_address == '0.0.0.0': + logger.warning('Configuring server firewall rule, \'azure-access\', to accept connections from all ' + 'Azure resources...') + firewall_rule_name = 'AllowAllAzureServicesAndResourcesWithinAzureIps_{}-{}-{}_{}-{}-{}'.format(now.year, now.month, + now.day, now.hour, + now.minute, now.second) + elif start_ip_address == end_ip_address: + logger.warning('Configuring server firewall rule to accept connections from \'%s\'...', start_ip_address) + else: + if start_ip_address == '0.0.0.0' and end_ip_address == '255.255.255.255': + firewall_rule_name = 'AllowAll_{}-{}-{}_{}-{}-{}'.format(now.year, now.month, now.day, + now.hour, now.minute, now.second) + logger.warning('Configuring server firewall rule to accept connections from \'%s\' to \'%s\'...', start_ip_address, + end_ip_address) + + parameters = { + 'properties': { + 'startIpAddress': start_ip_address, + 'endIpAddress': end_ip_address + } + } + + return client.begin_create_or_update( + resource_group_name, + server_name, + firewall_rule_name, + parameters) + + +def flexible_firewall_rule_custom_getter(cmd, client, resource_group_name, server_name, firewall_rule_name): + validate_resource_group(resource_group_name) + validate_public_access_server(cmd, resource_group_name, server_name) + return client.get(resource_group_name, server_name, firewall_rule_name) + + +def flexible_firewall_rule_custom_setter(client, resource_group_name, server_name, firewall_rule_name, parameters): + validate_resource_group(resource_group_name) + + endIpAddress = parameters.get('properties', {}).get('endIpAddress') + startIpAddress = parameters.get('properties', {}).get('startIpAddress') + parameters = {"properties": {"endIpAddress": endIpAddress, "startIpAddress": startIpAddress}} + + return client.begin_create_or_update( + resource_group_name, + server_name, + firewall_rule_name, + parameters) + + +def flexible_firewall_rule_update_custom_func(instance, start_ip_address=None, end_ip_address=None): + if start_ip_address is not None: + instance.start_ip_address = start_ip_address + if end_ip_address is not None: + instance.end_ip_address = end_ip_address + return instance + + +def firewall_rule_get_func(cmd, client, resource_group_name, server_name, firewall_rule_name): + validate_resource_group(resource_group_name) + validate_public_access_server(cmd, resource_group_name, server_name) + return client.get(resource_group_name, server_name, firewall_rule_name) + + +def firewall_rule_list_func(cmd, client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + validate_public_access_server(cmd, resource_group_name, server_name) + return client.list_by_server(resource_group_name, server_name) + + +def create_firewall_rule(db_context, cmd, resource_group_name, server_name, start_ip, end_ip): + validate_resource_group(resource_group_name) + + # allow access to azure ip addresses + cf_firewall = db_context.cf_firewall # NOQA pylint: disable=unused-variable + firewall_client = cf_firewall(cmd.cli_ctx, None) + firewall = firewall_rule_create_func(cmd=cmd, + client=firewall_client, + resource_group_name=resource_group_name, + server_name=server_name, + start_ip_address=start_ip, end_ip_address=end_ip) + return firewall.result().name + + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py new file mode 100644 index 00000000000..b40cda13e25 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py @@ -0,0 +1,811 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from ._github import create_firewall_rule +from .flexible_server_microsoft_entra import _create_admin +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + + +# region create without args +# pylint: disable=too-many-locals +# pylint: disable=too-many-statements +# pylint: disable=raise-missing-from, unbalanced-tuple-unpacking +def flexible_server_create(cmd, client, + resource_group_name=None, server_name=None, + location=None, backup_retention=None, + sku_name=None, tier=None, + storage_gb=None, version=None, microsoft_entra_auth=None, + admin_name=None, admin_id=None, admin_type=None, + password_auth=None, administrator_login=None, administrator_login_password=None, + tags=None, subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, + private_dns_zone_arguments=None, public_access=None, + high_availability=None, zonal_resiliency=None, allow_same_zone=False, + zone=None, standby_availability_zone=None, + geo_redundant_backup=None, byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, + auto_grow=None, performance_tier=None, + storage_type=None, iops=None, throughput=None, create_cluster=None, cluster_size=None, database_name=None, yes=False): + + if not check_resource_group(resource_group_name): + resource_group_name = None + + # Generate missing parameters + location, resource_group_name, server_name = generate_missing_parameters(cmd, location, resource_group_name, + server_name, 'postgres') + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + server_name = server_name.lower() + high_availability_mode = high_availability + + if (sku_name is None) or (version is None) or \ + (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): + list_location_capability_info = get_postgres_location_capability_info(cmd, location) + + # set sku_name from capability API + if sku_name is None: + tiers = [item.lower() for item in get_postgres_tiers(list_location_capability_info['sku_info'])] + try: + sku_info = list_location_capability_info['sku_info'] + skus = list(get_postgres_skus(sku_info, tier.lower())) + skus = sorted(skus, key=cmp_to_key(compare_sku_names)) + sku_name = skus[0] + except: + raise CLIError('Incorrect value for --tier. Allowed values : {}'.format(tiers)) + # default to the latest version + if version is None: + supported_server_versions = sorted(list_location_capability_info['supported_server_versions']) + version = supported_server_versions[-1] + # set high availability from capability API + if (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): + single_az = list_location_capability_info['single_az'] + high_availability_mode = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' + + pg_arguments_validator(db_context, + server_name=server_name, + location=location, + tier=tier, sku_name=sku_name, + storage_gb=storage_gb, + auto_grow=auto_grow, + storage_type=storage_type, + iops=iops, throughput=throughput, + high_availability=high_availability, + zonal_resiliency=zonal_resiliency, + allow_same_zone=allow_same_zone, + standby_availability_zone=standby_availability_zone, + zone=zone, + subnet=subnet, + public_access=public_access, + version=version, + geo_redundant_backup=geo_redundant_backup, + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key, + performance_tier=performance_tier, + create_cluster=create_cluster, + password_auth=password_auth, microsoft_entra_auth=microsoft_entra_auth, + admin_name=admin_name, admin_id=admin_id, admin_type=admin_type,) + + cluster = None + if create_cluster == 'ElasticCluster': + cluster_size = cluster_size if cluster_size else 2 + cluster = postgresql_flexibleservers.models.Cluster(cluster_size=cluster_size, default_database_name=database_name if database_name else POSTGRES_DB_NAME) + + server_result = firewall_id = None + + network, start_ip, end_ip = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access=public_access, + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + + storage = postgresql_flexibleservers.models.Storage(storage_size_gb=storage_gb, auto_grow=auto_grow, tier=performance_tier, type=storage_type, iops=iops, throughput=throughput) + + backup = postgresql_flexibleservers.models.Backup(backup_retention_days=backup_retention, + geo_redundant_backup=geo_redundant_backup) + + sku = postgresql_flexibleservers.models.Sku(name=sku_name, tier=tier) + + high_availability = postgresql_flexibleservers.models.HighAvailability(mode=high_availability_mode, + standby_availability_zone=standby_availability_zone) + + is_password_auth_enabled = bool(password_auth is not None and password_auth.lower() == 'enabled') + is_microsoft_entra_auth_enabled = bool(microsoft_entra_auth is not None and microsoft_entra_auth.lower() == 'enabled') + if is_password_auth_enabled: + administrator_login_password = generate_password(administrator_login_password) + + identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + auth_config = postgresql_flexibleservers.models.AuthConfig(active_directory_auth='Enabled' if is_microsoft_entra_auth_enabled else 'Disabled', + password_auth=password_auth) + + # Create postgresql + # Note : passing public_access has no effect as the accepted values are 'Enabled' and 'Disabled'. So the value ends up being ignored. + server_result = _create_server(db_context, cmd, resource_group_name, server_name, + tags=tags, + location=location, + sku=sku, + administrator_login=administrator_login, + administrator_login_password=administrator_login_password, + storage=storage, + backup=backup, + network=network, + version=version, + high_availability=high_availability, + availability_zone=zone, + identity=identity, + data_encryption=data_encryption, + auth_config=auth_config, + cluster=cluster) + + # Add Microsoft Entra Admin + if is_microsoft_entra_auth_enabled and admin_name is not None or admin_id is not None: + server_admin_client = cf_postgres_flexible_admin(cmd.cli_ctx, '_') + logger.warning("Add Microsoft Entra Admin '%s'.", admin_name) + _create_admin(server_admin_client, resource_group_name, server_name, admin_name, admin_id, admin_type) + + # Adding firewall rule + if start_ip != -1 and end_ip != -1: + firewall_id = create_firewall_rule(db_context, cmd, resource_group_name, server_name, start_ip, end_ip) + + user = server_result.administrator_login if is_password_auth_enabled else '' + password = administrator_login_password if is_password_auth_enabled else '' + admin = quote(admin_name) if admin_name else '' + server_id = server_result.id + loc = server_result.location + version = server_result.version + sku = server_result.sku.name + host = server_result.fully_qualified_domain_name + subnet_id = None if network is None else network.delegated_subnet_resource_id + + if is_password_auth_enabled: + logger.warning('Make a note of your password. If you forget, you would have to ' + 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', + server_name, resource_group_name) + logger.warning('Try using \'az postgres flexible-server connect\' command to test out connection.') + + _update_local_contexts(cmd, server_name, resource_group_name, location, user) + + return _form_response(user, sku, loc, server_id, host, version, password, + firewall_id, subnet_id, is_password_auth_enabled, is_microsoft_entra_auth_enabled, admin_name) + + +def _create_server(db_context, cmd, resource_group_name, server_name, tags, location, sku, administrator_login, administrator_login_password, + storage, backup, network, version, high_availability, availability_zone, identity, data_encryption, auth_config, cluster): + validate_resource_group(resource_group_name) + + logging_name, server_client = db_context.logging_name, db_context.server_client + logger.warning('Creating %s Server \'%s\' in group \'%s\'...', logging_name, server_name, resource_group_name) + + logger.warning('Your server \'%s\' is using sku \'%s\' (Paid Tier). ' + 'Please refer to https://aka.ms/postgres-pricing for pricing details', server_name, sku.name) + + # Note : passing public-network-access has no effect as the accepted values are 'Enabled' and 'Disabled'. + # So when you pass an IP here(from the CLI args of public_access), it ends up being ignored. + parameters = postgresql_flexibleservers.models.Server( + tags=tags, + location=location, + sku=sku, + administrator_login=administrator_login, + administrator_login_password=administrator_login_password, + storage=storage, + backup=backup, + network=network, + version=version, + high_availability=high_availability, + availability_zone=availability_zone, + identity=identity, + data_encryption=data_encryption, + auth_config=auth_config, + cluster=cluster, + create_mode="Create") + + return resolve_poller( + server_client.begin_create_or_update(resource_group_name, server_name, parameters), cmd.cli_ctx, + '{} Server Create'.format(logging_name)) + + +def _update_local_contexts(cmd, server_name, resource_group_name, location, user): + validate_resource_group(resource_group_name) + + if cmd.cli_ctx.local_context.is_on: + cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'server_name', + server_name) # Setting the server name in the local context + cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'administrator_login', + user) # Setting the server name in the local context + cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'database_name', + POSTGRES_DB_NAME) # Setting the server name in the local context + cmd.cli_ctx.local_context.set([ALL], 'location', + location) # Setting the location in the local context + cmd.cli_ctx.local_context.set([ALL], 'resource_group_name', resource_group_name) + + +def _form_response(username, sku, location, server_id, host, version, password, firewall_id=None, + subnet_id=None, is_password_auth=True, is_microsoft_entra_auth_enabled=False, microsoft_admin=None): + + connection_kwargs = { + 'user': username if username is not None else '{user}', + 'host': host, + 'password': password if password is not None else '{password}', + 'database': POSTGRES_DB_NAME, + } + output = { + 'host': host, + 'username': username if is_password_auth else None, + 'password': password if is_password_auth else None, + 'skuname': sku, + 'location': location, + 'id': server_id, + 'version': version, + 'databaseName': POSTGRES_DB_NAME, + 'connectionString': 'postgresql://{user}:{password}@{host}/{database}?sslmode=require'.format(**connection_kwargs) + } + if is_microsoft_entra_auth_enabled: + user = quote(microsoft_admin) if microsoft_admin else '' + connection_kwargs = { + 'user': user, + 'host': host, + 'database': POSTGRES_DB_NAME, + } + output['admin'] = microsoft_admin + output['connectionStringMicrosoftEntra'] = 'postgresql://{user}:@{host}/{database}?sslmode=require'.format(**connection_kwargs) + if firewall_id is not None: + output['firewallName'] = firewall_id + if subnet_id is not None: + output['subnetId'] = subnet_id + return output + + +def flexible_server_restore(cmd, client, + resource_group_name, server_name, + source_server, restore_point_in_time=None, zone=None, no_wait=False, + subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, + private_dns_zone_arguments=None, geo_redundant_backup=None, + byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, storage_type=None, yes=False): + + server_name = server_name.lower() + + validate_resource_group(resource_group_name) + + if not is_valid_resource_id(source_server): + if len(source_server.split('/')) == 1: + source_server_id = resource_id( + subscription=get_subscription_id(cmd.cli_ctx), + resource_group=resource_group_name, + namespace=RESOURCE_PROVIDER, + type='flexibleServers', + name=source_server) + else: + raise ValueError('The provided source server {} is invalid.'.format(source_server)) + else: + source_server_id = source_server + + restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) + + try: + id_parts = parse_resource_id(source_server_id) + source_subscription_id = id_parts['subscription'] + postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) + source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) + + location = ''.join(source_server_object.location.lower().split()) + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') + + pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) + + pg_restore_validator(source_server_object.sku.tier, storage_type=storage_type) + storage = postgresql_flexibleservers.models.Storage(type=storage_type if source_server_object.storage.type != "PremiumV2_LRS" else None) + + parameters = postgresql_flexibleservers.models.Server( + location=location, + point_in_time_utc=restore_point_in_time, + source_server_resource_id=source_server_id, # this should be the source server name, not id + create_mode="PointInTimeRestore", + availability_zone=zone, + storage=storage + ) + + if source_server_object.network.public_network_access == 'Disabled' and any((vnet, subnet)): + parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access='Disabled', + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + else: + parameters.network = source_server_object.network + + parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) + + parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + except Exception as e: + raise ResourceNotFoundError(e) + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) + + +# pylint: disable=too-many-branches +def flexible_server_update_custom_func(cmd, client, instance, + sku_name=None, tier=None, + storage_gb=None, + backup_retention=None, + administrator_login_password=None, + high_availability=None, + zonal_resiliency=None, + allow_same_zone=False, + standby_availability_zone=None, + maintenance_window=None, + byok_identity=None, byok_key=None, + backup_byok_identity=None, backup_byok_key=None, + microsoft_entra_auth=None, password_auth=None, + private_dns_zone_arguments=None, + public_access=None, + tags=None, + auto_grow=None, + performance_tier=None, + iops=None, throughput=None, + cluster_size=None, yes=False): + + # validator + location = ''.join(instance.location.lower().split()) + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + pg_arguments_validator(db_context, + location=location, + tier=tier, + sku_name=sku_name, + storage_gb=storage_gb, + auto_grow=auto_grow, + iops=iops, + throughput=throughput, + high_availability=high_availability, + zonal_resiliency=zonal_resiliency, + allow_same_zone=allow_same_zone, + zone=instance.availability_zone, + standby_availability_zone=standby_availability_zone, + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key, + performance_tier=performance_tier, + cluster_size=cluster_size, instance=instance) + + server_module_path = instance.__module__ + module = import_module(server_module_path) + ServerForPatch = getattr(module, 'ServerForPatch') + + server_id_parts = parse_resource_id(instance.id) + resource_group_name = server_id_parts['resource_group'] + server_name = server_id_parts['name'] + + if public_access: + instance.network.public_network_access = public_access + + if private_dns_zone_arguments: + private_dns_zone_id = prepare_private_dns_zone(db_context, + resource_group_name, + server_name, + private_dns_zone=private_dns_zone_arguments, + subnet_id=instance.network.delegated_subnet_resource_id, + location=location, + yes=yes) + instance.network.private_dns_zone_arm_resource_id = private_dns_zone_id + + _confirm_restart_server(instance, sku_name, storage_gb, yes) + + if sku_name: + instance.sku.name = sku_name + + if tier: + instance.sku.tier = tier + + if storage_gb: + instance.storage.storage_size_gb = storage_gb + + if auto_grow: + instance.storage.auto_grow = auto_grow + + instance.storage.tier = performance_tier if performance_tier else None + + if instance.storage.type == "PremiumV2_LRS": + instance.storage.tier = None + + if sku_name or storage_gb: + logger.warning("You are changing the compute and/or storage size of the server. " + "The server will be restarted for this operation and you will see a short downtime.") + + if iops: + instance.storage.iops = iops + + if throughput: + instance.storage.throughput = throughput + else: + instance.storage.type = None + instance.storage.iops = None + instance.storage.throughput = None + + if backup_retention: + instance.backup.backup_retention_days = backup_retention + + if maintenance_window: + if maintenance_window.lower() == "disabled": + # if disabled is pass in reset to default values + day_of_week = start_hour = start_minute = 0 + custom_window = "Disabled" + else: + day_of_week, start_hour, start_minute = parse_maintenance_window(maintenance_window) + custom_window = "Enabled" + + # set values - if maintenance_window when is None when created then create a new object + instance.maintenance_window.day_of_week = day_of_week + instance.maintenance_window.start_hour = start_hour + instance.maintenance_window.start_minute = start_minute + instance.maintenance_window.custom_window = custom_window + + identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key, + instance=instance) + + auth_config = instance.auth_config + administrator_login = instance.administrator_login if instance.administrator_login else None + if microsoft_entra_auth: + auth_config.active_directory_auth = microsoft_entra_auth + if password_auth: + administrator_login, administrator_login_password = _update_login(server_name, resource_group_name, auth_config, + password_auth, administrator_login, administrator_login_password) + auth_config.password_auth = password_auth + + if cluster_size: + instance.cluster.cluster_size = cluster_size + + params = ServerForPatch(sku=instance.sku, + storage=instance.storage, + backup=instance.backup, + administrator_login=administrator_login, + administrator_login_password=administrator_login_password, + availability_zone=instance.availability_zone, + maintenance_window=instance.maintenance_window, + network=instance.network, + identity=identity, + data_encryption=data_encryption, + auth_config=auth_config, + cluster=instance.cluster, + tags=tags) + + # High availability can't be updated with existing properties + high_availability_param = postgresql_flexibleservers.models.HighAvailability() + if zonal_resiliency is not None: + if zonal_resiliency.lower() == 'disabled': + high_availability = 'Disabled' + else: + list_capability_info = get_postgres_server_capability_info(cmd, resource_group_name, server_name) + single_az = list_capability_info['single_az'] + high_availability = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' + if high_availability: + high_availability_param.mode = high_availability + + if high_availability.lower() != "disabled" and standby_availability_zone: + high_availability_param.standby_availability_zone = standby_availability_zone + + # PG 11 and 12 will never receive fabric mirroring support. Ignite 2025 Fabric mirroring supported on 17. Skip this check for servers of these versions + if high_availability.lower() != "disabled" and str(instance.version) not in ["11", "12", "17", "18"]: + config_client = cf_postgres_flexible_config(cmd.cli_ctx, '_') + fabric_mirror_status = config_client.get(resource_group_name, server_name, 'azure.fabric_mirror_enabled') + if (fabric_mirror_status and fabric_mirror_status.value.lower() == 'on'): + raise CLIError("High availability cannot be enabled while Fabric mirroring is Active. Please disable Fabric mirroring to enable high availability.") + + params.high_availability = high_availability_param + + return params + + +# Common functions used by other providers +def flexible_server_update_get(client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + + return client.get(resource_group_name, server_name) + + +def flexible_server_update_set(client, resource_group_name, server_name, parameters): + validate_resource_group(resource_group_name) + + return client.begin_update(resource_group_name, server_name, parameters) + + +def _update_login(server_name, resource_group_name, auth_config, password_auth, administrator_login, administrator_login_password): + if auth_config.password_auth.lower() == 'disabled' and password_auth.lower() == 'enabled': + administrator_login = administrator_login if administrator_login else prompt('Please enter administrator username for the server. Once set, it cannot be changed: ') + if not administrator_login: + raise CLIError('Administrator username is required for enabling password authentication.') + if not administrator_login_password: + administrator_login_password = generate_password(administrator_login_password) + logger.warning('Make a note of password "%s". You can ' + 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', + administrator_login_password, server_name, resource_group_name) + + return administrator_login, administrator_login_password + + +# pylint: disable=chained-comparison +def _confirm_restart_server(instance, sku_name, storage_gb, yes): + show_confirmation = False + + # check if sku_name is changed + if sku_name and sku_name != instance.sku.name: + show_confirmation = True + + # check if requested storage growth is crossing the 4096 threshold + if storage_gb and storage_gb > 4096 and instance.storage.storage_size_gb <= 4096 and instance.storage.type == "": + show_confirmation = True + + # check if storage_gb changed for PremiumV2_LRS + if storage_gb and instance.storage.type == "PremiumV2_LRS" and instance.storage.storage_size_gb != storage_gb: + show_confirmation = True + + if not yes and show_confirmation: + user_confirmation("You are trying to change the compute or the size of storage assigned to your server in a way that \ + requires a server restart. During the restart, you'll experience some downtime of the server. Do you want to proceed?", yes=yes) + + +def flexible_server_delete(cmd, client, resource_group_name, server_name, yes=False): + validate_resource_group(resource_group_name) + result = None + if not yes: + user_confirmation( + "Are you sure you want to delete the server '{0}' in resource group '{1}'".format(server_name, + resource_group_name), yes=yes) + try: + result = client.begin_delete(resource_group_name, server_name) + if cmd.cli_ctx.local_context.is_on: + local_context_file = cmd.cli_ctx.local_context._get_local_context_file() # pylint: disable=protected-access + local_context_file.remove_option('postgres flexible-server', 'server_name') + local_context_file.remove_option('postgres flexible-server', 'administrator_login') + local_context_file.remove_option('postgres flexible-server', 'database_name') + except Exception as ex: # pylint: disable=broad-except + logger.error(ex) + raise CLIError(ex) + return result + + +def flexible_server_postgresql_get(cmd, resource_group_name, server_name): + validate_resource_group(resource_group_name) + client = get_postgresql_flexible_management_client(cmd.cli_ctx) + return client.servers.get(resource_group_name, server_name) + + +def flexible_list_skus(cmd, client, location): + result = client.list(location) + logger.warning('For prices please refer to https://aka.ms/postgres-pricing') + return result + + +def flexible_server_georestore(cmd, client, resource_group_name, server_name, source_server, location, zone=None, + vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, + private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, + byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, restore_point_in_time=None): + validate_resource_group(resource_group_name) + + server_name = server_name.lower() + + if not is_valid_resource_id(source_server): + if _is_resource_name(source_server): + source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), + resource_group=resource_group_name, + namespace='Microsoft.DBforPostgreSQL', + type='flexibleServers', + name=source_server) + else: + raise CLIError('The provided source-server {} is invalid.'.format(source_server)) + else: + source_server_id = source_server + + restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) + + try: + id_parts = parse_resource_id(source_server_id) + validate_citus_cluster(cmd, id_parts['resource_group'], id_parts['name']) + source_subscription_id = id_parts['subscription'] + postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) + source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) + except Exception as e: + raise ResourceNotFoundError(e) + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') + if source_server_object.network.delegated_subnet_resource_id is not None: + validate_georestore_network(source_server_object, None, vnet, subnet, 'postgres') + + pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) + + storage = postgresql_flexibleservers.models.Storage(type=None) + + parameters = postgresql_flexibleservers.models.Server( + point_in_time_utc=restore_point_in_time, + location=location, + source_server_resource_id=source_server_id, + create_mode="GeoRestore", + availability_zone=zone, + storage=storage + ) + + if source_server_object.network.public_network_access == 'Disabled': + parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access='Disabled', + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + + parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) + + parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) + + +def flexible_server_revivedropped(cmd, client, resource_group_name, server_name, source_server, location, zone=None, + vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, + private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, + byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None): + validate_resource_group(resource_group_name) + + server_name = server_name.lower() + + if not is_valid_resource_id(source_server): + if _is_resource_name(source_server): + source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), + resource_group=resource_group_name, + namespace='Microsoft.DBforPostgreSQL', + type='flexibleServers', + name=source_server) + else: + raise CLIError('The provided source-server {} is invalid.'.format(source_server)) + else: + source_server_id = source_server + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') + + pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) + + storage = postgresql_flexibleservers.models.Storage(type=None) + + parameters = postgresql_flexibleservers.models.Server( + point_in_time_utc=get_current_time(), + location=location, + source_server_resource_id=source_server_id, + create_mode="ReviveDropped", + availability_zone=zone, + storage=storage + ) + + if vnet is not None or vnet_address_prefix is not None or subnet is not None or \ + subnet_address_prefix is not None or private_dns_zone_arguments is not None: + parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access='Disabled', + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + + parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) + + parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) \ No newline at end of file diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_common.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_common.py deleted file mode 100644 index 7ba472ce9be..00000000000 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_common.py +++ /dev/null @@ -1,346 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# pylint: disable=unused-argument, line-too-long - -import re -from datetime import datetime, timedelta -from dateutil.tz import tzutc -from knack.log import get_logger -from knack.util import CLIError -from urllib.request import urlretrieve -from azure.cli.core.util import sdk_no_wait, user_confirmation, run_cmd -from azure.cli.core.azclierror import ClientRequestError, RequiredArgumentMissingError -from ._client_factory import cf_postgres_flexible_replica -from ._flexible_server_util import run_subprocess, \ - fill_action_template, get_git_root_dir, resolve_poller, GITHUB_ACTION_PATH -from ._flexible_server_location_capabilities_util import get_postgres_server_capability_info -from .validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster - -logger = get_logger(__name__) -# pylint: disable=raise-missing-from - - -# Common functions used by other providers -def flexible_server_update_get(client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - - return client.get(resource_group_name, server_name) - - -def flexible_server_stop(client, resource_group_name=None, server_name=None, no_wait=False): - if not check_resource_group(resource_group_name): - resource_group_name = None - - days = 7 - logger.warning("Server will be automatically started after %d days " - "if you do not perform a manual start operation", days) - return sdk_no_wait(no_wait, client.begin_stop, resource_group_name, server_name) - - -def flexible_server_update_set(client, resource_group_name, server_name, parameters): - validate_resource_group(resource_group_name) - - return client.begin_update(resource_group_name, server_name, parameters) - - -def server_list_custom_func(client, resource_group_name=None, show_cluster=None): - if not check_resource_group(resource_group_name): - resource_group_name = None - - servers = client.list_by_subscription() - - if resource_group_name: - servers = client.list_by_resource_group(resource_group_name) - - if show_cluster: - servers = [s for s in servers if s.cluster is not None] - else: - servers = [s for s in servers if s.cluster is None] - - return servers - - -def firewall_rule_delete_func(cmd, client, resource_group_name, server_name, firewall_rule_name, yes=None): - validate_resource_group(resource_group_name) - validate_public_access_server(cmd, resource_group_name, server_name) - - result = None - if not yes: - user_confirmation( - "Are you sure you want to delete the firewall-rule '{0}' in server '{1}', resource group '{2}'".format( - firewall_rule_name, server_name, resource_group_name)) - try: - result = client.begin_delete(resource_group_name, server_name, firewall_rule_name) - except Exception as ex: # pylint: disable=broad-except - logger.error(ex) - return result - - -def firewall_rule_create_func(cmd, client, resource_group_name, server_name, firewall_rule_name=None, start_ip_address=None, end_ip_address=None): - validate_resource_group(resource_group_name) - validate_public_access_server(cmd, resource_group_name, server_name) - - if end_ip_address is None and start_ip_address is not None: - end_ip_address = start_ip_address - elif start_ip_address is None and end_ip_address is not None: - start_ip_address = end_ip_address - elif start_ip_address is None and end_ip_address is None: - raise CLIError("Incorrect Usage : Need to pass in value for either \'--start-ip-address\' or \'--end-ip-address\'.") - - if firewall_rule_name is None: - now = datetime.now() - firewall_rule_name = 'FirewallIPAddress_{}-{}-{}_{}-{}-{}'.format(now.year, now.month, now.day, now.hour, now.minute, - now.second) - if start_ip_address == '0.0.0.0' and end_ip_address == '0.0.0.0': - logger.warning('Configuring server firewall rule, \'azure-access\', to accept connections from all ' - 'Azure resources...') - firewall_rule_name = 'AllowAllAzureServicesAndResourcesWithinAzureIps_{}-{}-{}_{}-{}-{}'.format(now.year, now.month, - now.day, now.hour, - now.minute, now.second) - elif start_ip_address == end_ip_address: - logger.warning('Configuring server firewall rule to accept connections from \'%s\'...', start_ip_address) - else: - if start_ip_address == '0.0.0.0' and end_ip_address == '255.255.255.255': - firewall_rule_name = 'AllowAll_{}-{}-{}_{}-{}-{}'.format(now.year, now.month, now.day, - now.hour, now.minute, now.second) - logger.warning('Configuring server firewall rule to accept connections from \'%s\' to \'%s\'...', start_ip_address, - end_ip_address) - - parameters = { - 'properties': { - 'startIpAddress': start_ip_address, - 'endIpAddress': end_ip_address - } - } - - return client.begin_create_or_update( - resource_group_name, - server_name, - firewall_rule_name, - parameters) - - -def flexible_firewall_rule_custom_getter(cmd, client, resource_group_name, server_name, firewall_rule_name): - validate_resource_group(resource_group_name) - validate_public_access_server(cmd, resource_group_name, server_name) - return client.get(resource_group_name, server_name, firewall_rule_name) - - -def flexible_firewall_rule_custom_setter(client, resource_group_name, server_name, firewall_rule_name, parameters): - validate_resource_group(resource_group_name) - - endIpAddress = parameters.get('properties', {}).get('endIpAddress') - startIpAddress = parameters.get('properties', {}).get('startIpAddress') - parameters = {"properties": {"endIpAddress": endIpAddress, "startIpAddress": startIpAddress}} - - return client.begin_create_or_update( - resource_group_name, - server_name, - firewall_rule_name, - parameters) - - -def flexible_firewall_rule_update_custom_func(instance, start_ip_address=None, end_ip_address=None): - if start_ip_address is not None: - instance.start_ip_address = start_ip_address - if end_ip_address is not None: - instance.end_ip_address = end_ip_address - return instance - - -def firewall_rule_get_func(cmd, client, resource_group_name, server_name, firewall_rule_name): - validate_resource_group(resource_group_name) - validate_public_access_server(cmd, resource_group_name, server_name) - return client.get(resource_group_name, server_name, firewall_rule_name) - - -def firewall_rule_list_func(cmd, client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - validate_public_access_server(cmd, resource_group_name, server_name) - return client.list_by_server(resource_group_name, server_name) - - -def database_delete_func(cmd, client, resource_group_name=None, server_name=None, database_name=None, yes=None): - if not check_resource_group(resource_group_name): - resource_group_name = None - - result = None - if resource_group_name is None or server_name is None or database_name is None: - raise CLIError("Incorrect Usage : Deleting a database needs resource-group, server-name and database-name. " - "If your parameter persistence is turned ON, make sure these three parameters exist in " - "persistent parameters using \'az config param-persist show\'. " - "If your parameter persistence is turned OFF, consider passing them explicitly.") - if not yes: - user_confirmation( - "Are you sure you want to delete the database '{0}' of server '{1}'".format(database_name, - server_name), yes=yes) - - validate_citus_cluster(cmd, resource_group_name, server_name) - try: - result = client.begin_delete(resource_group_name, server_name, database_name) - except Exception as ex: # pylint: disable=broad-except - logger.error(ex) - return result - - -def create_firewall_rule(db_context, cmd, resource_group_name, server_name, start_ip, end_ip): - validate_resource_group(resource_group_name) - - # allow access to azure ip addresses - cf_firewall = db_context.cf_firewall # NOQA pylint: disable=unused-variable - firewall_client = cf_firewall(cmd.cli_ctx, None) - firewall = firewall_rule_create_func(cmd=cmd, - client=firewall_client, - resource_group_name=resource_group_name, - server_name=server_name, - start_ip_address=start_ip, end_ip_address=end_ip) - return firewall.result().name - - -def github_actions_setup(cmd, client, resource_group_name, server_name, database_name, administrator_login, administrator_login_password, sql_file_path, repository, action_name=None, branch=None, allow_push=None): - validate_resource_group(resource_group_name) - - server = client.get(resource_group_name, server_name) - if server.network.public_network_access == 'Disabled': - raise ClientRequestError("This command only works with public access enabled server.") - if allow_push and not branch: - raise RequiredArgumentMissingError("Provide remote branch name to allow pushing the action file to your remote branch.") - if action_name is None: - action_name = server.name + '_' + database_name + "_deploy" - gitcli_check_and_login() - - database_engine = 'postgresql' - - fill_action_template(cmd, - database_engine=database_engine, - server=server, - database_name=database_name, - administrator_login=administrator_login, - administrator_login_password=administrator_login_password, - file_name=sql_file_path, - repository=repository, - action_name=action_name) - - action_path = get_git_root_dir() + GITHUB_ACTION_PATH + action_name + '.yml' - logger.warning("Making git commit for file %s", action_path) - run_subprocess("git add {}".format(action_path)) - run_subprocess("git commit -m \"Add github action file\"") - - if allow_push: - logger.warning("Pushing the created action file to origin %s branch", branch) - run_subprocess("git push origin {}".format(branch)) - else: - logger.warning('You did not set --allow-push parameter. Please push the prepared file %s to your remote repo and run "deploy run" command to activate the workflow.', action_path) - - -def github_actions_run(action_name, branch): - - gitcli_check_and_login() - logger.warning("Created an event for %s.yml in branch %s", action_name, branch) - run_subprocess("gh workflow run {}.yml --ref {}".format(action_name, branch)) - - -def gitcli_check_and_login(): - output = run_cmd(["gh"], capture_output=True) - if output.returncode: - raise ClientRequestError('Please install "Github CLI" to run this command.') - - output = run_cmd(["gh", "auth", "status"], capture_output=True) - if output.returncode: - run_subprocess("gh auth login", stdout_show=True) - - -# Custom functions for server logs -def flexible_server_log_download(client, resource_group_name, server_name, file_name): - validate_resource_group(resource_group_name) - - files = client.list_by_server(resource_group_name, server_name) - - for f in files: - if f.name in file_name: - urlretrieve(f.url, f.name) - - -def flexible_server_log_list(client, resource_group_name, server_name, filename_contains=None, - file_last_written=None, max_file_size=None): - validate_resource_group(resource_group_name) - - all_files = client.list_by_server(resource_group_name, server_name) - files = [] - - if file_last_written is None: - file_last_written = 72 - time_line = datetime.utcnow().replace(tzinfo=tzutc()) - timedelta(hours=file_last_written) - - for f in all_files: - if f.last_modified_time < time_line: - continue - if filename_contains is not None and re.search(filename_contains, f.name) is None: - continue - if max_file_size is not None and f.size_in_kb > max_file_size: - continue - - del f.created_time - files.append(f) - - return files - - -def flexible_server_version_upgrade(cmd, client, resource_group_name, server_name, version, yes=None): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - if not yes: - user_confirmation( - "Upgrading major version in server {} is irreversible. The action you're about to take can't be undone. " - "Going further will initiate major version upgrade to the selected version on this server." - .format(server_name), yes=yes) - - instance = client.get(resource_group_name, server_name) - - current_version = int(instance.version.split('.')[0]) - if current_version >= int(version): - raise CLIError("The version to upgrade to must be greater than the current version.") - - list_server_capability_info = get_postgres_server_capability_info(cmd, resource_group_name, server_name) - eligible_versions = list_server_capability_info['supported_server_versions'][str(current_version)] - - if version == '13': - logger.warning("PostgreSQL version 13 will reach end-of-life (EOL) soon. " - "Upgrade to PostgreSQL 14 or later as soon as possible to " - "maintain security, performance, and supportability.") - - if version not in eligible_versions: - # version not supported - error_message = "" - if len(eligible_versions) > 0: - error_message = "Server is running version {}. It can only be upgraded to the following versions: {} ".format(str(current_version), eligible_versions) - else: - error_message = "Server is running version {}. It cannot be upgraded to any higher version. ".format(str(current_version)) - - raise CLIError(error_message) - - replica_operations_client = cf_postgres_flexible_replica(cmd.cli_ctx, '_') - version_mapped = version - - replicas = replica_operations_client.list_by_server(resource_group_name, server_name) - - if 'replica' in instance.replication_role.lower() or len(list(replicas)) > 0: - raise CLIError("Major version upgrade is not yet supported for servers in a read replica setup.") - - parameters = { - 'properties': { - 'version': version_mapped - } - } - - return resolve_poller( - client.begin_update( - resource_group_name=resource_group_name, - server_name=server_name, - parameters=parameters), - cmd.cli_ctx, 'Upgrading server {} to major version {}'.format(server_name, version) - ) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py index 8ff7842307f..9f5de686a95 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule +from ._github import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ @@ -52,194 +52,7 @@ RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' -def database_create_func(cmd, client, resource_group_name, server_name, database_name=None, charset=None, collation=None): - validate_database_name(database_name) - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - if charset is None and collation is None: - charset = 'utf8' - collation = 'en_US.utf8' - logger.warning("Creating database with utf8 charset and en_US.utf8 collation") - elif (not charset and collation) or (charset and not collation): - raise RequiredArgumentMissingError("charset and collation have to be input together.") - - parameters = { - 'name': database_name, - 'charset': charset, - 'collation': collation - } - - return client.begin_create( - resource_group_name, - server_name, - database_name, - parameters) - - # Custom functions for server logs -def backup_create_func(client, resource_group_name, server_name, backup_name): - validate_resource_group(resource_group_name) - validate_backup_name(backup_name) - - return client.begin_create( - resource_group_name, - server_name, - backup_name) - - -def ltr_precheck_func(client, resource_group_name, server_name, backup_name): - validate_resource_group(resource_group_name) - - return client.check_prerequisites( - resource_group_name=resource_group_name, - server_name=server_name, - parameters={"backupSettings": {"backupName": backup_name}} - ) - - -def ltr_start_func(client, resource_group_name, server_name, backup_name, sas_url): - validate_resource_group(resource_group_name) - - parameters = { - "backupSettings": { - "backupName": backup_name - }, - "targetDetails": { - "sasUriList": [sas_url] - } - } - - return client.begin_start( - resource_group_name=resource_group_name, - server_name=server_name, - parameters=parameters - ) - - -def backup_delete_func(client, resource_group_name, server_name, backup_name, yes=False): - validate_resource_group(resource_group_name) - - if not yes: - user_confirmation( - "Are you sure you want to delete the backup '{0}' in server '{1}'".format(backup_name, server_name), yes=yes) - - return client.begin_delete( - resource_group_name, - server_name, - backup_name) - - -def flexible_server_approve_private_endpoint_connection(cmd, client, resource_group_name, server_name, private_endpoint_connection_name, - description=None): - """Approve a private endpoint connection request for a server.""" - validate_resource_group(resource_group_name) - - return _update_private_endpoint_connection_status( - cmd, client, resource_group_name, server_name, private_endpoint_connection_name, is_approved=True, - description=description) - - -def flexible_server_reject_private_endpoint_connection(cmd, client, resource_group_name, server_name, private_endpoint_connection_name, - description=None): - """Reject a private endpoint connection request for a server.""" - validate_resource_group(resource_group_name) - - return _update_private_endpoint_connection_status( - cmd, client, resource_group_name, server_name, private_endpoint_connection_name, is_approved=False, - description=description) - - -def flexible_server_private_link_resource_get( - client, - resource_group_name, - server_name): - ''' - Gets a private link resource for a PostgreSQL flexible server. - ''' - validate_resource_group(resource_group_name) - - return client.get( - resource_group_name=resource_group_name, - server_name=server_name, - group_name="postgresqlServer") - - -def flexible_server_fabric_mirroring_start(cmd, client, resource_group_name, server_name, database_names, yes=False): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - flexible_servers_client = cf_postgres_flexible_servers(cmd.cli_ctx, '_') - server = flexible_servers_client.get(resource_group_name, server_name) - - if server.high_availability.mode != "Disabled" and server.version not in ["17", "18"]: - # disable fabric mirroring on HA server - raise CLIError("Fabric mirroring is not supported on servers with high availability enabled.") - - databases = ','.join(database_names) - user_confirmation("Are you sure you want to prepare and enable your server" + - " '{0}' in resource group '{1}' for mirroring of databases '{2}'.".format(server_name, resource_group_name, databases) + - " This requires restart.", yes=yes) - - if (server.identity is None or 'SystemAssigned' not in server.identity.type): - logger.warning('Enabling system assigned managed identity on the server.') - flexible_server_identity_update(cmd, flexible_servers_client, resource_group_name, server_name, 'Enabled') - - logger.warning('Updating necessary server parameters.') - source = "user-override" - configuration_name = "azure.fabric_mirror_enabled" - value = "on" - _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) - configuration_name = "azure.mirror_databases" - value = databases - return _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value) - - -def flexible_server_fabric_mirroring_stop(cmd, client, resource_group_name, server_name, yes=False): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - flexible_servers_client = cf_postgres_flexible_servers(cmd.cli_ctx, '_') - server = flexible_servers_client.get(resource_group_name, server_name) - - if server.high_availability.mode != "Disabled" and server.version not in ["17", "18"]: - # disable fabric mirroring on HA server - raise CLIError("Fabric mirroring is not supported on servers with high availability enabled.") - - user_confirmation("Are you sure you want to disable mirroring for server '{0}' in resource group '{1}'".format(server_name, resource_group_name), yes=yes) - - configuration_name = "azure.fabric_mirror_enabled" - parameters = postgresql_flexibleservers.models.Configuration( - value="off", - source="user-override" - ) - - return client.begin_update(resource_group_name, server_name, configuration_name, parameters) - - -def flexible_server_fabric_mirroring_update_databases(cmd, client, resource_group_name, server_name, database_names, yes=False): - validate_resource_group(resource_group_name) - validate_citus_cluster(cmd, resource_group_name, server_name) - - flexible_servers_client = cf_postgres_flexible_servers(cmd.cli_ctx, '_') - server = flexible_servers_client.get(resource_group_name, server_name) - - if server.high_availability.mode != "Disabled" and server.version not in ["17", "18"]: - # disable fabric mirroring on HA server - raise CLIError("Fabric mirroring is not supported on servers with high availability enabled.") - - databases = ','.join(database_names) - user_confirmation("Are you sure for server '{0}' in resource group '{1}' you want to update the databases being mirrored to be '{2}'" - .format(server_name, resource_group_name, databases), yes=yes) - - configuration_name = "azure.mirror_databases" - parameters = postgresql_flexibleservers.models.Configuration( - value=databases, - source="user-override" - ) - - return client.begin_update(resource_group_name, server_name, configuration_name, parameters) - - def _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value): parameters = postgresql_flexibleservers.models.Configuration( value=value, @@ -250,12 +63,6 @@ def _update_parameters(cmd, client, server_name, configuration_name, resource_gr client.begin_update(resource_group_name, server_name, configuration_name, parameters), cmd.cli_ctx, 'PostgreSQL Parameter update') -def flexible_server_migrate_network(client, resource_group_name, server_name, no_wait=False): - validate_resource_group(resource_group_name) - - return sdk_no_wait(no_wait, client.begin_migrate_network_mode, resource_group_name, server_name) - - def _update_private_endpoint_connection_status(cmd, client, resource_group_name, server_name, private_endpoint_connection_name, is_approved=True, description=None): # pylint: disable=unused-argument validate_resource_group(resource_group_name) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_power.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_power.py new file mode 100644 index 00000000000..6b391eb8071 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_power.py @@ -0,0 +1,84 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from ._github import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + +def flexible_server_restart(cmd, client, resource_group_name, server_name, fail_over=None): + validate_resource_group(resource_group_name) + instance = client.get(resource_group_name, server_name) + if fail_over is not None and instance.high_availability.mode not in ("ZoneRedundant", "SameZone"): + raise ArgumentUsageError("Failing over can only be triggered for zone redundant or same zone servers.") + + if fail_over is not None: + validate_citus_cluster(cmd, resource_group_name, server_name) + if fail_over.lower() not in ['planned', 'forced']: + raise InvalidArgumentValueError("Allowed failover parameters are 'Planned' and 'Forced'.") + if fail_over.lower() == 'planned': + fail_over = 'plannedFailover' + elif fail_over.lower() == 'forced': + fail_over = 'forcedFailover' + parameters = postgresql_flexibleservers.models.RestartParameter(restart_with_failover=True, + failover_mode=fail_over) + else: + parameters = postgresql_flexibleservers.models.RestartParameter(restart_with_failover=False) + + return resolve_poller( + client.begin_restart(resource_group_name, server_name, parameters), cmd.cli_ctx, 'PostgreSQL Server Restart') + + +def flexible_server_stop(client, resource_group_name=None, server_name=None, no_wait=False): + if not check_resource_group(resource_group_name): + resource_group_name = None + + days = 7 + logger.warning("Server will be automatically started after %d days " + "if you do not perform a manual start operation", days) + return sdk_no_wait(no_wait, client.begin_stop, resource_group_name, server_name) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_replica.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_replica.py new file mode 100644 index 00000000000..d11d25e3884 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_replica.py @@ -0,0 +1,90 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from ._github import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + +def flexible_replica_promote(cmd, client, resource_group_name, replica_name, promote_mode='standalone', promote_option='planned'): + validate_resource_group(resource_group_name) + if is_citus_cluster(cmd, resource_group_name, replica_name): + # some settings validation + if promote_mode.lower() == 'standalone': + raise ValidationError("Standalone replica promotion on elastic cluster isn't currently supported. Please use 'switchover' instead.") + if promote_option.lower() == 'planned': + raise ValidationError("Planned replica promotion on elastic cluster isn't currently supported. Please use 'forced' instead.") + + try: + server_object = client.get(resource_group_name, replica_name) + except Exception as e: + raise ResourceNotFoundError(e) + + if server_object.replica.role is not None and "replica" not in server_object.replica.role.lower(): + raise CLIError('Server {} is not a replica server.'.format(replica_name)) + + if promote_mode == "standalone": + params = postgresql_flexibleservers.models.ServerForPatch( + replica=postgresql_flexibleservers.models.Replica( + role='None', + promote_mode=promote_mode, + promote_option=promote_option + ) + ) + else: + params = postgresql_flexibleservers.models.ServerForPatch( + replica=postgresql_flexibleservers.models.Replica( + role='Primary', + promote_mode=promote_mode, + promote_option=promote_option + ) + ) + + return client.begin_update(resource_group_name, replica_name, params) + + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py index c05d954c4a1..3627e85d38c 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule +from ._github import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py index 0c79495e47f..40991420f71 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule +from ._github import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py index 16c3d76b29c..703112bcb02 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py @@ -38,8 +38,8 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule -from ._network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from ._github import create_firewall_rule +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/_network.py b/src/azure-cli/azure/cli/command_modules/postgresql/network_commands.py similarity index 98% rename from src/azure-cli/azure/cli/command_modules/postgresql/_network.py rename to src/azure-cli/azure/cli/command_modules/postgresql/network_commands.py index e0fac858385..6f5cf2cdaca 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/_network.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/network_commands.py @@ -9,7 +9,7 @@ from azure.mgmt.core.tools import is_valid_resource_id, parse_resource_id, is_valid_resource_name, resource_id # pylint: disable=import-error from azure.cli.core.commands import LongRunningOperation from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.util import CLIError, user_confirmation +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation from azure.cli.core.azclierror import ValidationError, RequiredArgumentMissingError from azure.mgmt.privatedns.models import PrivateZone from azure.mgmt.privatedns.models import SubResource @@ -30,6 +30,12 @@ IP_ADDRESS_CHECKER = 'https://api.ipify.org' +def flexible_server_migrate_network(client, resource_group_name, server_name, no_wait=False): + validate_resource_group(resource_group_name) + + return sdk_no_wait(no_wait, client.begin_migrate_network_mode, resource_group_name, server_name) + + # pylint: disable=too-many-locals, too-many-statements, too-many-branches, import-outside-toplevel def prepare_private_network(cmd, resource_group_name, server_name, vnet, subnet, location, delegation_service_name, vnet_address_pref, subnet_address_pref, yes): diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py index 890522c3c14..ce3a9c85b26 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule +from ._github import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py index 9960c55415a..6b391eb8071 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule +from ._github import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/private_endpoint_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/private_endpoint_commands.py new file mode 100644 index 00000000000..bccdbfb48f4 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/private_endpoint_commands.py @@ -0,0 +1,112 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from datetime import datetime, timedelta +import os +import json +from importlib import import_module +from functools import cmp_to_key +import re +from urllib.parse import quote +from urllib.request import urlretrieve +from dateutil.tz import tzutc # pylint: disable=import-error +import uuid +from knack.log import get_logger +from knack.prompting import ( + prompt +) +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id +from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ + cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ + cf_postgres_flexible_private_dns_zone_suffix_operations, \ + cf_postgres_flexible_private_endpoint_connections, \ + cf_postgres_flexible_tuning_options, \ + cf_postgres_flexible_config, cf_postgres_flexible_admin +from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ + generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ + _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ + get_postgres_tiers, get_postgres_skus +from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from ._util import get_autonomous_tuning_settings_map +from ._db_context import DbContext +from ._github import create_firewall_rule +from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ + validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ + validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ + validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + + +def flexible_server_approve_private_endpoint_connection(cmd, client, resource_group_name, server_name, private_endpoint_connection_name, + description=None): + """Approve a private endpoint connection request for a server.""" + validate_resource_group(resource_group_name) + + return _update_private_endpoint_connection_status( + cmd, client, resource_group_name, server_name, private_endpoint_connection_name, is_approved=True, + description=description) + + +def flexible_server_reject_private_endpoint_connection(cmd, client, resource_group_name, server_name, private_endpoint_connection_name, + description=None): + """Reject a private endpoint connection request for a server.""" + validate_resource_group(resource_group_name) + + return _update_private_endpoint_connection_status( + cmd, client, resource_group_name, server_name, private_endpoint_connection_name, is_approved=False, + description=description) + + +def _update_private_endpoint_connection_status(cmd, client, resource_group_name, server_name, + private_endpoint_connection_name, is_approved=True, description=None): # pylint: disable=unused-argument + validate_resource_group(resource_group_name) + + private_endpoint_connections_client = cf_postgres_flexible_private_endpoint_connections(cmd.cli_ctx, None) + private_endpoint_connection = private_endpoint_connections_client.get(resource_group_name=resource_group_name, + server_name=server_name, + private_endpoint_connection_name=private_endpoint_connection_name) + new_status = 'Approved' if is_approved else 'Rejected' + + private_link_service_connection_state = { + 'status': new_status, + 'description': description + } + + private_endpoint_connection.private_link_service_connection_state = private_link_service_connection_state + + return client.begin_update(resource_group_name=resource_group_name, + server_name=server_name, + private_endpoint_connection_name=private_endpoint_connection_name, + parameters=private_endpoint_connection) + + +def flexible_server_private_link_resource_get( + client, + resource_group_name, + server_name): + ''' + Gets a private link resource for a PostgreSQL flexible server. + ''' + validate_resource_group(resource_group_name) + + return client.get( + resource_group_name=resource_group_name, + server_name=server_name, + group_name="postgresqlServer") + + diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py index 7e984f8aa52..d11d25e3884 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule +from ._github import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py index 3da338881c0..75519c743a2 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py @@ -30,7 +30,7 @@ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin + cf_postgres_flexible_config, cf_postgres_flexible_admin, cf_postgres_flexible_replica from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule +from ._github import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ @@ -88,3 +88,83 @@ def flexible_server_list_log_files_with_filter(client, resource_group_name, serv return files +def flexible_server_log_list(client, resource_group_name, server_name, filename_contains=None, + file_last_written=None, max_file_size=None): + validate_resource_group(resource_group_name) + + all_files = client.list_by_server(resource_group_name, server_name) + files = [] + + if file_last_written is None: + file_last_written = 72 + time_line = datetime.utcnow().replace(tzinfo=tzutc()) - timedelta(hours=file_last_written) + + for f in all_files: + if f.last_modified_time < time_line: + continue + if filename_contains is not None and re.search(filename_contains, f.name) is None: + continue + if max_file_size is not None and f.size_in_kb > max_file_size: + continue + + del f.created_time + files.append(f) + + return files + + +def flexible_server_version_upgrade(cmd, client, resource_group_name, server_name, version, yes=None): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + if not yes: + user_confirmation( + "Upgrading major version in server {} is irreversible. The action you're about to take can't be undone. " + "Going further will initiate major version upgrade to the selected version on this server." + .format(server_name), yes=yes) + + instance = client.get(resource_group_name, server_name) + + current_version = int(instance.version.split('.')[0]) + if current_version >= int(version): + raise CLIError("The version to upgrade to must be greater than the current version.") + + list_server_capability_info = get_postgres_server_capability_info(cmd, resource_group_name, server_name) + eligible_versions = list_server_capability_info['supported_server_versions'][str(current_version)] + + if version == '13': + logger.warning("PostgreSQL version 13 will reach end-of-life (EOL) soon. " + "Upgrade to PostgreSQL 14 or later as soon as possible to " + "maintain security, performance, and supportability.") + + if version not in eligible_versions: + # version not supported + error_message = "" + if len(eligible_versions) > 0: + error_message = "Server is running version {}. It can only be upgraded to the following versions: {} ".format(str(current_version), eligible_versions) + else: + error_message = "Server is running version {}. It cannot be upgraded to any higher version. ".format(str(current_version)) + + raise CLIError(error_message) + + replica_operations_client = cf_postgres_flexible_replica(cmd.cli_ctx, '_') + version_mapped = version + + replicas = replica_operations_client.list_by_server(resource_group_name, server_name) + + if 'replica' in instance.replication_role.lower() or len(list(replicas)) > 0: + raise CLIError("Major version upgrade is not yet supported for servers in a read replica setup.") + + parameters = { + 'properties': { + 'version': version_mapped + } + } + + return resolve_poller( + client.begin_update( + resource_group_name=resource_group_name, + server_name=server_name, + parameters=parameters), + cmd.cli_ctx, 'Upgrading server {} to major version {}'.format(server_name, version) + ) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py index b31dd1aaa81..e2bf5f9b4a5 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule +from ._github import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/upgrade_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/upgrade_commands.py new file mode 100644 index 00000000000..7fb5a7aaeb5 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/upgrade_commands.py @@ -0,0 +1,80 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long + +import re +from datetime import datetime, timedelta +from dateutil.tz import tzutc +from knack.log import get_logger +from knack.util import CLIError +from urllib.request import urlretrieve +from azure.cli.core.util import sdk_no_wait, user_confirmation, run_cmd +from azure.cli.core.azclierror import ClientRequestError, RequiredArgumentMissingError +from ._client_factory import cf_postgres_flexible_replica +from ._flexible_server_util import run_subprocess, \ + fill_action_template, get_git_root_dir, resolve_poller, GITHUB_ACTION_PATH +from ._flexible_server_location_capabilities_util import get_postgres_server_capability_info +from .validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster + +logger = get_logger(__name__) +# pylint: disable=raise-missing-from + + +def flexible_server_version_upgrade(cmd, client, resource_group_name, server_name, version, yes=None): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + + if not yes: + user_confirmation( + "Upgrading major version in server {} is irreversible. The action you're about to take can't be undone. " + "Going further will initiate major version upgrade to the selected version on this server." + .format(server_name), yes=yes) + + instance = client.get(resource_group_name, server_name) + + current_version = int(instance.version.split('.')[0]) + if current_version >= int(version): + raise CLIError("The version to upgrade to must be greater than the current version.") + + list_server_capability_info = get_postgres_server_capability_info(cmd, resource_group_name, server_name) + eligible_versions = list_server_capability_info['supported_server_versions'][str(current_version)] + + if version == '13': + logger.warning("PostgreSQL version 13 will reach end-of-life (EOL) soon. " + "Upgrade to PostgreSQL 14 or later as soon as possible to " + "maintain security, performance, and supportability.") + + if version not in eligible_versions: + # version not supported + error_message = "" + if len(eligible_versions) > 0: + error_message = "Server is running version {}. It can only be upgraded to the following versions: {} ".format(str(current_version), eligible_versions) + else: + error_message = "Server is running version {}. It cannot be upgraded to any higher version. ".format(str(current_version)) + + raise CLIError(error_message) + + replica_operations_client = cf_postgres_flexible_replica(cmd.cli_ctx, '_') + version_mapped = version + + replicas = replica_operations_client.list_by_server(resource_group_name, server_name) + + if 'replica' in instance.replication_role.lower() or len(list(replicas)) > 0: + raise CLIError("Major version upgrade is not yet supported for servers in a read replica setup.") + + parameters = { + 'properties': { + 'version': version_mapped + } + } + + return resolve_poller( + client.begin_update( + resource_group_name=resource_group_name, + server_name=server_name, + parameters=parameters), + cmd.cli_ctx, 'Upgrading server {} to major version {}'.format(server_name, version) + ) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py index ee93c8ffec9..6a01787861d 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from .flexible_server_custom_common import create_firewall_rule +from ._github import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ From abbad079455937efca28aa57ff6494129ed25ab0 Mon Sep 17 00:00:00 2001 From: Naia Scott Date: Thu, 26 Feb 2026 16:04:35 -0500 Subject: [PATCH 04/10] clean up --- .../postgresql/autonomous_tuning_commands.py | 2 +- .../postgresql/backup_commands.py | 2 +- .../postgresql/custom_commands.py | 2 +- .../postgresql/database_commands.py | 2 +- .../{_github.py => deploy_commands.py} | 0 .../postgresql/fabric_mirroring_commands.py | 2 +- .../postgresql/flexible_server_custom.py | 2 +- .../flexible_server_custom_postgres.py | 2 +- .../postgresql/flexible_server_power.py | 84 ----------------- .../postgresql/flexible_server_replica.py | 90 ------------------- .../postgresql/identity_commands.py | 2 +- .../postgresql/microsoft_entra_commands.py | 2 +- .../postgresql/migration_commands.py | 2 +- .../postgresql/parameter_commands.py | 2 +- .../postgresql/power_commands.py | 2 +- .../postgresql/private_endpoint_commands.py | 2 +- .../postgresql/replica_commands.py | 2 +- .../postgresql/server_logs_commands.py | 2 +- .../postgresql/threat_protection_commands.py | 2 +- .../postgresql/virtual_endpoint_commands.py | 2 +- 20 files changed, 17 insertions(+), 191 deletions(-) rename src/azure-cli/azure/cli/command_modules/postgresql/{_github.py => deploy_commands.py} (100%) delete mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_power.py delete mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_replica.py diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py index 0357b9e0715..c5af27a6b05 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .parameter_commands import flexible_parameter_update, _update_parameters from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/backup_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/backup_commands.py index 8d3dc4ea56d..f4d0cdbcdc8 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/backup_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/backup_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py index 3e80109804d..4039ded8930 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_microsoft_entra import _create_admin from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/database_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/database_commands.py index 129f9667b96..035c4ff0171 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/database_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/database_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/_github.py b/src/azure-cli/azure/cli/command_modules/postgresql/deploy_commands.py similarity index 100% rename from src/azure-cli/azure/cli/command_modules/postgresql/_github.py rename to src/azure-cli/azure/cli/command_modules/postgresql/deploy_commands.py diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/fabric_mirroring_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/fabric_mirroring_commands.py index a3f4ba1e97b..1212e4d95a3 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/fabric_mirroring_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/fabric_mirroring_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py index b40cda13e25..3c7372b5ec4 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_microsoft_entra import _create_admin from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py index 9f5de686a95..28b4896d637 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_power.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_power.py deleted file mode 100644 index 6b391eb8071..00000000000 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_power.py +++ /dev/null @@ -1,84 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext -from ._github import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator - -logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' - -def flexible_server_restart(cmd, client, resource_group_name, server_name, fail_over=None): - validate_resource_group(resource_group_name) - instance = client.get(resource_group_name, server_name) - if fail_over is not None and instance.high_availability.mode not in ("ZoneRedundant", "SameZone"): - raise ArgumentUsageError("Failing over can only be triggered for zone redundant or same zone servers.") - - if fail_over is not None: - validate_citus_cluster(cmd, resource_group_name, server_name) - if fail_over.lower() not in ['planned', 'forced']: - raise InvalidArgumentValueError("Allowed failover parameters are 'Planned' and 'Forced'.") - if fail_over.lower() == 'planned': - fail_over = 'plannedFailover' - elif fail_over.lower() == 'forced': - fail_over = 'forcedFailover' - parameters = postgresql_flexibleservers.models.RestartParameter(restart_with_failover=True, - failover_mode=fail_over) - else: - parameters = postgresql_flexibleservers.models.RestartParameter(restart_with_failover=False) - - return resolve_poller( - client.begin_restart(resource_group_name, server_name, parameters), cmd.cli_ctx, 'PostgreSQL Server Restart') - - -def flexible_server_stop(client, resource_group_name=None, server_name=None, no_wait=False): - if not check_resource_group(resource_group_name): - resource_group_name = None - - days = 7 - logger.warning("Server will be automatically started after %d days " - "if you do not perform a manual start operation", days) - return sdk_no_wait(no_wait, client.begin_stop, resource_group_name, server_name) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_replica.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_replica.py deleted file mode 100644 index d11d25e3884..00000000000 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_replica.py +++ /dev/null @@ -1,90 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext -from ._github import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator - -logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' - -def flexible_replica_promote(cmd, client, resource_group_name, replica_name, promote_mode='standalone', promote_option='planned'): - validate_resource_group(resource_group_name) - if is_citus_cluster(cmd, resource_group_name, replica_name): - # some settings validation - if promote_mode.lower() == 'standalone': - raise ValidationError("Standalone replica promotion on elastic cluster isn't currently supported. Please use 'switchover' instead.") - if promote_option.lower() == 'planned': - raise ValidationError("Planned replica promotion on elastic cluster isn't currently supported. Please use 'forced' instead.") - - try: - server_object = client.get(resource_group_name, replica_name) - except Exception as e: - raise ResourceNotFoundError(e) - - if server_object.replica.role is not None and "replica" not in server_object.replica.role.lower(): - raise CLIError('Server {} is not a replica server.'.format(replica_name)) - - if promote_mode == "standalone": - params = postgresql_flexibleservers.models.ServerForPatch( - replica=postgresql_flexibleservers.models.Replica( - role='None', - promote_mode=promote_mode, - promote_option=promote_option - ) - ) - else: - params = postgresql_flexibleservers.models.ServerForPatch( - replica=postgresql_flexibleservers.models.Replica( - role='Primary', - promote_mode=promote_mode, - promote_option=promote_option - ) - ) - - return client.begin_update(resource_group_name, replica_name, params) - - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py index 3627e85d38c..5e723c2e9c2 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py index 40991420f71..bc50c6c5777 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py index 703112bcb02..0db3ed0fe59 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py index ce3a9c85b26..485ba151d8a 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py index 6b391eb8071..4399ff60213 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/private_endpoint_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/private_endpoint_commands.py index bccdbfb48f4..75608a5ed10 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/private_endpoint_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/private_endpoint_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py index d11d25e3884..cff01dabb4c 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py index 75519c743a2..47061414257 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py index e2bf5f9b4a5..f66e8d30ba5 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py index 6a01787861d..3b81a122d7f 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py @@ -38,7 +38,7 @@ from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info from ._util import get_autonomous_tuning_settings_map from ._db_context import DbContext -from ._github import create_firewall_rule +from .deploy_commands import create_firewall_rule from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ From 1a50fd39a1209119fec0ef5c134d5d610447e2a3 Mon Sep 17 00:00:00 2001 From: Naia Scott Date: Tue, 3 Mar 2026 18:21:11 -0500 Subject: [PATCH 05/10] Update folders --- .../cli/command_modules/postgresql/_params.py | 10 ++++------ .../{ => commands}/autonomous_tuning_commands.py | 14 +++++++------- .../postgresql/{ => commands}/backup_commands.py | 14 +++++++------- .../postgresql/{ => commands}/database_commands.py | 14 +++++++------- .../postgresql/{ => commands}/deploy_commands.py | 8 ++++---- .../{ => commands}/fabric_mirroring_commands.py | 14 +++++++------- .../{ => commands}/firewall_rule_commands.py | 8 ++++---- .../postgresql/{ => commands}/identity_commands.py | 14 +++++++------- .../{ => commands}/microsoft_entra_commands.py | 14 +++++++------- .../{ => commands}/migration_commands.py | 12 ++++++------ .../postgresql/{ => commands}/network_commands.py | 6 +++--- .../{ => commands}/parameter_commands.py | 14 +++++++------- .../postgresql/{ => commands}/power_commands.py | 14 +++++++------- .../{ => commands}/private_endpoint_commands.py | 14 +++++++------- .../postgresql/{ => commands}/replica_commands.py | 14 +++++++------- .../{ => commands}/server_logs_commands.py | 14 +++++++------- .../{ => commands}/threat_protection_commands.py | 14 +++++++------- .../postgresql/{ => commands}/upgrade_commands.py | 8 ++++---- .../{ => commands}/virtual_endpoint_commands.py | 14 +++++++------- .../postgresql/flexible_server_commands.py | 10 ++++------ .../_flexible_server_location_capabilities_util.py | 2 +- .../{ => utils}/_flexible_server_util.py | 2 +- .../postgresql/{ => utils}/_transformers.py | 0 .../postgresql/{ => utils}/_util.py | 0 .../postgresql/{ => utils}/validators.py | 2 +- 25 files changed, 123 insertions(+), 127 deletions(-) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/autonomous_tuning_commands.py (92%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/backup_commands.py (81%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/database_commands.py (83%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/deploy_commands.py (87%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/fabric_mirroring_commands.py (87%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/firewall_rule_commands.py (92%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/identity_commands.py (92%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/microsoft_entra_commands.py (83%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/migration_commands.py (93%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/network_commands.py (97%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/parameter_commands.py (82%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/power_commands.py (82%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/private_endpoint_commands.py (85%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/replica_commands.py (82%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/server_logs_commands.py (88%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/threat_protection_commands.py (83%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/upgrade_commands.py (87%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => commands}/virtual_endpoint_commands.py (84%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => utils}/_flexible_server_location_capabilities_util.py (98%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => utils}/_flexible_server_util.py (99%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => utils}/_transformers.py (100%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => utils}/_util.py (100%) rename src/azure-cli/azure/cli/command_modules/postgresql/{ => utils}/validators.py (99%) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/_params.py b/src/azure-cli/azure/cli/command_modules/postgresql/_params.py index 84da1f35bc4..1ac3157f4f4 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/_params.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/_params.py @@ -7,22 +7,20 @@ # pylint: disable=too-many-statements from knack.arguments import CLIArgumentType - +from argcomplete.completers import FilesCompleter from azure.cli.core.commands.parameters import ( tags_type, get_location_type, get_enum_type, file_type, resource_group_name_type, get_three_state_flag) -from azure.cli.command_modules.postgresql.validators import public_access_validator, maintenance_window_validator, ip_address_validator, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import get_current_time +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql.utils.validators import public_access_validator, maintenance_window_validator, ip_address_validator, \ retention_validator, validate_identity, validate_byok_identity, validate_identities, \ virtual_endpoint_name_validator, node_count_validator, postgres_firewall_rule_name_validator, \ db_renaming_cluster_validator from azure.cli.core.local_context import LocalContextAttribute, LocalContextAction - from .randomname.generate import generate_username -from ._flexible_server_util import get_current_time -from argcomplete.completers import FilesCompleter -from ._util import get_autonomous_tuning_settings_map def load_arguments(self, _): # pylint: disable=too-many-statements, too-many-locals diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/autonomous_tuning_commands.py similarity index 92% rename from src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/autonomous_tuning_commands.py index c5af27a6b05..eda4f5fc13f 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/autonomous_tuning_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/autonomous_tuning_commands.py @@ -25,23 +25,23 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource from .parameter_commands import flexible_parameter_update, _update_parameters -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/backup_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py similarity index 81% rename from src/azure-cli/azure/cli/command_modules/postgresql/backup_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py index f4d0cdbcdc8..5ac259a4274 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/backup_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/database_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/database_commands.py similarity index 83% rename from src/azure-cli/azure/cli/command_modules/postgresql/database_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/database_commands.py index 035c4ff0171..cc8653b649d 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/database_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/database_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/deploy_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/deploy_commands.py similarity index 87% rename from src/azure-cli/azure/cli/command_modules/postgresql/deploy_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/deploy_commands.py index 99a7b9401ee..c236511d9f9 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/deploy_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/deploy_commands.py @@ -13,11 +13,11 @@ from urllib.request import urlretrieve from azure.cli.core.util import sdk_no_wait, user_confirmation, run_cmd from azure.cli.core.azclierror import ClientRequestError, RequiredArgumentMissingError -from ._client_factory import cf_postgres_flexible_replica -from ._flexible_server_util import run_subprocess, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_replica +from azure.cli.command_modules.postgresql.utils._flexible_server_util import run_subprocess, \ fill_action_template, get_git_root_dir, resolve_poller, GITHUB_ACTION_PATH -from ._flexible_server_location_capabilities_util import get_postgres_server_capability_info -from .validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils.validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster logger = get_logger(__name__) # pylint: disable=raise-missing-from diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/fabric_mirroring_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/fabric_mirroring_commands.py similarity index 87% rename from src/azure-cli/azure/cli/command_modules/postgresql/fabric_mirroring_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/fabric_mirroring_commands.py index 1212e4d95a3..668177632cc 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/fabric_mirroring_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/fabric_mirroring_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/firewall_rule_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/firewall_rule_commands.py similarity index 92% rename from src/azure-cli/azure/cli/command_modules/postgresql/firewall_rule_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/firewall_rule_commands.py index 31c06d99ee4..0c7bb972874 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/firewall_rule_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/firewall_rule_commands.py @@ -13,11 +13,11 @@ from urllib.request import urlretrieve from azure.cli.core.util import sdk_no_wait, user_confirmation, run_cmd from azure.cli.core.azclierror import ClientRequestError, RequiredArgumentMissingError -from ._client_factory import cf_postgres_flexible_replica -from ._flexible_server_util import run_subprocess, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_replica +from azure.cli.command_modules.postgresql.utils._flexible_server_util import run_subprocess, \ fill_action_template, get_git_root_dir, resolve_poller, GITHUB_ACTION_PATH -from ._flexible_server_location_capabilities_util import get_postgres_server_capability_info -from .validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils.validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster logger = get_logger(__name__) # pylint: disable=raise-missing-from diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/identity_commands.py similarity index 92% rename from src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/identity_commands.py index 5e723c2e9c2..0ce543dc09d 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/identity_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/identity_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/microsoft_entra_commands.py similarity index 83% rename from src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/microsoft_entra_commands.py index bc50c6c5777..d567c6bcb33 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/microsoft_entra_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/microsoft_entra_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/migration_commands.py similarity index 93% rename from src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/migration_commands.py index 0db3ed0fe59..1af41fed457 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/migration_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/migration_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/network_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/network_commands.py similarity index 97% rename from src/azure-cli/azure/cli/command_modules/postgresql/network_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/network_commands.py index 6f5cf2cdaca..1ef0576256c 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/network_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/network_commands.py @@ -15,10 +15,10 @@ from azure.mgmt.privatedns.models import SubResource from azure.mgmt.privatedns.models import VirtualNetworkLink from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import resource_client_factory, private_dns_client_factory, private_dns_link_client_factory +from azure.cli.command_modules.postgresql._client_factory import resource_client_factory, private_dns_client_factory, private_dns_link_client_factory from ._config_reader import get_cloud_cluster -from ._flexible_server_util import get_id_components, check_existence, _is_resource_name, parse_public_access_input, get_user_confirmation, _check_resource_group_existence -from .validators import validate_private_dns_zone, validate_vnet_location, validate_resource_group +from azure.cli.command_modules.postgresql.utils._flexible_server_util import get_id_components, check_existence, _is_resource_name, parse_public_access_input, get_user_confirmation, _check_resource_group_existence +from azure.cli.command_modules.postgresql.utils.validators import validate_private_dns_zone, validate_vnet_location, validate_resource_group from .aaz.latest.network.vnet import Create as VNetCreate, Show as VNetShow, Update as _VNetUpdate from .aaz.latest.network.vnet.subnet import Create as SubnetCreate, Show as SubnetShow, Update as SubnetUpdate diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/parameter_commands.py similarity index 82% rename from src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/parameter_commands.py index 485ba151d8a..3e31344c323 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/parameter_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/parameter_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/power_commands.py similarity index 82% rename from src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/power_commands.py index 4399ff60213..84b6f60d1db 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/power_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/power_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/private_endpoint_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/private_endpoint_commands.py similarity index 85% rename from src/azure-cli/azure/cli/command_modules/postgresql/private_endpoint_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/private_endpoint_commands.py index 75608a5ed10..50b644896b5 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/private_endpoint_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/private_endpoint_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py similarity index 82% rename from src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py index cff01dabb4c..eade200de87 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/replica_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py similarity index 88% rename from src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py index 47061414257..bfde3d5eff6 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/server_logs_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin, cf_postgres_flexible_replica -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/threat_protection_commands.py similarity index 83% rename from src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/threat_protection_commands.py index f66e8d30ba5..927298708b7 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/threat_protection_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/threat_protection_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/upgrade_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/upgrade_commands.py similarity index 87% rename from src/azure-cli/azure/cli/command_modules/postgresql/upgrade_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/upgrade_commands.py index 7fb5a7aaeb5..e2e15a7bf2a 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/upgrade_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/upgrade_commands.py @@ -13,11 +13,11 @@ from urllib.request import urlretrieve from azure.cli.core.util import sdk_no_wait, user_confirmation, run_cmd from azure.cli.core.azclierror import ClientRequestError, RequiredArgumentMissingError -from ._client_factory import cf_postgres_flexible_replica -from ._flexible_server_util import run_subprocess, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_replica +from azure.cli.command_modules.postgresql.utils._flexible_server_util import run_subprocess, \ fill_action_template, get_git_root_dir, resolve_poller, GITHUB_ACTION_PATH -from ._flexible_server_location_capabilities_util import get_postgres_server_capability_info -from .validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils.validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster logger = get_logger(__name__) # pylint: disable=raise-missing-from diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/virtual_endpoint_commands.py similarity index 84% rename from src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py rename to src/azure-cli/azure/cli/command_modules/postgresql/commands/virtual_endpoint_commands.py index 3b81a122d7f..d506a514800 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/virtual_endpoint_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/virtual_endpoint_commands.py @@ -25,22 +25,22 @@ from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ cf_postgres_flexible_private_dns_zone_suffix_operations, \ cf_postgres_flexible_private_endpoint_connections, \ cf_postgres_flexible_tuning_options, \ cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ +from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map +from azure.cli.command_modules.postgresql._db_context import DbContext from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ +from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_commands.py index 2907292477f..72943549f97 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_commands.py @@ -3,9 +3,7 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -from azure.cli.command_modules.postgresql.validators import validate_private_endpoint_connection_id from azure.cli.core.commands import CliCommandType - from azure.cli.command_modules.postgresql._client_factory import ( cf_postgres_flexible_servers, cf_postgres_flexible_firewall_rules, @@ -23,8 +21,8 @@ cf_postgres_flexible_server_threat_protection_settings, cf_postgres_flexible_advanced_threat_protection_settings, cf_postgres_flexible_server_log_files) - -from ._transformers import ( +from azure.cli.command_modules.postgresql.utils.validators import validate_private_endpoint_connection_id +from azure.cli.command_modules.postgresql.utils._transformers import ( table_transform_output, table_transform_output_list_servers, postgres_table_transform_output_list_skus, @@ -32,8 +30,8 @@ transform_backup, transform_backups_list) -# from .transformers import table_transform_connection_string -# from .validators import db_up_namespace_processor +# from azure.cli.command_modules.postgresql.utils._transformers import table_transform_connection_string +# from azure.cli.command_modules.postgresql.utils.validators import db_up_namespace_processor # pylint: disable=too-many-locals, too-many-statements, line-too-long diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/_flexible_server_location_capabilities_util.py b/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_location_capabilities_util.py similarity index 98% rename from src/azure-cli/azure/cli/command_modules/postgresql/_flexible_server_location_capabilities_util.py rename to src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_location_capabilities_util.py index ee5dcfd1260..e4358cb3002 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/_flexible_server_location_capabilities_util.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_location_capabilities_util.py @@ -6,7 +6,7 @@ # pylint: disable=unused-argument, line-too-long, import-outside-toplevel, raise-missing-from from azure.cli.core.azclierror import InvalidArgumentValueError from azure.core.paging import ItemPaged -from ._client_factory import cf_postgres_flexible_location_capabilities, cf_postgres_flexible_server_capabilities +from .._client_factory import cf_postgres_flexible_location_capabilities, cf_postgres_flexible_server_capabilities from collections import defaultdict diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/_flexible_server_util.py b/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_util.py similarity index 99% rename from src/azure-cli/azure/cli/command_modules/postgresql/_flexible_server_util.py rename to src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_util.py index 0e20dceee23..15366ae430d 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/_flexible_server_util.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_util.py @@ -26,7 +26,7 @@ from azure.cli.command_modules.role.custom import create_service_principal_for_rbac from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers from azure.mgmt.resource.resources.models import ResourceGroup -from ._client_factory import resource_client_factory +from .._client_factory import resource_client_factory logger = get_logger(__name__) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/_transformers.py b/src/azure-cli/azure/cli/command_modules/postgresql/utils/_transformers.py similarity index 100% rename from src/azure-cli/azure/cli/command_modules/postgresql/_transformers.py rename to src/azure-cli/azure/cli/command_modules/postgresql/utils/_transformers.py diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/_util.py b/src/azure-cli/azure/cli/command_modules/postgresql/utils/_util.py similarity index 100% rename from src/azure-cli/azure/cli/command_modules/postgresql/_util.py rename to src/azure-cli/azure/cli/command_modules/postgresql/utils/_util.py diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/validators.py b/src/azure-cli/azure/cli/command_modules/postgresql/utils/validators.py similarity index 99% rename from src/azure-cli/azure/cli/command_modules/postgresql/validators.py rename to src/azure-cli/azure/cli/command_modules/postgresql/utils/validators.py index b1811bdb8dd..a43b82c093d 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/validators.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/utils/validators.py @@ -17,7 +17,7 @@ from azure.cli.core.util import parse_proxy_resource_id from azure.cli.core.profiles import ResourceType from azure.core.exceptions import HttpResponseError -from ._client_factory import (cf_postgres_flexible_servers, +from .._client_factory import (cf_postgres_flexible_servers, cf_postgres_check_resource_availability) from ._flexible_server_util import (get_postgres_skus, get_postgres_storage_sizes, get_postgres_tiers, _is_resource_name) From 1badf84ff95e48cb0a08a0540279925bcd4387b3 Mon Sep 17 00:00:00 2001 From: Naia Scott Date: Tue, 3 Mar 2026 19:03:55 -0500 Subject: [PATCH 06/10] CLean up files --- .../command_modules/postgresql/__init__.py | 2 +- .../command_modules/postgresql/_db_context.py | 3 +- .../commands/autonomous_tuning_commands.py | 56 +- .../postgresql/commands/backup_commands.py | 46 +- .../postgresql/commands/database_commands.py | 52 +- .../postgresql/commands/deploy_commands.py | 21 +- .../commands/fabric_mirroring_commands.py | 50 +- .../commands/firewall_rule_commands.py | 17 +- .../postgresql/commands/identity_commands.py | 50 +- .../commands/microsoft_entra_commands.py | 44 +- .../postgresql/commands/migration_commands.py | 60 +- .../postgresql/commands/network_commands.py | 51 +- .../postgresql/commands/parameter_commands.py | 50 +- .../postgresql/commands/power_commands.py | 49 +- .../commands/private_endpoint_commands.py | 50 +- .../postgresql/commands/replica_commands.py | 50 +- .../commands/server_logs_commands.py | 50 +- .../commands/threat_protection_commands.py | 50 +- .../postgresql/commands/upgrade_commands.py | 17 +- .../commands/virtual_endpoint_commands.py | 53 +- .../postgresql/custom_commands.py | 828 ------------------ .../postgresql/flexible_server_custom.py | 811 ----------------- .../flexible_server_custom_postgres.py | 291 ------ .../postgresql/utils/validators.py | 38 +- 24 files changed, 170 insertions(+), 2619 deletions(-) delete mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py delete mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py delete mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/__init__.py b/src/azure-cli/azure/cli/command_modules/postgresql/__init__.py index 223a14c14c4..8f35df566b3 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/__init__.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/__init__.py @@ -7,7 +7,7 @@ from azure.cli.core import ModExtensionSuppress from azure.cli.core.commands import CliCommandType from azure.cli.core.profiles import ResourceType -from azure.cli.command_modules.postgresql._util import PostgreSQLArgumentContext +from azure.cli.command_modules.postgresql.utils._util import PostgreSQLArgumentContext from azure.cli.command_modules.postgresql.flexible_server_commands import load_flexibleserver_command_table from azure.cli.command_modules.postgresql._params import load_arguments import azure.cli.command_modules.postgresql._help # pylint: disable=unused-import diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/_db_context.py b/src/azure-cli/azure/cli/command_modules/postgresql/_db_context.py index 9f805eea23c..0c60d8317a6 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/_db_context.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/_db_context.py @@ -4,9 +4,10 @@ # -------------------------------------------------------------------------------------------- +# pylint: disable=too-many-instance-attributes, too-few-public-methods class DbContext: """Database context class for PostgreSQL flexible server operations. - + This class serves as a context container for various database-related configurations, factory functions, and clients used throughout PostgreSQL command operations. """ diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/autonomous_tuning_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/autonomous_tuning_commands.py index eda4f5fc13f..e1ff5d93670 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/autonomous_tuning_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/autonomous_tuning_commands.py @@ -4,53 +4,21 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info +from azure.cli.command_modules.postgresql._client_factory import \ + get_postgresql_flexible_management_client, \ + cf_postgres_flexible_tuning_options +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import \ + get_postgres_location_capability_info, \ + get_postgres_server_capability_info from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource +from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.util import CLIError +from knack.log import get_logger from .parameter_commands import flexible_parameter_update, _update_parameters -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + def index_tuning_update(cmd, client, resource_group_name, server_name, index_tuning_enabled): validate_resource_group(resource_group_name) @@ -228,5 +196,3 @@ def autonomous_tuning_table_recommendations_list(cmd, resource_group_name, serve tuning_option="table", recommendation_type=recommendation_type ) - - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py index 5ac259a4274..612aae1ebb8 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py @@ -4,52 +4,11 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid +from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group, validate_backup_name +from azure.cli.core.util import user_confirmation from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' def backup_create_func(client, resource_group_name, server_name, backup_name): @@ -102,4 +61,3 @@ def backup_delete_func(client, resource_group_name, server_name, backup_name, ye resource_group_name, server_name, backup_name) - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/database_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/database_commands.py index cc8653b649d..214d6934f02 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/database_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/database_commands.py @@ -4,52 +4,16 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid +from azure.cli.command_modules.postgresql.utils.validators import \ + validate_resource_group, \ + check_resource_group, \ + validate_citus_cluster, \ + validate_database_name +from azure.cli.core.azclierror import RequiredArgumentMissingError +from azure.cli.core.util import CLIError, user_confirmation from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' def database_create_func(cmd, client, resource_group_name, server_name, database_name=None, charset=None, collation=None): @@ -98,5 +62,3 @@ def database_delete_func(cmd, client, resource_group_name=None, server_name=None except Exception as ex: # pylint: disable=broad-except logger.error(ex) return result - - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/deploy_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/deploy_commands.py index c236511d9f9..2a0ba844d55 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/deploy_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/deploy_commands.py @@ -4,20 +4,15 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long - -import re -from datetime import datetime, timedelta -from dateutil.tz import tzutc -from knack.log import get_logger -from knack.util import CLIError -from urllib.request import urlretrieve -from azure.cli.core.util import sdk_no_wait, user_confirmation, run_cmd +from azure.cli.command_modules.postgresql.utils._flexible_server_util import \ + run_subprocess, \ + fill_action_template, \ + get_git_root_dir, \ + GITHUB_ACTION_PATH +from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group from azure.cli.core.azclierror import ClientRequestError, RequiredArgumentMissingError -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_replica -from azure.cli.command_modules.postgresql.utils._flexible_server_util import run_subprocess, \ - fill_action_template, get_git_root_dir, resolve_poller, GITHUB_ACTION_PATH -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils.validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster +from azure.cli.core.util import run_cmd +from knack.log import get_logger logger = get_logger(__name__) # pylint: disable=raise-missing-from diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/fabric_mirroring_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/fabric_mirroring_commands.py index 668177632cc..038be3e2bfd 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/fabric_mirroring_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/fabric_mirroring_commands.py @@ -4,52 +4,15 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_servers +from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group, validate_citus_cluster +from azure.cli.core.util import CLIError, user_confirmation from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator +from knack.log import get_logger +from .identity_commands import flexible_server_identity_update +from .parameter_commands import _update_parameters logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' def flexible_server_fabric_mirroring_start(cmd, client, resource_group_name, server_name, database_names, yes=False): @@ -125,4 +88,3 @@ def flexible_server_fabric_mirroring_update_databases(cmd, client, resource_grou ) return client.begin_update(resource_group_name, server_name, configuration_name, parameters) - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/firewall_rule_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/firewall_rule_commands.py index 0c7bb972874..acfd0a89792 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/firewall_rule_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/firewall_rule_commands.py @@ -4,20 +4,11 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long - -import re -from datetime import datetime, timedelta -from dateutil.tz import tzutc +from azure.cli.command_modules.postgresql.utils.validators import validate_public_access_server, validate_resource_group +from azure.cli.core.util import user_confirmation +from datetime import datetime from knack.log import get_logger from knack.util import CLIError -from urllib.request import urlretrieve -from azure.cli.core.util import sdk_no_wait, user_confirmation, run_cmd -from azure.cli.core.azclierror import ClientRequestError, RequiredArgumentMissingError -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_replica -from azure.cli.command_modules.postgresql.utils._flexible_server_util import run_subprocess, \ - fill_action_template, get_git_root_dir, resolve_poller, GITHUB_ACTION_PATH -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils.validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster logger = get_logger(__name__) # pylint: disable=raise-missing-from @@ -135,5 +126,3 @@ def create_firewall_rule(db_context, cmd, resource_group_name, server_name, star server_name=server_name, start_ip_address=start_ip, end_ip_address=end_ip) return firewall.result().name - - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/identity_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/identity_commands.py index 0ce543dc09d..1fc96c665e2 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/identity_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/identity_commands.py @@ -4,52 +4,12 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_config +from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller +from azure.cli.command_modules.postgresql.utils.validators import validate_citus_cluster, validate_resource_group +from azure.cli.core.util import CLIError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator - -logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + def flexible_server_identity_update(cmd, client, resource_group_name, server_name, system_assigned): validate_resource_group(resource_group_name) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/microsoft_entra_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/microsoft_entra_commands.py index d567c6bcb33..663b18bacb8 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/microsoft_entra_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/microsoft_entra_commands.py @@ -4,46 +4,10 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_servers +from azure.cli.command_modules.postgresql.utils._flexible_server_util import get_tenant_id +from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group +from azure.cli.core.util import CLIError, sdk_no_wait def flexible_server_microsoft_entra_admin_set(cmd, client, resource_group_name, server_name, login, sid, principal_type=None, no_wait=False): diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/migration_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/migration_commands.py index 1af41fed457..0ee4480f8be 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/migration_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/migration_commands.py @@ -4,52 +4,32 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error +import os import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt + +from azure.cli.command_modules.postgresql.utils._flexible_server_util import ( + generate_missing_parameters, + get_case_insensitive_key_value, + get_enum_value_true_false, +) +from azure.cli.command_modules.postgresql.utils.validators import ( + validate_citus_cluster, + validate_migration_runtime_server, + validate_resource_group, +) +from azure.cli.core.azclierror import ( + BadRequestError, + FileOperationError, + MutuallyExclusiveArgumentError, + RequiredArgumentMissingError, ) from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator +from knack.log import get_logger logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + def migration_create_func(cmd, client, resource_group_name, server_name, properties, migration_mode="offline", migration_name=None, migration_option=None, tags=None, location=None): @@ -186,5 +166,3 @@ def migration_check_name_availability(cmd, client, resource_group_name, server_n migration_name_availability_parammeters = {"name": "%s" % migration_name, "type": "Microsoft.DBforPostgreSQL/flexibleServers/migrations"} return client.check_name_availability(resource_group_name, server_name, migration_name_availability_parammeters) - - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/network_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/network_commands.py index 1ef0576256c..f1260dad11c 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/network_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/network_commands.py @@ -4,24 +4,51 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long, import-outside-toplevel -from requests import get -from knack.log import get_logger -from azure.mgmt.core.tools import is_valid_resource_id, parse_resource_id, is_valid_resource_name, resource_id # pylint: disable=import-error +from azure.cli.command_modules.postgresql._client_factory import ( + private_dns_client_factory, + private_dns_link_client_factory, + resource_client_factory, +) +from azure.cli.command_modules.postgresql._config_reader import get_cloud_cluster +from azure.cli.command_modules.postgresql.aaz.latest.network.vnet import ( + Create as VNetCreate, + Show as VNetShow, + Update as _VNetUpdate, +) +from azure.cli.command_modules.postgresql.aaz.latest.network.vnet.subnet import ( + Create as SubnetCreate, + Show as SubnetShow, + Update as SubnetUpdate, +) +from azure.cli.command_modules.postgresql.utils._flexible_server_util import ( + _check_resource_group_existence, + _is_resource_name, + check_existence, + get_id_components, + get_user_confirmation, + parse_public_access_input, +) +from azure.cli.command_modules.postgresql.utils.validators import ( + validate_private_dns_zone, + validate_resource_group, + validate_vnet_location, +) +from azure.cli.core.azclierror import RequiredArgumentMissingError, ValidationError from azure.cli.core.commands import LongRunningOperation from azure.cli.core.commands.client_factory import get_subscription_id from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.cli.core.azclierror import ValidationError, RequiredArgumentMissingError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from azure.mgmt.core.tools import ( # pylint: disable=import-error + is_valid_resource_id, + is_valid_resource_name, + parse_resource_id, + resource_id, +) from azure.mgmt.privatedns.models import PrivateZone from azure.mgmt.privatedns.models import SubResource from azure.mgmt.privatedns.models import VirtualNetworkLink -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import resource_client_factory, private_dns_client_factory, private_dns_link_client_factory -from ._config_reader import get_cloud_cluster -from azure.cli.command_modules.postgresql.utils._flexible_server_util import get_id_components, check_existence, _is_resource_name, parse_public_access_input, get_user_confirmation, _check_resource_group_existence -from azure.cli.command_modules.postgresql.utils.validators import validate_private_dns_zone, validate_vnet_location, validate_resource_group - -from .aaz.latest.network.vnet import Create as VNetCreate, Show as VNetShow, Update as _VNetUpdate -from .aaz.latest.network.vnet.subnet import Create as SubnetCreate, Show as SubnetShow, Update as SubnetUpdate +from knack.log import get_logger +from requests import get logger = get_logger(__name__) DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/parameter_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/parameter_commands.py index 3e31344c323..5f9e3f09184 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/parameter_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/parameter_commands.py @@ -4,52 +4,11 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller +from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group +from azure.cli.core.util import CLIError +from azure.core.exceptions import HttpResponseError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator - -logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' def flexible_parameter_update(client, server_name, configuration_name, resource_group_name, source=None, value=None): @@ -81,6 +40,7 @@ def flexible_parameter_update(client, server_name, configuration_name, resource_ return client.begin_update(resource_group_name, server_name, configuration_name, parameters) + def _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value): parameters = postgresql_flexibleservers.models.Configuration( value=value, diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/power_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/power_commands.py index 84b6f60d1db..668910c6025 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/power_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/power_commands.py @@ -4,52 +4,15 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller +from azure.cli.command_modules.postgresql.utils.validators import check_resource_group, validate_citus_cluster, validate_resource_group +from azure.cli.core.azclierror import ArgumentUsageError, InvalidArgumentValueError +from azure.cli.core.util import sdk_no_wait from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator +from knack.log import get_logger logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + def flexible_server_restart(cmd, client, resource_group_name, server_name, fail_over=None): validate_resource_group(resource_group_name) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/private_endpoint_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/private_endpoint_commands.py index 50b644896b5..9b797befc9f 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/private_endpoint_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/private_endpoint_commands.py @@ -4,52 +4,8 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator - -logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_private_endpoint_connections +from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group def flexible_server_approve_private_endpoint_connection(cmd, client, resource_group_name, server_name, private_endpoint_connection_name, @@ -108,5 +64,3 @@ def flexible_server_private_link_resource_get( resource_group_name=resource_group_name, server_name=server_name, group_name="postgresqlServer") - - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py index eade200de87..336a9575770 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py @@ -4,52 +4,12 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError +from azure.cli.command_modules.postgresql.utils.validators import is_citus_cluster, validate_resource_group +from azure.cli.core.azclierror import ValidationError +from azure.cli.core.util import CLIError +from azure.core.exceptions import ResourceNotFoundError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator -logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' def flexible_replica_promote(cmd, client, resource_group_name, replica_name, promote_mode='standalone', promote_option='planned'): validate_resource_group(resource_group_name) @@ -86,5 +46,3 @@ def flexible_replica_promote(cmd, client, resource_group_name, replica_name, pro ) return client.begin_update(resource_group_name, replica_name, params) - - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py index bfde3d5eff6..57b4916a971 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py @@ -4,52 +4,20 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key import re -from urllib.parse import quote -from urllib.request import urlretrieve + +from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_replica +from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_server_capability_info +from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller +from azure.cli.command_modules.postgresql.utils.validators import validate_citus_cluster, validate_resource_group +from azure.cli.core.util import CLIError, user_confirmation +from datetime import datetime, timedelta from dateutil.tz import tzutc # pylint: disable=import-error -import uuid from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin, cf_postgres_flexible_replica -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator +from urllib.request import urlretrieve logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + def flexible_server_download_log_files(client, resource_group_name, server_name, file_name): validate_resource_group(resource_group_name) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/threat_protection_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/threat_protection_commands.py index 927298708b7..cb79d4ccf84 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/threat_protection_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/threat_protection_commands.py @@ -4,52 +4,10 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator +from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller +from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group +from azure.core.exceptions import HttpResponseError -logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' def flexible_server_threat_protection_get( client, @@ -116,5 +74,3 @@ def flexible_server_threat_protection_set( parameters=parameters), cmd.cli_ctx, 'PostgreSQL Flexible Server Advanced Threat Protection Setting Update') - - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/upgrade_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/upgrade_commands.py index e2e15a7bf2a..e41c2b94b1e 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/upgrade_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/upgrade_commands.py @@ -4,20 +4,13 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long - -import re -from datetime import datetime, timedelta -from dateutil.tz import tzutc -from knack.log import get_logger -from knack.util import CLIError -from urllib.request import urlretrieve -from azure.cli.core.util import sdk_no_wait, user_confirmation, run_cmd -from azure.cli.core.azclierror import ClientRequestError, RequiredArgumentMissingError from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_replica -from azure.cli.command_modules.postgresql.utils._flexible_server_util import run_subprocess, \ - fill_action_template, get_git_root_dir, resolve_poller, GITHUB_ACTION_PATH from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils.validators import validate_public_access_server, validate_resource_group, check_resource_group, validate_citus_cluster +from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller +from azure.cli.command_modules.postgresql.utils.validators import validate_citus_cluster, validate_resource_group +from azure.cli.core.util import user_confirmation +from knack.log import get_logger +from knack.util import CLIError logger = get_logger(__name__) # pylint: disable=raise-missing-from diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/virtual_endpoint_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/virtual_endpoint_commands.py index d506a514800..f6875ba108f 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/virtual_endpoint_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/virtual_endpoint_commands.py @@ -4,52 +4,13 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt +from azure.cli.command_modules.postgresql.utils.validators import ( + validate_citus_cluster, + validate_resource_group, + validate_virtual_endpoint_name_availability, ) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from azure.cli.command_modules.postgresql.utils._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .network_commands import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from azure.cli.command_modules.postgresql.utils.validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator - -logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' +from azure.cli.core.util import user_confirmation + def virtual_endpoint_create_func(cmd, client, resource_group_name, server_name, virtual_endpoint_name, endpoint_type, members): validate_resource_group(resource_group_name) @@ -120,5 +81,3 @@ def virtual_endpoint_update_func(cmd, client, resource_group_name, server_name, server_name, virtual_endpoint_name, parameters) - - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py deleted file mode 100644 index 4039ded8930..00000000000 --- a/src/azure-cli/azure/cli/command_modules/postgresql/custom_commands.py +++ /dev/null @@ -1,828 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .flexible_server_microsoft_entra import _create_admin -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator - -logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' - - -# region create without args -# pylint: disable=too-many-locals -# pylint: disable=too-many-statements -# pylint: disable=raise-missing-from, unbalanced-tuple-unpacking -def flexible_server_create(cmd, client, - resource_group_name=None, server_name=None, - location=None, backup_retention=None, - sku_name=None, tier=None, - storage_gb=None, version=None, microsoft_entra_auth=None, - admin_name=None, admin_id=None, admin_type=None, - password_auth=None, administrator_login=None, administrator_login_password=None, - tags=None, subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, - private_dns_zone_arguments=None, public_access=None, - high_availability=None, zonal_resiliency=None, allow_same_zone=False, - zone=None, standby_availability_zone=None, - geo_redundant_backup=None, byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, - auto_grow=None, performance_tier=None, - storage_type=None, iops=None, throughput=None, create_cluster=None, cluster_size=None, database_name=None, yes=False): - - if not check_resource_group(resource_group_name): - resource_group_name = None - - # Generate missing parameters - location, resource_group_name, server_name = generate_missing_parameters(cmd, location, resource_group_name, - server_name, 'postgres') - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - server_name = server_name.lower() - high_availability_mode = high_availability - - if (sku_name is None) or (version is None) or \ - (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): - list_location_capability_info = get_postgres_location_capability_info(cmd, location) - - # set sku_name from capability API - if sku_name is None: - tiers = [item.lower() for item in get_postgres_tiers(list_location_capability_info['sku_info'])] - try: - sku_info = list_location_capability_info['sku_info'] - skus = list(get_postgres_skus(sku_info, tier.lower())) - skus = sorted(skus, key=cmp_to_key(compare_sku_names)) - sku_name = skus[0] - except: - raise CLIError('Incorrect value for --tier. Allowed values : {}'.format(tiers)) - # default to the latest version - if version is None: - supported_server_versions = sorted(list_location_capability_info['supported_server_versions']) - version = supported_server_versions[-1] - # set high availability from capability API - if (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): - single_az = list_location_capability_info['single_az'] - high_availability_mode = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' - - pg_arguments_validator(db_context, - server_name=server_name, - location=location, - tier=tier, sku_name=sku_name, - storage_gb=storage_gb, - auto_grow=auto_grow, - storage_type=storage_type, - iops=iops, throughput=throughput, - high_availability=high_availability, - zonal_resiliency=zonal_resiliency, - allow_same_zone=allow_same_zone, - standby_availability_zone=standby_availability_zone, - zone=zone, - subnet=subnet, - public_access=public_access, - version=version, - geo_redundant_backup=geo_redundant_backup, - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key, - performance_tier=performance_tier, - create_cluster=create_cluster, - password_auth=password_auth, microsoft_entra_auth=microsoft_entra_auth, - admin_name=admin_name, admin_id=admin_id, admin_type=admin_type,) - - cluster = None - if create_cluster == 'ElasticCluster': - cluster_size = cluster_size if cluster_size else 2 - cluster = postgresql_flexibleservers.models.Cluster(cluster_size=cluster_size, default_database_name=database_name if database_name else POSTGRES_DB_NAME) - - server_result = firewall_id = None - - network, start_ip, end_ip = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access=public_access, - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - - storage = postgresql_flexibleservers.models.Storage(storage_size_gb=storage_gb, auto_grow=auto_grow, tier=performance_tier, type=storage_type, iops=iops, throughput=throughput) - - backup = postgresql_flexibleservers.models.Backup(backup_retention_days=backup_retention, - geo_redundant_backup=geo_redundant_backup) - - sku = postgresql_flexibleservers.models.Sku(name=sku_name, tier=tier) - - high_availability = postgresql_flexibleservers.models.HighAvailability(mode=high_availability_mode, - standby_availability_zone=standby_availability_zone) - - is_password_auth_enabled = bool(password_auth is not None and password_auth.lower() == 'enabled') - is_microsoft_entra_auth_enabled = bool(microsoft_entra_auth is not None and microsoft_entra_auth.lower() == 'enabled') - if is_password_auth_enabled: - administrator_login_password = generate_password(administrator_login_password) - - identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - auth_config = postgresql_flexibleservers.models.AuthConfig(active_directory_auth='Enabled' if is_microsoft_entra_auth_enabled else 'Disabled', - password_auth=password_auth) - - # Create postgresql - # Note : passing public_access has no effect as the accepted values are 'Enabled' and 'Disabled'. So the value ends up being ignored. - server_result = _create_server(db_context, cmd, resource_group_name, server_name, - tags=tags, - location=location, - sku=sku, - administrator_login=administrator_login, - administrator_login_password=administrator_login_password, - storage=storage, - backup=backup, - network=network, - version=version, - high_availability=high_availability, - availability_zone=zone, - identity=identity, - data_encryption=data_encryption, - auth_config=auth_config, - cluster=cluster) - - # Add Microsoft Entra Admin - if is_microsoft_entra_auth_enabled and admin_name is not None or admin_id is not None: - server_admin_client = cf_postgres_flexible_admin(cmd.cli_ctx, '_') - logger.warning("Add Microsoft Entra Admin '%s'.", admin_name) - _create_admin(server_admin_client, resource_group_name, server_name, admin_name, admin_id, admin_type) - - # Adding firewall rule - if start_ip != -1 and end_ip != -1: - firewall_id = create_firewall_rule(db_context, cmd, resource_group_name, server_name, start_ip, end_ip) - - user = server_result.administrator_login if is_password_auth_enabled else '' - password = administrator_login_password if is_password_auth_enabled else '' - admin = quote(admin_name) if admin_name else '' - server_id = server_result.id - loc = server_result.location - version = server_result.version - sku = server_result.sku.name - host = server_result.fully_qualified_domain_name - subnet_id = None if network is None else network.delegated_subnet_resource_id - - if is_password_auth_enabled: - logger.warning('Make a note of your password. If you forget, you would have to ' - 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', - server_name, resource_group_name) - logger.warning('Try using \'az postgres flexible-server connect\' command to test out connection.') - - _update_local_contexts(cmd, server_name, resource_group_name, location, user) - - return _form_response(user, sku, loc, server_id, host, version, password, - firewall_id, subnet_id, is_password_auth_enabled, is_microsoft_entra_auth_enabled, admin_name) - - -def _create_server(db_context, cmd, resource_group_name, server_name, tags, location, sku, administrator_login, administrator_login_password, - storage, backup, network, version, high_availability, availability_zone, identity, data_encryption, auth_config, cluster): - validate_resource_group(resource_group_name) - - logging_name, server_client = db_context.logging_name, db_context.server_client - logger.warning('Creating %s Server \'%s\' in group \'%s\'...', logging_name, server_name, resource_group_name) - - logger.warning('Your server \'%s\' is using sku \'%s\' (Paid Tier). ' - 'Please refer to https://aka.ms/postgres-pricing for pricing details', server_name, sku.name) - - # Note : passing public-network-access has no effect as the accepted values are 'Enabled' and 'Disabled'. - # So when you pass an IP here(from the CLI args of public_access), it ends up being ignored. - parameters = postgresql_flexibleservers.models.Server( - tags=tags, - location=location, - sku=sku, - administrator_login=administrator_login, - administrator_login_password=administrator_login_password, - storage=storage, - backup=backup, - network=network, - version=version, - high_availability=high_availability, - availability_zone=availability_zone, - identity=identity, - data_encryption=data_encryption, - auth_config=auth_config, - cluster=cluster, - create_mode="Create") - - return resolve_poller( - server_client.begin_create_or_update(resource_group_name, server_name, parameters), cmd.cli_ctx, - '{} Server Create'.format(logging_name)) - - -def _update_local_contexts(cmd, server_name, resource_group_name, location, user): - validate_resource_group(resource_group_name) - - if cmd.cli_ctx.local_context.is_on: - cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'server_name', - server_name) # Setting the server name in the local context - cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'administrator_login', - user) # Setting the server name in the local context - cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'database_name', - POSTGRES_DB_NAME) # Setting the server name in the local context - cmd.cli_ctx.local_context.set([ALL], 'location', - location) # Setting the location in the local context - cmd.cli_ctx.local_context.set([ALL], 'resource_group_name', resource_group_name) - - -def _form_response(username, sku, location, server_id, host, version, password, firewall_id=None, - subnet_id=None, is_password_auth=True, is_microsoft_entra_auth_enabled=False, microsoft_admin=None): - - connection_kwargs = { - 'user': username if username is not None else '{user}', - 'host': host, - 'password': password if password is not None else '{password}', - 'database': POSTGRES_DB_NAME, - } - output = { - 'host': host, - 'username': username if is_password_auth else None, - 'password': password if is_password_auth else None, - 'skuname': sku, - 'location': location, - 'id': server_id, - 'version': version, - 'databaseName': POSTGRES_DB_NAME, - 'connectionString': 'postgresql://{user}:{password}@{host}/{database}?sslmode=require'.format(**connection_kwargs) - } - if is_microsoft_entra_auth_enabled: - user = quote(microsoft_admin) if microsoft_admin else '' - connection_kwargs = { - 'user': user, - 'host': host, - 'database': POSTGRES_DB_NAME, - } - output['admin'] = microsoft_admin - output['connectionStringMicrosoftEntra'] = 'postgresql://{user}:@{host}/{database}?sslmode=require'.format(**connection_kwargs) - if firewall_id is not None: - output['firewallName'] = firewall_id - if subnet_id is not None: - output['subnetId'] = subnet_id - return output - - -def flexible_server_restore(cmd, client, - resource_group_name, server_name, - source_server, restore_point_in_time=None, zone=None, no_wait=False, - subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, - private_dns_zone_arguments=None, geo_redundant_backup=None, - byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, storage_type=None, yes=False): - - server_name = server_name.lower() - - validate_resource_group(resource_group_name) - - if not is_valid_resource_id(source_server): - if len(source_server.split('/')) == 1: - source_server_id = resource_id( - subscription=get_subscription_id(cmd.cli_ctx), - resource_group=resource_group_name, - namespace=RESOURCE_PROVIDER, - type='flexibleServers', - name=source_server) - else: - raise ValueError('The provided source server {} is invalid.'.format(source_server)) - else: - source_server_id = source_server - - restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) - - try: - id_parts = parse_resource_id(source_server_id) - source_subscription_id = id_parts['subscription'] - postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) - source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) - - location = ''.join(source_server_object.location.lower().split()) - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') - - pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) - - pg_restore_validator(source_server_object.sku.tier, storage_type=storage_type) - storage = postgresql_flexibleservers.models.Storage(type=storage_type if source_server_object.storage.type != "PremiumV2_LRS" else None) - - parameters = postgresql_flexibleservers.models.Server( - location=location, - point_in_time_utc=restore_point_in_time, - source_server_resource_id=source_server_id, # this should be the source server name, not id - create_mode="PointInTimeRestore", - availability_zone=zone, - storage=storage - ) - - if source_server_object.network.public_network_access == 'Disabled' and any((vnet, subnet)): - parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access='Disabled', - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - else: - parameters.network = source_server_object.network - - parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) - - parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - except Exception as e: - raise ResourceNotFoundError(e) - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) - - -# pylint: disable=too-many-branches -def flexible_server_update_custom_func(cmd, client, instance, - sku_name=None, tier=None, - storage_gb=None, - backup_retention=None, - administrator_login_password=None, - high_availability=None, - zonal_resiliency=None, - allow_same_zone=False, - standby_availability_zone=None, - maintenance_window=None, - byok_identity=None, byok_key=None, - backup_byok_identity=None, backup_byok_key=None, - microsoft_entra_auth=None, password_auth=None, - private_dns_zone_arguments=None, - public_access=None, - tags=None, - auto_grow=None, - performance_tier=None, - iops=None, throughput=None, - cluster_size=None, yes=False): - - # validator - location = ''.join(instance.location.lower().split()) - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - pg_arguments_validator(db_context, - location=location, - tier=tier, - sku_name=sku_name, - storage_gb=storage_gb, - auto_grow=auto_grow, - iops=iops, - throughput=throughput, - high_availability=high_availability, - zonal_resiliency=zonal_resiliency, - allow_same_zone=allow_same_zone, - zone=instance.availability_zone, - standby_availability_zone=standby_availability_zone, - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key, - performance_tier=performance_tier, - cluster_size=cluster_size, instance=instance) - - server_module_path = instance.__module__ - module = import_module(server_module_path) - ServerForPatch = getattr(module, 'ServerForPatch') - - server_id_parts = parse_resource_id(instance.id) - resource_group_name = server_id_parts['resource_group'] - server_name = server_id_parts['name'] - - if public_access: - instance.network.public_network_access = public_access - - if private_dns_zone_arguments: - private_dns_zone_id = prepare_private_dns_zone(db_context, - resource_group_name, - server_name, - private_dns_zone=private_dns_zone_arguments, - subnet_id=instance.network.delegated_subnet_resource_id, - location=location, - yes=yes) - instance.network.private_dns_zone_arm_resource_id = private_dns_zone_id - - _confirm_restart_server(instance, sku_name, storage_gb, yes) - - if sku_name: - instance.sku.name = sku_name - - if tier: - instance.sku.tier = tier - - if storage_gb: - instance.storage.storage_size_gb = storage_gb - - if auto_grow: - instance.storage.auto_grow = auto_grow - - instance.storage.tier = performance_tier if performance_tier else None - - if instance.storage.type == "PremiumV2_LRS": - instance.storage.tier = None - - if sku_name or storage_gb: - logger.warning("You are changing the compute and/or storage size of the server. " - "The server will be restarted for this operation and you will see a short downtime.") - - if iops: - instance.storage.iops = iops - - if throughput: - instance.storage.throughput = throughput - else: - instance.storage.type = None - instance.storage.iops = None - instance.storage.throughput = None - - if backup_retention: - instance.backup.backup_retention_days = backup_retention - - if maintenance_window: - if maintenance_window.lower() == "disabled": - # if disabled is pass in reset to default values - day_of_week = start_hour = start_minute = 0 - custom_window = "Disabled" - else: - day_of_week, start_hour, start_minute = parse_maintenance_window(maintenance_window) - custom_window = "Enabled" - - # set values - if maintenance_window when is None when created then create a new object - instance.maintenance_window.day_of_week = day_of_week - instance.maintenance_window.start_hour = start_hour - instance.maintenance_window.start_minute = start_minute - instance.maintenance_window.custom_window = custom_window - - identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key, - instance=instance) - - auth_config = instance.auth_config - administrator_login = instance.administrator_login if instance.administrator_login else None - if microsoft_entra_auth: - auth_config.active_directory_auth = microsoft_entra_auth - if password_auth: - administrator_login, administrator_login_password = _update_login(server_name, resource_group_name, auth_config, - password_auth, administrator_login, administrator_login_password) - auth_config.password_auth = password_auth - - if cluster_size: - instance.cluster.cluster_size = cluster_size - - params = ServerForPatch(sku=instance.sku, - storage=instance.storage, - backup=instance.backup, - administrator_login=administrator_login, - administrator_login_password=administrator_login_password, - availability_zone=instance.availability_zone, - maintenance_window=instance.maintenance_window, - network=instance.network, - identity=identity, - data_encryption=data_encryption, - auth_config=auth_config, - cluster=instance.cluster, - tags=tags) - - # High availability can't be updated with existing properties - high_availability_param = postgresql_flexibleservers.models.HighAvailability() - if zonal_resiliency is not None: - if zonal_resiliency.lower() == 'disabled': - high_availability = 'Disabled' - else: - list_capability_info = get_postgres_server_capability_info(cmd, resource_group_name, server_name) - single_az = list_capability_info['single_az'] - high_availability = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' - if high_availability: - high_availability_param.mode = high_availability - - if high_availability.lower() != "disabled" and standby_availability_zone: - high_availability_param.standby_availability_zone = standby_availability_zone - - # PG 11 and 12 will never receive fabric mirroring support. Ignite 2025 Fabric mirroring supported on 17. Skip this check for servers of these versions - if high_availability.lower() != "disabled" and str(instance.version) not in ["11", "12", "17", "18"]: - config_client = cf_postgres_flexible_config(cmd.cli_ctx, '_') - fabric_mirror_status = config_client.get(resource_group_name, server_name, 'azure.fabric_mirror_enabled') - if (fabric_mirror_status and fabric_mirror_status.value.lower() == 'on'): - raise CLIError("High availability cannot be enabled while Fabric mirroring is Active. Please disable Fabric mirroring to enable high availability.") - - params.high_availability = high_availability_param - - return params - - -# Common functions used by other providers -def flexible_server_update_get(client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - - return client.get(resource_group_name, server_name) - - -def flexible_server_update_set(client, resource_group_name, server_name, parameters): - validate_resource_group(resource_group_name) - - return client.begin_update(resource_group_name, server_name, parameters) - - -def _update_login(server_name, resource_group_name, auth_config, password_auth, administrator_login, administrator_login_password): - if auth_config.password_auth.lower() == 'disabled' and password_auth.lower() == 'enabled': - administrator_login = administrator_login if administrator_login else prompt('Please enter administrator username for the server. Once set, it cannot be changed: ') - if not administrator_login: - raise CLIError('Administrator username is required for enabling password authentication.') - if not administrator_login_password: - administrator_login_password = generate_password(administrator_login_password) - logger.warning('Make a note of password "%s". You can ' - 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', - administrator_login_password, server_name, resource_group_name) - - return administrator_login, administrator_login_password - - -# pylint: disable=chained-comparison -def _confirm_restart_server(instance, sku_name, storage_gb, yes): - show_confirmation = False - - # check if sku_name is changed - if sku_name and sku_name != instance.sku.name: - show_confirmation = True - - # check if requested storage growth is crossing the 4096 threshold - if storage_gb and storage_gb > 4096 and instance.storage.storage_size_gb <= 4096 and instance.storage.type == "": - show_confirmation = True - - # check if storage_gb changed for PremiumV2_LRS - if storage_gb and instance.storage.type == "PremiumV2_LRS" and instance.storage.storage_size_gb != storage_gb: - show_confirmation = True - - if not yes and show_confirmation: - user_confirmation("You are trying to change the compute or the size of storage assigned to your server in a way that \ - requires a server restart. During the restart, you'll experience some downtime of the server. Do you want to proceed?", yes=yes) - - -def flexible_server_delete(cmd, client, resource_group_name, server_name, yes=False): - validate_resource_group(resource_group_name) - result = None - if not yes: - user_confirmation( - "Are you sure you want to delete the server '{0}' in resource group '{1}'".format(server_name, - resource_group_name), yes=yes) - try: - result = client.begin_delete(resource_group_name, server_name) - if cmd.cli_ctx.local_context.is_on: - local_context_file = cmd.cli_ctx.local_context._get_local_context_file() # pylint: disable=protected-access - local_context_file.remove_option('postgres flexible-server', 'server_name') - local_context_file.remove_option('postgres flexible-server', 'administrator_login') - local_context_file.remove_option('postgres flexible-server', 'database_name') - except Exception as ex: # pylint: disable=broad-except - logger.error(ex) - raise CLIError(ex) - return result - - -def flexible_server_postgresql_get(cmd, resource_group_name, server_name): - validate_resource_group(resource_group_name) - client = get_postgresql_flexible_management_client(cmd.cli_ctx) - return client.servers.get(resource_group_name, server_name) - - -def server_list_custom_func(client, resource_group_name=None, show_cluster=None): - if not check_resource_group(resource_group_name): - resource_group_name = None - - servers = client.list_by_subscription() - - if resource_group_name: - servers = client.list_by_resource_group(resource_group_name) - - if show_cluster: - servers = [s for s in servers if s.cluster is not None] - else: - servers = [s for s in servers if s.cluster is None] - - return servers - - -def flexible_list_skus(cmd, client, location): - result = client.list(location) - logger.warning('For prices please refer to https://aka.ms/postgres-pricing') - return result - - -def flexible_server_georestore(cmd, client, resource_group_name, server_name, source_server, location, zone=None, - vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, - private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, - byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, restore_point_in_time=None): - validate_resource_group(resource_group_name) - - server_name = server_name.lower() - - if not is_valid_resource_id(source_server): - if _is_resource_name(source_server): - source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), - resource_group=resource_group_name, - namespace='Microsoft.DBforPostgreSQL', - type='flexibleServers', - name=source_server) - else: - raise CLIError('The provided source-server {} is invalid.'.format(source_server)) - else: - source_server_id = source_server - - restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) - - try: - id_parts = parse_resource_id(source_server_id) - validate_citus_cluster(cmd, id_parts['resource_group'], id_parts['name']) - source_subscription_id = id_parts['subscription'] - postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) - source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) - except Exception as e: - raise ResourceNotFoundError(e) - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') - if source_server_object.network.delegated_subnet_resource_id is not None: - validate_georestore_network(source_server_object, None, vnet, subnet, 'postgres') - - pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) - - storage = postgresql_flexibleservers.models.Storage(type=None) - - parameters = postgresql_flexibleservers.models.Server( - point_in_time_utc=restore_point_in_time, - location=location, - source_server_resource_id=source_server_id, - create_mode="GeoRestore", - availability_zone=zone, - storage=storage - ) - - if source_server_object.network.public_network_access == 'Disabled': - parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access='Disabled', - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - - parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) - - parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) - - -def flexible_server_revivedropped(cmd, client, resource_group_name, server_name, source_server, location, zone=None, - vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, - private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, - byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None): - validate_resource_group(resource_group_name) - - server_name = server_name.lower() - - if not is_valid_resource_id(source_server): - if _is_resource_name(source_server): - source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), - resource_group=resource_group_name, - namespace='Microsoft.DBforPostgreSQL', - type='flexibleServers', - name=source_server) - else: - raise CLIError('The provided source-server {} is invalid.'.format(source_server)) - else: - source_server_id = source_server - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') - - pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) - - storage = postgresql_flexibleservers.models.Storage(type=None) - - parameters = postgresql_flexibleservers.models.Server( - point_in_time_utc=get_current_time(), - location=location, - source_server_resource_id=source_server_id, - create_mode="ReviveDropped", - availability_zone=zone, - storage=storage - ) - - if vnet is not None or vnet_address_prefix is not None or subnet is not None or \ - subnet_address_prefix is not None or private_dns_zone_arguments is not None: - parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access='Disabled', - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - - parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) - - parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) \ No newline at end of file diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py deleted file mode 100644 index 3c7372b5ec4..00000000000 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom.py +++ /dev/null @@ -1,811 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .flexible_server_microsoft_entra import _create_admin -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator - -logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' - - -# region create without args -# pylint: disable=too-many-locals -# pylint: disable=too-many-statements -# pylint: disable=raise-missing-from, unbalanced-tuple-unpacking -def flexible_server_create(cmd, client, - resource_group_name=None, server_name=None, - location=None, backup_retention=None, - sku_name=None, tier=None, - storage_gb=None, version=None, microsoft_entra_auth=None, - admin_name=None, admin_id=None, admin_type=None, - password_auth=None, administrator_login=None, administrator_login_password=None, - tags=None, subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, - private_dns_zone_arguments=None, public_access=None, - high_availability=None, zonal_resiliency=None, allow_same_zone=False, - zone=None, standby_availability_zone=None, - geo_redundant_backup=None, byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, - auto_grow=None, performance_tier=None, - storage_type=None, iops=None, throughput=None, create_cluster=None, cluster_size=None, database_name=None, yes=False): - - if not check_resource_group(resource_group_name): - resource_group_name = None - - # Generate missing parameters - location, resource_group_name, server_name = generate_missing_parameters(cmd, location, resource_group_name, - server_name, 'postgres') - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - server_name = server_name.lower() - high_availability_mode = high_availability - - if (sku_name is None) or (version is None) or \ - (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): - list_location_capability_info = get_postgres_location_capability_info(cmd, location) - - # set sku_name from capability API - if sku_name is None: - tiers = [item.lower() for item in get_postgres_tiers(list_location_capability_info['sku_info'])] - try: - sku_info = list_location_capability_info['sku_info'] - skus = list(get_postgres_skus(sku_info, tier.lower())) - skus = sorted(skus, key=cmp_to_key(compare_sku_names)) - sku_name = skus[0] - except: - raise CLIError('Incorrect value for --tier. Allowed values : {}'.format(tiers)) - # default to the latest version - if version is None: - supported_server_versions = sorted(list_location_capability_info['supported_server_versions']) - version = supported_server_versions[-1] - # set high availability from capability API - if (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): - single_az = list_location_capability_info['single_az'] - high_availability_mode = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' - - pg_arguments_validator(db_context, - server_name=server_name, - location=location, - tier=tier, sku_name=sku_name, - storage_gb=storage_gb, - auto_grow=auto_grow, - storage_type=storage_type, - iops=iops, throughput=throughput, - high_availability=high_availability, - zonal_resiliency=zonal_resiliency, - allow_same_zone=allow_same_zone, - standby_availability_zone=standby_availability_zone, - zone=zone, - subnet=subnet, - public_access=public_access, - version=version, - geo_redundant_backup=geo_redundant_backup, - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key, - performance_tier=performance_tier, - create_cluster=create_cluster, - password_auth=password_auth, microsoft_entra_auth=microsoft_entra_auth, - admin_name=admin_name, admin_id=admin_id, admin_type=admin_type,) - - cluster = None - if create_cluster == 'ElasticCluster': - cluster_size = cluster_size if cluster_size else 2 - cluster = postgresql_flexibleservers.models.Cluster(cluster_size=cluster_size, default_database_name=database_name if database_name else POSTGRES_DB_NAME) - - server_result = firewall_id = None - - network, start_ip, end_ip = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access=public_access, - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - - storage = postgresql_flexibleservers.models.Storage(storage_size_gb=storage_gb, auto_grow=auto_grow, tier=performance_tier, type=storage_type, iops=iops, throughput=throughput) - - backup = postgresql_flexibleservers.models.Backup(backup_retention_days=backup_retention, - geo_redundant_backup=geo_redundant_backup) - - sku = postgresql_flexibleservers.models.Sku(name=sku_name, tier=tier) - - high_availability = postgresql_flexibleservers.models.HighAvailability(mode=high_availability_mode, - standby_availability_zone=standby_availability_zone) - - is_password_auth_enabled = bool(password_auth is not None and password_auth.lower() == 'enabled') - is_microsoft_entra_auth_enabled = bool(microsoft_entra_auth is not None and microsoft_entra_auth.lower() == 'enabled') - if is_password_auth_enabled: - administrator_login_password = generate_password(administrator_login_password) - - identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - auth_config = postgresql_flexibleservers.models.AuthConfig(active_directory_auth='Enabled' if is_microsoft_entra_auth_enabled else 'Disabled', - password_auth=password_auth) - - # Create postgresql - # Note : passing public_access has no effect as the accepted values are 'Enabled' and 'Disabled'. So the value ends up being ignored. - server_result = _create_server(db_context, cmd, resource_group_name, server_name, - tags=tags, - location=location, - sku=sku, - administrator_login=administrator_login, - administrator_login_password=administrator_login_password, - storage=storage, - backup=backup, - network=network, - version=version, - high_availability=high_availability, - availability_zone=zone, - identity=identity, - data_encryption=data_encryption, - auth_config=auth_config, - cluster=cluster) - - # Add Microsoft Entra Admin - if is_microsoft_entra_auth_enabled and admin_name is not None or admin_id is not None: - server_admin_client = cf_postgres_flexible_admin(cmd.cli_ctx, '_') - logger.warning("Add Microsoft Entra Admin '%s'.", admin_name) - _create_admin(server_admin_client, resource_group_name, server_name, admin_name, admin_id, admin_type) - - # Adding firewall rule - if start_ip != -1 and end_ip != -1: - firewall_id = create_firewall_rule(db_context, cmd, resource_group_name, server_name, start_ip, end_ip) - - user = server_result.administrator_login if is_password_auth_enabled else '' - password = administrator_login_password if is_password_auth_enabled else '' - admin = quote(admin_name) if admin_name else '' - server_id = server_result.id - loc = server_result.location - version = server_result.version - sku = server_result.sku.name - host = server_result.fully_qualified_domain_name - subnet_id = None if network is None else network.delegated_subnet_resource_id - - if is_password_auth_enabled: - logger.warning('Make a note of your password. If you forget, you would have to ' - 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', - server_name, resource_group_name) - logger.warning('Try using \'az postgres flexible-server connect\' command to test out connection.') - - _update_local_contexts(cmd, server_name, resource_group_name, location, user) - - return _form_response(user, sku, loc, server_id, host, version, password, - firewall_id, subnet_id, is_password_auth_enabled, is_microsoft_entra_auth_enabled, admin_name) - - -def _create_server(db_context, cmd, resource_group_name, server_name, tags, location, sku, administrator_login, administrator_login_password, - storage, backup, network, version, high_availability, availability_zone, identity, data_encryption, auth_config, cluster): - validate_resource_group(resource_group_name) - - logging_name, server_client = db_context.logging_name, db_context.server_client - logger.warning('Creating %s Server \'%s\' in group \'%s\'...', logging_name, server_name, resource_group_name) - - logger.warning('Your server \'%s\' is using sku \'%s\' (Paid Tier). ' - 'Please refer to https://aka.ms/postgres-pricing for pricing details', server_name, sku.name) - - # Note : passing public-network-access has no effect as the accepted values are 'Enabled' and 'Disabled'. - # So when you pass an IP here(from the CLI args of public_access), it ends up being ignored. - parameters = postgresql_flexibleservers.models.Server( - tags=tags, - location=location, - sku=sku, - administrator_login=administrator_login, - administrator_login_password=administrator_login_password, - storage=storage, - backup=backup, - network=network, - version=version, - high_availability=high_availability, - availability_zone=availability_zone, - identity=identity, - data_encryption=data_encryption, - auth_config=auth_config, - cluster=cluster, - create_mode="Create") - - return resolve_poller( - server_client.begin_create_or_update(resource_group_name, server_name, parameters), cmd.cli_ctx, - '{} Server Create'.format(logging_name)) - - -def _update_local_contexts(cmd, server_name, resource_group_name, location, user): - validate_resource_group(resource_group_name) - - if cmd.cli_ctx.local_context.is_on: - cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'server_name', - server_name) # Setting the server name in the local context - cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'administrator_login', - user) # Setting the server name in the local context - cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'database_name', - POSTGRES_DB_NAME) # Setting the server name in the local context - cmd.cli_ctx.local_context.set([ALL], 'location', - location) # Setting the location in the local context - cmd.cli_ctx.local_context.set([ALL], 'resource_group_name', resource_group_name) - - -def _form_response(username, sku, location, server_id, host, version, password, firewall_id=None, - subnet_id=None, is_password_auth=True, is_microsoft_entra_auth_enabled=False, microsoft_admin=None): - - connection_kwargs = { - 'user': username if username is not None else '{user}', - 'host': host, - 'password': password if password is not None else '{password}', - 'database': POSTGRES_DB_NAME, - } - output = { - 'host': host, - 'username': username if is_password_auth else None, - 'password': password if is_password_auth else None, - 'skuname': sku, - 'location': location, - 'id': server_id, - 'version': version, - 'databaseName': POSTGRES_DB_NAME, - 'connectionString': 'postgresql://{user}:{password}@{host}/{database}?sslmode=require'.format(**connection_kwargs) - } - if is_microsoft_entra_auth_enabled: - user = quote(microsoft_admin) if microsoft_admin else '' - connection_kwargs = { - 'user': user, - 'host': host, - 'database': POSTGRES_DB_NAME, - } - output['admin'] = microsoft_admin - output['connectionStringMicrosoftEntra'] = 'postgresql://{user}:@{host}/{database}?sslmode=require'.format(**connection_kwargs) - if firewall_id is not None: - output['firewallName'] = firewall_id - if subnet_id is not None: - output['subnetId'] = subnet_id - return output - - -def flexible_server_restore(cmd, client, - resource_group_name, server_name, - source_server, restore_point_in_time=None, zone=None, no_wait=False, - subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, - private_dns_zone_arguments=None, geo_redundant_backup=None, - byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, storage_type=None, yes=False): - - server_name = server_name.lower() - - validate_resource_group(resource_group_name) - - if not is_valid_resource_id(source_server): - if len(source_server.split('/')) == 1: - source_server_id = resource_id( - subscription=get_subscription_id(cmd.cli_ctx), - resource_group=resource_group_name, - namespace=RESOURCE_PROVIDER, - type='flexibleServers', - name=source_server) - else: - raise ValueError('The provided source server {} is invalid.'.format(source_server)) - else: - source_server_id = source_server - - restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) - - try: - id_parts = parse_resource_id(source_server_id) - source_subscription_id = id_parts['subscription'] - postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) - source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) - - location = ''.join(source_server_object.location.lower().split()) - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') - - pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) - - pg_restore_validator(source_server_object.sku.tier, storage_type=storage_type) - storage = postgresql_flexibleservers.models.Storage(type=storage_type if source_server_object.storage.type != "PremiumV2_LRS" else None) - - parameters = postgresql_flexibleservers.models.Server( - location=location, - point_in_time_utc=restore_point_in_time, - source_server_resource_id=source_server_id, # this should be the source server name, not id - create_mode="PointInTimeRestore", - availability_zone=zone, - storage=storage - ) - - if source_server_object.network.public_network_access == 'Disabled' and any((vnet, subnet)): - parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access='Disabled', - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - else: - parameters.network = source_server_object.network - - parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) - - parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - except Exception as e: - raise ResourceNotFoundError(e) - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) - - -# pylint: disable=too-many-branches -def flexible_server_update_custom_func(cmd, client, instance, - sku_name=None, tier=None, - storage_gb=None, - backup_retention=None, - administrator_login_password=None, - high_availability=None, - zonal_resiliency=None, - allow_same_zone=False, - standby_availability_zone=None, - maintenance_window=None, - byok_identity=None, byok_key=None, - backup_byok_identity=None, backup_byok_key=None, - microsoft_entra_auth=None, password_auth=None, - private_dns_zone_arguments=None, - public_access=None, - tags=None, - auto_grow=None, - performance_tier=None, - iops=None, throughput=None, - cluster_size=None, yes=False): - - # validator - location = ''.join(instance.location.lower().split()) - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - pg_arguments_validator(db_context, - location=location, - tier=tier, - sku_name=sku_name, - storage_gb=storage_gb, - auto_grow=auto_grow, - iops=iops, - throughput=throughput, - high_availability=high_availability, - zonal_resiliency=zonal_resiliency, - allow_same_zone=allow_same_zone, - zone=instance.availability_zone, - standby_availability_zone=standby_availability_zone, - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key, - performance_tier=performance_tier, - cluster_size=cluster_size, instance=instance) - - server_module_path = instance.__module__ - module = import_module(server_module_path) - ServerForPatch = getattr(module, 'ServerForPatch') - - server_id_parts = parse_resource_id(instance.id) - resource_group_name = server_id_parts['resource_group'] - server_name = server_id_parts['name'] - - if public_access: - instance.network.public_network_access = public_access - - if private_dns_zone_arguments: - private_dns_zone_id = prepare_private_dns_zone(db_context, - resource_group_name, - server_name, - private_dns_zone=private_dns_zone_arguments, - subnet_id=instance.network.delegated_subnet_resource_id, - location=location, - yes=yes) - instance.network.private_dns_zone_arm_resource_id = private_dns_zone_id - - _confirm_restart_server(instance, sku_name, storage_gb, yes) - - if sku_name: - instance.sku.name = sku_name - - if tier: - instance.sku.tier = tier - - if storage_gb: - instance.storage.storage_size_gb = storage_gb - - if auto_grow: - instance.storage.auto_grow = auto_grow - - instance.storage.tier = performance_tier if performance_tier else None - - if instance.storage.type == "PremiumV2_LRS": - instance.storage.tier = None - - if sku_name or storage_gb: - logger.warning("You are changing the compute and/or storage size of the server. " - "The server will be restarted for this operation and you will see a short downtime.") - - if iops: - instance.storage.iops = iops - - if throughput: - instance.storage.throughput = throughput - else: - instance.storage.type = None - instance.storage.iops = None - instance.storage.throughput = None - - if backup_retention: - instance.backup.backup_retention_days = backup_retention - - if maintenance_window: - if maintenance_window.lower() == "disabled": - # if disabled is pass in reset to default values - day_of_week = start_hour = start_minute = 0 - custom_window = "Disabled" - else: - day_of_week, start_hour, start_minute = parse_maintenance_window(maintenance_window) - custom_window = "Enabled" - - # set values - if maintenance_window when is None when created then create a new object - instance.maintenance_window.day_of_week = day_of_week - instance.maintenance_window.start_hour = start_hour - instance.maintenance_window.start_minute = start_minute - instance.maintenance_window.custom_window = custom_window - - identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key, - instance=instance) - - auth_config = instance.auth_config - administrator_login = instance.administrator_login if instance.administrator_login else None - if microsoft_entra_auth: - auth_config.active_directory_auth = microsoft_entra_auth - if password_auth: - administrator_login, administrator_login_password = _update_login(server_name, resource_group_name, auth_config, - password_auth, administrator_login, administrator_login_password) - auth_config.password_auth = password_auth - - if cluster_size: - instance.cluster.cluster_size = cluster_size - - params = ServerForPatch(sku=instance.sku, - storage=instance.storage, - backup=instance.backup, - administrator_login=administrator_login, - administrator_login_password=administrator_login_password, - availability_zone=instance.availability_zone, - maintenance_window=instance.maintenance_window, - network=instance.network, - identity=identity, - data_encryption=data_encryption, - auth_config=auth_config, - cluster=instance.cluster, - tags=tags) - - # High availability can't be updated with existing properties - high_availability_param = postgresql_flexibleservers.models.HighAvailability() - if zonal_resiliency is not None: - if zonal_resiliency.lower() == 'disabled': - high_availability = 'Disabled' - else: - list_capability_info = get_postgres_server_capability_info(cmd, resource_group_name, server_name) - single_az = list_capability_info['single_az'] - high_availability = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' - if high_availability: - high_availability_param.mode = high_availability - - if high_availability.lower() != "disabled" and standby_availability_zone: - high_availability_param.standby_availability_zone = standby_availability_zone - - # PG 11 and 12 will never receive fabric mirroring support. Ignite 2025 Fabric mirroring supported on 17. Skip this check for servers of these versions - if high_availability.lower() != "disabled" and str(instance.version) not in ["11", "12", "17", "18"]: - config_client = cf_postgres_flexible_config(cmd.cli_ctx, '_') - fabric_mirror_status = config_client.get(resource_group_name, server_name, 'azure.fabric_mirror_enabled') - if (fabric_mirror_status and fabric_mirror_status.value.lower() == 'on'): - raise CLIError("High availability cannot be enabled while Fabric mirroring is Active. Please disable Fabric mirroring to enable high availability.") - - params.high_availability = high_availability_param - - return params - - -# Common functions used by other providers -def flexible_server_update_get(client, resource_group_name, server_name): - validate_resource_group(resource_group_name) - - return client.get(resource_group_name, server_name) - - -def flexible_server_update_set(client, resource_group_name, server_name, parameters): - validate_resource_group(resource_group_name) - - return client.begin_update(resource_group_name, server_name, parameters) - - -def _update_login(server_name, resource_group_name, auth_config, password_auth, administrator_login, administrator_login_password): - if auth_config.password_auth.lower() == 'disabled' and password_auth.lower() == 'enabled': - administrator_login = administrator_login if administrator_login else prompt('Please enter administrator username for the server. Once set, it cannot be changed: ') - if not administrator_login: - raise CLIError('Administrator username is required for enabling password authentication.') - if not administrator_login_password: - administrator_login_password = generate_password(administrator_login_password) - logger.warning('Make a note of password "%s". You can ' - 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', - administrator_login_password, server_name, resource_group_name) - - return administrator_login, administrator_login_password - - -# pylint: disable=chained-comparison -def _confirm_restart_server(instance, sku_name, storage_gb, yes): - show_confirmation = False - - # check if sku_name is changed - if sku_name and sku_name != instance.sku.name: - show_confirmation = True - - # check if requested storage growth is crossing the 4096 threshold - if storage_gb and storage_gb > 4096 and instance.storage.storage_size_gb <= 4096 and instance.storage.type == "": - show_confirmation = True - - # check if storage_gb changed for PremiumV2_LRS - if storage_gb and instance.storage.type == "PremiumV2_LRS" and instance.storage.storage_size_gb != storage_gb: - show_confirmation = True - - if not yes and show_confirmation: - user_confirmation("You are trying to change the compute or the size of storage assigned to your server in a way that \ - requires a server restart. During the restart, you'll experience some downtime of the server. Do you want to proceed?", yes=yes) - - -def flexible_server_delete(cmd, client, resource_group_name, server_name, yes=False): - validate_resource_group(resource_group_name) - result = None - if not yes: - user_confirmation( - "Are you sure you want to delete the server '{0}' in resource group '{1}'".format(server_name, - resource_group_name), yes=yes) - try: - result = client.begin_delete(resource_group_name, server_name) - if cmd.cli_ctx.local_context.is_on: - local_context_file = cmd.cli_ctx.local_context._get_local_context_file() # pylint: disable=protected-access - local_context_file.remove_option('postgres flexible-server', 'server_name') - local_context_file.remove_option('postgres flexible-server', 'administrator_login') - local_context_file.remove_option('postgres flexible-server', 'database_name') - except Exception as ex: # pylint: disable=broad-except - logger.error(ex) - raise CLIError(ex) - return result - - -def flexible_server_postgresql_get(cmd, resource_group_name, server_name): - validate_resource_group(resource_group_name) - client = get_postgresql_flexible_management_client(cmd.cli_ctx) - return client.servers.get(resource_group_name, server_name) - - -def flexible_list_skus(cmd, client, location): - result = client.list(location) - logger.warning('For prices please refer to https://aka.ms/postgres-pricing') - return result - - -def flexible_server_georestore(cmd, client, resource_group_name, server_name, source_server, location, zone=None, - vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, - private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, - byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, restore_point_in_time=None): - validate_resource_group(resource_group_name) - - server_name = server_name.lower() - - if not is_valid_resource_id(source_server): - if _is_resource_name(source_server): - source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), - resource_group=resource_group_name, - namespace='Microsoft.DBforPostgreSQL', - type='flexibleServers', - name=source_server) - else: - raise CLIError('The provided source-server {} is invalid.'.format(source_server)) - else: - source_server_id = source_server - - restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) - - try: - id_parts = parse_resource_id(source_server_id) - validate_citus_cluster(cmd, id_parts['resource_group'], id_parts['name']) - source_subscription_id = id_parts['subscription'] - postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) - source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) - except Exception as e: - raise ResourceNotFoundError(e) - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') - if source_server_object.network.delegated_subnet_resource_id is not None: - validate_georestore_network(source_server_object, None, vnet, subnet, 'postgres') - - pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) - - storage = postgresql_flexibleservers.models.Storage(type=None) - - parameters = postgresql_flexibleservers.models.Server( - point_in_time_utc=restore_point_in_time, - location=location, - source_server_resource_id=source_server_id, - create_mode="GeoRestore", - availability_zone=zone, - storage=storage - ) - - if source_server_object.network.public_network_access == 'Disabled': - parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access='Disabled', - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - - parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) - - parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) - - -def flexible_server_revivedropped(cmd, client, resource_group_name, server_name, source_server, location, zone=None, - vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, - private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, - byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None): - validate_resource_group(resource_group_name) - - server_name = server_name.lower() - - if not is_valid_resource_id(source_server): - if _is_resource_name(source_server): - source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), - resource_group=resource_group_name, - namespace='Microsoft.DBforPostgreSQL', - type='flexibleServers', - name=source_server) - else: - raise CLIError('The provided source-server {} is invalid.'.format(source_server)) - else: - source_server_id = source_server - - db_context = DbContext( - cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, - cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, - cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, - logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) - - validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') - - pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) - - storage = postgresql_flexibleservers.models.Storage(type=None) - - parameters = postgresql_flexibleservers.models.Server( - point_in_time_utc=get_current_time(), - location=location, - source_server_resource_id=source_server_id, - create_mode="ReviveDropped", - availability_zone=zone, - storage=storage - ) - - if vnet is not None or vnet_address_prefix is not None or subnet is not None or \ - subnet_address_prefix is not None or private_dns_zone_arguments is not None: - parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, - resource_group_name=resource_group_name, - server_name=server_name, - location=location, - db_context=db_context, - private_dns_zone_arguments=private_dns_zone_arguments, - public_access='Disabled', - vnet=vnet, - subnet=subnet, - vnet_address_prefix=vnet_address_prefix, - subnet_address_prefix=subnet_address_prefix, - yes=yes) - - parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) - - parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', - byok_identity=byok_identity, - byok_key=byok_key, - backup_byok_identity=backup_byok_identity, - backup_byok_key=backup_byok_key) - - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) \ No newline at end of file diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py deleted file mode 100644 index 28b4896d637..00000000000 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_custom_postgres.py +++ /dev/null @@ -1,291 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# pylint: disable=unused-argument, line-too-long -from datetime import datetime, timedelta -import os -import json -from importlib import import_module -from functools import cmp_to_key -import re -from urllib.parse import quote -from urllib.request import urlretrieve -from dateutil.tz import tzutc # pylint: disable=import-error -import uuid -from knack.log import get_logger -from knack.prompting import ( - prompt -) -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.local_context import ALL -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from azure.mgmt.core.tools import resource_id, is_valid_resource_id, parse_resource_id -from azure.cli.core.azclierror import BadRequestError, FileOperationError, MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ArgumentUsageError, InvalidArgumentValueError, ValidationError -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ._client_factory import cf_postgres_flexible_firewall_rules, get_postgresql_flexible_management_client, \ - cf_postgres_flexible_db, cf_postgres_check_resource_availability, cf_postgres_flexible_servers, \ - cf_postgres_flexible_private_dns_zone_suffix_operations, \ - cf_postgres_flexible_private_endpoint_connections, \ - cf_postgres_flexible_tuning_options, \ - cf_postgres_flexible_config, cf_postgres_flexible_admin -from ._flexible_server_util import generate_missing_parameters, resolve_poller, \ - generate_password, parse_maintenance_window, get_current_time, build_identity_and_data_encryption, \ - _is_resource_name, get_tenant_id, get_case_insensitive_key_value, get_enum_value_true_false, \ - get_postgres_tiers, get_postgres_skus -from ._flexible_server_location_capabilities_util import get_postgres_location_capability_info, get_postgres_server_capability_info -from ._util import get_autonomous_tuning_settings_map -from ._db_context import DbContext -from .deploy_commands import create_firewall_rule -from .flexible_server_network import prepare_private_network, prepare_private_dns_zone, prepare_public_network, flexible_server_provision_network_resource -from .validators import pg_arguments_validator, validate_server_name, validate_and_format_restore_point_in_time, \ - validate_postgres_replica, validate_georestore_network, pg_byok_validator, validate_migration_runtime_server, \ - validate_resource_group, check_resource_group, validate_citus_cluster, validate_backup_name, \ - validate_virtual_endpoint_name_availability, validate_database_name, compare_sku_names, is_citus_cluster, pg_restore_validator - -logger = get_logger(__name__) -DEFAULT_DB_NAME = 'flexibleserverdb' -POSTGRES_DB_NAME = 'postgres' -DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" -RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' - - -# Custom functions for server logs -def _update_parameters(cmd, client, server_name, configuration_name, resource_group_name, source, value): - parameters = postgresql_flexibleservers.models.Configuration( - value=value, - source=source - ) - - return resolve_poller( - client.begin_update(resource_group_name, server_name, configuration_name, parameters), cmd.cli_ctx, 'PostgreSQL Parameter update') - - -def _update_private_endpoint_connection_status(cmd, client, resource_group_name, server_name, - private_endpoint_connection_name, is_approved=True, description=None): # pylint: disable=unused-argument - validate_resource_group(resource_group_name) - - private_endpoint_connections_client = cf_postgres_flexible_private_endpoint_connections(cmd.cli_ctx, None) - private_endpoint_connection = private_endpoint_connections_client.get(resource_group_name=resource_group_name, - server_name=server_name, - private_endpoint_connection_name=private_endpoint_connection_name) - new_status = 'Approved' if is_approved else 'Rejected' - - private_link_service_connection_state = { - 'status': new_status, - 'description': description - } - - private_endpoint_connection.private_link_service_connection_state = private_link_service_connection_state - - return client.begin_update(resource_group_name=resource_group_name, - server_name=server_name, - private_endpoint_connection_name=private_endpoint_connection_name, - parameters=private_endpoint_connection) - - -def _create_postgresql_connection_strings(host, user, password, database, port): - - result = { - 'psql_cmd': "postgresql://{user}:{password}@{host}/{database}?sslmode=require", - 'ado.net': "Server={host};Database={database};Port={port};User Id={user};Password={password};Ssl Mode=Require;", - 'jdbc': "jdbc:postgresql://{host}:{port}/{database}?user={user}&password={password}&sslmode=require", - 'jdbc Spring': "spring.datasource.url=jdbc:postgresql://{host}:{port}/{database} " - "spring.datasource.username={user} " - "spring.datasource.password={password}", - 'node.js': "var conn= new Client({open_brace}host:'{host}', user:'{user}', password:'{password}', database:'{database}', port:{port}, ssl:{open_brace}ca:fs.readFileSync(\"{ca-cert filename}\"){close_brace}{close_brace});", - 'php': "pg_connect(\"host={host} port={port} dbname={database} user={user} password={password}\");", - 'python': "cnx = psycopg2.connect(user='{user}', password='{password}', host='{host}', " - "port={port}, database='{database}')", - 'ruby': "connection = PG::Connection.new(user => \"{user}\", password => \"{password}\", database => \"{database}\", host => \"{host}\", " - "port => '{port}')", - } - - connection_kwargs = { - 'host': host, - 'user': user, - 'password': password if password is not None else '{password}', - 'database': database, - 'port': port, - 'open_brace': '{', - 'close_brace': '}', - 'ca-cert filename': '{ca-cert filename}' - } - - for k, v in result.items(): - result[k] = v.format(**connection_kwargs) - return result - - -def _create_postgresql_connection_string(host, user, password, database=POSTGRES_DB_NAME): - connection_kwargs = { - 'user': user if user is not None else '{user}', - 'host': host, - 'password': password if password is not None else '{password}', - 'database': database, - } - return 'postgresql://{user}:{password}@{host}/{database}?sslmode=require'.format(**connection_kwargs) - - -def _create_microsoft_entra_connection_string(host, database=POSTGRES_DB_NAME, admin=''): - connection_kwargs = { - 'user': admin, - 'host': host, - 'database': database, - } - return 'postgresql://{user}:@{host}/{database}?sslmode=require'.format(**connection_kwargs) - - -def _form_response(username, sku, location, server_id, host, version, password, connection_string, firewall_id=None, - subnet_id=None, is_password_auth=True, is_microsoft_entra_auth_enabled=False, microsoft_admin=None, connection_string_microsoft_entra=None): - - output = { - 'host': host, - 'username': username if is_password_auth else None, - 'password': password if is_password_auth else None, - 'skuname': sku, - 'location': location, - 'id': server_id, - 'version': version, - 'databaseName': POSTGRES_DB_NAME, - 'connectionString': connection_string - } - if is_microsoft_entra_auth_enabled: - output['admin'] = microsoft_admin - output['connectionStringMicrosoftEntra'] = connection_string_microsoft_entra - if firewall_id is not None: - output['firewallName'] = firewall_id - if subnet_id is not None: - output['subnetId'] = subnet_id - return output - - -def _update_local_contexts(cmd, server_name, resource_group_name, location, user): - validate_resource_group(resource_group_name) - - if cmd.cli_ctx.local_context.is_on: - cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'server_name', - server_name) # Setting the server name in the local context - cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'administrator_login', - user) # Setting the server name in the local context - cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'database_name', - POSTGRES_DB_NAME) # Setting the server name in the local context - cmd.cli_ctx.local_context.set([ALL], 'location', - location) # Setting the location in the local context - cmd.cli_ctx.local_context.set([ALL], 'resource_group_name', resource_group_name) - - -def _get_pg_replica_zone(availabilityZones, sourceServerZone, replicaZone): - preferredZone = 'none' - for _index, zone in enumerate(availabilityZones): - if zone != sourceServerZone and zone != 'none': - preferredZone = zone - - if not preferredZone: - preferredZone = 'none' - - selectZone = preferredZone if not replicaZone else replicaZone - - selectZoneSupported = False - for _index, zone in enumerate(availabilityZones): - if zone == selectZone: - selectZoneSupported = True - - pg_replica_zone = None - if len(availabilityZones) > 1 and selectZone and selectZoneSupported: - pg_replica_zone = selectZone if selectZone != 'none' else None - else: - sourceZoneSupported = False - for _index, zone in enumerate(availabilityZones): - if zone == sourceServerZone: - sourceZoneSupported = True - if sourceZoneSupported: - pg_replica_zone = sourceServerZone - else: - pg_replica_zone = None - - return pg_replica_zone - - -def _create_migration(cmd, logging_name, client, subscription_id, resource_group_name, target_db_server_name, - migration_name, migration_mode, migration_option, parameters, tags, location): - validate_resource_group(resource_group_name) - - parameter_keys = list(parameters.keys()) - migrationInstanceResourceId = get_case_insensitive_key_value("MigrationRuntimeResourceId", parameter_keys, parameters) - if migrationInstanceResourceId is not None: - validate_migration_runtime_server(cmd, migrationInstanceResourceId, resource_group_name, target_db_server_name) - - logger.warning('Creating %s Migration for server \'%s\' in group \'%s\' and subscription \'%s\'...', logging_name, target_db_server_name, resource_group_name, subscription_id) - secret_parameter_dictionary = get_case_insensitive_key_value("SecretParameters", parameter_keys, parameters) - secret_parameter_keys = list(secret_parameter_dictionary.keys()) - admin_credentials_dictionary = get_case_insensitive_key_value("AdminCredentials", secret_parameter_keys, secret_parameter_dictionary) - admin_credentials_keys = list(admin_credentials_dictionary.keys()) - source_type = get_case_insensitive_key_value("SourceType", parameter_keys, parameters) - ssl_mode = get_case_insensitive_key_value("SslMode", parameter_keys, parameters) - - admin_credentials = postgresql_flexibleservers.models.AdminCredentials( - source_server_password=get_case_insensitive_key_value("SourceServerPassword", admin_credentials_keys, admin_credentials_dictionary), - target_server_password=get_case_insensitive_key_value("TargetServerPassword", admin_credentials_keys, admin_credentials_dictionary)) - secret_parameters = postgresql_flexibleservers.models.MigrationSecretParameters( - admin_credentials=admin_credentials, - source_server_username=get_case_insensitive_key_value("SourceServerUsername", secret_parameter_keys, secret_parameter_dictionary), - target_server_username=get_case_insensitive_key_value("TargetServerUsername", secret_parameter_keys, secret_parameter_dictionary)) - migration_parameters = postgresql_flexibleservers.models.Migration( - tags=tags, - location=location, - migration_mode=migration_mode, - source_db_server_resource_id=get_case_insensitive_key_value("SourceDbServerResourceId", parameter_keys, parameters), - secret_parameters=secret_parameters, - source_db_server_fully_qualified_domain_name=get_case_insensitive_key_value("SourceDbServerFullyQualifiedDomainName", parameter_keys, parameters), - target_db_server_fully_qualified_domain_name=get_case_insensitive_key_value("TargetDbServerFullyQualifiedDomainName", parameter_keys, parameters), - dbs_to_migrate=get_case_insensitive_key_value("DbsToMigrate", parameter_keys, parameters), - setup_logical_replication_on_source_db_if_needed=get_enum_value_true_false(get_case_insensitive_key_value("SetupLogicalReplicationOnSourceDbIfNeeded", parameter_keys, parameters), "SetupLogicalReplicationOnSourceDbIfNeeded"), - overwrite_dbs_in_target=get_enum_value_true_false(get_case_insensitive_key_value("OverwriteDbsInTarget", parameter_keys, parameters), "OverwriteDbsInTarget"), - source_type=source_type, - migration_option=migration_option, - ssl_mode=ssl_mode, - migration_instance_resource_id=migrationInstanceResourceId) - - return client.create(resource_group_name, server_name=target_db_server_name, migration_name=migration_name, parameters=migration_parameters) - - -def _update_login(server_name, resource_group_name, auth_config, password_auth, administrator_login, administrator_login_password): - if auth_config.password_auth.lower() == 'disabled' and password_auth.lower() == 'enabled': - administrator_login = administrator_login if administrator_login else prompt('Please enter administrator username for the server. Once set, it cannot be changed: ') - if not administrator_login: - raise CLIError('Administrator username is required for enabling password authentication.') - if not administrator_login_password: - administrator_login_password = generate_password(administrator_login_password) - logger.warning('Make a note of password "%s". You can ' - 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', - administrator_login_password, server_name, resource_group_name) - - return administrator_login, administrator_login_password - - -# pylint: disable=chained-comparison -def _confirm_restart_server(instance, sku_name, storage_gb, yes): - show_confirmation = False - - # check if sku_name is changed - if sku_name and sku_name != instance.sku.name: - show_confirmation = True - - # check if requested storage growth is crossing the 4096 threshold - if storage_gb and storage_gb > 4096 and instance.storage.storage_size_gb <= 4096 and instance.storage.type == "": - show_confirmation = True - - # check if storage_gb changed for PremiumV2_LRS - if storage_gb and instance.storage.type == "PremiumV2_LRS" and instance.storage.storage_size_gb != storage_gb: - show_confirmation = True - - if not yes and show_confirmation: - user_confirmation("You are trying to change the compute or the size of storage assigned to your server in a way that \ - requires a server restart. During the restart, you'll experience some downtime of the server. Do you want to proceed?", yes=yes) - - -# pylint: disable=too-many-instance-attributes, too-few-public-methods - diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/utils/validators.py b/src/azure-cli/azure/cli/command_modules/postgresql/utils/validators.py index a43b82c093d..a575f666916 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/utils/validators.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/utils/validators.py @@ -2,29 +2,37 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- +import math +import re + from dateutil import parser from functools import cmp_to_key -import re -from knack.prompting import prompt_pass, NoTTYException -from knack.util import CLIError from knack.log import get_logger -import math -from azure.mgmt.core.tools import parse_resource_id, resource_id, is_valid_resource_id, is_valid_resource_name -from azure.cli.core.azclierror import ValidationError, ArgumentUsageError +from knack.prompting import NoTTYException, prompt_pass +from knack.util import CLIError +from azure.cli.core.azclierror import ArgumentUsageError, ValidationError from azure.cli.core.commands.client_factory import get_mgmt_service_client, get_subscription_id from azure.cli.core.commands.validators import ( get_default_location_from_resource_group, validate_tags) -from azure.cli.core.util import parse_proxy_resource_id from azure.cli.core.profiles import ResourceType +from azure.cli.core.util import parse_proxy_resource_id from azure.core.exceptions import HttpResponseError -from .._client_factory import (cf_postgres_flexible_servers, - cf_postgres_check_resource_availability) -from ._flexible_server_util import (get_postgres_skus, get_postgres_storage_sizes, get_postgres_tiers, - _is_resource_name) -from ._flexible_server_location_capabilities_util import (get_postgres_location_capability_info, - get_postgres_server_capability_info, - get_performance_tiers, - get_performance_tiers_for_storage) +from azure.mgmt.core.tools import ( + is_valid_resource_id, + is_valid_resource_name, + parse_resource_id, + resource_id) +from .._client_factory import cf_postgres_check_resource_availability, cf_postgres_flexible_servers +from ._flexible_server_location_capabilities_util import ( + get_performance_tiers, + get_performance_tiers_for_storage, + get_postgres_location_capability_info, + get_postgres_server_capability_info) +from ._flexible_server_util import ( + _is_resource_name, + get_postgres_skus, + get_postgres_storage_sizes, + get_postgres_tiers) logger = get_logger(__name__) From 19c649ec79a9ae3df4bb75c94263e2b3a2674582 Mon Sep 17 00:00:00 2001 From: Naia Scott Date: Tue, 3 Mar 2026 19:31:55 -0500 Subject: [PATCH 07/10] clean up --- .../commands/autonomous_tuning_commands.py | 18 +- .../postgresql/commands/backup_commands.py | 2 +- .../postgresql/commands/custom_commands.py | 835 ++++++++++++++++++ .../postgresql/commands/database_commands.py | 10 +- .../postgresql/commands/deploy_commands.py | 12 +- .../commands/fabric_mirroring_commands.py | 4 +- .../commands/firewall_rule_commands.py | 2 +- .../postgresql/commands/identity_commands.py | 6 +- .../commands/microsoft_entra_commands.py | 6 +- .../postgresql/commands/migration_commands.py | 20 +- .../postgresql/commands/network_commands.py | 42 +- .../postgresql/commands/parameter_commands.py | 4 +- .../postgresql/commands/power_commands.py | 4 +- .../commands/private_endpoint_commands.py | 4 +- .../postgresql/commands/replica_commands.py | 2 +- .../commands/server_logs_commands.py | 8 +- .../commands/threat_protection_commands.py | 4 +- .../postgresql/commands/upgrade_commands.py | 8 +- .../commands/virtual_endpoint_commands.py | 4 +- ...gres_flexible_commands_private_dns_zone.py | 9 +- 20 files changed, 919 insertions(+), 85 deletions(-) create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/commands/custom_commands.py diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/autonomous_tuning_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/autonomous_tuning_commands.py index e1ff5d93670..ba827efac7c 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/autonomous_tuning_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/autonomous_tuning_commands.py @@ -4,18 +4,18 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql._client_factory import \ - get_postgresql_flexible_management_client, \ - cf_postgres_flexible_tuning_options -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import \ - get_postgres_location_capability_info, \ - get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._util import get_autonomous_tuning_settings_map -from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group from azure.cli.core.commands.client_factory import get_subscription_id from azure.cli.core.util import CLIError from knack.log import get_logger -from .parameter_commands import flexible_parameter_update, _update_parameters +from .._client_factory import ( + cf_postgres_flexible_tuning_options, + get_postgresql_flexible_management_client) +from ..utils._flexible_server_location_capabilities_util import ( + get_postgres_location_capability_info, + get_postgres_server_capability_info) +from ..utils._util import get_autonomous_tuning_settings_map +from ..utils.validators import validate_resource_group +from .parameter_commands import _update_parameters, flexible_parameter_update logger = get_logger(__name__) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py index 612aae1ebb8..9ac2bf9b353 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py @@ -4,9 +4,9 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group, validate_backup_name from azure.cli.core.util import user_confirmation from knack.log import get_logger +from ..utils.validators import validate_resource_group, validate_backup_name logger = get_logger(__name__) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/custom_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/custom_commands.py new file mode 100644 index 00000000000..fe38d462cbd --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/custom_commands.py @@ -0,0 +1,835 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument, line-too-long +from functools import cmp_to_key +from importlib import import_module +from urllib.parse import quote +from knack.log import get_logger +from knack.prompting import prompt +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.local_context import ALL +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.core.exceptions import ResourceNotFoundError +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from azure.mgmt.core.tools import is_valid_resource_id, parse_resource_id, resource_id +from .._client_factory import ( + cf_postgres_check_resource_availability, + cf_postgres_flexible_admin, + cf_postgres_flexible_config, + cf_postgres_flexible_db, + cf_postgres_flexible_firewall_rules, + cf_postgres_flexible_private_dns_zone_suffix_operations, + get_postgresql_flexible_management_client) +from .._db_context import DbContext +from ..utils._flexible_server_location_capabilities_util import ( + get_postgres_location_capability_info, + get_postgres_server_capability_info) +from ..utils._flexible_server_util import ( + _is_resource_name, + build_identity_and_data_encryption, + generate_missing_parameters, + generate_password, + get_current_time, + get_postgres_skus, + get_postgres_tiers, + parse_maintenance_window, + resolve_poller) +from ..utils.validators import ( + check_resource_group, + compare_sku_names, + pg_arguments_validator, + pg_byok_validator, + pg_restore_validator, + validate_and_format_restore_point_in_time, + validate_citus_cluster, + validate_georestore_network, + validate_resource_group, + validate_server_name) +from .firewall_rule_commands import create_firewall_rule +from .microsoft_entra_commands import _create_admin +from .network_commands import ( + flexible_server_provision_network_resource, + prepare_private_dns_zone) + +logger = get_logger(__name__) +DEFAULT_DB_NAME = 'flexibleserverdb' +POSTGRES_DB_NAME = 'postgres' +DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" +RESOURCE_PROVIDER = 'Microsoft.DBforPostgreSQL' + + +# region create without args +# pylint: disable=too-many-locals +# pylint: disable=too-many-statements +# pylint: disable=raise-missing-from, unbalanced-tuple-unpacking +def flexible_server_create(cmd, client, + resource_group_name=None, server_name=None, + location=None, backup_retention=None, + sku_name=None, tier=None, + storage_gb=None, version=None, microsoft_entra_auth=None, + admin_name=None, admin_id=None, admin_type=None, + password_auth=None, administrator_login=None, administrator_login_password=None, + tags=None, subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, + private_dns_zone_arguments=None, public_access=None, + high_availability=None, zonal_resiliency=None, allow_same_zone=False, + zone=None, standby_availability_zone=None, + geo_redundant_backup=None, byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, + auto_grow=None, performance_tier=None, + storage_type=None, iops=None, throughput=None, create_cluster=None, cluster_size=None, database_name=None, yes=False): + + if not check_resource_group(resource_group_name): + resource_group_name = None + + # Generate missing parameters + location, resource_group_name, server_name = generate_missing_parameters(cmd, location, resource_group_name, + server_name, 'postgres') + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + server_name = server_name.lower() + high_availability_mode = high_availability + + if (sku_name is None) or (version is None) or \ + (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): + list_location_capability_info = get_postgres_location_capability_info(cmd, location) + + # set sku_name from capability API + if sku_name is None: + tiers = [item.lower() for item in get_postgres_tiers(list_location_capability_info['sku_info'])] + try: + sku_info = list_location_capability_info['sku_info'] + skus = list(get_postgres_skus(sku_info, tier.lower())) + skus = sorted(skus, key=cmp_to_key(compare_sku_names)) + sku_name = skus[0] + except: + raise CLIError('Incorrect value for --tier. Allowed values : {}'.format(tiers)) + # default to the latest version + if version is None: + supported_server_versions = sorted(list_location_capability_info['supported_server_versions']) + version = supported_server_versions[-1] + # set high availability from capability API + if (zonal_resiliency is not None and zonal_resiliency.lower() != 'disabled'): + single_az = list_location_capability_info['single_az'] + high_availability_mode = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' + + pg_arguments_validator(db_context, + server_name=server_name, + location=location, + tier=tier, sku_name=sku_name, + storage_gb=storage_gb, + auto_grow=auto_grow, + storage_type=storage_type, + iops=iops, throughput=throughput, + high_availability=high_availability, + zonal_resiliency=zonal_resiliency, + allow_same_zone=allow_same_zone, + standby_availability_zone=standby_availability_zone, + zone=zone, + subnet=subnet, + public_access=public_access, + version=version, + geo_redundant_backup=geo_redundant_backup, + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key, + performance_tier=performance_tier, + create_cluster=create_cluster, + password_auth=password_auth, microsoft_entra_auth=microsoft_entra_auth, + admin_name=admin_name, admin_id=admin_id, admin_type=admin_type,) + + cluster = None + if create_cluster == 'ElasticCluster': + cluster_size = cluster_size if cluster_size else 2 + cluster = postgresql_flexibleservers.models.Cluster(cluster_size=cluster_size, default_database_name=database_name if database_name else POSTGRES_DB_NAME) + + server_result = firewall_id = None + + network, start_ip, end_ip = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access=public_access, + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + + storage = postgresql_flexibleservers.models.Storage(storage_size_gb=storage_gb, auto_grow=auto_grow, tier=performance_tier, type=storage_type, iops=iops, throughput=throughput) + + backup = postgresql_flexibleservers.models.Backup(backup_retention_days=backup_retention, + geo_redundant_backup=geo_redundant_backup) + + sku = postgresql_flexibleservers.models.Sku(name=sku_name, tier=tier) + + high_availability = postgresql_flexibleservers.models.HighAvailability(mode=high_availability_mode, + standby_availability_zone=standby_availability_zone) + + is_password_auth_enabled = bool(password_auth is not None and password_auth.lower() == 'enabled') + is_microsoft_entra_auth_enabled = bool(microsoft_entra_auth is not None and microsoft_entra_auth.lower() == 'enabled') + if is_password_auth_enabled: + administrator_login_password = generate_password(administrator_login_password) + + identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + auth_config = postgresql_flexibleservers.models.AuthConfig(active_directory_auth='Enabled' if is_microsoft_entra_auth_enabled else 'Disabled', + password_auth=password_auth) + + # Create postgresql + # Note : passing public_access has no effect as the accepted values are 'Enabled' and 'Disabled'. So the value ends up being ignored. + server_result = _create_server(db_context, cmd, resource_group_name, server_name, + tags=tags, + location=location, + sku=sku, + administrator_login=administrator_login, + administrator_login_password=administrator_login_password, + storage=storage, + backup=backup, + network=network, + version=version, + high_availability=high_availability, + availability_zone=zone, + identity=identity, + data_encryption=data_encryption, + auth_config=auth_config, + cluster=cluster) + + # Add Microsoft Entra Admin + if is_microsoft_entra_auth_enabled and admin_name is not None or admin_id is not None: + server_admin_client = cf_postgres_flexible_admin(cmd.cli_ctx, '_') + logger.warning("Add Microsoft Entra Admin '%s'.", admin_name) + _create_admin(server_admin_client, resource_group_name, server_name, admin_name, admin_id, admin_type) + + # Adding firewall rule + if start_ip != -1 and end_ip != -1: + firewall_id = create_firewall_rule(db_context, cmd, resource_group_name, server_name, start_ip, end_ip) + + user = server_result.administrator_login if is_password_auth_enabled else '' + password = administrator_login_password if is_password_auth_enabled else '' + server_id = server_result.id + loc = server_result.location + version = server_result.version + sku = server_result.sku.name + host = server_result.fully_qualified_domain_name + subnet_id = None if network is None else network.delegated_subnet_resource_id + + if is_password_auth_enabled: + logger.warning('Make a note of your password. If you forget, you would have to ' + 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', + server_name, resource_group_name) + logger.warning('Try using \'az postgres flexible-server connect\' command to test out connection.') + + _update_local_contexts(cmd, server_name, resource_group_name, location, user) + + return _form_response(user, sku, loc, server_id, host, version, password, + firewall_id, subnet_id, is_password_auth_enabled, is_microsoft_entra_auth_enabled, admin_name) + + +def _create_server(db_context, cmd, resource_group_name, server_name, tags, location, sku, administrator_login, administrator_login_password, + storage, backup, network, version, high_availability, availability_zone, identity, data_encryption, auth_config, cluster): + validate_resource_group(resource_group_name) + + logging_name, server_client = db_context.logging_name, db_context.server_client + logger.warning('Creating %s Server \'%s\' in group \'%s\'...', logging_name, server_name, resource_group_name) + + logger.warning('Your server \'%s\' is using sku \'%s\' (Paid Tier). ' + 'Please refer to https://aka.ms/postgres-pricing for pricing details', server_name, sku.name) + + # Note : passing public-network-access has no effect as the accepted values are 'Enabled' and 'Disabled'. + # So when you pass an IP here(from the CLI args of public_access), it ends up being ignored. + parameters = postgresql_flexibleservers.models.Server( + tags=tags, + location=location, + sku=sku, + administrator_login=administrator_login, + administrator_login_password=administrator_login_password, + storage=storage, + backup=backup, + network=network, + version=version, + high_availability=high_availability, + availability_zone=availability_zone, + identity=identity, + data_encryption=data_encryption, + auth_config=auth_config, + cluster=cluster, + create_mode="Create") + + return resolve_poller( + server_client.begin_create_or_update(resource_group_name, server_name, parameters), cmd.cli_ctx, + '{} Server Create'.format(logging_name)) + + +def _update_local_contexts(cmd, server_name, resource_group_name, location, user): + validate_resource_group(resource_group_name) + + if cmd.cli_ctx.local_context.is_on: + cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'server_name', + server_name) # Setting the server name in the local context + cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'administrator_login', + user) # Setting the server name in the local context + cmd.cli_ctx.local_context.set(['postgres flexible-server'], 'database_name', + POSTGRES_DB_NAME) # Setting the server name in the local context + cmd.cli_ctx.local_context.set([ALL], 'location', + location) # Setting the location in the local context + cmd.cli_ctx.local_context.set([ALL], 'resource_group_name', resource_group_name) + + +def _form_response(username, sku, location, server_id, host, version, password, firewall_id=None, + subnet_id=None, is_password_auth=True, is_microsoft_entra_auth_enabled=False, microsoft_admin=None): + + connection_kwargs = { + 'user': username if username is not None else '{user}', + 'host': host, + 'password': password if password is not None else '{password}', + 'database': POSTGRES_DB_NAME, + } + output = { + 'host': host, + 'username': username if is_password_auth else None, + 'password': password if is_password_auth else None, + 'skuname': sku, + 'location': location, + 'id': server_id, + 'version': version, + 'databaseName': POSTGRES_DB_NAME, + 'connectionString': 'postgresql://{user}:{password}@{host}/{database}?sslmode=require'.format(**connection_kwargs) + } + if is_microsoft_entra_auth_enabled: + user = quote(microsoft_admin) if microsoft_admin else '' + connection_kwargs = { + 'user': user, + 'host': host, + 'database': POSTGRES_DB_NAME, + } + output['admin'] = microsoft_admin + output['connectionStringMicrosoftEntra'] = 'postgresql://{user}:@{host}/{database}?sslmode=require'.format(**connection_kwargs) + if firewall_id is not None: + output['firewallName'] = firewall_id + if subnet_id is not None: + output['subnetId'] = subnet_id + return output + + +def flexible_server_restore(cmd, client, + resource_group_name, server_name, + source_server, restore_point_in_time=None, zone=None, no_wait=False, + subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, + private_dns_zone_arguments=None, geo_redundant_backup=None, + byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, storage_type=None, yes=False): + + server_name = server_name.lower() + + validate_resource_group(resource_group_name) + + if not is_valid_resource_id(source_server): + if len(source_server.split('/')) == 1: + source_server_id = resource_id( + subscription=get_subscription_id(cmd.cli_ctx), + resource_group=resource_group_name, + namespace=RESOURCE_PROVIDER, + type='flexibleServers', + name=source_server) + else: + raise ValueError('The provided source server {} is invalid.'.format(source_server)) + else: + source_server_id = source_server + + restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) + + try: + id_parts = parse_resource_id(source_server_id) + source_subscription_id = id_parts['subscription'] + postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) + source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) + + location = ''.join(source_server_object.location.lower().split()) + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') + + pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) + + pg_restore_validator(source_server_object.sku.tier, storage_type=storage_type) + storage = postgresql_flexibleservers.models.Storage(type=storage_type if source_server_object.storage.type != "PremiumV2_LRS" else None) + + parameters = postgresql_flexibleservers.models.Server( + location=location, + point_in_time_utc=restore_point_in_time, + source_server_resource_id=source_server_id, # this should be the source server name, not id + create_mode="PointInTimeRestore", + availability_zone=zone, + storage=storage + ) + + if source_server_object.network.public_network_access == 'Disabled' and any((vnet, subnet)): + parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access='Disabled', + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + else: + parameters.network = source_server_object.network + + parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) + + parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + except Exception as e: + raise ResourceNotFoundError(e) + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) + + +# pylint: disable=too-many-branches +def flexible_server_update_custom_func(cmd, client, instance, + sku_name=None, tier=None, + storage_gb=None, + backup_retention=None, + administrator_login_password=None, + high_availability=None, + zonal_resiliency=None, + allow_same_zone=False, + standby_availability_zone=None, + maintenance_window=None, + byok_identity=None, byok_key=None, + backup_byok_identity=None, backup_byok_key=None, + microsoft_entra_auth=None, password_auth=None, + private_dns_zone_arguments=None, + public_access=None, + tags=None, + auto_grow=None, + performance_tier=None, + iops=None, throughput=None, + cluster_size=None, yes=False): + + # validator + location = ''.join(instance.location.lower().split()) + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + pg_arguments_validator(db_context, + location=location, + tier=tier, + sku_name=sku_name, + storage_gb=storage_gb, + auto_grow=auto_grow, + iops=iops, + throughput=throughput, + high_availability=high_availability, + zonal_resiliency=zonal_resiliency, + allow_same_zone=allow_same_zone, + zone=instance.availability_zone, + standby_availability_zone=standby_availability_zone, + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key, + performance_tier=performance_tier, + cluster_size=cluster_size, instance=instance) + + server_module_path = instance.__module__ + module = import_module(server_module_path) + ServerForPatch = getattr(module, 'ServerForPatch') + + server_id_parts = parse_resource_id(instance.id) + resource_group_name = server_id_parts['resource_group'] + server_name = server_id_parts['name'] + + if public_access: + instance.network.public_network_access = public_access + + if private_dns_zone_arguments: + private_dns_zone_id = prepare_private_dns_zone(db_context, + resource_group_name, + server_name, + private_dns_zone=private_dns_zone_arguments, + subnet_id=instance.network.delegated_subnet_resource_id, + location=location, + yes=yes) + instance.network.private_dns_zone_arm_resource_id = private_dns_zone_id + + _confirm_restart_server(instance, sku_name, storage_gb, yes) + + if sku_name: + instance.sku.name = sku_name + + if tier: + instance.sku.tier = tier + + if storage_gb: + instance.storage.storage_size_gb = storage_gb + + if auto_grow: + instance.storage.auto_grow = auto_grow + + instance.storage.tier = performance_tier if performance_tier else None + + if instance.storage.type == "PremiumV2_LRS": + instance.storage.tier = None + + if sku_name or storage_gb: + logger.warning("You are changing the compute and/or storage size of the server. " + "The server will be restarted for this operation and you will see a short downtime.") + + if iops: + instance.storage.iops = iops + + if throughput: + instance.storage.throughput = throughput + else: + instance.storage.type = None + instance.storage.iops = None + instance.storage.throughput = None + + if backup_retention: + instance.backup.backup_retention_days = backup_retention + + if maintenance_window: + if maintenance_window.lower() == "disabled": + # if disabled is pass in reset to default values + day_of_week = start_hour = start_minute = 0 + custom_window = "Disabled" + else: + day_of_week, start_hour, start_minute = parse_maintenance_window(maintenance_window) + custom_window = "Enabled" + + # set values - if maintenance_window when is None when created then create a new object + instance.maintenance_window.day_of_week = day_of_week + instance.maintenance_window.start_hour = start_hour + instance.maintenance_window.start_minute = start_minute + instance.maintenance_window.custom_window = custom_window + + identity, data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key, + instance=instance) + + auth_config = instance.auth_config + administrator_login = instance.administrator_login if instance.administrator_login else None + if microsoft_entra_auth: + auth_config.active_directory_auth = microsoft_entra_auth + if password_auth: + administrator_login, administrator_login_password = _update_login(server_name, resource_group_name, auth_config, + password_auth, administrator_login, administrator_login_password) + auth_config.password_auth = password_auth + + if cluster_size: + instance.cluster.cluster_size = cluster_size + + params = ServerForPatch(sku=instance.sku, + storage=instance.storage, + backup=instance.backup, + administrator_login=administrator_login, + administrator_login_password=administrator_login_password, + availability_zone=instance.availability_zone, + maintenance_window=instance.maintenance_window, + network=instance.network, + identity=identity, + data_encryption=data_encryption, + auth_config=auth_config, + cluster=instance.cluster, + tags=tags) + + # High availability can't be updated with existing properties + high_availability_param = postgresql_flexibleservers.models.HighAvailability() + if zonal_resiliency is not None: + if zonal_resiliency.lower() == 'disabled': + high_availability = 'Disabled' + else: + list_capability_info = get_postgres_server_capability_info(cmd, resource_group_name, server_name) + single_az = list_capability_info['single_az'] + high_availability = 'SameZone' if single_az and allow_same_zone else 'ZoneRedundant' + if high_availability: + high_availability_param.mode = high_availability + + if high_availability.lower() != "disabled" and standby_availability_zone: + high_availability_param.standby_availability_zone = standby_availability_zone + + # PG 11 and 12 will never receive fabric mirroring support. Ignite 2025 Fabric mirroring supported on 17. Skip this check for servers of these versions + if high_availability.lower() != "disabled" and str(instance.version) not in ["11", "12", "17", "18"]: + config_client = cf_postgres_flexible_config(cmd.cli_ctx, '_') + fabric_mirror_status = config_client.get(resource_group_name, server_name, 'azure.fabric_mirror_enabled') + if (fabric_mirror_status and fabric_mirror_status.value.lower() == 'on'): + raise CLIError("High availability cannot be enabled while Fabric mirroring is Active. Please disable Fabric mirroring to enable high availability.") + + params.high_availability = high_availability_param + + return params + + +# Common functions used by other providers +def flexible_server_update_get(client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + + return client.get(resource_group_name, server_name) + + +def flexible_server_update_set(client, resource_group_name, server_name, parameters): + validate_resource_group(resource_group_name) + + return client.begin_update(resource_group_name, server_name, parameters) + + +def _update_login(server_name, resource_group_name, auth_config, password_auth, administrator_login, administrator_login_password): + if auth_config.password_auth.lower() == 'disabled' and password_auth.lower() == 'enabled': + administrator_login = administrator_login if administrator_login else prompt('Please enter administrator username for the server. Once set, it cannot be changed: ') + if not administrator_login: + raise CLIError('Administrator username is required for enabling password authentication.') + if not administrator_login_password: + administrator_login_password = generate_password(administrator_login_password) + logger.warning('Make a note of password "%s". You can ' + 'reset your password with "az postgres flexible-server update -n %s -g %s -p ".', + administrator_login_password, server_name, resource_group_name) + + return administrator_login, administrator_login_password + + +# pylint: disable=chained-comparison +def _confirm_restart_server(instance, sku_name, storage_gb, yes): + show_confirmation = False + + # check if sku_name is changed + if sku_name and sku_name != instance.sku.name: + show_confirmation = True + + # check if requested storage growth is crossing the 4096 threshold + if storage_gb and storage_gb > 4096 and instance.storage.storage_size_gb <= 4096 and instance.storage.type == "": + show_confirmation = True + + # check if storage_gb changed for PremiumV2_LRS + if storage_gb and instance.storage.type == "PremiumV2_LRS" and instance.storage.storage_size_gb != storage_gb: + show_confirmation = True + + if not yes and show_confirmation: + user_confirmation("You are trying to change the compute or the size of storage assigned to your server in a way that \ + requires a server restart. During the restart, you'll experience some downtime of the server. Do you want to proceed?", yes=yes) + + +def flexible_server_delete(cmd, client, resource_group_name, server_name, yes=False): + validate_resource_group(resource_group_name) + result = None + if not yes: + user_confirmation( + "Are you sure you want to delete the server '{0}' in resource group '{1}'".format(server_name, + resource_group_name), yes=yes) + try: + result = client.begin_delete(resource_group_name, server_name) + if cmd.cli_ctx.local_context.is_on: + local_context_file = cmd.cli_ctx.local_context._get_local_context_file() # pylint: disable=protected-access + local_context_file.remove_option('postgres flexible-server', 'server_name') + local_context_file.remove_option('postgres flexible-server', 'administrator_login') + local_context_file.remove_option('postgres flexible-server', 'database_name') + except Exception as ex: # pylint: disable=broad-except + logger.error(ex) + raise CLIError(ex) + return result + + +def flexible_server_postgresql_get(cmd, resource_group_name, server_name): + validate_resource_group(resource_group_name) + client = get_postgresql_flexible_management_client(cmd.cli_ctx) + return client.servers.get(resource_group_name, server_name) + + +def server_list_custom_func(client, resource_group_name=None, show_cluster=None): + if not check_resource_group(resource_group_name): + resource_group_name = None + + servers = client.list_by_subscription() + + if resource_group_name: + servers = client.list_by_resource_group(resource_group_name) + + if show_cluster: + servers = [s for s in servers if s.cluster is not None] + else: + servers = [s for s in servers if s.cluster is None] + + return servers + + +def flexible_list_skus(cmd, client, location): + result = client.list(location) + logger.warning('For prices please refer to https://aka.ms/postgres-pricing') + return result + + +def flexible_server_georestore(cmd, client, resource_group_name, server_name, source_server, location, zone=None, + vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, + private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, + byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None, restore_point_in_time=None): + validate_resource_group(resource_group_name) + + server_name = server_name.lower() + + if not is_valid_resource_id(source_server): + if _is_resource_name(source_server): + source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), + resource_group=resource_group_name, + namespace='Microsoft.DBforPostgreSQL', + type='flexibleServers', + name=source_server) + else: + raise CLIError('The provided source-server {} is invalid.'.format(source_server)) + else: + source_server_id = source_server + + restore_point_in_time = validate_and_format_restore_point_in_time(restore_point_in_time) + + try: + id_parts = parse_resource_id(source_server_id) + validate_citus_cluster(cmd, id_parts['resource_group'], id_parts['name']) + source_subscription_id = id_parts['subscription'] + postgres_source_client = get_postgresql_flexible_management_client(cmd.cli_ctx, source_subscription_id) + source_server_object = postgres_source_client.servers.get(id_parts['resource_group'], id_parts['name']) + except Exception as e: + raise ResourceNotFoundError(e) + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') + if source_server_object.network.delegated_subnet_resource_id is not None: + validate_georestore_network(source_server_object, None, vnet, subnet, 'postgres') + + pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) + + storage = postgresql_flexibleservers.models.Storage(type=None) + + parameters = postgresql_flexibleservers.models.Server( + point_in_time_utc=restore_point_in_time, + location=location, + source_server_resource_id=source_server_id, + create_mode="GeoRestore", + availability_zone=zone, + storage=storage + ) + + if source_server_object.network.public_network_access == 'Disabled': + parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access='Disabled', + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + + parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) + + parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) + + +def flexible_server_revivedropped(cmd, client, resource_group_name, server_name, source_server, location, zone=None, + vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, + private_dns_zone_arguments=None, geo_redundant_backup=None, no_wait=False, yes=False, + byok_identity=None, byok_key=None, backup_byok_identity=None, backup_byok_key=None): + validate_resource_group(resource_group_name) + + server_name = server_name.lower() + + if not is_valid_resource_id(source_server): + if _is_resource_name(source_server): + source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), + resource_group=resource_group_name, + namespace='Microsoft.DBforPostgreSQL', + type='flexibleServers', + name=source_server) + else: + raise CLIError('The provided source-server {} is invalid.'.format(source_server)) + else: + source_server_id = source_server + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + + validate_server_name(db_context, server_name, 'Microsoft.DBforPostgreSQL/flexibleServers') + + pg_byok_validator(byok_identity, byok_key, backup_byok_identity, backup_byok_key, geo_redundant_backup) + + storage = postgresql_flexibleservers.models.Storage(type=None) + + parameters = postgresql_flexibleservers.models.Server( + point_in_time_utc=get_current_time(), + location=location, + source_server_resource_id=source_server_id, + create_mode="ReviveDropped", + availability_zone=zone, + storage=storage + ) + + if vnet is not None or vnet_address_prefix is not None or subnet is not None or \ + subnet_address_prefix is not None or private_dns_zone_arguments is not None: + parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=server_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access='Disabled', + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + + parameters.backup = postgresql_flexibleservers.models.Backup(geo_redundant_backup=geo_redundant_backup) + + parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key, + backup_byok_identity=backup_byok_identity, + backup_byok_key=backup_byok_key) + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/database_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/database_commands.py index 214d6934f02..a9fc902e279 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/database_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/database_commands.py @@ -4,14 +4,14 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql.utils.validators import \ - validate_resource_group, \ - check_resource_group, \ - validate_citus_cluster, \ - validate_database_name from azure.cli.core.azclierror import RequiredArgumentMissingError from azure.cli.core.util import CLIError, user_confirmation from knack.log import get_logger +from ..utils.validators import ( + validate_resource_group, + check_resource_group, + validate_citus_cluster, + validate_database_name) logger = get_logger(__name__) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/deploy_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/deploy_commands.py index 2a0ba844d55..0a8a3bc3c46 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/deploy_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/deploy_commands.py @@ -4,15 +4,15 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql.utils._flexible_server_util import \ - run_subprocess, \ - fill_action_template, \ - get_git_root_dir, \ - GITHUB_ACTION_PATH -from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group from azure.cli.core.azclierror import ClientRequestError, RequiredArgumentMissingError from azure.cli.core.util import run_cmd from knack.log import get_logger +from ..utils._flexible_server_util import ( + run_subprocess, + fill_action_template, + get_git_root_dir, + GITHUB_ACTION_PATH) +from ..utils.validators import validate_resource_group logger = get_logger(__name__) # pylint: disable=raise-missing-from diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/fabric_mirroring_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/fabric_mirroring_commands.py index 038be3e2bfd..5138a1e4174 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/fabric_mirroring_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/fabric_mirroring_commands.py @@ -4,13 +4,13 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_servers -from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group, validate_citus_cluster from azure.cli.core.util import CLIError, user_confirmation from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers from knack.log import get_logger from .identity_commands import flexible_server_identity_update from .parameter_commands import _update_parameters +from .._client_factory import cf_postgres_flexible_servers +from ..utils.validators import validate_resource_group, validate_citus_cluster logger = get_logger(__name__) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/firewall_rule_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/firewall_rule_commands.py index acfd0a89792..09202ac4708 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/firewall_rule_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/firewall_rule_commands.py @@ -4,11 +4,11 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql.utils.validators import validate_public_access_server, validate_resource_group from azure.cli.core.util import user_confirmation from datetime import datetime from knack.log import get_logger from knack.util import CLIError +from ..utils.validators import validate_public_access_server, validate_resource_group logger = get_logger(__name__) # pylint: disable=raise-missing-from diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/identity_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/identity_commands.py index 1fc96c665e2..f6070cf265b 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/identity_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/identity_commands.py @@ -4,11 +4,11 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_config -from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller -from azure.cli.command_modules.postgresql.utils.validators import validate_citus_cluster, validate_resource_group from azure.cli.core.util import CLIError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from .._client_factory import cf_postgres_flexible_config +from ..utils._flexible_server_util import resolve_poller +from ..utils.validators import validate_citus_cluster, validate_resource_group def flexible_server_identity_update(cmd, client, resource_group_name, server_name, system_assigned): diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/microsoft_entra_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/microsoft_entra_commands.py index 663b18bacb8..97c50dc2e50 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/microsoft_entra_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/microsoft_entra_commands.py @@ -4,10 +4,10 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_servers -from azure.cli.command_modules.postgresql.utils._flexible_server_util import get_tenant_id -from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group from azure.cli.core.util import CLIError, sdk_no_wait +from .._client_factory import cf_postgres_flexible_servers +from ..utils._flexible_server_util import get_tenant_id +from ..utils.validators import validate_resource_group def flexible_server_microsoft_entra_admin_set(cmd, client, resource_group_name, server_name, login, sid, principal_type=None, no_wait=False): diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/migration_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/migration_commands.py index 0ee4480f8be..038759a9f69 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/migration_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/migration_commands.py @@ -8,16 +8,6 @@ import os import uuid -from azure.cli.command_modules.postgresql.utils._flexible_server_util import ( - generate_missing_parameters, - get_case_insensitive_key_value, - get_enum_value_true_false, -) -from azure.cli.command_modules.postgresql.utils.validators import ( - validate_citus_cluster, - validate_migration_runtime_server, - validate_resource_group, -) from azure.cli.core.azclierror import ( BadRequestError, FileOperationError, @@ -27,6 +17,16 @@ from azure.cli.core.commands.client_factory import get_subscription_id from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers from knack.log import get_logger +from ..utils._flexible_server_util import ( + generate_missing_parameters, + get_case_insensitive_key_value, + get_enum_value_true_false, +) +from ..utils.validators import ( + validate_citus_cluster, + validate_migration_runtime_server, + validate_resource_group, +) logger = get_logger(__name__) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/network_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/network_commands.py index f1260dad11c..13e61044a97 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/network_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/network_commands.py @@ -4,23 +4,37 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long, import-outside-toplevel -from azure.cli.command_modules.postgresql._client_factory import ( +from azure.cli.core.azclierror import RequiredArgumentMissingError, ValidationError +from azure.cli.core.commands import LongRunningOperation +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation +from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from azure.mgmt.core.tools import ( # pylint: disable=import-error + is_valid_resource_id, + is_valid_resource_name, + parse_resource_id, + resource_id, +) +from azure.mgmt.privatedns.models import PrivateZone, SubResource, VirtualNetworkLink +from knack.log import get_logger +from requests import get +from .._client_factory import ( private_dns_client_factory, private_dns_link_client_factory, resource_client_factory, ) -from azure.cli.command_modules.postgresql._config_reader import get_cloud_cluster -from azure.cli.command_modules.postgresql.aaz.latest.network.vnet import ( +from .._config_reader import get_cloud_cluster +from ..aaz.latest.network.vnet import ( Create as VNetCreate, Show as VNetShow, Update as _VNetUpdate, ) -from azure.cli.command_modules.postgresql.aaz.latest.network.vnet.subnet import ( +from ..aaz.latest.network.vnet.subnet import ( Create as SubnetCreate, Show as SubnetShow, Update as SubnetUpdate, ) -from azure.cli.command_modules.postgresql.utils._flexible_server_util import ( +from ..utils._flexible_server_util import ( _check_resource_group_existence, _is_resource_name, check_existence, @@ -28,27 +42,11 @@ get_user_confirmation, parse_public_access_input, ) -from azure.cli.command_modules.postgresql.utils.validators import ( +from ..utils.validators import ( validate_private_dns_zone, validate_resource_group, validate_vnet_location, ) -from azure.cli.core.azclierror import RequiredArgumentMissingError, ValidationError -from azure.cli.core.commands import LongRunningOperation -from azure.cli.core.commands.client_factory import get_subscription_id -from azure.cli.core.util import CLIError, sdk_no_wait, user_confirmation -from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from azure.mgmt.core.tools import ( # pylint: disable=import-error - is_valid_resource_id, - is_valid_resource_name, - parse_resource_id, - resource_id, -) -from azure.mgmt.privatedns.models import PrivateZone -from azure.mgmt.privatedns.models import SubResource -from azure.mgmt.privatedns.models import VirtualNetworkLink -from knack.log import get_logger -from requests import get logger = get_logger(__name__) DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers" diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/parameter_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/parameter_commands.py index 5f9e3f09184..99b0202332d 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/parameter_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/parameter_commands.py @@ -4,11 +4,11 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller -from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group from azure.cli.core.util import CLIError from azure.core.exceptions import HttpResponseError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ..utils._flexible_server_util import resolve_poller +from ..utils.validators import validate_resource_group def flexible_parameter_update(client, server_name, configuration_name, resource_group_name, source=None, value=None): diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/power_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/power_commands.py index 668910c6025..d723511316e 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/power_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/power_commands.py @@ -4,12 +4,12 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller -from azure.cli.command_modules.postgresql.utils.validators import check_resource_group, validate_citus_cluster, validate_resource_group from azure.cli.core.azclierror import ArgumentUsageError, InvalidArgumentValueError from azure.cli.core.util import sdk_no_wait from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers from knack.log import get_logger +from ..utils._flexible_server_util import resolve_poller +from ..utils.validators import check_resource_group, validate_citus_cluster, validate_resource_group logger = get_logger(__name__) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/private_endpoint_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/private_endpoint_commands.py index 9b797befc9f..2c415c4c82f 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/private_endpoint_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/private_endpoint_commands.py @@ -4,8 +4,8 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_private_endpoint_connections -from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group +from .._client_factory import cf_postgres_flexible_private_endpoint_connections +from ..utils.validators import validate_resource_group def flexible_server_approve_private_endpoint_connection(cmd, client, resource_group_name, server_name, private_endpoint_connection_name, diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py index 336a9575770..6b694a4ed53 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py @@ -4,11 +4,11 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql.utils.validators import is_citus_cluster, validate_resource_group from azure.cli.core.azclierror import ValidationError from azure.cli.core.util import CLIError from azure.core.exceptions import ResourceNotFoundError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers +from ..utils.validators import is_citus_cluster, validate_resource_group def flexible_replica_promote(cmd, client, resource_group_name, replica_name, promote_mode='standalone', promote_option='planned'): diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py index 57b4916a971..95b9c1cb1fa 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py @@ -6,15 +6,15 @@ # pylint: disable=unused-argument, line-too-long import re -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_replica -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller -from azure.cli.command_modules.postgresql.utils.validators import validate_citus_cluster, validate_resource_group from azure.cli.core.util import CLIError, user_confirmation from datetime import datetime, timedelta from dateutil.tz import tzutc # pylint: disable=import-error from knack.log import get_logger from urllib.request import urlretrieve +from .._client_factory import cf_postgres_flexible_replica +from ..utils._flexible_server_location_capabilities_util import get_postgres_server_capability_info +from ..utils._flexible_server_util import resolve_poller +from ..utils.validators import validate_citus_cluster, validate_resource_group logger = get_logger(__name__) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/threat_protection_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/threat_protection_commands.py index cb79d4ccf84..8c5621279a0 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/threat_protection_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/threat_protection_commands.py @@ -4,9 +4,9 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller -from azure.cli.command_modules.postgresql.utils.validators import validate_resource_group from azure.core.exceptions import HttpResponseError +from ..utils._flexible_server_util import resolve_poller +from ..utils.validators import validate_resource_group def flexible_server_threat_protection_get( diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/upgrade_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/upgrade_commands.py index e41c2b94b1e..ddb5cde6e30 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/upgrade_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/upgrade_commands.py @@ -4,13 +4,13 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql._client_factory import cf_postgres_flexible_replica -from azure.cli.command_modules.postgresql.utils._flexible_server_location_capabilities_util import get_postgres_server_capability_info -from azure.cli.command_modules.postgresql.utils._flexible_server_util import resolve_poller -from azure.cli.command_modules.postgresql.utils.validators import validate_citus_cluster, validate_resource_group from azure.cli.core.util import user_confirmation from knack.log import get_logger from knack.util import CLIError +from .._client_factory import cf_postgres_flexible_replica +from ..utils._flexible_server_location_capabilities_util import get_postgres_server_capability_info +from ..utils._flexible_server_util import resolve_poller +from ..utils.validators import validate_citus_cluster, validate_resource_group logger = get_logger(__name__) # pylint: disable=raise-missing-from diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/virtual_endpoint_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/virtual_endpoint_commands.py index f6875ba108f..5ee8f898ee6 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/virtual_endpoint_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/virtual_endpoint_commands.py @@ -4,12 +4,12 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.command_modules.postgresql.utils.validators import ( +from azure.cli.core.util import user_confirmation +from ..utils.validators import ( validate_citus_cluster, validate_resource_group, validate_virtual_endpoint_name_availability, ) -from azure.cli.core.util import user_confirmation def virtual_endpoint_create_func(cmd, client, resource_group_name, server_name, virtual_endpoint_name, endpoint_type, members): diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_private_dns_zone.py b/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_private_dns_zone.py index e828d3a9b91..f3a7ff2d692 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_private_dns_zone.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/tests/latest/test_postgres_flexible_commands_private_dns_zone.py @@ -4,17 +4,18 @@ # -------------------------------------------------------------------------------------------- import time -from azure.cli.testsdk.scenario_tests import AllowLargeResponse + from azure.cli.testsdk import ( JMESPathCheck, NoneCheck, ResourceGroupPreparer, ScenarioTest, StringContainCheck) -from ..._client_factory import cf_postgres_flexible_private_dns_zone_suffix_operations -from ...flexible_server_network import prepare_private_dns_zone -from ...flexible_server_custom_postgres import DbContext as PostgresDbContext +from azure.cli.testsdk.scenario_tests import AllowLargeResponse from .constants import DEFAULT_LOCATION, SERVER_NAME_PREFIX, SERVER_NAME_MAX_LENGTH +from ..._client_factory import cf_postgres_flexible_private_dns_zone_suffix_operations +from ..._db_context import DbContext as PostgresDbContext +from ...commands.network_commands import prepare_private_dns_zone class PostgreSQLFlexibleServerPrivateDnsZoneScenarioTest(ScenarioTest): From 5cd9324d45c5d5b1d805e4a2acb7863da4a4acf6 Mon Sep 17 00:00:00 2001 From: Naia Scott Date: Wed, 4 Mar 2026 13:15:50 -0500 Subject: [PATCH 08/10] Fixes --- .../postgresql/commands/custom_commands.py | 50 +++++ .../postgresql/commands/replica_commands.py | 156 ++++++++++++- .../postgresql/flexible_server_commands.py | 206 +++++++++++------- 3 files changed, 330 insertions(+), 82 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/custom_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/custom_commands.py index fe38d462cbd..58be4360940 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/custom_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/custom_commands.py @@ -833,3 +833,53 @@ def flexible_server_revivedropped(cmd, client, resource_group_name, server_name, backup_byok_key=backup_byok_key) return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, server_name, parameters) + + +def flexible_server_connection_string( + server_name='{server}', + database_name='{database}', + administrator_login='{login}', + administrator_login_password='{password}', + show_pg_bouncer=False): + host = '{}.postgres.database.azure.com'.format(server_name) + port = 5432 + if show_pg_bouncer is True: + port = 6432 + + return { + 'connectionStrings': _create_postgresql_connection_strings(host, administrator_login, + administrator_login_password, database_name, port) + } + + +def _create_postgresql_connection_strings(host, user, password, database, port): + + result = { + 'psql_cmd': "postgresql://{user}:{password}@{host}/{database}?sslmode=require", + 'ado.net': "Server={host};Database={database};Port={port};User Id={user};Password={password};Ssl Mode=Require;", + 'jdbc': "jdbc:postgresql://{host}:{port}/{database}?user={user}&password={password}&sslmode=require", + 'jdbc Spring': "spring.datasource.url=jdbc:postgresql://{host}:{port}/{database} " + "spring.datasource.username={user} " + "spring.datasource.password={password}", + 'node.js': "var conn= new Client({open_brace}host:'{host}', user:'{user}', password:'{password}', database:'{database}', port:{port}, ssl:{open_brace}ca:fs.readFileSync(\"{ca-cert filename}\"){close_brace}{close_brace});", + 'php': "pg_connect(\"host={host} port={port} dbname={database} user={user} password={password}\");", + 'python': "cnx = psycopg2.connect(user='{user}', password='{password}', host='{host}', " + "port={port}, database='{database}')", + 'ruby': "connection = PG::Connection.new(user => \"{user}\", password => \"{password}\", database => \"{database}\", host => \"{host}\", " + "port => '{port}')", + } + + connection_kwargs = { + 'host': host, + 'user': user, + 'password': password if password is not None else '{password}', + 'database': database, + 'port': port, + 'open_brace': '{', + 'close_brace': '}', + 'ca-cert filename': '{ca-cert filename}' + } + + for k, v in result.items(): + result[k] = v.format(**connection_kwargs) + return result diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py index 6b694a4ed53..211c33e09ca 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py @@ -4,11 +4,155 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=unused-argument, line-too-long -from azure.cli.core.azclierror import ValidationError -from azure.cli.core.util import CLIError +from azure.cli.core.azclierror import MutuallyExclusiveArgumentError, RequiredArgumentMissingError, ValidationError +from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.util import CLIError, sdk_no_wait from azure.core.exceptions import ResourceNotFoundError from azure.mgmt import postgresqlflexibleservers as postgresql_flexibleservers -from ..utils.validators import is_citus_cluster, validate_resource_group +from azure.mgmt.core.tools import is_valid_resource_id, parse_resource_id, resource_id +from ..utils._flexible_server_location_capabilities_util import get_postgres_location_capability_info +from ..utils._flexible_server_util import _is_resource_name, build_identity_and_data_encryption +from ..utils.validators import ( + is_citus_cluster, + pg_byok_validator, + validate_citus_cluster, + validate_postgres_replica, + validate_resource_group, + validate_server_name) +from .._client_factory import ( + cf_postgres_flexible_firewall_rules, + cf_postgres_flexible_db, + cf_postgres_check_resource_availability, + cf_postgres_flexible_private_dns_zone_suffix_operations) +from .._db_context import DbContext +from .network_commands import flexible_server_provision_network_resource + + +def flexible_replica_create(cmd, client, resource_group_name, source_server, replica_name=None, name=None, zone=None, + location=None, vnet=None, vnet_address_prefix=None, subnet=None, + subnet_address_prefix=None, private_dns_zone_arguments=None, no_wait=False, + byok_identity=None, byok_key=None, + sku_name=None, tier=None, + storage_gb=None, performance_tier=None, yes=False, tags=None): + validate_resource_group(resource_group_name) + + if replica_name is None and name is None: + raise RequiredArgumentMissingError('the following arguments are required: --name') + if replica_name is not None and name is not None: + raise MutuallyExclusiveArgumentError('usage error: --name and --replica-name cannot be used together. Please use --name.') + replica_name = replica_name.lower() if name is None else name.lower() + + if not is_valid_resource_id(source_server): + if _is_resource_name(source_server): + source_server_id = resource_id(subscription=get_subscription_id(cmd.cli_ctx), + resource_group=resource_group_name, + namespace='Microsoft.DBforPostgreSQL', + type='flexibleServers', + name=source_server) + else: + raise CLIError('The provided source-server {} is invalid.'.format(source_server)) + else: + source_server_id = source_server + + source_server_id_parts = parse_resource_id(source_server_id) + try: + source_server_object = client.get(source_server_id_parts['resource_group'], source_server_id_parts['name']) + except Exception as e: + raise ResourceNotFoundError(e) + + if not location: + location = source_server_object.location + location = ''.join(location.lower().split()) + + list_location_capability_info = get_postgres_location_capability_info(cmd, location) + + if tier is None and source_server_object is not None: + tier = source_server_object.sku.tier + if sku_name is None and source_server_object is not None: + sku_name = source_server_object.sku.name + if storage_gb is None and source_server_object is not None: + storage_gb = source_server_object.storage.storage_size_gb + validate_postgres_replica(cmd, tier, location, source_server_object, + sku_name, storage_gb, performance_tier, list_location_capability_info) + + if not zone: + zone = _get_pg_replica_zone(list_location_capability_info['zones'], + source_server_object.availability_zone, + zone) + + db_context = DbContext( + cmd=cmd, azure_sdk=postgresql_flexibleservers, cf_firewall=cf_postgres_flexible_firewall_rules, + cf_db=cf_postgres_flexible_db, cf_availability=cf_postgres_check_resource_availability, + cf_private_dns_zone_suffix=cf_postgres_flexible_private_dns_zone_suffix_operations, + logging_name='PostgreSQL', command_group='postgres', server_client=client, location=location) + validate_server_name(db_context, replica_name, 'Microsoft.DBforPostgreSQL/flexibleServers') + + pg_byok_validator(byok_identity, byok_key) + + parameters = postgresql_flexibleservers.models.Server( + tags=tags, + source_server_resource_id=source_server_id, + location=location, + availability_zone=zone, + create_mode="Replica") + + if source_server_object.network.public_network_access == 'Disabled' and any((vnet, subnet)): + parameters.network, _, _ = flexible_server_provision_network_resource(cmd=cmd, + resource_group_name=resource_group_name, + server_name=replica_name, + location=location, + db_context=db_context, + private_dns_zone_arguments=private_dns_zone_arguments, + public_access='Disabled', + vnet=vnet, + subnet=subnet, + vnet_address_prefix=vnet_address_prefix, + subnet_address_prefix=subnet_address_prefix, + yes=yes) + else: + parameters.network = source_server_object.network + + parameters.identity, parameters.data_encryption = build_identity_and_data_encryption(db_engine='postgres', + byok_identity=byok_identity, + byok_key=byok_key) + + parameters.sku = postgresql_flexibleservers.models.Sku(name=sku_name, tier=tier) + + parameters.storage = postgresql_flexibleservers.models.Storage(storage_size_gb=storage_gb, auto_grow=source_server_object.storage.auto_grow, tier=performance_tier) + + return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, replica_name, parameters) + + +def _get_pg_replica_zone(availabilityZones, sourceServerZone, replicaZone): + preferredZone = 'none' + for _index, zone in enumerate(availabilityZones): + if zone != sourceServerZone and zone != 'none': + preferredZone = zone + + if not preferredZone: + preferredZone = 'none' + + selectZone = preferredZone if not replicaZone else replicaZone + + selectZoneSupported = False + for _index, zone in enumerate(availabilityZones): + if zone == selectZone: + selectZoneSupported = True + + pg_replica_zone = None + if len(availabilityZones) > 1 and selectZone and selectZoneSupported: + pg_replica_zone = selectZone if selectZone != 'none' else None + else: + sourceZoneSupported = False + for _index, zone in enumerate(availabilityZones): + if zone == sourceServerZone: + sourceZoneSupported = True + if sourceZoneSupported: + pg_replica_zone = sourceServerZone + else: + pg_replica_zone = None + + return pg_replica_zone def flexible_replica_promote(cmd, client, resource_group_name, replica_name, promote_mode='standalone', promote_option='planned'): @@ -46,3 +190,9 @@ def flexible_replica_promote(cmd, client, resource_group_name, replica_name, pro ) return client.begin_update(resource_group_name, replica_name, params) + + +def flexible_replica_list_by_server(cmd, client, resource_group_name, server_name): + validate_resource_group(resource_group_name) + validate_citus_cluster(cmd, resource_group_name, server_name) + return client.list_by_server(resource_group_name, server_name) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_commands.py index 72943549f97..2bb2be44167 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/flexible_server_commands.py @@ -117,121 +117,155 @@ def load_flexibleserver_command_table(self, _): client_factory=cf_postgres_flexible_private_link_resources ) - # MERU COMMANDS - flexible_server_custom_common = CliCommandType( - operations_tmpl='azure.cli.command_modules.postgresql.flexible_server_custom_common#{}') - flexible_servers_custom_postgres = CliCommandType( - operations_tmpl='azure.cli.command_modules.postgresql.flexible_server_custom_postgres#{}') - # Postgres commands + custom_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.custom_commands#{}') with self.command_group('postgres flexible-server', postgres_flexible_servers_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=custom_commands, client_factory=cf_postgres_flexible_servers) as g: g.custom_command('create', 'flexible_server_create', table_transformer=table_transform_output) g.custom_command('restore', 'flexible_server_restore', supports_no_wait=True) g.custom_command('geo-restore', 'flexible_server_georestore', supports_no_wait=True) g.custom_command('revive-dropped', 'flexible_server_revivedropped', supports_no_wait=True) - g.command('start', 'begin_start', supports_no_wait=True) - g.custom_command('stop', 'flexible_server_stop', custom_command_type=flexible_server_custom_common, supports_no_wait=True) g.custom_command('delete', 'flexible_server_delete') g.show_command('show', 'get') - g.custom_command('list', 'server_list_custom_func', custom_command_type=flexible_server_custom_common, table_transformer=table_transform_output_list_servers) + g.custom_command('list', 'server_list_custom_func', table_transformer=table_transform_output_list_servers) g.generic_update_command('update', - getter_name='flexible_server_update_get', getter_type=flexible_server_custom_common, - setter_name='flexible_server_update_set', setter_type=flexible_server_custom_common, + getter_name='flexible_server_update_get', getter_type=custom_commands, + setter_name='flexible_server_update_set', setter_type=custom_commands, setter_arg_name='parameters', custom_func_name='flexible_server_update_custom_func') - g.custom_command('upgrade', 'flexible_server_version_upgrade', custom_command_type=flexible_server_custom_common) g.custom_wait_command('wait', 'flexible_server_postgresql_get') + g.custom_command('show-connection-string', 'flexible_server_connection_string') + + with self.command_group('postgres flexible-server', postgres_flexible_location_capabilities_sdk, + custom_command_type=custom_commands, + client_factory=cf_postgres_flexible_location_capabilities) as g: + g.custom_command('list-skus', 'flexible_list_skus', table_transformer=postgres_table_transform_output_list_skus) + + power_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.power_commands#{}') + with self.command_group('postgres flexible-server', postgres_flexible_servers_sdk, + custom_command_type=power_commands, + client_factory=cf_postgres_flexible_servers) as g: + g.command('start', 'begin_start', supports_no_wait=True) + g.custom_command('stop', 'flexible_server_stop', supports_no_wait=True) g.custom_command('restart', 'flexible_server_restart') + + upgrade_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.upgrade_commands#{}') + with self.command_group('postgres flexible-server', postgres_flexible_servers_sdk, + custom_command_type=upgrade_commands, + client_factory=cf_postgres_flexible_servers) as g: + g.custom_command('upgrade', 'flexible_server_version_upgrade') + + network_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.network_commands#{}') + with self.command_group('postgres flexible-server', postgres_flexible_servers_sdk, + custom_command_type=network_commands, + client_factory=cf_postgres_flexible_servers) as g: g.custom_command('migrate-network', 'flexible_server_migrate_network', supports_no_wait=True) + firewall_rule_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.firewall_rule_commands#{}') with self.command_group('postgres flexible-server firewall-rule', postgres_flexible_firewall_rule_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=firewall_rule_commands, client_factory=cf_postgres_flexible_firewall_rules) as g: - g.custom_command('create', 'firewall_rule_create_func', custom_command_type=flexible_server_custom_common) - g.custom_command('delete', 'firewall_rule_delete_func', custom_command_type=flexible_server_custom_common) - g.custom_show_command('show', 'firewall_rule_get_func', custom_command_type=flexible_server_custom_common) - g.custom_command('list', 'firewall_rule_list_func', custom_command_type=flexible_server_custom_common) + g.custom_command('create', 'firewall_rule_create_func') + g.custom_command('delete', 'firewall_rule_delete_func') + g.custom_show_command('show', 'firewall_rule_get_func') + g.custom_command('list', 'firewall_rule_list_func') g.generic_update_command('update', - getter_name='flexible_firewall_rule_custom_getter', getter_type=flexible_server_custom_common, - setter_name='flexible_firewall_rule_custom_setter', setter_type=flexible_server_custom_common, + getter_name='flexible_firewall_rule_custom_getter', getter_type=firewall_rule_commands, + setter_name='flexible_firewall_rule_custom_setter', setter_type=firewall_rule_commands, setter_arg_name='parameters', custom_func_name='flexible_firewall_rule_update_custom_func', - custom_func_type=flexible_server_custom_common) + custom_func_type=firewall_rule_commands) + migration_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.migration_commands#{}') with self.command_group('postgres flexible-server migration', postgres_flexible_migrations_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=migration_commands, client_factory=cf_postgres_flexible_migrations) as g: - g.custom_command('create', 'migration_create_func', custom_command_type=flexible_servers_custom_postgres) - g.custom_show_command('show', 'migration_show_func', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('list', 'migration_list_func', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('update', 'migration_update_func', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('check-name-availability', 'migration_check_name_availability', custom_command_type=flexible_servers_custom_postgres) - + g.custom_command('create', 'migration_create_func') + g.custom_show_command('show', 'migration_show_func') + g.custom_command('list', 'migration_list_func') + g.custom_command('update', 'migration_update_func') + g.custom_command('check-name-availability', 'migration_check_name_availability') + + virtual_endpoint_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.virtual_endpoint_commands#{}') with self.command_group('postgres flexible-server virtual-endpoint', postgres_flexible_virtual_endpoints_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=virtual_endpoint_commands, client_factory=cf_postgres_flexible_virtual_endpoints) as g: - g.custom_command('create', 'virtual_endpoint_create_func', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('delete', 'virtual_endpoint_delete_func', custom_command_type=flexible_servers_custom_postgres) - g.custom_show_command('show', 'virtual_endpoint_show_func', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('list', 'virtual_endpoint_list_func', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('update', 'virtual_endpoint_update_func', custom_command_type=flexible_servers_custom_postgres) - + g.custom_command('create', 'virtual_endpoint_create_func') + g.custom_command('delete', 'virtual_endpoint_delete_func') + g.custom_show_command('show', 'virtual_endpoint_show_func') + g.custom_command('list', 'virtual_endpoint_list_func') + g.custom_command('update', 'virtual_endpoint_update_func') + + server_parameter_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.parameter_commands#{}') with self.command_group('postgres flexible-server parameter', postgres_flexible_config_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=server_parameter_commands, client_factory=cf_postgres_flexible_config, table_transformer=table_transform_output_parameters) as g: g.custom_command('set', 'flexible_parameter_update') g.show_command('show', 'get') g.command('list', 'list_by_server') - with self.command_group('postgres flexible-server', postgres_flexible_location_capabilities_sdk, - custom_command_type=flexible_servers_custom_postgres, - client_factory=cf_postgres_flexible_location_capabilities) as g: - g.custom_command('list-skus', 'flexible_list_skus', table_transformer=postgres_table_transform_output_list_skus) - g.custom_command('show-connection-string', 'flexible_server_connection_string') - + database_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.database_commands#{}') with self.command_group('postgres flexible-server db', postgres_flexible_db_sdk, - custom_command_type=flexible_server_custom_common, + custom_command_type=database_commands, client_factory=cf_postgres_flexible_db) as g: - g.custom_command('create', 'database_create_func', custom_command_type=flexible_servers_custom_postgres) + g.custom_command('create', 'database_create_func') g.custom_command('delete', 'database_delete_func') g.show_command('show', 'get') g.command('list', 'list_by_server') + deploy_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.deploy_commands#{}') with self.command_group('postgres flexible-server deploy', postgres_flexible_servers_sdk, - custom_command_type=flexible_server_custom_common, + custom_command_type=deploy_commands, client_factory=cf_postgres_flexible_servers) as g: g.custom_command('setup', 'github_actions_setup') g.custom_command('run', 'github_actions_run') + backup_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.backup_commands#{}') with self.command_group('postgres flexible-server backup', postgres_flexible_backups_sdk, + custom_command_type=backup_commands, client_factory=cf_postgres_flexible_backups) as g: g.command('list', 'list_by_server', transform=transform_backups_list) g.show_command('show', 'get', transform=transform_backup) - g.custom_command('create', 'backup_create_func', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('delete', 'backup_delete_func', custom_command_type=flexible_servers_custom_postgres) + g.custom_command('create', 'backup_create_func') + g.custom_command('delete', 'backup_delete_func') with self.command_group('postgres flexible-server long-term-retention', postgres_flexible_ltr_backup_sdk, + custom_command_type=backup_commands, client_factory=cf_postgres_flexible_ltr_backups) as g: g.command('list', 'list_by_server', transform=transform_backups_list) g.show_command('show', 'get', transform=transform_backup) - g.custom_command('pre-check', 'ltr_precheck_func', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('start', 'ltr_start_func', custom_command_type=flexible_servers_custom_postgres) + g.custom_command('pre-check', 'ltr_precheck_func') + g.custom_command('start', 'ltr_start_func') + replica_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.replica_commands#{}') with self.command_group('postgres flexible-server replica', postgres_flexible_replica_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=replica_commands, client_factory=cf_postgres_flexible_replica) as g: g.custom_command('list', 'flexible_replica_list_by_server') with self.command_group('postgres flexible-server replica', postgres_flexible_servers_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=replica_commands, client_factory=cf_postgres_flexible_servers) as g: g.custom_command('create', 'flexible_replica_create', supports_no_wait=True) g.custom_command('promote', 'flexible_replica_promote', confirmation=True) + identity_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.identity_commands#{}') with self.command_group('postgres flexible-server identity', postgres_flexible_servers_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=identity_commands, client_factory=cf_postgres_flexible_servers) as g: g.custom_command('update', 'flexible_server_identity_update', supports_no_wait=True) g.custom_command('assign', 'flexible_server_identity_assign', supports_no_wait=True) @@ -239,8 +273,10 @@ def load_flexibleserver_command_table(self, _): g.custom_show_command('show', 'flexible_server_identity_show') g.custom_command('list', 'flexible_server_identity_list') + microsoft_entra_admin_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.microsoft_entra_commands#{}') with self.command_group('postgres flexible-server microsoft-entra-admin', postgres_flexible_admin_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=microsoft_entra_admin_commands, client_factory=cf_postgres_flexible_admin) as g: g.custom_command('create', 'flexible_server_microsoft_entra_admin_set', supports_no_wait=True) g.custom_command('delete', 'flexible_server_microsoft_entra_admin_delete', supports_no_wait=True, confirmation=True) @@ -248,61 +284,73 @@ def load_flexibleserver_command_table(self, _): g.custom_show_command('show', 'flexible_server_microsoft_entra_admin_show') g.custom_wait_command('wait', 'flexible_server_microsoft_entra_admin_show') + advanced_threat_protection_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.threat_protection_commands#{}') with self.command_group('postgres flexible-server advanced-threat-protection-setting', postgres_flexible_advanced_threat_protection_settings_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=advanced_threat_protection_commands, client_factory=cf_postgres_flexible_advanced_threat_protection_settings) as g: - g.custom_show_command('show', 'flexible_server_threat_protection_get', custom_command_type=flexible_servers_custom_postgres) + g.custom_show_command('show', 'flexible_server_threat_protection_get') with self.command_group('postgres flexible-server advanced-threat-protection-setting', postgres_flexible_server_threat_protection_settings_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=advanced_threat_protection_commands, client_factory=cf_postgres_flexible_server_threat_protection_settings) as g: - g.custom_command('update', 'flexible_server_threat_protection_update', custom_command_type=flexible_servers_custom_postgres) + g.custom_command('update', 'flexible_server_threat_protection_update') + server_logs_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.server_logs_commands#{}') with self.command_group('postgres flexible-server server-logs', postgres_flexible_server_log_files_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=server_logs_commands, client_factory=cf_postgres_flexible_server_log_files) as g: - g.custom_command('list', 'flexible_server_list_log_files_with_filter', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('download', 'flexible_server_download_log_files', custom_command_type=flexible_servers_custom_postgres) + g.custom_command('list', 'flexible_server_list_log_files_with_filter') + g.custom_command('download', 'flexible_server_download_log_files') + private_endpoint_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.private_endpoint_commands#{}') with self.command_group('postgres flexible-server private-endpoint-connection', postgres_flexible_server_private_endpoint_connections_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=private_endpoint_commands, client_factory=cf_postgres_flexible_private_endpoint_connections) as g: g.command('list', 'list_by_server') g.show_command('show', 'get', validator=validate_private_endpoint_connection_id) g.command('delete', 'begin_delete', validator=validate_private_endpoint_connection_id) - g.custom_command('approve', 'flexible_server_approve_private_endpoint_connection', custom_command_type=flexible_servers_custom_postgres, + g.custom_command('approve', 'flexible_server_approve_private_endpoint_connection', validator=validate_private_endpoint_connection_id) - g.custom_command('reject', 'flexible_server_reject_private_endpoint_connection', custom_command_type=flexible_servers_custom_postgres, + g.custom_command('reject', 'flexible_server_reject_private_endpoint_connection', validator=validate_private_endpoint_connection_id) with self.command_group('postgres flexible-server private-link-resource', postgres_flexible_server_private_link_resources_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=private_endpoint_commands, client_factory=cf_postgres_flexible_private_link_resources) as g: g.command('list', 'list_by_server') - g.custom_show_command('show', 'flexible_server_private_link_resource_get', custom_command_type=flexible_servers_custom_postgres) + g.custom_show_command('show', 'flexible_server_private_link_resource_get') + fabric_mirroring_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.fabric_mirroring_commands#{}') with self.command_group('postgres flexible-server fabric-mirroring', postgres_flexible_config_sdk, - custom_command_type=flexible_servers_custom_postgres, + custom_command_type=fabric_mirroring_commands, client_factory=cf_postgres_flexible_config) as g: g.custom_command('start', 'flexible_server_fabric_mirroring_start') g.custom_command('stop', 'flexible_server_fabric_mirroring_stop') g.custom_command('update-databases', 'flexible_server_fabric_mirroring_update_databases') + autonomous_tuning_commands = CliCommandType( + operations_tmpl='azure.cli.command_modules.postgresql.commands.autonomous_tuning_commands#{}') with self.command_group('postgres flexible-server index-tuning', postgres_flexible_config_sdk, + custom_command_type=autonomous_tuning_commands, client_factory=cf_postgres_flexible_config) as g: - g.custom_command('update', 'index_tuning_update', custom_command_type=flexible_servers_custom_postgres) - g.custom_show_command('show', 'index_tuning_show', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('list-settings', 'index_tuning_settings_list', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('show-settings', 'index_tuning_settings_get', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('set-settings', 'index_tuning_settings_set', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('list-recommendations', 'index_tuning_recommendations_list', custom_command_type=flexible_servers_custom_postgres) + g.custom_command('update', 'index_tuning_update') + g.custom_show_command('show', 'index_tuning_show') + g.custom_command('list-settings', 'index_tuning_settings_list') + g.custom_command('show-settings', 'index_tuning_settings_get') + g.custom_command('set-settings', 'index_tuning_settings_set') + g.custom_command('list-recommendations', 'index_tuning_recommendations_list') with self.command_group('postgres flexible-server autonomous-tuning', postgres_flexible_config_sdk, + custom_command_type=autonomous_tuning_commands, client_factory=cf_postgres_flexible_config) as g: - g.custom_command('update', 'autonomous_tuning_update', custom_command_type=flexible_servers_custom_postgres) - g.custom_show_command('show', 'autonomous_tuning_show', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('list-settings', 'autonomous_tuning_settings_list', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('show-settings', 'autonomous_tuning_settings_get', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('set-settings', 'autonomous_tuning_settings_set', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('list-table-recommendations', 'autonomous_tuning_table_recommendations_list', custom_command_type=flexible_servers_custom_postgres) - g.custom_command('list-index-recommendations', 'autonomous_tuning_index_recommendations_list', custom_command_type=flexible_servers_custom_postgres) + g.custom_command('update', 'autonomous_tuning_update') + g.custom_show_command('show', 'autonomous_tuning_show') + g.custom_command('list-settings', 'autonomous_tuning_settings_list') + g.custom_command('show-settings', 'autonomous_tuning_settings_get') + g.custom_command('set-settings', 'autonomous_tuning_settings_set') + g.custom_command('list-table-recommendations', 'autonomous_tuning_table_recommendations_list') + g.custom_command('list-index-recommendations', 'autonomous_tuning_index_recommendations_list') From af982fd6824b8f1264bfa08d2e3eda95dc396963 Mon Sep 17 00:00:00 2001 From: Naia Scott Date: Fri, 6 Mar 2026 15:55:58 -0500 Subject: [PATCH 09/10] add init files to new folders --- .../azure/cli/command_modules/postgresql/commands/__init__.py | 4 ++++ .../azure/cli/command_modules/postgresql/utils/__init__.py | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/commands/__init__.py create mode 100644 src/azure-cli/azure/cli/command_modules/postgresql/utils/__init__.py diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/__init__.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/__init__.py new file mode 100644 index 00000000000..34913fb394d --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/__init__.py @@ -0,0 +1,4 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/utils/__init__.py b/src/azure-cli/azure/cli/command_modules/postgresql/utils/__init__.py new file mode 100644 index 00000000000..34913fb394d --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/postgresql/utils/__init__.py @@ -0,0 +1,4 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- From 7c35ea94d93ee986802613c2f7223f7e42dc05e8 Mon Sep 17 00:00:00 2001 From: Naia Scott Date: Mon, 9 Mar 2026 18:29:13 -0400 Subject: [PATCH 10/10] add lint suppresion --- .../cli/command_modules/postgresql/commands/replica_commands.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py index 211c33e09ca..672c3fa4250 100644 --- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py +++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/replica_commands.py @@ -28,6 +28,7 @@ from .network_commands import flexible_server_provision_network_resource +# pylint: disable=too-many-locals def flexible_replica_create(cmd, client, resource_group_name, source_server, replica_name=None, name=None, zone=None, location=None, vnet=None, vnet_address_prefix=None, subnet=None, subnet_address_prefix=None, private_dns_zone_arguments=None, no_wait=False,