1357 lines
50 KiB
Python
1357 lines
50 KiB
Python
# -*- coding: utf-8 -*- #
|
|
# Copyright 2017 Google LLC. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
"""Common utility functions for sql instance commands."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
import re
|
|
|
|
from googlecloudsdk.api_lib.sql import constants
|
|
from googlecloudsdk.api_lib.sql import exceptions as sql_exceptions
|
|
from googlecloudsdk.api_lib.sql import instance_prop_reducers as reducers
|
|
from googlecloudsdk.api_lib.sql import instances as api_util
|
|
from googlecloudsdk.api_lib.sql import validate
|
|
from googlecloudsdk.calliope import base
|
|
from googlecloudsdk.calliope import exceptions
|
|
from googlecloudsdk.command_lib import info_holder
|
|
from googlecloudsdk.command_lib.util.args import labels_util
|
|
from googlecloudsdk.core import execution_utils
|
|
from googlecloudsdk.core import log
|
|
from googlecloudsdk.core import properties
|
|
from googlecloudsdk.core.console import console_io
|
|
import six
|
|
|
|
DEFAULT_RELEASE_TRACK = base.ReleaseTrack.GA
|
|
|
|
# Argument mapping to internal storage type.
|
|
STORAGE_TYPE_MAPPING = {
|
|
'HDD': 'PD_HDD',
|
|
'SSD': 'PD_SSD',
|
|
'HYPERDISK_BALANCED': 'HYPERDISK_BALANCED',
|
|
}
|
|
|
|
|
|
def GetInstanceRef(args, client):
|
|
"""Validates and returns the instance reference."""
|
|
validate.ValidateInstanceName(args.instance)
|
|
return client.resource_parser.Parse(
|
|
args.instance,
|
|
params={'project': properties.VALUES.core.project.GetOrFail},
|
|
collection='sql.instances',
|
|
)
|
|
|
|
|
|
def GetDatabaseArgs(args, flags):
|
|
"""Gets the args for specifying a database during instance connection."""
|
|
command_line_args = []
|
|
if args.IsSpecified('database'):
|
|
try:
|
|
command_line_args.extend([flags['database'], args.database])
|
|
except KeyError:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--database', 'This instance does not support the database argument.'
|
|
)
|
|
return command_line_args
|
|
|
|
|
|
def ConnectToInstance(cmd_args, sql_user):
|
|
"""Connects to the instance using the relevant CLI."""
|
|
try:
|
|
log.status.write(
|
|
'Connecting to database with SQL user [{0}].'.format(sql_user)
|
|
)
|
|
execution_utils.Exec(cmd_args)
|
|
except OSError:
|
|
log.error('Failed to execute command "{0}"'.format(' '.join(cmd_args)))
|
|
log.Print(info_holder.InfoHolder())
|
|
|
|
|
|
def _GetAndValidateCmekKeyName(args, is_primary):
|
|
"""Parses the CMEK resource arg, makes sure the key format was correct."""
|
|
kms_ref = args.CONCEPTS.kms_key.Parse()
|
|
if kms_ref:
|
|
# Since CMEK is required for replicas of CMEK primaries, this prompt is only
|
|
# actionable for primary instances.
|
|
if is_primary:
|
|
_ShowCmekPrompt()
|
|
return kms_ref.RelativeName()
|
|
else:
|
|
# Check for partially specified disk-encryption-key.
|
|
for keyword in [
|
|
'disk-encryption-key',
|
|
'disk-encryption-key-keyring',
|
|
'disk-encryption-key-location',
|
|
'disk-encryption-key-project',
|
|
]:
|
|
if getattr(args, keyword.replace('-', '_'), None):
|
|
raise exceptions.InvalidArgumentException(
|
|
'--disk-encryption-key', 'not fully specified.'
|
|
)
|
|
|
|
|
|
def _GetZone(args):
|
|
return args.zone or args.gce_zone
|
|
|
|
|
|
def _GetSecondaryZone(args):
|
|
if 'secondary_zone' in args:
|
|
return args.secondary_zone
|
|
|
|
return None
|
|
|
|
|
|
def DoesEnterprisePlusReplicaInferTierForDatabaseType(replica_database_version):
|
|
"""Checks if the replica inherits the tier of the primary for E+ instances.
|
|
|
|
Ideally, this would be the case for all database versions. However, changing
|
|
it now is technically a breaking change, so we are only adding support for new
|
|
database types going forward.
|
|
|
|
Args:
|
|
replica_database_version: The database version of the replica.
|
|
|
|
Returns:
|
|
True if the replica infers the tier from the primary (database version is
|
|
PG16+).
|
|
"""
|
|
if replica_database_version.startswith('POSTGRES_'):
|
|
# Extract the database major version from the database version string:
|
|
# POSTGRES_16 -> 16
|
|
database_major_version = int(
|
|
re.search(r'^POSTGRES_(\d+).*', replica_database_version).group(1)
|
|
)
|
|
return database_major_version > 15
|
|
if replica_database_version.startswith('MYSQL_'):
|
|
# Extract the database major version from the database version string:
|
|
# MYSQL_8_4 -> 8.4
|
|
match = re.search(r'^MYSQL_(\d+)_(\d+).*', replica_database_version)
|
|
database_major_version = (int(match.group(1)), int(match.group(2)))
|
|
return database_major_version > (8, 0)
|
|
return False
|
|
|
|
|
|
def _IsAlpha(release_track):
|
|
return release_track == base.ReleaseTrack.ALPHA
|
|
|
|
|
|
def IsBetaOrNewer(release_track):
|
|
return release_track == base.ReleaseTrack.BETA or _IsAlpha(release_track)
|
|
|
|
|
|
def _ParseActivationPolicy(sql_messages, policy):
|
|
if policy:
|
|
return sql_messages.Settings.ActivationPolicyValueValuesEnum.lookup_by_name(
|
|
policy.replace('-', '_').upper()
|
|
)
|
|
return None
|
|
|
|
|
|
def _ParseAvailabilityType(sql_messages, availability_type):
|
|
if availability_type:
|
|
return sql_messages.Settings.AvailabilityTypeValueValuesEnum.lookup_by_name(
|
|
availability_type.upper()
|
|
)
|
|
return None
|
|
|
|
|
|
def ParseDatabaseVersion(sql_messages, database_version):
|
|
if database_version:
|
|
return sql_messages.DatabaseInstance.DatabaseVersionValueValuesEnum.lookup_by_name(
|
|
database_version.upper()
|
|
)
|
|
return None
|
|
|
|
|
|
def _ParsePricingPlan(sql_messages, pricing_plan):
|
|
if pricing_plan:
|
|
return sql_messages.Settings.PricingPlanValueValuesEnum.lookup_by_name(
|
|
pricing_plan.upper()
|
|
)
|
|
return None
|
|
|
|
|
|
def _ParseReplicationType(sql_messages, replication):
|
|
if replication:
|
|
return sql_messages.Settings.ReplicationTypeValueValuesEnum.lookup_by_name(
|
|
replication.upper()
|
|
)
|
|
return None
|
|
|
|
|
|
def _ParseStorageType(sql_messages, storage_type):
|
|
if storage_type:
|
|
return sql_messages.Settings.DataDiskTypeValueValuesEnum.lookup_by_name(
|
|
storage_type.upper()
|
|
)
|
|
return None
|
|
|
|
|
|
def _ParseEdition(sql_messages, edition):
|
|
if edition:
|
|
return sql_messages.Settings.EditionValueValuesEnum.lookup_by_name(
|
|
edition.replace('-', '_').upper()
|
|
)
|
|
return None
|
|
|
|
|
|
def _ParseInstanceType(sql_messages, instance_type):
|
|
if instance_type:
|
|
return sql_messages.DatabaseInstance.InstanceTypeValueValuesEnum.lookup_by_name(
|
|
instance_type.replace('-', '_').upper()
|
|
)
|
|
return None
|
|
|
|
|
|
# The caller must make sure that the connector_enforcement is specified.
|
|
def _ParseConnectorEnforcement(sql_messages, connector_enforcement):
|
|
return (
|
|
sql_messages.Settings.ConnectorEnforcementValueValuesEnum.lookup_by_name(
|
|
connector_enforcement.upper()
|
|
)
|
|
)
|
|
|
|
|
|
def _ParseDataApiAccess(sql_messages, data_api_access):
|
|
return (
|
|
sql_messages.Settings.DataApiAccessValueValuesEnum.lookup_by_name(
|
|
data_api_access.upper()
|
|
)
|
|
)
|
|
|
|
|
|
def _ParseSslMode(sql_messages, ssl_mode):
|
|
return sql_messages.IpConfiguration.SslModeValueValuesEnum.lookup_by_name(
|
|
ssl_mode.upper()
|
|
)
|
|
|
|
|
|
def _ParseServerCaMode(sql_messages, server_ca_mode):
|
|
return (
|
|
sql_messages.IpConfiguration.ServerCaModeValueValuesEnum.lookup_by_name(
|
|
server_ca_mode.upper()
|
|
)
|
|
)
|
|
|
|
|
|
def _ParseServerCertificateRotationMode(sql_messages, server_certificate_rotation_mode):
|
|
return (
|
|
sql_messages.IpConfiguration.ServerCertificateRotationModeValueValuesEnum.lookup_by_name(
|
|
server_certificate_rotation_mode.upper()
|
|
)
|
|
)
|
|
|
|
|
|
# TODO(b/122660263): Remove when V1 instances are no longer supported.
|
|
def ShowV1DeprecationWarning(plural=False):
|
|
message = (
|
|
'Upgrade your First Generation instance{} to Second Generation before we '
|
|
'auto-upgrade {} on March 4, 2020, ahead of the full decommission of '
|
|
'First Generation on March 25, 2020.'
|
|
)
|
|
if plural:
|
|
log.warning(message.format('s', 'them'))
|
|
else:
|
|
log.warning(message.format('', 'it'))
|
|
|
|
|
|
def ShowZoneDeprecationWarnings(args):
|
|
"""Show warnings if both region and zone are specified or neither is.
|
|
|
|
Args:
|
|
args: argparse.Namespace, The arguments that the command was invoked with.
|
|
"""
|
|
|
|
region_specified = args.IsSpecified('region')
|
|
zone_specified = args.IsSpecified('gce_zone') or args.IsSpecified('zone')
|
|
|
|
# TODO(b/73362371): Remove this check; user must specify a location flag.
|
|
if not (region_specified or zone_specified):
|
|
log.warning(
|
|
'Starting with release 233.0.0, you will need to specify '
|
|
'either a region or a zone to create an instance.'
|
|
)
|
|
|
|
|
|
def ShowCmekWarning(resource_type_label, instance_type_label=None):
|
|
if instance_type_label is None:
|
|
log.warning(
|
|
'Your {} will be encrypted with a customer-managed key. If anyone '
|
|
'destroys this key, all data encrypted with it will be permanently '
|
|
'lost.'.format(resource_type_label)
|
|
)
|
|
else:
|
|
log.warning(
|
|
"Your {} will be encrypted with {}'s customer-managed encryption key. "
|
|
'If anyone destroys this key, all data encrypted with it will be '
|
|
'permanently lost.'.format(resource_type_label, instance_type_label)
|
|
)
|
|
|
|
|
|
def _ShowCmekPrompt():
|
|
log.warning(
|
|
'You are creating a Cloud SQL instance encrypted with a customer-managed '
|
|
'key. If anyone destroys a customer-managed key, all data encrypted with '
|
|
'it will be permanently lost.\n'
|
|
)
|
|
console_io.PromptContinue(cancel_on_no=True)
|
|
|
|
|
|
def _ShowFailoverReplicaDeprecationWarning():
|
|
log.warning(
|
|
'Failover replicas will soon be deprecated and support will be '
|
|
'discontinued. We recommend migrating to the new '
|
|
'high availability configuration, based on regional persistent '
|
|
'disks (RePD). For more information, see '
|
|
'https://cloud.google.com/sql/docs/mysql/configure-legacy-ha#update-from-legacy'
|
|
)
|
|
|
|
|
|
def _ShowAcceleratedReplicaModeWarning():
|
|
log.warning(
|
|
'Enabling accelerated replica mode on a replica may cause it to be '
|
|
'recreated in the event of an unplanned restart.'
|
|
)
|
|
|
|
|
|
class _BaseInstances(object):
|
|
"""Common utility functions for sql instance commands."""
|
|
|
|
@classmethod
|
|
def _ConstructBaseSettingsFromArgs(
|
|
cls,
|
|
sql_messages,
|
|
args,
|
|
instance=None,
|
|
release_track=DEFAULT_RELEASE_TRACK,
|
|
):
|
|
"""Constructs instance settings from the command line arguments.
|
|
|
|
Args:
|
|
sql_messages: module, The messages module that should be used.
|
|
args: argparse.Namespace, The arguments that this command was invoked
|
|
with.
|
|
instance: sql_messages.DatabaseInstance, The original instance, for
|
|
settings that depend on the previous state.
|
|
release_track: base.ReleaseTrack, the release track that this was run
|
|
under.
|
|
|
|
Returns:
|
|
A settings object representing the instance settings.
|
|
|
|
Raises:
|
|
ToolException: An error other than http error occurred while executing the
|
|
command.
|
|
"""
|
|
|
|
# This code is shared by create and patch, but these args don't exist in
|
|
# create anymore, so insert them here to avoid regressions below.
|
|
if 'authorized_gae_apps' not in args:
|
|
args.authorized_gae_apps = None
|
|
if 'follow_gae_app' not in args:
|
|
args.follow_gae_app = None
|
|
if 'pricing_plan' not in args:
|
|
args.pricing_plan = 'PER_USE'
|
|
if not args.IsKnownAndSpecified('replication'):
|
|
args.replication = None
|
|
|
|
settings = sql_messages.Settings(
|
|
kind='sql#settings',
|
|
tier=reducers.MachineType(instance, args.tier, args.memory, args.cpu),
|
|
pricingPlan=_ParsePricingPlan(sql_messages, args.pricing_plan),
|
|
replicationType=_ParseReplicationType(sql_messages, args.replication),
|
|
activationPolicy=_ParseActivationPolicy(
|
|
sql_messages, args.activation_policy
|
|
),
|
|
)
|
|
|
|
if args.authorized_gae_apps:
|
|
settings.authorizedGaeApplications = args.authorized_gae_apps
|
|
|
|
if any([
|
|
args.assign_ip is not None,
|
|
args.require_ssl is not None,
|
|
args.authorized_networks,
|
|
]):
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
if args.assign_ip is not None:
|
|
cls.SetIpConfigurationEnabled(settings, args.assign_ip)
|
|
|
|
if args.authorized_networks:
|
|
cls.SetAuthorizedNetworks(
|
|
settings, args.authorized_networks, sql_messages.AclEntry
|
|
)
|
|
|
|
if args.require_ssl is not None:
|
|
settings.ipConfiguration.requireSsl = args.require_ssl
|
|
|
|
if any([args.follow_gae_app, _GetZone(args), _GetSecondaryZone(args)]):
|
|
settings.locationPreference = sql_messages.LocationPreference(
|
|
kind='sql#locationPreference',
|
|
followGaeApplication=args.follow_gae_app,
|
|
zone=_GetZone(args),
|
|
secondaryZone=_GetSecondaryZone(args),
|
|
)
|
|
|
|
if args.storage_size:
|
|
settings.dataDiskSizeGb = int(args.storage_size / constants.BYTES_TO_GB)
|
|
|
|
if args.IsKnownAndSpecified('storage_provisioned_iops'):
|
|
settings.dataDiskProvisionedIops = int(args.storage_provisioned_iops)
|
|
|
|
if args.IsKnownAndSpecified('storage_provisioned_throughput'):
|
|
settings.dataDiskProvisionedThroughput = int(
|
|
args.storage_provisioned_throughput
|
|
)
|
|
|
|
if args.storage_auto_increase is not None:
|
|
settings.storageAutoResize = args.storage_auto_increase
|
|
|
|
if args.IsSpecified('availability_type'):
|
|
settings.availabilityType = _ParseAvailabilityType(
|
|
sql_messages, args.availability_type
|
|
)
|
|
|
|
if args.IsSpecified('network'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
settings.ipConfiguration.privateNetwork = reducers.PrivateNetworkUrl(
|
|
args.network
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('enable_google_private_path'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
settings.ipConfiguration.enablePrivatePathForGoogleCloudServices = (
|
|
args.enable_google_private_path
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('enable_private_service_connect'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
if not settings.ipConfiguration.pscConfig:
|
|
settings.ipConfiguration.pscConfig = sql_messages.PscConfig()
|
|
settings.ipConfiguration.pscConfig.pscEnabled = (
|
|
args.enable_private_service_connect
|
|
)
|
|
|
|
if args.IsSpecified('allowed_psc_projects'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
if not settings.ipConfiguration.pscConfig:
|
|
settings.ipConfiguration.pscConfig = sql_messages.PscConfig()
|
|
settings.ipConfiguration.pscConfig.allowedConsumerProjects = (
|
|
args.allowed_psc_projects
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('clear_allowed_psc_projects'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
if not settings.ipConfiguration.pscConfig:
|
|
settings.ipConfiguration.pscConfig = sql_messages.PscConfig()
|
|
settings.ipConfiguration.pscConfig.allowedConsumerProjects = []
|
|
|
|
if args.IsKnownAndSpecified('psc_network_attachment_uri'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
if not settings.ipConfiguration.pscConfig:
|
|
settings.ipConfiguration.pscConfig = sql_messages.PscConfig()
|
|
settings.ipConfiguration.pscConfig.networkAttachmentUri = (
|
|
args.psc_network_attachment_uri
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('clear_psc_network_attachment_uri'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
if not settings.ipConfiguration.pscConfig:
|
|
settings.ipConfiguration.pscConfig = sql_messages.PscConfig()
|
|
settings.ipConfiguration.pscConfig.networkAttachmentUri = ''
|
|
|
|
if args.deletion_protection is not None:
|
|
settings.deletionProtectionEnabled = args.deletion_protection
|
|
|
|
if args.IsSpecified('connector_enforcement'):
|
|
settings.connectorEnforcement = _ParseConnectorEnforcement(
|
|
sql_messages, args.connector_enforcement
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('recreate_replicas_on_primary_crash'):
|
|
settings.recreateReplicasOnPrimaryCrash = (
|
|
args.recreate_replicas_on_primary_crash
|
|
)
|
|
|
|
if args.IsSpecified('edition'):
|
|
settings.edition = _ParseEdition(sql_messages, args.edition)
|
|
|
|
if args.IsKnownAndSpecified('enable_data_cache'):
|
|
if not settings.dataCacheConfig:
|
|
settings.dataCacheConfig = sql_messages.DataCacheConfig()
|
|
settings.dataCacheConfig.dataCacheEnabled = args.enable_data_cache
|
|
|
|
if args.IsSpecified('ssl_mode'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
settings.ipConfiguration.sslMode = _ParseSslMode(
|
|
sql_messages, args.ssl_mode
|
|
)
|
|
|
|
if args.enable_google_ml_integration is not None:
|
|
settings.enableGoogleMlIntegration = args.enable_google_ml_integration
|
|
|
|
if args.enable_dataplex_integration is not None:
|
|
settings.enableDataplexIntegration = args.enable_dataplex_integration
|
|
|
|
if args.IsKnownAndSpecified('server_ca_mode'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
settings.ipConfiguration.serverCaMode = _ParseServerCaMode(
|
|
sql_messages, args.server_ca_mode
|
|
)
|
|
|
|
if args.retain_backups_on_delete is not None:
|
|
settings.retainBackupsOnDelete = args.retain_backups_on_delete
|
|
|
|
if args.IsKnownAndSpecified('enable_auto_upgrade_minor_version'):
|
|
settings.autoUpgradeEnabled = True
|
|
|
|
if args.IsKnownAndSpecified('server_ca_pool'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
settings.ipConfiguration.serverCaPool = args.server_ca_pool
|
|
# Customers can set `--server-ca-pool=''` to explicitly clear the
|
|
# server_ca_pool field.
|
|
if args.IsKnownAndSpecified('server_ca_pool') and args.server_ca_pool:
|
|
if (
|
|
settings.ipConfiguration.serverCaMode
|
|
!= sql_messages.IpConfiguration.ServerCaModeValueValuesEnum.CUSTOMER_MANAGED_CAS_CA
|
|
):
|
|
raise sql_exceptions.ArgumentError(
|
|
'`--server-ca-pool` can only be specified when the server CA mode'
|
|
' is CUSTOMER_MANAGED_CAS_CA.'
|
|
)
|
|
elif (
|
|
settings.ipConfiguration
|
|
and settings.ipConfiguration.serverCaMode
|
|
== sql_messages.IpConfiguration.ServerCaModeValueValuesEnum.CUSTOMER_MANAGED_CAS_CA
|
|
):
|
|
raise exceptions.RequiredArgumentException(
|
|
'--server-ca-pool',
|
|
(
|
|
'To create an instance with server CA mode '
|
|
'CUSTOMER_MANAGED_CAS_CA, [--server-ca-pool] must be '
|
|
'specified.'
|
|
),
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('server_certificate_rotation_mode'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
settings.ipConfiguration.serverCertificateRotationMode = (
|
|
_ParseServerCertificateRotationMode(
|
|
sql_messages, args.server_certificate_rotation_mode
|
|
)
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('custom_subject_alternative_names'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
settings.ipConfiguration.customSubjectAlternativeNames = (
|
|
args.custom_subject_alternative_names
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('clear_custom_subject_alternative_names'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
settings.ipConfiguration.customSubjectAlternativeNames = []
|
|
|
|
# BETA args.
|
|
if IsBetaOrNewer(release_track):
|
|
if args.IsSpecified('data_api_access'):
|
|
settings.dataApiAccess = _ParseDataApiAccess(
|
|
sql_messages, args.data_api_access
|
|
)
|
|
|
|
if args.IsSpecified('storage_auto_increase_limit'):
|
|
# Resize limit should be settable if the original instance has resize
|
|
# turned on, or if the instance to be created has resize flag.
|
|
if (instance and instance.settings.storageAutoResize) or (
|
|
args.storage_auto_increase
|
|
):
|
|
# If the limit is set to None, we want it to be set to 0. This is a
|
|
# backend requirement.
|
|
settings.storageAutoResizeLimit = (
|
|
args.storage_auto_increase_limit or 0
|
|
)
|
|
else:
|
|
raise exceptions.RequiredArgumentException(
|
|
'--storage-auto-increase',
|
|
(
|
|
'To set the storage capacity limit '
|
|
'using [--storage-auto-increase-limit], '
|
|
'[--storage-auto-increase] must be enabled.'
|
|
),
|
|
)
|
|
|
|
if args.replication_lag_max_seconds_for_recreate is not None:
|
|
settings.replicationLagMaxSeconds = (
|
|
args.replication_lag_max_seconds_for_recreate
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('enable_db_aligned_atomic_writes'):
|
|
if not settings.dbAlignedAtomicWritesConfig:
|
|
settings.dbAlignedAtomicWritesConfig = (
|
|
sql_messages.DbAlignedAtomicWritesConfig()
|
|
)
|
|
settings.dbAlignedAtomicWritesConfig.dbAlignedAtomicWrites = (
|
|
args.enable_db_aligned_atomic_writes
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('enable_accelerated_replica_mode'):
|
|
_ShowAcceleratedReplicaModeWarning()
|
|
settings.acceleratedReplicaMode = args.enable_accelerated_replica_mode
|
|
|
|
return settings
|
|
|
|
@classmethod
|
|
def _ConstructCreateSettingsFromArgs(
|
|
cls,
|
|
sql_messages,
|
|
args,
|
|
instance=None,
|
|
release_track=DEFAULT_RELEASE_TRACK,
|
|
):
|
|
"""Constructs create settings object from base settings and args."""
|
|
original_settings = instance.settings if instance else None
|
|
settings = cls._ConstructBaseSettingsFromArgs(
|
|
sql_messages, args, instance, release_track
|
|
)
|
|
|
|
backup_configuration = reducers.BackupConfiguration(
|
|
sql_messages,
|
|
instance,
|
|
backup_enabled=args.backup,
|
|
backup_location=args.backup_location,
|
|
backup_start_time=args.backup_start_time,
|
|
enable_bin_log=args.enable_bin_log,
|
|
enable_point_in_time_recovery=args.enable_point_in_time_recovery,
|
|
retained_backups_count=args.retained_backups_count,
|
|
retained_transaction_log_days=args.retained_transaction_log_days,
|
|
patch_request=False,
|
|
)
|
|
if backup_configuration:
|
|
cls.AddBackupConfigToSettings(settings, backup_configuration)
|
|
|
|
if args and args.IsKnownAndSpecified('database_flags'):
|
|
settings.databaseFlags = reducers.DatabaseFlags(
|
|
sql_messages, original_settings, database_flags=args.database_flags
|
|
)
|
|
|
|
settings.maintenanceWindow = reducers.MaintenanceWindow(
|
|
sql_messages,
|
|
instance,
|
|
maintenance_release_channel=args.maintenance_release_channel,
|
|
maintenance_window_day=args.maintenance_window_day,
|
|
maintenance_window_hour=args.maintenance_window_hour,
|
|
)
|
|
|
|
if (
|
|
args.deny_maintenance_period_start_date
|
|
and args.deny_maintenance_period_end_date
|
|
):
|
|
settings.denyMaintenancePeriods = []
|
|
settings.denyMaintenancePeriods.append(
|
|
reducers.DenyMaintenancePeriod(
|
|
sql_messages,
|
|
instance,
|
|
deny_maintenance_period_start_date=args.deny_maintenance_period_start_date,
|
|
deny_maintenance_period_end_date=args.deny_maintenance_period_end_date,
|
|
deny_maintenance_period_time=args.deny_maintenance_period_time,
|
|
)
|
|
)
|
|
|
|
settings.insightsConfig = reducers.InsightsConfig(
|
|
sql_messages,
|
|
insights_config_query_insights_enabled=args.insights_config_query_insights_enabled,
|
|
insights_config_query_string_length=args.insights_config_query_string_length,
|
|
insights_config_record_application_tags=args.insights_config_record_application_tags,
|
|
insights_config_record_client_address=args.insights_config_record_client_address,
|
|
insights_config_query_plans_per_minute=args.insights_config_query_plans_per_minute,
|
|
)
|
|
|
|
if args.storage_type:
|
|
settings.dataDiskType = _ParseStorageType(
|
|
sql_messages, STORAGE_TYPE_MAPPING.get(args.storage_type)
|
|
)
|
|
|
|
settings.activeDirectoryConfig = reducers.ActiveDirectoryConfig(
|
|
sql_messages,
|
|
domain=args.active_directory_domain,
|
|
mode=args.active_directory_mode,
|
|
dns_servers=args.active_directory_dns_servers,
|
|
admin_credential_secret_key=args.active_directory_secret_manager_key,
|
|
organizational_unit=args.active_directory_organizational_unit,
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('password_policy_min_length'):
|
|
settings.passwordValidationPolicy = reducers.PasswordPolicy(
|
|
sql_messages,
|
|
password_policy_min_length=args.password_policy_min_length,
|
|
password_policy_complexity=args.password_policy_complexity,
|
|
password_policy_reuse_interval=args.password_policy_reuse_interval,
|
|
password_policy_disallow_username_substring=args.password_policy_disallow_username_substring,
|
|
password_policy_password_change_interval=args.password_policy_password_change_interval,
|
|
enable_password_policy=args.enable_password_policy,
|
|
)
|
|
|
|
settings.sqlServerAuditConfig = reducers.SqlServerAuditConfig(
|
|
sql_messages,
|
|
args.audit_bucket_path,
|
|
args.audit_retention_interval,
|
|
args.audit_upload_interval,
|
|
)
|
|
|
|
if args.time_zone is not None:
|
|
settings.timeZone = args.time_zone
|
|
|
|
if args.IsKnownAndSpecified(
|
|
'entra_id_tenant_id'
|
|
) or args.IsKnownAndSpecified('entra_id_application_id'):
|
|
settings.entraidConfig = reducers.SqlServerEntraIdConfig(
|
|
sql_messages,
|
|
args.entra_id_tenant_id,
|
|
args.entra_id_application_id,
|
|
)
|
|
|
|
if (
|
|
args.IsKnownAndSpecified('threads_per_core')
|
|
and args.threads_per_core is not None
|
|
):
|
|
settings.advancedMachineFeatures = sql_messages.AdvancedMachineFeatures()
|
|
settings.advancedMachineFeatures.threadsPerCore = args.threads_per_core
|
|
|
|
if args.IsSpecified('psc_auto_connections'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
if not settings.ipConfiguration.pscConfig:
|
|
settings.ipConfiguration.pscConfig = sql_messages.PscConfig()
|
|
settings.ipConfiguration.pscConfig.pscAutoConnections = (
|
|
reducers.PscAutoConnections(sql_messages, args.psc_auto_connections)
|
|
)
|
|
final_backup_configuration = reducers.FinalBackupConfiguration(
|
|
sql_messages,
|
|
instance,
|
|
final_backup_enabled=args.final_backup,
|
|
final_backup_retention_days=args.final_backup_retention_days,
|
|
)
|
|
if final_backup_configuration:
|
|
cls.AddFinalBackupConfigToSettings(settings, final_backup_configuration)
|
|
|
|
# MCP settings.
|
|
if args.IsKnownAndSpecified(
|
|
'enable_connection_pooling'
|
|
) or args.IsKnownAndSpecified('connection_pool_flags'):
|
|
mcp_config = reducers.ConnectionPoolConfig(
|
|
sql_messages,
|
|
enable_connection_pooling=args.enable_connection_pooling,
|
|
connection_pool_flags=args.connection_pool_flags,
|
|
clear_connection_pool_flags=None,
|
|
current_config=None,
|
|
)
|
|
if mcp_config is not None:
|
|
settings.connectionPoolConfig = mcp_config
|
|
|
|
read_pool_auto_scale_config = reducers.ReadPoolAutoScaleConfig(
|
|
sql_messages,
|
|
auto_scale_enabled=args.auto_scale_enabled,
|
|
auto_scale_min_node_count=args.auto_scale_min_node_count,
|
|
auto_scale_max_node_count=args.auto_scale_max_node_count,
|
|
auto_scale_target_metrics=args.auto_scale_target_metrics,
|
|
auto_scale_disable_scale_in=args.auto_scale_disable_scale_in,
|
|
auto_scale_in_cooldown_seconds=args.auto_scale_in_cooldown_seconds,
|
|
auto_scale_out_cooldown_seconds=args.auto_scale_out_cooldown_seconds,
|
|
)
|
|
if read_pool_auto_scale_config is not None:
|
|
settings.readPoolAutoScaleConfig = read_pool_auto_scale_config
|
|
|
|
# BETA args.
|
|
if IsBetaOrNewer(release_track):
|
|
settings.userLabels = labels_util.ParseCreateArgs(
|
|
args, sql_messages.Settings.UserLabelsValue
|
|
)
|
|
|
|
if args.allocated_ip_range_name:
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
settings.ipConfiguration.allocatedIpRange = args.allocated_ip_range_name
|
|
|
|
db_aligned_atomic_writes_config = reducers.DbAlignedAtomicWritesConfig(
|
|
sql_messages,
|
|
db_aligned_atomic_writes=args.enable_db_aligned_atomic_writes,
|
|
)
|
|
if db_aligned_atomic_writes_config is not None:
|
|
settings.dbAlignedAtomicWritesConfig = db_aligned_atomic_writes_config
|
|
|
|
if args.IsKnownAndSpecified('performance_capture_config'):
|
|
performance_capture_config = reducers.PerformanceCaptureConfig(
|
|
sql_messages,
|
|
performance_capture_config=args.performance_capture_config,
|
|
current_config=None,
|
|
)
|
|
if performance_capture_config is not None:
|
|
settings.performanceCaptureConfig = performance_capture_config
|
|
|
|
if args.IsKnownAndSpecified('unc_mappings'):
|
|
settings.uncMappings = reducers.UncMappings(
|
|
sql_messages,
|
|
unc_mappings=args.unc_mappings,
|
|
)
|
|
|
|
return settings
|
|
|
|
@classmethod
|
|
def _ConstructPatchSettingsFromArgs(
|
|
cls, sql_messages, args, instance, release_track=DEFAULT_RELEASE_TRACK
|
|
):
|
|
"""Constructs patch settings object from base settings and args."""
|
|
original_settings = instance.settings
|
|
settings = cls._ConstructBaseSettingsFromArgs(
|
|
sql_messages, args, instance, release_track
|
|
)
|
|
|
|
if args.clear_gae_apps:
|
|
settings.authorizedGaeApplications = []
|
|
|
|
if any([args.follow_gae_app, _GetZone(args), _GetSecondaryZone(args)]):
|
|
settings.locationPreference = sql_messages.LocationPreference(
|
|
kind='sql#locationPreference',
|
|
followGaeApplication=args.follow_gae_app,
|
|
zone=_GetZone(args),
|
|
secondaryZone=_GetSecondaryZone(args),
|
|
)
|
|
|
|
if args.clear_authorized_networks:
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
settings.ipConfiguration.authorizedNetworks = []
|
|
|
|
if args.enable_database_replication is not None:
|
|
settings.databaseReplicationEnabled = args.enable_database_replication
|
|
|
|
backup_configuration = reducers.BackupConfiguration(
|
|
sql_messages,
|
|
instance,
|
|
backup_enabled=not args.no_backup,
|
|
backup_location=args.backup_location,
|
|
backup_start_time=args.backup_start_time,
|
|
enable_bin_log=args.enable_bin_log,
|
|
enable_point_in_time_recovery=args.enable_point_in_time_recovery,
|
|
retained_backups_count=args.retained_backups_count,
|
|
retained_transaction_log_days=args.retained_transaction_log_days,
|
|
patch_request=True,
|
|
)
|
|
|
|
if backup_configuration:
|
|
cls.AddBackupConfigToSettings(settings, backup_configuration)
|
|
|
|
if args and args.IsKnownAndSpecified('database_flags'):
|
|
settings.databaseFlags = reducers.DatabaseFlags(
|
|
sql_messages,
|
|
original_settings,
|
|
database_flags=args.database_flags,
|
|
clear_database_flags=args.clear_database_flags,
|
|
)
|
|
|
|
settings.maintenanceWindow = reducers.MaintenanceWindow(
|
|
sql_messages,
|
|
instance,
|
|
maintenance_release_channel=args.maintenance_release_channel,
|
|
maintenance_window_day=args.maintenance_window_day,
|
|
maintenance_window_hour=args.maintenance_window_hour,
|
|
)
|
|
|
|
if args.remove_deny_maintenance_period:
|
|
settings.denyMaintenancePeriods = []
|
|
|
|
if (
|
|
args.deny_maintenance_period_start_date
|
|
or args.deny_maintenance_period_end_date
|
|
or args.deny_maintenance_period_time
|
|
):
|
|
settings.denyMaintenancePeriods = []
|
|
settings.denyMaintenancePeriods.append(
|
|
reducers.DenyMaintenancePeriod(
|
|
sql_messages,
|
|
instance,
|
|
deny_maintenance_period_start_date=args.deny_maintenance_period_start_date,
|
|
deny_maintenance_period_end_date=args.deny_maintenance_period_end_date,
|
|
deny_maintenance_period_time=args.deny_maintenance_period_time,
|
|
)
|
|
)
|
|
|
|
if args.storage_type:
|
|
settings.dataDiskType = _ParseStorageType(
|
|
sql_messages, STORAGE_TYPE_MAPPING.get(args.storage_type)
|
|
)
|
|
|
|
settings.insightsConfig = reducers.InsightsConfig(
|
|
sql_messages,
|
|
insights_config_query_insights_enabled=args.insights_config_query_insights_enabled,
|
|
insights_config_query_string_length=args.insights_config_query_string_length,
|
|
insights_config_record_application_tags=args.insights_config_record_application_tags,
|
|
insights_config_record_client_address=args.insights_config_record_client_address,
|
|
insights_config_query_plans_per_minute=args.insights_config_query_plans_per_minute,
|
|
)
|
|
|
|
settings.activeDirectoryConfig = reducers.ActiveDirectoryConfig(
|
|
sql_messages,
|
|
domain=args.active_directory_domain,
|
|
mode=args.active_directory_mode,
|
|
dns_servers=args.active_directory_dns_servers,
|
|
admin_credential_secret_key=args.active_directory_secret_manager_key,
|
|
organizational_unit=args.active_directory_organizational_unit,
|
|
)
|
|
|
|
settings.passwordValidationPolicy = reducers.PasswordPolicy(
|
|
sql_messages,
|
|
password_policy_min_length=args.password_policy_min_length,
|
|
password_policy_complexity=args.password_policy_complexity,
|
|
password_policy_reuse_interval=args.password_policy_reuse_interval,
|
|
password_policy_disallow_username_substring=args.password_policy_disallow_username_substring,
|
|
password_policy_password_change_interval=args.password_policy_password_change_interval,
|
|
enable_password_policy=args.enable_password_policy,
|
|
)
|
|
|
|
settings.sqlServerAuditConfig = reducers.SqlServerAuditConfig(
|
|
sql_messages,
|
|
bucket=args.audit_bucket_path,
|
|
retention_interval=args.audit_retention_interval,
|
|
upload_interval=args.audit_upload_interval,
|
|
)
|
|
|
|
if args.threads_per_core is not None:
|
|
settings.advancedMachineFeatures = sql_messages.AdvancedMachineFeatures()
|
|
settings.advancedMachineFeatures.threadsPerCore = args.threads_per_core
|
|
|
|
if args.time_zone is not None:
|
|
settings.timeZone = args.time_zone
|
|
|
|
if (
|
|
args.IsKnownAndSpecified('entra_id_tenant_id')
|
|
or args.IsKnownAndSpecified('entra_id_application_id')
|
|
or args.IsKnownAndSpecified('clear_entra_id_config')
|
|
):
|
|
settings.entraidConfig = reducers.SqlServerEntraIdConfig(
|
|
sql_messages,
|
|
args.entra_id_tenant_id,
|
|
args.entra_id_application_id,
|
|
args.clear_entra_id_config,
|
|
)
|
|
|
|
final_backup_configuration = reducers.FinalBackupConfiguration(
|
|
sql_messages,
|
|
instance,
|
|
final_backup_enabled=args.final_backup,
|
|
final_backup_retention_days=args.final_backup_retention_days,
|
|
)
|
|
if final_backup_configuration:
|
|
cls.AddFinalBackupConfigToSettings(settings, final_backup_configuration)
|
|
|
|
# MCP settings.
|
|
updated_config = reducers.ConnectionPoolConfig(
|
|
sql_messages,
|
|
enable_connection_pooling=args.enable_connection_pooling,
|
|
connection_pool_flags=args.connection_pool_flags,
|
|
clear_connection_pool_flags=args.clear_connection_pool_flags,
|
|
current_config=original_settings.connectionPoolConfig,
|
|
)
|
|
if updated_config is not None:
|
|
settings.connectionPoolConfig = updated_config
|
|
|
|
if args.IsKnownAndSpecified('psc_auto_connections'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
if not settings.ipConfiguration.pscConfig:
|
|
settings.ipConfiguration.pscConfig = sql_messages.PscConfig()
|
|
settings.ipConfiguration.pscConfig.pscAutoConnections = (
|
|
reducers.PscAutoConnections(sql_messages, args.psc_auto_connections)
|
|
)
|
|
if args.IsKnownAndSpecified('clear_psc_auto_connections'):
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
if not settings.ipConfiguration.pscConfig:
|
|
settings.ipConfiguration.pscConfig = sql_messages.PscConfig()
|
|
settings.ipConfiguration.pscConfig.pscAutoConnections = []
|
|
|
|
read_pool_auto_scale_config = reducers.ReadPoolAutoScaleConfig(
|
|
sql_messages,
|
|
auto_scale_enabled=args.auto_scale_enabled,
|
|
auto_scale_min_node_count=args.auto_scale_min_node_count,
|
|
auto_scale_max_node_count=args.auto_scale_max_node_count,
|
|
auto_scale_target_metrics=args.auto_scale_target_metrics,
|
|
auto_scale_disable_scale_in=args.auto_scale_disable_scale_in,
|
|
auto_scale_in_cooldown_seconds=args.auto_scale_in_cooldown_seconds,
|
|
auto_scale_out_cooldown_seconds=args.auto_scale_out_cooldown_seconds,
|
|
current_config=original_settings.readPoolAutoScaleConfig,
|
|
)
|
|
if read_pool_auto_scale_config is not None:
|
|
settings.readPoolAutoScaleConfig = read_pool_auto_scale_config
|
|
|
|
# BETA args.
|
|
if IsBetaOrNewer(release_track):
|
|
labels_diff = labels_util.ExplicitNullificationDiff.FromUpdateArgs(args)
|
|
labels_update = labels_diff.Apply(
|
|
sql_messages.Settings.UserLabelsValue, instance.settings.userLabels
|
|
)
|
|
if labels_update.needs_update:
|
|
settings.userLabels = labels_update.labels
|
|
|
|
# TODO(b/199412671): merge the logic of assigning ip range to
|
|
# _ConstructBaseSettingsFromArgs
|
|
if args.allocated_ip_range_name:
|
|
if not settings.ipConfiguration:
|
|
settings.ipConfiguration = sql_messages.IpConfiguration()
|
|
settings.ipConfiguration.allocatedIpRange = args.allocated_ip_range_name
|
|
|
|
if args.IsKnownAndSpecified('unc_mappings'):
|
|
settings.uncMappings = reducers.UncMappings(
|
|
sql_messages,
|
|
unc_mappings=args.unc_mappings,
|
|
clear_unc_mappings=args.clear_unc_mappings,
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('performance_capture_config'):
|
|
performance_capture_config = reducers.PerformanceCaptureConfig(
|
|
sql_messages,
|
|
performance_capture_config=args.performance_capture_config,
|
|
current_config=original_settings.performanceCaptureConfig,
|
|
)
|
|
if performance_capture_config is not None:
|
|
settings.performanceCaptureConfig = performance_capture_config
|
|
|
|
# ALPHA args.
|
|
if _IsAlpha(release_track):
|
|
pass
|
|
|
|
return settings
|
|
|
|
@classmethod
|
|
def _ConstructBaseInstanceFromArgs(
|
|
cls,
|
|
sql_messages,
|
|
args,
|
|
original=None,
|
|
instance_ref=None,
|
|
release_track=DEFAULT_RELEASE_TRACK,
|
|
):
|
|
"""Construct a Cloud SQL instance from command line args.
|
|
|
|
Args:
|
|
sql_messages: module, The messages module that should be used.
|
|
args: argparse.Namespace, The CLI arg namespace.
|
|
original: sql_messages.DatabaseInstance, The original instance, if some of
|
|
it might be used to fill fields in the new one.
|
|
instance_ref: reference to DatabaseInstance object, used to fill project
|
|
and instance information.
|
|
release_track: base.ReleaseTrack, the release track that this was run
|
|
under.
|
|
|
|
Returns:
|
|
sql_messages.DatabaseInstance, The constructed (and possibly partial)
|
|
database instance.
|
|
|
|
Raises:
|
|
ToolException: An error other than http error occurred while executing the
|
|
command.
|
|
"""
|
|
del args, original, release_track # Currently unused in base function.
|
|
instance_resource = sql_messages.DatabaseInstance(kind='sql#instance')
|
|
|
|
if instance_ref:
|
|
cls.SetProjectAndInstanceFromRef(instance_resource, instance_ref)
|
|
|
|
return instance_resource
|
|
|
|
@classmethod
|
|
def ConstructCreateInstanceFromArgs(
|
|
cls,
|
|
sql_messages,
|
|
args,
|
|
original=None,
|
|
instance_ref=None,
|
|
release_track=DEFAULT_RELEASE_TRACK,
|
|
):
|
|
"""Constructs Instance for create request from base instance and args."""
|
|
ShowZoneDeprecationWarnings(args)
|
|
instance_resource = cls._ConstructBaseInstanceFromArgs(
|
|
sql_messages, args, original, instance_ref
|
|
)
|
|
|
|
instance_resource.region = reducers.Region(
|
|
args.region, _GetZone(args), _GetSecondaryZone(args)
|
|
)
|
|
instance_resource.databaseVersion = ParseDatabaseVersion(
|
|
sql_messages, args.database_version
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('master_instance_name'):
|
|
instance_resource.masterInstanceName = args.master_instance_name
|
|
|
|
if args.IsKnownAndSpecified('root_password'):
|
|
instance_resource.rootPassword = args.root_password
|
|
|
|
# BETA: Set the host port and return early if external master instance.
|
|
if IsBetaOrNewer(release_track) and args.IsSpecified('source_ip_address'):
|
|
on_premises_configuration = reducers.OnPremisesConfiguration(
|
|
sql_messages, args.source_ip_address, args.source_port
|
|
)
|
|
instance_resource.onPremisesConfiguration = on_premises_configuration
|
|
return instance_resource
|
|
|
|
instance_resource.settings = cls._ConstructCreateSettingsFromArgs(
|
|
sql_messages, args, original, release_track
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('enforce_new_sql_network_architecture'):
|
|
instance_resource.sqlNetworkArchitecture = (
|
|
sql_messages.DatabaseInstance.SqlNetworkArchitectureValueValuesEnum.NEW_NETWORK_ARCHITECTURE
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('master_instance_name'):
|
|
replication = (
|
|
sql_messages.Settings.ReplicationTypeValueValuesEnum.ASYNCHRONOUS
|
|
)
|
|
if args.replica_type == 'FAILOVER':
|
|
_ShowFailoverReplicaDeprecationWarning()
|
|
instance_resource.replicaConfiguration = (
|
|
sql_messages.ReplicaConfiguration(
|
|
kind='sql#demoteMasterMysqlReplicaConfiguration',
|
|
failoverTarget=True,
|
|
)
|
|
)
|
|
if args.cascadable_replica:
|
|
if instance_resource.replicaConfiguration:
|
|
instance_resource.replicaConfiguration.cascadableReplica = (
|
|
args.cascadable_replica
|
|
)
|
|
else:
|
|
instance_resource.replicaConfiguration = (
|
|
sql_messages.ReplicaConfiguration(
|
|
kind='sql#replicaConfiguration',
|
|
cascadableReplica=args.cascadable_replica,
|
|
)
|
|
)
|
|
|
|
else:
|
|
replication = (
|
|
sql_messages.Settings.ReplicationTypeValueValuesEnum.SYNCHRONOUS
|
|
)
|
|
if not args.IsKnownAndSpecified('replication'):
|
|
instance_resource.settings.replicationType = replication
|
|
|
|
if args.IsKnownAndSpecified('failover_replica_name'):
|
|
_ShowFailoverReplicaDeprecationWarning()
|
|
instance_resource.failoverReplica = (
|
|
sql_messages.DatabaseInstance.FailoverReplicaValue(
|
|
name=args.failover_replica_name
|
|
)
|
|
)
|
|
|
|
if args.collation:
|
|
instance_resource.settings.collation = args.collation
|
|
|
|
# BETA: Config for creating a replica of an external primary instance.
|
|
if IsBetaOrNewer(release_track) and args.IsSpecified('master_username'):
|
|
# Ensure that the primary instance name is specified.
|
|
if not args.IsSpecified('master_instance_name'):
|
|
raise exceptions.RequiredArgumentException(
|
|
'--master-instance-name',
|
|
(
|
|
'To create a read replica of an external '
|
|
'master instance, [--master-instance-name] must be specified'
|
|
),
|
|
)
|
|
|
|
# TODO(b/78648703): Remove when mutex required status is fixed.
|
|
# Ensure that the primary replication user password is specified.
|
|
if not (
|
|
args.IsSpecified('master_password')
|
|
or args.IsSpecified('prompt_for_master_password')
|
|
):
|
|
raise exceptions.RequiredArgumentException(
|
|
'--master-password',
|
|
(
|
|
'To create a read replica of an external '
|
|
'master instance, [--master-password] or '
|
|
'[--prompt-for-master-password] must be specified'
|
|
),
|
|
)
|
|
|
|
# Get password if not specified on command line.
|
|
if args.prompt_for_master_password:
|
|
args.master_password = console_io.PromptPassword(
|
|
'Master Instance Password: '
|
|
)
|
|
|
|
instance_resource.replicaConfiguration = reducers.ReplicaConfiguration(
|
|
sql_messages,
|
|
args.master_username,
|
|
args.master_password,
|
|
args.master_dump_file_path,
|
|
args.master_ca_certificate_path,
|
|
args.client_certificate_path,
|
|
args.client_key_path,
|
|
)
|
|
|
|
is_primary = instance_resource.masterInstanceName is None
|
|
key_name = _GetAndValidateCmekKeyName(args, is_primary)
|
|
if key_name:
|
|
config = sql_messages.DiskEncryptionConfiguration(
|
|
kind='sql#diskEncryptionConfiguration', kmsKeyName=key_name
|
|
)
|
|
instance_resource.diskEncryptionConfiguration = config
|
|
|
|
tags = getattr(args, 'tags')
|
|
if tags is not None:
|
|
instance_resource.tags = sql_messages.DatabaseInstance.TagsValue(
|
|
additionalProperties=[
|
|
sql_messages.DatabaseInstance.TagsValue.AdditionalProperty(
|
|
key=tag,
|
|
value=value,
|
|
)
|
|
for tag, value in six.iteritems(tags)
|
|
]
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('instance_type'):
|
|
instance_resource.instanceType = _ParseInstanceType(
|
|
sql_messages, args.instance_type
|
|
)
|
|
if args.IsKnownAndSpecified('node_count'):
|
|
instance_resource.nodeCount = args.node_count
|
|
|
|
return instance_resource
|
|
|
|
@classmethod
|
|
def ConstructPatchInstanceFromArgs(
|
|
cls,
|
|
sql_messages,
|
|
args,
|
|
original,
|
|
instance_ref=None,
|
|
release_track=DEFAULT_RELEASE_TRACK,
|
|
):
|
|
"""Constructs Instance for patch request from base instance and args."""
|
|
instance_resource = cls._ConstructBaseInstanceFromArgs(
|
|
sql_messages, args, original, instance_ref
|
|
)
|
|
|
|
instance_resource.databaseVersion = ParseDatabaseVersion(
|
|
sql_messages, args.database_version
|
|
)
|
|
|
|
instance_resource.maintenanceVersion = args.maintenance_version
|
|
|
|
instance_resource.settings = cls._ConstructPatchSettingsFromArgs(
|
|
sql_messages, args, original, release_track
|
|
)
|
|
|
|
if args.upgrade_sql_network_architecture:
|
|
instance_resource.sqlNetworkArchitecture = (
|
|
sql_messages.DatabaseInstance.SqlNetworkArchitectureValueValuesEnum.NEW_NETWORK_ARCHITECTURE
|
|
)
|
|
if args.enforce_new_sql_network_architecture:
|
|
instance_resource.sqlNetworkArchitecture = (
|
|
sql_messages.DatabaseInstance.SqlNetworkArchitectureValueValuesEnum.NEW_NETWORK_ARCHITECTURE
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('switch_transaction_logs_to_cloud_storage'):
|
|
instance_resource.switchTransactionLogsToCloudStorageEnabled = (
|
|
args.switch_transaction_logs_to_cloud_storage
|
|
)
|
|
|
|
if args.IsSpecified('simulate_maintenance_event'):
|
|
instance_resource.maintenanceVersion = original.maintenanceVersion
|
|
api_util.InstancesV1Beta4.PrintAndConfirmSimulatedMaintenanceEvent()
|
|
# Have the simulate maintenance event flag take precedence.
|
|
# Confirm simulation, maintenance-version flag cannot be supplied with
|
|
# simulate-maintenance-event flag.
|
|
if (
|
|
args.IsSpecified('maintenance_version')
|
|
and args.maintenance_version == original.maintenanceVersion
|
|
):
|
|
api_util.InstancesV1Beta4.PrintAndConfirmSimulatedMaintenanceEvent()
|
|
|
|
if IsBetaOrNewer(release_track) and args.IsSpecified(
|
|
'reconcile_psa_networking'
|
|
):
|
|
if instance_resource.settings.ipConfiguration is None:
|
|
instance_resource.settings.ipConfiguration = (
|
|
sql_messages.IpConfiguration()
|
|
)
|
|
instance_resource.settings.ipConfiguration.privateNetwork = (
|
|
original.settings.ipConfiguration.privateNetwork
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('failover_dr_replica_name'):
|
|
replication_cluster = sql_messages.ReplicationCluster()
|
|
replication_cluster.failoverDrReplicaName = args.failover_dr_replica_name
|
|
instance_resource.replicationCluster = replication_cluster
|
|
if args.IsKnownAndSpecified('clear_failover_dr_replica_name'):
|
|
if instance_resource.replicationCluster is not None:
|
|
instance_resource.replicationCluster.ClearFailoverDrReplicaName()
|
|
|
|
if args.IsKnownAndSpecified('include_replicas_for_major_version_upgrade'):
|
|
instance_resource.includeReplicasForMajorVersionUpgrade = (
|
|
args.include_replicas_for_major_version_upgrade
|
|
)
|
|
|
|
if args.IsKnownAndSpecified('instance_type'):
|
|
instance_resource.instanceType = _ParseInstanceType(
|
|
sql_messages, args.instance_type
|
|
)
|
|
if args.IsKnownAndSpecified('node_count'):
|
|
instance_resource.nodeCount = args.node_count
|
|
|
|
return instance_resource
|
|
|
|
|
|
class InstancesV1Beta4(_BaseInstances):
|
|
"""Common utility functions for sql instances V1Beta4."""
|
|
|
|
@staticmethod
|
|
def SetProjectAndInstanceFromRef(instance_resource, instance_ref):
|
|
instance_resource.project = instance_ref.project
|
|
instance_resource.name = instance_ref.instance
|
|
|
|
@staticmethod
|
|
def AddBackupConfigToSettings(settings, backup_config):
|
|
settings.backupConfiguration = backup_config
|
|
|
|
@staticmethod
|
|
def AddFinalBackupConfigToSettings(settings, final_backup_config):
|
|
settings.finalBackupConfig = final_backup_config
|
|
|
|
@staticmethod
|
|
def SetIpConfigurationEnabled(settings, assign_ip):
|
|
settings.ipConfiguration.ipv4Enabled = assign_ip
|
|
|
|
@staticmethod
|
|
def SetAuthorizedNetworks(settings, authorized_networks, acl_entry_value):
|
|
settings.ipConfiguration.authorizedNetworks = [
|
|
acl_entry_value(kind='sql#aclEntry', value=n)
|
|
for n in authorized_networks
|
|
]
|