File: //snap/google-cloud-cli/394/platform/bq/frontend/command_delete.py
#!/usr/bin/env python
"""The BigQuery delete CLI command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from typing import Optional
from absl import app
from absl import flags
import bq_flags
from clients import client_connection
from clients import client_data_transfer
from clients import client_dataset
from clients import client_job
from clients import client_model
from clients import client_reservation
from clients import client_routine
from clients import client_row_access_policy
from clients import client_table
from clients import utils as bq_client_utils
from frontend import bigquery_command
from frontend import bq_cached_client
from frontend import utils as frontend_utils
from frontend import utils_flags
from frontend import utils_id as frontend_id_utils
from utils import bq_error
from utils import bq_id_utils
# These aren't relevant for user-facing docstrings:
# pylint: disable=g-doc-return-or-yield
# pylint: disable=g-doc-args
class Delete(bigquery_command.BigqueryCmd):
"""The Delete CLI command."""
usage = """rm [-f] [-r] [(-d|-t)] <identifier>"""
def __init__(self, name: str, fv: flags.FlagValues):
super(Delete, self).__init__(name, fv)
flags.DEFINE_boolean(
'dataset',
False,
'Remove dataset described by this identifier.',
short_name='d',
flag_values=fv,
)
flags.DEFINE_boolean(
'table',
False,
'Remove table described by this identifier.',
short_name='t',
flag_values=fv,
)
flags.DEFINE_boolean(
'job',
False,
'Remove job described by this identifier.',
short_name='j',
flag_values=fv,
)
flags.DEFINE_boolean(
'transfer_config',
False,
'Remove transfer configuration described by this identifier.',
flag_values=fv,
)
flags.DEFINE_boolean(
'force',
None,
"Ignore existing tables and datasets, don't prompt.",
short_name='f',
flag_values=fv,
)
flags.DEFINE_boolean(
'recursive',
False,
'Remove dataset and any tables it may contain.',
short_name='r',
flag_values=fv,
)
flags.DEFINE_boolean(
'reservation',
False,
'Deletes the reservation described by this identifier.',
flag_values=fv,
)
flags.DEFINE_boolean(
'capacity_commitment',
False,
'Deletes the capacity commitment described by this identifier.',
flag_values=fv,
)
flags.DEFINE_boolean(
'reservation_assignment',
False,
'Delete a reservation assignment.',
flag_values=fv,
)
flags.DEFINE_boolean(
'reservation_group',
False,
'Delete a reservation group described by this identifier.',
flag_values=fv,
)
flags.DEFINE_boolean(
'model',
False,
'Remove model with this model ID.',
short_name='m',
flag_values=fv,
)
flags.DEFINE_boolean(
'routine', False, 'Remove routine with this routine ID.', flag_values=fv
)
flags.DEFINE_boolean(
'connection', False, 'Delete a connection.', flag_values=fv
)
flags.DEFINE_boolean(
'migration_workflow',
False,
'Delete a migration workflow.',
flag_values=fv,
)
self._ProcessCommandRc(fv)
def RunWithArgs(self, identifier: str) -> Optional[int]:
"""Delete the resource described by the identifier.
Always requires an identifier, unlike the show and ls commands.
By default, also requires confirmation before deleting. Supports
the -d -t flags to signify that the identifier is a dataset
or table.
* With -f, don't ask for confirmation before deleting.
* With -r, remove all tables in the named dataset.
Examples:
bq rm ds.table
bq rm -m ds.model
bq rm --routine ds.routine
bq rm -r -f old_dataset
bq rm --transfer_config=projects/p/locations/l/transferConfigs/c
bq rm --connection --project_id=proj --location=us con
bq rm --capacity_commitment proj:US.capacity_commitment_id
bq rm --reservation --project_id=proj --location=us reservation_name
bq rm --reservation_assignment --project_id=proj --location=us
assignment_name
bq rm --reservation_group --project_id=proj --location=us
reservation_group_name
"""
client = bq_cached_client.Client.Get()
# pylint: disable=g-doc-exception
if frontend_utils.ValidateAtMostOneSelected(
self.d,
self.t,
self.j,
self.routine,
self.transfer_config,
self.reservation,
self.reservation_assignment,
self.capacity_commitment,
self.reservation_group,
self.connection,
):
raise app.UsageError('Cannot specify more than one resource type.')
if not identifier:
raise app.UsageError('Must provide an identifier for rm.')
if self.t:
reference = bq_client_utils.GetTableReference(
id_fallbacks=client, identifier=identifier
)
elif self.m:
reference = bq_client_utils.GetModelReference(
id_fallbacks=client, identifier=identifier
)
elif self.routine:
reference = bq_client_utils.GetRoutineReference(
id_fallbacks=client, identifier=identifier
)
elif self.d:
reference = bq_client_utils.GetDatasetReference(
id_fallbacks=client, identifier=identifier
)
elif self.j:
reference = bq_client_utils.GetJobReference(
id_fallbacks=client,
identifier=identifier,
default_location=bq_flags.LOCATION.value,
)
elif self.transfer_config:
formatted_identifier = frontend_id_utils.FormatDataTransferIdentifiers(
client, identifier
)
reference = bq_id_utils.ApiClientHelper.TransferConfigReference(
transferConfigName=formatted_identifier
)
elif self.reservation:
try:
reference = bq_client_utils.GetReservationReference(
id_fallbacks=client,
identifier=identifier,
default_location=bq_flags.LOCATION.value,
)
client_reservation.DeleteReservation(
client=client.GetReservationApiClient(),
reference=reference,
)
print("Reservation '%s' successfully deleted." % identifier)
except BaseException as e:
raise bq_error.BigqueryError(
"Failed to delete reservation '%s': %s" % (identifier, e)
)
elif self.reservation_assignment:
try:
reference = bq_client_utils.GetReservationAssignmentReference(
id_fallbacks=client,
identifier=identifier,
default_location=bq_flags.LOCATION.value,
)
client_reservation.DeleteReservationAssignment(
client=client.GetReservationApiClient(), reference=reference
)
print("Reservation assignment '%s' successfully deleted." % identifier)
except BaseException as e:
raise bq_error.BigqueryError(
"Failed to delete reservation assignment '%s': %s" % (identifier, e)
)
elif self.capacity_commitment:
try:
reference = bq_client_utils.GetCapacityCommitmentReference(
id_fallbacks=client,
identifier=identifier,
default_location=bq_flags.LOCATION.value,
)
client_reservation.DeleteCapacityCommitment(
client=client.GetReservationApiClient(),
reference=reference,
force=self.force,
)
print("Capacity commitment '%s' successfully deleted." % identifier)
except BaseException as e:
raise bq_error.BigqueryError(
"Failed to delete capacity commitment '%s': %s" % (identifier, e)
)
elif self.reservation_group:
try:
utils_flags.fail_if_not_using_alpha_feature(
bq_flags.AlphaFeatures.RESERVATION_GROUPS
)
reference = bq_client_utils.GetReservationGroupReference(
id_fallbacks=client,
identifier=identifier,
default_location=bq_flags.LOCATION.value,
)
client_reservation.DeleteReservationGroup(
reservation_group_client=client.GetReservationApiClient(),
reference=reference,
)
# TODO(b/392704450): Refactor the print and error handling for
# reservation resources.
print("Reservation group '%s' successfully deleted." % identifier)
except BaseException as e:
raise bq_error.BigqueryError(
"Failed to delete reservation group '%s': %s" % (identifier, e)
)
elif self.connection:
reference = bq_client_utils.GetConnectionReference(
id_fallbacks=client,
identifier=identifier,
default_location=bq_flags.LOCATION.value,
)
client_connection.DeleteConnection(
client=client.GetConnectionV1ApiClient(), reference=reference
)
elif self.migration_workflow:
reference = identifier
else:
reference = bq_client_utils.GetReference(
id_fallbacks=client, identifier=identifier
)
bq_id_utils.typecheck(
reference,
(
bq_id_utils.ApiClientHelper.DatasetReference,
bq_id_utils.ApiClientHelper.TableReference,
),
'Invalid identifier "%s" for rm.' % (identifier,),
is_usage_error=True,
)
if (
isinstance(reference, bq_id_utils.ApiClientHelper.TableReference)
and self.r
):
raise app.UsageError('Cannot specify -r with %r' % (reference,))
if (
isinstance(reference, bq_id_utils.ApiClientHelper.ModelReference)
and self.r
):
raise app.UsageError('Cannot specify -r with %r' % (reference,))
if (
isinstance(reference, bq_id_utils.ApiClientHelper.RoutineReference)
and self.r
):
raise app.UsageError('Cannot specify -r with %r' % (reference,))
if self.migration_workflow and self.r:
raise app.UsageError('Cannot specify -r with %r' % (reference,))
if not self.force:
if (
(
isinstance(
reference, bq_id_utils.ApiClientHelper.DatasetReference
)
and client_dataset.DatasetExists(
apiclient=client.apiclient, reference=reference
)
)
or (
isinstance(reference, bq_id_utils.ApiClientHelper.TableReference)
and client_table.table_exists(
apiclient=client.apiclient, reference=reference
)
)
or (
isinstance(reference, bq_id_utils.ApiClientHelper.JobReference)
and client_job.JobExists(client, reference)
)
or (
isinstance(reference, bq_id_utils.ApiClientHelper.ModelReference)
and client_model.model_exists(
model_client=client.GetModelsApiClient(), reference=reference
)
)
or (
isinstance(
reference, bq_id_utils.ApiClientHelper.RoutineReference
)
and client_routine.RoutineExists(
routines_api_client=client.GetRoutinesApiClient(),
reference=reference,
)
)
or (
isinstance(
reference, bq_id_utils.ApiClientHelper.TransferConfigReference
)
and client_data_transfer.transfer_exists(
client.GetTransferV1ApiClient(), reference
)
)
or self.migration_workflow
):
if 'y' != frontend_utils.PromptYN(
'rm: remove %r? (y/N) ' % (reference,)
):
print('NOT deleting %r, exiting.' % (reference,))
return 0
if isinstance(reference, bq_id_utils.ApiClientHelper.DatasetReference):
# Prompt for confirmation has already occurred.
self.PossiblyDelegateToGcloudAndExit(
resource='datasets',
bq_command='rm',
identifier=identifier,
command_flags_for_this_resource={'recursive': self.recursive},
)
client_dataset.DeleteDataset(
client.apiclient,
reference,
ignore_not_found=self.force,
delete_contents=self.recursive,
)
elif isinstance(reference, bq_id_utils.ApiClientHelper.TableReference):
client_table.delete_table(
apiclient=client.apiclient,
reference=reference,
ignore_not_found=self.force,
)
elif isinstance(reference, bq_id_utils.ApiClientHelper.JobReference):
client_job.DeleteJob(client, reference, ignore_not_found=self.force)
elif isinstance(reference, bq_id_utils.ApiClientHelper.ModelReference):
client_model.delete_model(
model_client=client.GetModelsApiClient(),
reference=reference,
ignore_not_found=self.force,
)
elif isinstance(reference, bq_id_utils.ApiClientHelper.RoutineReference):
client_routine.DeleteRoutine(
routines_api_client=client.GetRoutinesApiClient(),
reference=reference,
ignore_not_found=self.force,
)
elif isinstance(
reference, bq_id_utils.ApiClientHelper.TransferConfigReference
):
client_data_transfer.delete_transfer_config(
client.GetTransferV1ApiClient(),
reference,
ignore_not_found=self.force,
)
elif self.migration_workflow:
# Prompt for confirmation has already occurred.
self.DelegateToGcloudAndExit(
'migration_workflows',
'rm',
identifier,
)