185 lines
6.3 KiB
Python
185 lines
6.3 KiB
Python
# -*- coding: utf-8 -*- #
|
|
# Copyright 2014 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.
|
|
"""Command for attaching a disk to an instance."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
from googlecloudsdk.api_lib.compute import base_classes
|
|
from googlecloudsdk.api_lib.compute import csek_utils
|
|
from googlecloudsdk.api_lib.compute import instance_utils
|
|
from googlecloudsdk.calliope import base
|
|
from googlecloudsdk.command_lib.compute import scope as compute_scopes
|
|
from googlecloudsdk.command_lib.compute.instances import flags
|
|
|
|
MODE_OPTIONS = {
|
|
'ro': 'Read-only.',
|
|
'rw': 'Read-write.',
|
|
}
|
|
|
|
PD_INTERFACE_OPTIONS = {
|
|
'SCSI': 'SCSI',
|
|
'NVME': 'NVME',
|
|
}
|
|
|
|
DETAILED_HELP = {
|
|
'DESCRIPTION': """
|
|
*{command}* is used to attach a disk to an instance. For example,
|
|
|
|
$ gcloud compute instances attach-disk example-instance --disk DISK --zone us-central1-a
|
|
|
|
attaches the disk named 'DISK' to the instance named
|
|
'example-instance' in zone ``us-central1-a''.
|
|
|
|
After you create and attach a new disk to an instance, you must
|
|
[format and mount](https://cloud.google.com/compute/docs/disks/add-persistent-disk#formatting)
|
|
the disk so that the operating system can use the available storage
|
|
space.
|
|
You can attach an existing non-boot disk to more than one instance. For
|
|
more information, see
|
|
[Share a disk between VMs](compute/docs/disks/add-persistent-disk#use_multi_instances).
|
|
""",
|
|
'EXAMPLES': """
|
|
To attach a disk named 'my-disk' as a boot disk to an instance named
|
|
'my-instance', run:
|
|
|
|
$ {command} my-instance --disk=my-disk --boot
|
|
|
|
To attach a device named 'my-device' for read-only access to an
|
|
instance named 'my-instance', run:
|
|
|
|
$ {command} my-instance --device-name=my-device --mode=ro
|
|
""",
|
|
}
|
|
|
|
|
|
@base.UniverseCompatible
|
|
@base.ReleaseTracks(
|
|
base.ReleaseTrack.GA, base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA)
|
|
class AttachDisk(base.SilentCommand):
|
|
"""Attach a disk to an instance."""
|
|
|
|
@staticmethod
|
|
def Args(parser):
|
|
flags.INSTANCE_ARG.AddArgument(parser)
|
|
|
|
parser.add_argument(
|
|
'--device-name',
|
|
help=('An optional name that indicates the disk name the guest '
|
|
'operating system will see. (Note: Device name does not '
|
|
'correspond to mounted volume name). Must match the disk name '
|
|
'if the disk is going to be mounted to a container with '
|
|
'--container-mount-disk (alpha feature).'))
|
|
|
|
parser.add_argument(
|
|
'--disk',
|
|
help='The name of the disk to attach to the instance.',
|
|
required=True)
|
|
|
|
parser.add_argument(
|
|
'--mode',
|
|
choices=MODE_OPTIONS,
|
|
default='rw',
|
|
help='Specifies the mode of the disk.')
|
|
|
|
parser.add_argument(
|
|
'--boot',
|
|
action='store_true',
|
|
help='Attach the disk to the instance as a boot disk.')
|
|
|
|
parser.add_argument(
|
|
'--interface',
|
|
choices=PD_INTERFACE_OPTIONS,
|
|
help="""
|
|
The interface of the disk.
|
|
""",
|
|
)
|
|
|
|
flags.AddDiskScopeFlag(parser)
|
|
|
|
parser.add_argument(
|
|
'--force-attach',
|
|
default=False,
|
|
action='store_true',
|
|
help="""\
|
|
Attach the disk to the instance even if it is currently attached to another
|
|
instance. The attachment will succeed even if detaching from the previous
|
|
instance fails at first. The server will continue trying to detach the disk from
|
|
the previous instance in the background.""")
|
|
|
|
csek_utils.AddCsekKeyArgs(parser, flags_about_creation=False)
|
|
|
|
def ParseDiskRef(self, resources, args, instance_ref):
|
|
if args.disk_scope == 'regional':
|
|
scope = compute_scopes.ScopeEnum.REGION
|
|
else:
|
|
scope = compute_scopes.ScopeEnum.ZONE
|
|
return instance_utils.ParseDiskResource(
|
|
resources, args.disk, instance_ref.project, instance_ref.zone, scope)
|
|
|
|
def Run(self, args):
|
|
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
|
|
client = holder.client
|
|
|
|
instance_ref = flags.INSTANCE_ARG.ResolveAsResource(
|
|
args, holder.resources,
|
|
scope_lister=flags.GetInstanceZoneScopeLister(client))
|
|
|
|
disk_ref = self.ParseDiskRef(holder.resources, args, instance_ref)
|
|
|
|
if args.mode == 'rw':
|
|
mode = client.messages.AttachedDisk.ModeValueValuesEnum.READ_WRITE
|
|
else:
|
|
mode = client.messages.AttachedDisk.ModeValueValuesEnum.READ_ONLY
|
|
|
|
allow_rsa_encrypted = self.ReleaseTrack() in [base.ReleaseTrack.ALPHA,
|
|
base.ReleaseTrack.BETA]
|
|
csek_keys = csek_utils.CsekKeyStore.FromArgs(args, allow_rsa_encrypted)
|
|
disk_key_or_none = csek_utils.MaybeLookupKeyMessage(csek_keys, disk_ref,
|
|
client.apitools_client)
|
|
|
|
attached_disk = client.messages.AttachedDisk(
|
|
deviceName=args.device_name,
|
|
mode=mode,
|
|
source=disk_ref.SelfLink(),
|
|
type=client.messages.AttachedDisk.TypeValueValuesEnum.PERSISTENT,
|
|
diskEncryptionKey=disk_key_or_none)
|
|
|
|
if args.interface:
|
|
if args.interface == 'SCSI':
|
|
interface = client.messages.AttachedDisk.InterfaceValueValuesEnum.SCSI
|
|
else:
|
|
interface = client.messages.AttachedDisk.InterfaceValueValuesEnum.NVME
|
|
attached_disk.interface = interface
|
|
|
|
if args.boot:
|
|
attached_disk.boot = args.boot
|
|
|
|
request = client.messages.ComputeInstancesAttachDiskRequest(
|
|
instance=instance_ref.Name(),
|
|
project=instance_ref.project,
|
|
attachedDisk=attached_disk,
|
|
zone=instance_ref.zone)
|
|
|
|
if args.force_attach:
|
|
request.forceAttach = args.force_attach
|
|
|
|
return client.MakeRequests([(client.apitools_client.instances, 'AttachDisk',
|
|
request)])
|
|
|
|
|
|
AttachDisk.detailed_help = DETAILED_HELP
|