567 lines
19 KiB
Python
567 lines
19 KiB
Python
# -*- coding: utf-8 -*- #
|
|
# Copyright 2016 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.
|
|
|
|
"""Flags and helpers for the compute disks commands."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
from googlecloudsdk.calliope import actions
|
|
from googlecloudsdk.command_lib.compute import completers as compute_completers
|
|
from googlecloudsdk.command_lib.compute import flags as compute_flags
|
|
from googlecloudsdk.command_lib.util import completers
|
|
from googlecloudsdk.core import properties
|
|
|
|
_DETAILED_SOURCE_SNAPSHOT_HELP = """\
|
|
Source snapshot used to create the disks. It is safe to
|
|
delete a snapshot after a disk has been created from the
|
|
snapshot. In such cases, the disks will no longer reference
|
|
the deleted snapshot. To get a list of snapshots in your
|
|
current project, run `gcloud compute snapshots list`. A
|
|
snapshot from an existing disk can be created using the
|
|
`gcloud compute disks snapshot` command. This flag is mutually
|
|
exclusive with *--image*.
|
|
|
|
When using this option, the size of the disks must be at least
|
|
as large as the snapshot size. Use *--size* to adjust the
|
|
size of the disks.
|
|
"""
|
|
|
|
_DETAILED_SOURCE_INSTANT_SNAPSHOT_HELP = """\
|
|
Name of the source instant snapshot used to create the disks.
|
|
"""
|
|
|
|
_DETAILED_SOURCE_INSTANT_SNAPSHOT_PROJECT_HELP = """\
|
|
The project containing the instant snapshot used to create the disks.
|
|
"""
|
|
|
|
_SOURCE_DISK_DETAILED_HELP = """\
|
|
Source disk used to create the disk(s). It is safe to
|
|
delete a source disk after a disk has been created from the
|
|
source disk. To get a list of disks in your current project,
|
|
run `gcloud compute disks list`. This flag is mutually
|
|
exclusive with *--image* and *--source-snapshot*.
|
|
|
|
When using this option, the size of the disks must be at least
|
|
as large as the source disk size. Use *--size* to adjust the
|
|
size of the disks.
|
|
|
|
The source disk must be in the same zone/region as the disk to be created.
|
|
"""
|
|
|
|
_SOURCE_DISK_ZONE_EXPLANATION = """\
|
|
Zone of the source disk. This argument is not required if the target disk
|
|
is in the same zone as the source disk.
|
|
"""
|
|
|
|
_SOURCE_DISK_REGION_EXPLANATION = """\
|
|
Region of the source disk. This argument is not required if the target
|
|
disk is in the same region as the source disk.
|
|
"""
|
|
|
|
_ASYNC_PRIMARY_DISK_HELP = """\
|
|
Primary disk for asynchronous replication. This flag is required when
|
|
creating a secondary disk.
|
|
"""
|
|
|
|
_ASYNC_PRIMARY_DISK_ZONE_EXPLANATION = """\
|
|
Zone of the primary disk for asynchronous replication. The primary and
|
|
secondary disks must not be in the same region.
|
|
"""
|
|
|
|
_ASYNC_PRIMARY_DISK_REGION_EXPLANATION = """\
|
|
Region of the primary disk for asynchronous replication. The primary and
|
|
secondary disks must not be in the same region.
|
|
"""
|
|
|
|
_ASYNC_SECONDARY_DISK_HELP = """\
|
|
Secondary disk for asynchronous replication. This flag is required when
|
|
starting replication.
|
|
"""
|
|
|
|
_ASYNC_SECONDARY_DISK_ZONE_EXPLANATION = """\
|
|
Zone of the secondary disk for asynchronous replication.
|
|
"""
|
|
|
|
_ASYNC_SECONDARY_DISK_REGION_EXPLANATION = """\
|
|
Region of the secondary disk for asynchronous replication.
|
|
"""
|
|
|
|
_ASYNC_SECONDARY_DISK_PROJECT_EXPLANATION = """\
|
|
Project of the secondary disk for asynchronous replication.
|
|
"""
|
|
|
|
_ASYNC_PRIMARY_DISK_PROJECT_EXPLANATION = """\
|
|
Project of the primary disk for asynchronous replication.
|
|
"""
|
|
|
|
DEFAULT_LIST_FORMAT = """\
|
|
table(
|
|
name,
|
|
zone.basename(),
|
|
sizeGb,
|
|
type.basename(),
|
|
status
|
|
)"""
|
|
|
|
|
|
MULTISCOPE_LIST_FORMAT = """
|
|
table(
|
|
name,
|
|
location(),
|
|
location_scope(),
|
|
sizeGb,
|
|
type.basename(),
|
|
status
|
|
)"""
|
|
|
|
|
|
class SnapshotsCompleter(compute_completers.ListCommandCompleter):
|
|
|
|
def __init__(self, **kwargs):
|
|
super(SnapshotsCompleter, self).__init__(
|
|
collection='compute.snapshots',
|
|
list_command='compute snapshots list --uri',
|
|
**kwargs)
|
|
|
|
|
|
class SnapshotGroupsCompleter(compute_completers.ListCommandCompleter):
|
|
|
|
def __init__(self, **kwargs):
|
|
super(SnapshotGroupsCompleter, self).__init__(
|
|
collection='compute.snapshotGroups',
|
|
list_command='alpha compute snapshot-groups list --uri',
|
|
api_version='alpha',
|
|
**kwargs)
|
|
|
|
|
|
class SnapshotsCompleterAlpha(completers.MultiResourceCompleter):
|
|
|
|
def __init__(self, **kwargs):
|
|
super(SnapshotsCompleterAlpha, self).__init__(
|
|
completers=[RegionSnapshotsCompleter, GlobalSnapshotsCompleter],
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class GlobalSnapshotsCompleter(compute_completers.ListCommandCompleter):
|
|
|
|
def __init__(self, **kwargs):
|
|
super(GlobalSnapshotsCompleter, self).__init__(
|
|
collection='compute.snapshots',
|
|
list_command='compute snapshots list --uri',
|
|
api_version='alpha',
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class RegionSnapshotsCompleter(compute_completers.ListCommandCompleter):
|
|
|
|
def __init__(self, **kwargs):
|
|
super(RegionSnapshotsCompleter, self).__init__(
|
|
collection='compute.regionSnapshots',
|
|
list_command='compute regionSnapshots list --uri',
|
|
api_version='alpha',
|
|
**kwargs
|
|
)
|
|
|
|
|
|
def MakeDiskArgZonal(plural):
|
|
return compute_flags.ResourceArgument(
|
|
resource_name='disk',
|
|
completer=compute_completers.DisksCompleter,
|
|
plural=plural,
|
|
name='DISK_NAME',
|
|
zonal_collection='compute.disks',
|
|
zone_explanation=compute_flags.ZONE_PROPERTY_EXPLANATION)
|
|
|
|
|
|
def MakeDiskArg(plural):
|
|
return compute_flags.ResourceArgument(
|
|
resource_name='disk',
|
|
completer=compute_completers.DisksCompleter,
|
|
plural=plural,
|
|
name='DISK_NAME',
|
|
zonal_collection='compute.disks',
|
|
regional_collection='compute.regionDisks',
|
|
zone_explanation=compute_flags.ZONE_PROPERTY_EXPLANATION,
|
|
region_explanation=compute_flags.REGION_PROPERTY_EXPLANATION)
|
|
|
|
|
|
def AddMultiWriterFlag(parser):
|
|
return parser.add_argument(
|
|
'--multi-writer',
|
|
action='store_true',
|
|
help="""
|
|
Create the disk in multi-writer mode so that it can be attached
|
|
with read-write access to two VMs. The multi-writer feature requires
|
|
specialized filesystems, among other restrictions. For more information,
|
|
see
|
|
https://cloud.google.com/compute/docs/disks/sharing-disks-between-vms.
|
|
""")
|
|
|
|
|
|
def AddEnableConfidentialComputeFlag(parser):
|
|
return parser.add_argument(
|
|
'--confidential-compute',
|
|
action='store_true',
|
|
help="""
|
|
Creates the disk with confidential compute mode enabled. Encryption with a Cloud KMS key is required to enable this option.
|
|
""",
|
|
)
|
|
|
|
|
|
def AddStopGroupAsyncReplicationArgs(parser):
|
|
"""Adds stop group async replication specific arguments to parser."""
|
|
parser.add_argument(
|
|
'DISK_CONSISTENCY_GROUP_POLICY',
|
|
help='URL of the disk consistency group resource policy. The resource'
|
|
'policy is always in the region of the primary disks.'
|
|
)
|
|
|
|
help_text = '{0} of the consistency group\'s primary or secondary disks. {1}'
|
|
scope_parser = parser.add_mutually_exclusive_group()
|
|
scope_parser.add_argument(
|
|
'--zone',
|
|
completer=compute_completers.ZonesCompleter,
|
|
action=actions.StoreProperty(properties.VALUES.compute.zone),
|
|
help=help_text.format('Zone', compute_flags.ZONE_PROPERTY_EXPLANATION))
|
|
scope_parser.add_argument(
|
|
'--region',
|
|
completer=compute_completers.RegionsCompleter,
|
|
action=actions.StoreProperty(properties.VALUES.compute.region),
|
|
help=help_text.format(
|
|
'Region',
|
|
compute_flags.REGION_PROPERTY_EXPLANATION))
|
|
|
|
|
|
def AddBulkCreateArgs(parser):
|
|
"""Adds bulk create specific arguments to parser."""
|
|
parser.add_argument(
|
|
'--source-consistency-group-policy',
|
|
help='''
|
|
URL of the source consistency group resource policy. The resource policy
|
|
is always the same region as the source disks.
|
|
''',
|
|
# This argument is required because consistent cloning is only supported
|
|
# feature under the BulkCreate now. May become optional in the future.
|
|
required=True)
|
|
|
|
help_text = """Target {0} of the created disks, which currently must be the same as the source {0}. {1}"""
|
|
scope_parser = parser.add_mutually_exclusive_group(required=True)
|
|
scope_parser.add_argument(
|
|
'--zone',
|
|
completer=compute_completers.ZonesCompleter,
|
|
action=actions.StoreProperty(properties.VALUES.compute.zone),
|
|
help=help_text.format('zone', compute_flags.ZONE_PROPERTY_EXPLANATION))
|
|
scope_parser.add_argument(
|
|
'--region',
|
|
completer=compute_completers.RegionsCompleter,
|
|
action=actions.StoreProperty(properties.VALUES.compute.region),
|
|
help=help_text.format('region',
|
|
compute_flags.REGION_PROPERTY_EXPLANATION))
|
|
|
|
|
|
def AddBulkCreateArgsAlpha(parser):
|
|
"""Adds bulk create specific arguments to parser."""
|
|
parser.add_argument(
|
|
'--source-consistency-group-policy',
|
|
help='''
|
|
URL of the source consistency group resource policy. The resource policy
|
|
is always the same region as the source disks.
|
|
''',
|
|
# This argument is optional because we now support bulk insert from
|
|
# multiple source types.
|
|
required=False)
|
|
|
|
help_text = """Target {0} of the created disks, which currently must be the same as the source {0}. {1}"""
|
|
scope_parser = parser.add_mutually_exclusive_group(required=True)
|
|
scope_parser.add_argument(
|
|
'--zone',
|
|
completer=compute_completers.ZonesCompleter,
|
|
action=actions.StoreProperty(properties.VALUES.compute.zone),
|
|
help=help_text.format('zone', compute_flags.ZONE_PROPERTY_EXPLANATION))
|
|
scope_parser.add_argument(
|
|
'--region',
|
|
completer=compute_completers.RegionsCompleter,
|
|
action=actions.StoreProperty(properties.VALUES.compute.region),
|
|
help=help_text.format('region',
|
|
compute_flags.REGION_PROPERTY_EXPLANATION))
|
|
|
|
|
|
def AddProvisionedIopsFlag(parser, arg_parsers):
|
|
return parser.add_argument(
|
|
'--provisioned-iops',
|
|
type=arg_parsers.BoundedInt(),
|
|
help=(
|
|
'Provisioned IOPS of disk to create. Only for use with disks of type '
|
|
'pd-extreme and hyperdisk-extreme.'
|
|
),
|
|
)
|
|
|
|
|
|
def AddProvisionedThroughputFlag(parser, arg_parsers):
|
|
return parser.add_argument(
|
|
'--provisioned-throughput',
|
|
type=arg_parsers.BoundedInt(),
|
|
help=(
|
|
'Provisioned throughput of disk to create. The throughput unit is '
|
|
'MB per sec. Only for use with disks of type hyperdisk-throughput.'))
|
|
|
|
|
|
def AddArchitectureFlag(parser, messages):
|
|
architecture_enum_type = messages.Disk.ArchitectureValueValuesEnum
|
|
excluded_enums = [architecture_enum_type.ARCHITECTURE_UNSPECIFIED.name]
|
|
architecture_choices = sorted(
|
|
[e for e in architecture_enum_type.names() if e not in excluded_enums])
|
|
return parser.add_argument(
|
|
'--architecture',
|
|
choices=architecture_choices,
|
|
help=(
|
|
'Specifies the architecture or processor type that this disk can '
|
|
'support. For available processor types on Compute Engine, '
|
|
'see https://cloud.google.com/compute/docs/cpu-platforms.'
|
|
),
|
|
)
|
|
|
|
|
|
def AddAccessModeFlag(parser, messages):
|
|
if hasattr(messages.Disk, 'AccessModeValueValuesEnum'):
|
|
access_mode_enum_type = messages.Disk.AccessModeValueValuesEnum
|
|
return parser.add_argument(
|
|
'--access-mode',
|
|
choices=access_mode_enum_type.names(),
|
|
help=(
|
|
'Specifies how VMs attached to the disk can access the data on the'
|
|
' disk. To grant read-only access to multiple VMs attached to the'
|
|
' disk, set access-mode to READ_ONLY_MANY.'
|
|
' To grant read-write access'
|
|
' to only one VM attached to the disk, use READ_WRITE_SINGLE.'
|
|
' READ_WRITE_SINGLE is used if omitted.'
|
|
),
|
|
)
|
|
|
|
|
|
def AddLocationHintArg(parser):
|
|
parser.add_argument(
|
|
'--location-hint',
|
|
hidden=True,
|
|
help="""\
|
|
Used by internal tools to control sub-zone location of the disk.
|
|
""")
|
|
|
|
|
|
def MakeSecondaryDiskArg(required=False):
|
|
return compute_flags.ResourceArgument(
|
|
resource_name='async secondary disk',
|
|
name='--secondary-disk',
|
|
completer=compute_completers.DisksCompleter,
|
|
zonal_collection='compute.disks',
|
|
regional_collection='compute.regionDisks',
|
|
short_help='Secondary disk for asynchronous replication.',
|
|
detailed_help=_ASYNC_SECONDARY_DISK_HELP,
|
|
plural=False,
|
|
required=required,
|
|
scope_flags_usage=compute_flags.ScopeFlagsUsage
|
|
.GENERATE_DEDICATED_SCOPE_FLAGS,
|
|
zone_help_text=_ASYNC_SECONDARY_DISK_ZONE_EXPLANATION,
|
|
region_help_text=_ASYNC_SECONDARY_DISK_REGION_EXPLANATION)
|
|
|
|
|
|
def AddSecondaryDiskProject(parser, category=None):
|
|
parser.add_argument(
|
|
'--secondary-disk-project',
|
|
category=category,
|
|
help=_ASYNC_SECONDARY_DISK_PROJECT_EXPLANATION,
|
|
)
|
|
|
|
|
|
def AddPrimaryDiskProject(parser, category=None):
|
|
parser.add_argument(
|
|
'--primary-disk-project',
|
|
category=category,
|
|
help=_ASYNC_PRIMARY_DISK_PROJECT_EXPLANATION,
|
|
)
|
|
|
|
|
|
def AddKeepOldDiskArgs(parser):
|
|
"""Adds keep old disk argument group to parser."""
|
|
group = parser.add_group()
|
|
group.add_argument(
|
|
'--keep-old-disk',
|
|
action='store_true',
|
|
help=(
|
|
'If true, the old disk will be kept after the conversion. '
|
|
'The old disk will be renamed to the original disk name with a '
|
|
'suffix.'
|
|
),
|
|
)
|
|
group.add_argument(
|
|
'--target-disk-name',
|
|
help=(
|
|
'Specifies the name of the new disk, '
|
|
'it can only be used with --keep-old-disk.'
|
|
' For details on the naming convention for this '
|
|
'resource, refer to: '
|
|
'https://cloud.google.com/compute/docs/'
|
|
'naming-resources'
|
|
),
|
|
)
|
|
|
|
|
|
def AddGuestOsFeatureArgs(parser, messages):
|
|
group = parser.add_group()
|
|
guest_os_feature_choices = [
|
|
messages.GuestOsFeature.TypeValueValuesEnum.GVNIC.name
|
|
]
|
|
group.add_argument(
|
|
'--add-guest-os-features',
|
|
choices=guest_os_feature_choices,
|
|
help=(
|
|
'Specifies guest OS features to add to the disk. Refer to'
|
|
' https://cloud.google.com/compute/docs/images/create-custom#guest-os-features'
|
|
' for a list of available options.'
|
|
),
|
|
)
|
|
|
|
|
|
def AddSourceInstantSnapshotProject(parser, category=None):
|
|
parser.add_argument(
|
|
'--source-instant-snapshot-project',
|
|
category=category,
|
|
help=_DETAILED_SOURCE_INSTANT_SNAPSHOT_PROJECT_HELP,
|
|
)
|
|
|
|
SOURCE_SNAPSHOT_ARG = compute_flags.ResourceArgument(
|
|
resource_name='snapshot',
|
|
completer=SnapshotsCompleter,
|
|
name='--source-snapshot',
|
|
plural=False,
|
|
required=False,
|
|
global_collection='compute.snapshots',
|
|
short_help='Source snapshot used to create the disks.',
|
|
detailed_help=_DETAILED_SOURCE_SNAPSHOT_HELP,
|
|
)
|
|
|
|
SOURCE_SNAPSHOT_ARG_ALPHA = compute_flags.ResourceArgument(
|
|
resource_name='snapshot',
|
|
completer=SnapshotsCompleterAlpha,
|
|
name='--source-snapshot',
|
|
plural=False,
|
|
required=False,
|
|
global_collection='compute.snapshots',
|
|
regional_collection='compute.regionSnapshots',
|
|
short_help='Source snapshot used to create the disks.',
|
|
detailed_help=_DETAILED_SOURCE_SNAPSHOT_HELP,
|
|
)
|
|
|
|
SOURCE_INSTANT_SNAPSHOT_ARG = compute_flags.ResourceArgument(
|
|
resource_name='source instant snapshot',
|
|
completer=compute_completers.InstantSnapshotsCompleter,
|
|
name='--source-instant-snapshot',
|
|
zonal_collection='compute.instantSnapshots',
|
|
regional_collection='compute.regionInstantSnapshots',
|
|
plural=False,
|
|
required=False,
|
|
short_help='Name of the source instant snapshot used to create the disks.',
|
|
detailed_help=_DETAILED_SOURCE_INSTANT_SNAPSHOT_HELP,
|
|
scope_flags_usage=compute_flags.ScopeFlagsUsage.USE_EXISTING_SCOPE_FLAGS)
|
|
|
|
SOURCE_INSTANT_SNAPSHOT_GROUP_ARG = compute_flags.ResourceArgument(
|
|
resource_name='source instant snapshot group',
|
|
name='--source-instant-snapshot-group',
|
|
completer=compute_completers.InstantSnapshotGroupsCompleter,
|
|
short_help='Source instant snapshot group used to create the disks.',
|
|
zonal_collection='compute.instantSnapshotGroups',
|
|
regional_collection='compute.regionInstantSnapshotGroups',
|
|
required=False,
|
|
)
|
|
|
|
SOURCE_SNAPSHOT_GROUP_ARG = compute_flags.ResourceArgument(
|
|
resource_name='source snapshot group',
|
|
name='--source-snapshot-group',
|
|
completer=SnapshotGroupsCompleter,
|
|
short_help='Source snapshot group used to create the disks.',
|
|
global_collection='compute.snapshotGroups',
|
|
required=False,
|
|
)
|
|
|
|
SOURCE_DISK_ARG = compute_flags.ResourceArgument(
|
|
resource_name='source disk',
|
|
name='--source-disk',
|
|
completer=compute_completers.DisksCompleter,
|
|
short_help='Source disk used to create the disks. Source disk must be in'
|
|
' the same zone/region as the disk to be created.',
|
|
detailed_help=_SOURCE_DISK_DETAILED_HELP,
|
|
zonal_collection='compute.disks',
|
|
regional_collection='compute.regionDisks',
|
|
required=False,
|
|
zone_help_text=_SOURCE_DISK_ZONE_EXPLANATION,
|
|
region_help_text=_SOURCE_DISK_REGION_EXPLANATION)
|
|
|
|
ASYNC_PRIMARY_DISK_ARG = compute_flags.ResourceArgument(
|
|
resource_name='async primary disk',
|
|
name='--primary-disk',
|
|
completer=compute_completers.DisksCompleter,
|
|
zonal_collection='compute.disks',
|
|
regional_collection='compute.regionDisks',
|
|
short_help='Primary disk for asynchronous replication. This option creates'
|
|
' a secondary disk for a given primary disk.',
|
|
detailed_help=_ASYNC_PRIMARY_DISK_HELP,
|
|
plural=False,
|
|
required=False,
|
|
scope_flags_usage=compute_flags.ScopeFlagsUsage
|
|
.GENERATE_DEDICATED_SCOPE_FLAGS,
|
|
zone_help_text=_ASYNC_PRIMARY_DISK_ZONE_EXPLANATION,
|
|
region_help_text=_ASYNC_PRIMARY_DISK_REGION_EXPLANATION)
|
|
|
|
STORAGE_POOL_ARG = compute_flags.ResourceArgument(
|
|
resource_name='storage pool',
|
|
name='--storage-pool',
|
|
short_help=('Specifies the URI of the storage pool in which the disk is '
|
|
'created.'),
|
|
zonal_collection='compute.storagePools',
|
|
plural=False,
|
|
required=False,
|
|
scope_flags_usage=compute_flags.ScopeFlagsUsage.USE_EXISTING_SCOPE_FLAGS)
|
|
|
|
|
|
def AddSourceMachineImageNameArg(parser):
|
|
# TODO: b/421424530 - switch to compute_flags.ResourceArgument when
|
|
# disks.insert goes GA. compute_flags.ResourceArgument does not support
|
|
# the hidden flag.
|
|
parser.add_argument(
|
|
'--source-machine-image',
|
|
help="""\
|
|
Specifies the URI of the source machine image contiaining the disk to
|
|
restore. Requires *--source-machine-image-disk-device-name* with the
|
|
disk to restores device name.
|
|
""",
|
|
hidden=True,
|
|
)
|
|
|
|
|
|
def AddSourceMachineImageDiskDeviceNameArg(parser):
|
|
parser.add_argument(
|
|
'--source-machine-image-disk-device-name',
|
|
help="""\
|
|
Specifies the name of the disk to be restored from the source machine
|
|
image. Requires *--source-machine-image* with the URI of the source
|
|
machine image.
|
|
""",
|
|
hidden=True,
|
|
)
|