def CreatePersistentCreateDiskMessages(compute_client, resources, csek_keys,
                                       create_disks, instance_ref):
    """Returns a list of AttachedDisk messages for newly creating disks.

  Args:
    compute_client: creates resources,
    resources: parser of resources,
    csek_keys: customer suplied encryption keys,
    create_disks: disk objects - contains following properties
             * name - the name of disk,
             * mode - 'rw' (R/W), 'ro' (R/O) access mode,
             * disk-size - the size of the disk,
             * disk-type - the type of the disk (HDD or SSD),
             * image - the name of the image to initialize from,
             * image-family - the image family name,
             * image-project - the project name that has the image,
             * auto-delete - whether disks is deleted when VM is deleted,
             * device-name - device name on VM.
    instance_ref: reference to the instance that will own the new disks.
  Returns:
    list of API messages for attached disks
  """
    disks_messages = []

    messages = compute_client.messages
    compute = compute_client.apitools_client
    for disk in create_disks or []:
        name = disk.get('name')

        # Resolves the mode.
        mode_value = disk.get('mode', 'rw')
        if mode_value == 'rw':
            mode = messages.AttachedDisk.ModeValueValuesEnum.READ_WRITE
        else:
            mode = messages.AttachedDisk.ModeValueValuesEnum.READ_ONLY

        auto_delete_value = disk.get('auto-delete', 'yes')
        auto_delete = auto_delete_value == 'yes'

        disk_size_gb = utils.BytesToGb(disk.get('size'))
        disk_type = disk.get('type')
        if disk_type:
            disk_type_ref = resources.Parse(disk_type,
                                            collection='compute.diskTypes',
                                            params={
                                                'project':
                                                instance_ref.project,
                                                'zone': instance_ref.zone
                                            })

            disk_type_uri = disk_type_ref.SelfLink()
        else:
            disk_type_ref = None
            disk_type_uri = None

        image_expander = image_utils.ImageExpander(compute_client, resources)
        image_uri, _ = image_expander.ExpandImageFlag(
            user_project=instance_ref.project,
            image=disk.get('image'),
            image_family=disk.get('image-family'),
            image_project=disk.get('image-project'),
            return_image_resource=False)

        image_key = None
        disk_key = None
        if csek_keys:
            image_key = csek_utils.MaybeLookupKeyMessagesByUri(
                csek_keys, resources, [image_uri], compute)
            if name:
                disk_ref = resources.Parse(name,
                                           collection='compute.disks',
                                           params={'zone': instance_ref.zone})
                disk_key = csek_utils.MaybeLookupKeyMessage(
                    csek_keys, disk_ref, compute)

        disk_key = kms_utils.MaybeGetKmsKeyFromDict(disk, instance_ref.project,
                                                    compute, disk_key)

        create_disk = messages.AttachedDisk(
            autoDelete=auto_delete,
            boot=False,
            deviceName=disk.get('device-name'),
            initializeParams=messages.AttachedDiskInitializeParams(
                diskName=name,
                sourceImage=image_uri,
                diskSizeGb=disk_size_gb,
                diskType=disk_type_uri,
                sourceImageEncryptionKey=image_key),
            mode=mode,
            type=messages.AttachedDisk.TypeValueValuesEnum.PERSISTENT,
            diskEncryptionKey=disk_key)

        disks_messages.append(create_disk)

    return disks_messages
def CreateDefaultBootAttachedDiskMessage(compute_client,
                                         resources,
                                         disk_type,
                                         disk_device_name,
                                         disk_auto_delete,
                                         disk_size_gb,
                                         require_csek_key_create,
                                         image_uri,
                                         instance_ref,
                                         csek_keys=None,
                                         kms_args=None):
    """Returns an AttachedDisk message for creating a new boot disk."""
    messages = compute_client.messages
    compute = compute_client.apitools_client

    if disk_type:
        disk_type_ref = resources.Parse(disk_type,
                                        collection='compute.diskTypes',
                                        params={
                                            'project': instance_ref.project,
                                            'zone': instance_ref.zone
                                        })
        disk_type_uri = disk_type_ref.SelfLink()
    else:
        disk_type_ref = None
        disk_type_uri = None

    if csek_keys:
        # If we're going to encrypt the boot disk make sure that we select
        # a name predictably, instead of letting the API deal with name
        # conflicts automatically.
        #
        # Note that when csek keys are being used we *always* want force this
        # even if we don't have any encryption key for default disk name.
        #
        # Consider the case where the user's key file has a key for disk `foo-1`
        # and no other disk.  Assume she runs
        #   gcloud compute instances create foo --csek-key-file f \
        #       --no-require-csek-key-create
        # and gcloud doesn't force the disk name to be `foo`.  The API might
        # select name `foo-1` for the new disk, but has no way of knowing
        # that the user has a key file mapping for that disk name.  That
        # behavior violates the principle of least surprise.
        #
        # Instead it's better for gcloud to force a specific disk name in the
        # instance create, and fail if that name isn't available.

        effective_boot_disk_name = (disk_device_name or instance_ref.Name())

        disk_ref = resources.Parse(effective_boot_disk_name,
                                   collection='compute.disks',
                                   params={
                                       'project': instance_ref.project,
                                       'zone': instance_ref.zone
                                   })
        disk_key_or_none = csek_utils.MaybeToMessage(
            csek_keys.LookupKey(disk_ref, require_csek_key_create), compute)
        [image_key_or_none
         ] = csek_utils.MaybeLookupKeyMessagesByUri(csek_keys, resources,
                                                    [image_uri], compute)
        kwargs_init_parms = {'sourceImageEncryptionKey': image_key_or_none}
        kwargs_disk = {'diskEncryptionKey': disk_key_or_none}
    else:
        kwargs_disk = {}
        kwargs_init_parms = {}
        effective_boot_disk_name = disk_device_name

    kms_key = kms_utils.MaybeGetKmsKey(
        kms_args, instance_ref.project, compute,
        kwargs_disk.get('diskEncryptionKey', None))
    if kms_key:
        kwargs_disk = {'diskEncryptionKey': kms_key}

    return messages.AttachedDisk(
        autoDelete=disk_auto_delete,
        boot=True,
        deviceName=effective_boot_disk_name,
        initializeParams=messages.AttachedDiskInitializeParams(
            sourceImage=image_uri,
            diskSizeGb=disk_size_gb,
            diskType=disk_type_uri,
            **kwargs_init_parms),
        mode=messages.AttachedDisk.ModeValueValuesEnum.READ_WRITE,
        type=messages.AttachedDisk.TypeValueValuesEnum.PERSISTENT,
        **kwargs_disk)
def CreatePersistentCreateDiskMessages(compute_client,
                                       resources, csek_keys, create_disks,
                                       instance_ref, enable_kms=False,
                                       enable_snapshots=False,
                                       container_mount_disk=None,
                                       resource_policy=False,
                                       enable_source_snapshot_csek=False,
                                       enable_image_csek=False):
  """Returns a list of AttachedDisk messages for newly creating disks.

  Args:
    compute_client: creates resources,
    resources: parser of resources,
    csek_keys: customer suplied encryption keys,
    create_disks: disk objects - contains following properties
             * name - the name of disk,
             * description - an optional description for the disk,
             * mode - 'rw' (R/W), 'ro' (R/O) access mode,
             * disk-size - the size of the disk,
             * disk-type - the type of the disk (HDD or SSD),
             * image - the name of the image to initialize from,
             * image-csek-required - the name of the CSK protected image,
             * image-family - the image family name,
             * image-project - the project name that has the image,
             * auto-delete - whether disks is deleted when VM is deleted,
             * device-name - device name on VM,
             * source-snapshot - the snapshot to initialize from,
             * source-snapshot-csek-required - CSK protected snapshot,
             * disk-resource-policy - resource policies applied to disk.
             * enable_source_snapshot_csek - CSK file for snapshot,
             * enable_image_csek - CSK file for image
    instance_ref: reference to the instance that will own the new disks.
    enable_kms: True if KMS keys are supported for the disk.
    enable_snapshots: True if snapshot initialization is supported for the disk.
    container_mount_disk: list of disks to be mounted to container, if any.
    resource_policy: True if resource-policies are enabled
    enable_source_snapshot_csek: True if snapshot CSK files are enabled
    enable_image_csek: True if image CSK files are enabled

  Returns:
    list of API messages for attached disks
  """
  disks_messages = []

  messages = compute_client.messages
  compute = compute_client.apitools_client
  for disk in create_disks or []:
    name = disk.get('name')

    # Resolves the mode.
    mode_value = disk.get('mode', 'rw')
    if mode_value == 'rw':
      mode = messages.AttachedDisk.ModeValueValuesEnum.READ_WRITE
    else:
      mode = messages.AttachedDisk.ModeValueValuesEnum.READ_ONLY

    auto_delete_value = disk.get('auto-delete', 'yes')
    auto_delete = auto_delete_value == 'yes'

    disk_size_gb = utils.BytesToGb(disk.get('size'))
    disk_type = disk.get('type')
    if disk_type:
      disk_type_ref = resources.Parse(disk_type,
                                      collection='compute.diskTypes',
                                      params={
                                          'project': instance_ref.project,
                                          'zone': instance_ref.zone
                                      })

      disk_type_uri = disk_type_ref.SelfLink()
    else:
      disk_type_uri = None

    img = disk.get('image')
    img_family = disk.get('image-family')
    img_project = disk.get('image-project')

    image_uri = None
    if img or img_family:
      image_expander = image_utils.ImageExpander(compute_client, resources)
      image_uri, _ = image_expander.ExpandImageFlag(
          user_project=instance_ref.project,
          image=img,
          image_family=img_family,
          image_project=img_project,
          return_image_resource=False)

    image_key = None
    disk_key = None
    if csek_keys:
      image_key = csek_utils.MaybeLookupKeyMessagesByUri(csek_keys,
                                                         resources,
                                                         [image_uri],
                                                         compute)
      if name:
        disk_ref = resources.Parse(name,
                                   collection='compute.disks',
                                   params={'zone': instance_ref.zone})
        disk_key = csek_utils.MaybeLookupKeyMessage(csek_keys, disk_ref,
                                                    compute)

    if enable_kms:
      disk_key = kms_utils.MaybeGetKmsKeyFromDict(disk, messages, disk_key)

    initialize_params = messages.AttachedDiskInitializeParams(
        diskName=name,
        description=disk.get('description'),
        sourceImage=image_uri,
        diskSizeGb=disk_size_gb,
        diskType=disk_type_uri,
        sourceImageEncryptionKey=image_key)

    if enable_snapshots:
      snapshot_name = disk.get('source-snapshot')
      attached_snapshot_uri = ResolveSnapshotURI(
          snapshot=snapshot_name, user_project=instance_ref.project,
          resource_parser=resources)
      if attached_snapshot_uri:
        initialize_params.sourceImage = None
        initialize_params.sourceSnapshot = attached_snapshot_uri

    if resource_policy:
      policies = disk.get('disk-resource-policy')
      if policies:
        initialize_params.resourcePolicies = policies

    if enable_image_csek:
      image_key_file = disk.get('image_csek')
      if image_key_file:
        initialize_params.imageKeyFile = image_key_file

    if enable_source_snapshot_csek:
      snapshot_key_file = disk.get('source_snapshot_csek')
      if snapshot_key_file:
        initialize_params.snapshotKeyFile = snapshot_key_file

    device_name = GetDiskDeviceName(disk, name, container_mount_disk)
    create_disk = messages.AttachedDisk(
        autoDelete=auto_delete,
        boot=False,
        deviceName=device_name,
        initializeParams=initialize_params,
        mode=mode,
        type=messages.AttachedDisk.TypeValueValuesEnum.PERSISTENT,
        diskEncryptionKey=disk_key)

    disks_messages.append(create_disk)

  return disks_messages
Exemple #4
0
    def CreateRequests(self, args):
        """Returns a list of requests necessary for adding disks."""
        size_gb = utils.BytesToGb(args.size)

        # TODO(user): remove getattr on image family GA
        from_image = args.image or getattr(args, 'image_family', None)
        if not size_gb and not args.source_snapshot and not from_image:
            if args.type and 'pd-ssd' in args.type:
                size_gb = constants.DEFAULT_SSD_DISK_SIZE_GB
            else:
                size_gb = constants.DEFAULT_STANDARD_DISK_SIZE_GB

        utils.WarnIfDiskSizeIsTooSmall(size_gb, args.type)

        requests = []

        disk_refs = self.CreateZonalReferences(args.names, args.zone)

        # Check if the zone is deprecated or has maintenance coming.
        self.WarnForZonalCreation(disk_refs)

        if from_image:
            source_image_uri, _ = self.ExpandImageFlag(
                args, return_image_resource=False)
        else:
            source_image_uri = None

        if args.source_snapshot:
            snapshot_ref = self.CreateGlobalReference(
                args.source_snapshot, resource_type='snapshots')
            snapshot_uri = snapshot_ref.SelfLink()
        else:
            snapshot_uri = None

        if hasattr(args, 'csek_key_file'):
            csek_keys = csek_utils.CsekKeyStore.FromArgs(args)
        else:
            csek_keys = None

        image_key_message_or_none, snapshot_key_message_or_none = (
            csek_utils.MaybeLookupKeyMessagesByUri(
                csek_keys, self.resources, [source_image_uri, snapshot_uri],
                self.compute))

        for disk_ref in disk_refs:
            if args.type:
                type_ref = self.CreateZonalReference(args.type,
                                                     disk_ref.zone,
                                                     resource_type='diskTypes')
                type_uri = type_ref.SelfLink()
            else:
                type_uri = None

            if csek_keys:
                disk_key_or_none = csek_keys.LookupKey(
                    disk_ref, args.require_csek_key_create)
                disk_key_message_or_none = csek_utils.MaybeToMessage(
                    disk_key_or_none, self.compute)
                kwargs = {
                    'diskEncryptionKey': disk_key_message_or_none,
                    'sourceImageEncryptionKey': image_key_message_or_none,
                    'sourceSnapshotEncryptionKey': snapshot_key_message_or_none
                }
            else:
                kwargs = {}

            request = self.messages.ComputeDisksInsertRequest(
                disk=self.messages.Disk(name=disk_ref.Name(),
                                        description=args.description,
                                        sizeGb=size_gb,
                                        sourceSnapshot=snapshot_uri,
                                        type=type_uri,
                                        **kwargs),
                project=self.project,
                sourceImage=source_image_uri,
                zone=disk_ref.zone)
            requests.append(request)

        return requests
Exemple #5
0
  def _Run(self, args, supports_kms_keys=False, supports_physical_block=False,
           support_shared_disk=False, support_vss_erase=False):
    compute_holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
    client = compute_holder.client

    self.show_unformated_message = not (args.IsSpecified('image') or
                                        args.IsSpecified('image_family') or
                                        args.IsSpecified('source_snapshot'))
    if self.source_disk_enabled:
      self.show_unformated_message = self.show_unformated_message and not (
          args.IsSpecified('source_disk'))

    disk_refs = self.ValidateAndParseDiskRefs(args, compute_holder)
    from_image = self.GetFromImage(args)
    size_gb = self.GetDiskSizeGb(args, from_image)
    self.WarnAboutScopeDeprecationsAndMaintenance(disk_refs, client)
    project_to_source_image = self.GetProjectToSourceImageDict(
        args, disk_refs, compute_holder, from_image)
    snapshot_uri = self.GetSnapshotUri(args, compute_holder)

    # Those features are only exposed in alpha/beta, it would be nice to have
    # code supporting them only in alpha and beta versions of the command.
    labels = self.GetLabels(args, client)

    allow_rsa_encrypted = self.ReleaseTrack() in [base.ReleaseTrack.ALPHA,
                                                  base.ReleaseTrack.BETA]
    csek_keys = csek_utils.CsekKeyStore.FromArgs(args, allow_rsa_encrypted)

    for project in project_to_source_image:
      source_image_uri = project_to_source_image[project].uri
      project_to_source_image[project].keys = (
          csek_utils.MaybeLookupKeyMessagesByUri(
              csek_keys, compute_holder.resources,
              [source_image_uri, snapshot_uri], client.apitools_client))

    # end of alpha/beta features.

    guest_os_feature_messages = _ParseGuestOsFeaturesToMessages(
        args, client.messages)

    requests = []
    for disk_ref in disk_refs:
      type_uri = self.GetDiskTypeUri(args, disk_ref, compute_holder)

      # Those features are only exposed in alpha/beta, it would be nice to have
      # code supporting them only in alpha and beta versions of the command.
      # TODO(b/65161039): Stop checking release path in the middle of GA code.
      kwargs = {}
      if csek_keys:
        disk_key_or_none = csek_keys.LookupKey(
            disk_ref, args.require_csek_key_create)
        disk_key_message_or_none = csek_utils.MaybeToMessage(
            disk_key_or_none, client.apitools_client)
        kwargs['diskEncryptionKey'] = disk_key_message_or_none
        kwargs['sourceImageEncryptionKey'] = (
            project_to_source_image[disk_ref.project].keys[0])
        kwargs['sourceSnapshotEncryptionKey'] = (
            project_to_source_image[disk_ref.project].keys[1])
      if labels:
        kwargs['labels'] = labels

      if supports_kms_keys:
        kwargs['diskEncryptionKey'] = kms_utils.MaybeGetKmsKey(
            args, client.messages, kwargs.get('diskEncryptionKey', None))

      # end of alpha/beta features.

      if supports_physical_block and args.IsSpecified('physical_block_size'):
        physical_block_size_bytes = int(args.physical_block_size)
      else:
        physical_block_size_bytes = None

      resource_policies = getattr(args, 'resource_policies', None)
      if resource_policies:
        if disk_ref.Collection() == 'compute.regionDisks':
          disk_region = disk_ref.region
        else:
          disk_region = utils.ZoneNameToRegionName(disk_ref.zone)
        parsed_resource_policies = []
        for policy in resource_policies:
          resource_policy_ref = resource_util.ParseResourcePolicy(
              compute_holder.resources,
              policy,
              project=disk_ref.project,
              region=disk_region)
          parsed_resource_policies.append(resource_policy_ref.SelfLink())
        kwargs['resourcePolicies'] = parsed_resource_policies

      disk = client.messages.Disk(
          name=disk_ref.Name(),
          description=args.description,
          sizeGb=size_gb,
          sourceSnapshot=snapshot_uri,
          type=type_uri,
          physicalBlockSizeBytes=physical_block_size_bytes,
          **kwargs)
      if self.source_disk_enabled:
        source_disk_ref = self.GetSourceDiskUri(args, compute_holder)
        disk.sourceDisk = source_disk_ref
      if (support_shared_disk and disk_ref.Collection() == 'compute.regionDisks'
          and args.IsSpecified('multi_writer')):
        raise exceptions.InvalidArgumentException('--multi-writer', (
            '--multi-writer can be used only with --zone flag'))

      if (support_shared_disk and disk_ref.Collection() == 'compute.disks' and
          args.IsSpecified('multi_writer')):
        disk.multiWriter = args.multi_writer

      if guest_os_feature_messages:
        disk.guestOsFeatures = guest_os_feature_messages

      if support_vss_erase and args.IsSpecified('erase_windows_vss_signature'):
        disk.eraseWindowsVssSignature = args.erase_windows_vss_signature

      disk.licenses = self.ParseLicenses(args)

      if disk_ref.Collection() == 'compute.disks':
        request = client.messages.ComputeDisksInsertRequest(
            disk=disk,
            project=disk_ref.project,
            sourceImage=project_to_source_image[disk_ref.project].uri,
            zone=disk_ref.zone)

        request = (client.apitools_client.disks, 'Insert', request)
      elif disk_ref.Collection() == 'compute.regionDisks':
        disk.replicaZones = self.GetReplicaZones(args, compute_holder, disk_ref)
        request = client.messages.ComputeRegionDisksInsertRequest(
            disk=disk,
            project=disk_ref.project,
            sourceImage=project_to_source_image[disk_ref.project].uri,
            region=disk_ref.region)

        request = (client.apitools_client.regionDisks, 'Insert', request)

      requests.append(request)

    return client.MakeRequests(requests)
Exemple #6
0
  def Run(self, args):
    compute_holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
    client = compute_holder.client

    self.show_unformated_message = not (args.IsSpecified('image') or
                                        args.IsSpecified('image_family') or
                                        args.IsSpecified('source_snapshot'))

    disk_refs = self.ValidateAndParseDiskRefs(args, compute_holder)
    from_image = self.GetFromImage(args)
    size_gb = self.GetDiskSizeGb(args, from_image)
    self.WarnAboutScopeDeprecationsAndMaintainance(disk_refs, client)
    project_to_source_image = self.GetProjectToSourceImageDict(
        args, disk_refs, compute_holder, from_image)
    snapshot_uri = self.GetSnapshotUri(args, compute_holder)

    # Those features are only exposed in alpha/beta, it would be nice to have
    # code supporting them only in alpha and beta versions of the command.
    labels = self.GetLabels(args, client)

    allow_rsa_encrypted = self.ReleaseTrack() in [base.ReleaseTrack.ALPHA,
                                                  base.ReleaseTrack.BETA]
    csek_keys = csek_utils.CsekKeyStore.FromArgs(args, allow_rsa_encrypted)

    for project in project_to_source_image:
      source_image_uri = project_to_source_image[project].uri
      project_to_source_image[project].keys = (
          csek_utils.MaybeLookupKeyMessagesByUri(
              csek_keys, compute_holder.resources,
              [source_image_uri, snapshot_uri], client.apitools_client))
    # end of alpha/beta features.

    guest_os_feature_messages = self.ParseGuestOsFeaturesToMessages(
        args, client.messages)

    requests = []
    for disk_ref in disk_refs:
      type_uri = self.GetDiskTypeUri(args, disk_ref, compute_holder)

      # Those features are only exposed in alpha/beta, it would be nice to have
      # code supporting them only in alpha and beta versions of the command.
      # TODO(b/65161039): Stop checking release path in the middle of GA code.
      kwargs = {}
      if csek_keys:
        disk_key_or_none = csek_keys.LookupKey(
            disk_ref, args.require_csek_key_create)
        disk_key_message_or_none = csek_utils.MaybeToMessage(
            disk_key_or_none, client.apitools_client)
        kwargs['diskEncryptionKey'] = disk_key_message_or_none
        kwargs['sourceImageEncryptionKey'] = (
            project_to_source_image[disk_ref.project].keys[0])
        kwargs['sourceSnapshotEncryptionKey'] = (
            project_to_source_image[disk_ref.project].keys[1])
      if labels:
        kwargs['labels'] = labels

      kwargs['diskEncryptionKey'] = kms_utils.MaybeGetKmsKey(
          args, disk_ref.project, client.apitools_client,
          kwargs.get('diskEncryptionKey', None))

      # end of alpha/beta features.

      disk = client.messages.Disk(
          name=disk_ref.Name(),
          description=args.description,
          sizeGb=size_gb,
          sourceSnapshot=snapshot_uri,
          type=type_uri,
          **kwargs)

      if guest_os_feature_messages:
        disk.guestOsFeatures = guest_os_feature_messages

      disk.licenses = self.ParseLicenses(args)

      if disk_ref.Collection() == 'compute.disks':
        request = client.messages.ComputeDisksInsertRequest(
            disk=disk,
            project=disk_ref.project,
            sourceImage=project_to_source_image[disk_ref.project].uri,
            zone=disk_ref.zone)

        request = (client.apitools_client.disks, 'Insert', request)
      elif disk_ref.Collection() == 'compute.regionDisks':
        disk.replicaZones = self.GetReplicaZones(args, compute_holder, disk_ref)
        request = client.messages.ComputeRegionDisksInsertRequest(
            disk=disk,
            project=disk_ref.project,
            sourceImage=project_to_source_image[disk_ref.project].uri,
            region=disk_ref.region)

        request = (client.apitools_client.regionDisks, 'Insert', request)

      requests.append(request)

    return client.MakeRequests(requests)
Exemple #7
0
    def Run(self, args):
        compute_holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
        client = compute_holder.client

        disk_refs = self.ValidateAndParse(args, compute_holder)

        size_gb = utils.BytesToGb(args.size)

        from_image = args.image or args.image_family
        if not size_gb and not args.source_snapshot and not from_image:
            if args.type and 'pd-ssd' in args.type:
                size_gb = constants.DEFAULT_SSD_DISK_SIZE_GB
            else:
                size_gb = constants.DEFAULT_STANDARD_DISK_SIZE_GB

        utils.WarnIfDiskSizeIsTooSmall(size_gb, args.type)

        requests = []

        # Check if the zone is deprecated or has maintenance coming.
        zone_resource_fetcher = zone_utils.ZoneResourceFetcher(client)
        zone_resource_fetcher.WarnForZonalCreation(
            (ref for ref in disk_refs if ref.Collection() == 'compute.disks'))
        # Check if the region is deprecated or has maintenance coming.
        region_resource_fetcher = region_utils.RegionResourceFetcher(client)
        region_resource_fetcher.WarnForRegionalCreation(
            (ref for ref in disk_refs
             if ref.Collection() == 'compute.regionDisks'))

        project_to_source_image = {}

        image_expander = image_utils.ImageExpander(client,
                                                   compute_holder.resources)

        for disk_ref in disk_refs:
            if from_image:
                if disk_ref.project not in project_to_source_image:
                    source_image_uri, _ = image_expander.ExpandImageFlag(
                        user_project=disk_ref.project,
                        image=args.image,
                        image_family=args.image_family,
                        image_project=args.image_project,
                        return_image_resource=False)
                    project_to_source_image[
                        disk_ref.project] = argparse.Namespace()
                    project_to_source_image[
                        disk_ref.project].uri = source_image_uri
            else:
                project_to_source_image[
                    disk_ref.project] = argparse.Namespace()
                project_to_source_image[disk_ref.project].uri = None

        snapshot_ref = disks_flags.SOURCE_SNAPSHOT_ARG.ResolveAsResource(
            args, compute_holder.resources)
        if snapshot_ref:
            snapshot_uri = snapshot_ref.SelfLink()
        else:
            snapshot_uri = None

        # This feature is only exposed in alpha/beta
        allow_rsa_encrypted = self.ReleaseTrack() in [
            base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA
        ]
        csek_keys = csek_utils.CsekKeyStore.FromArgs(args, allow_rsa_encrypted)

        for project in project_to_source_image:
            source_image_uri = project_to_source_image[project].uri
            project_to_source_image[project].keys = (
                csek_utils.MaybeLookupKeyMessagesByUri(
                    csek_keys, compute_holder.resources,
                    [source_image_uri, snapshot_uri], client.apitools_client))

        labels = None
        args_labels = getattr(args, 'labels', None)
        if args_labels:
            labels = client.messages.Disk.LabelsValue(additionalProperties=[
                client.messages.Disk.LabelsValue.AdditionalProperty(
                    key=key, value=value)
                for key, value in sorted(args.labels.iteritems())
            ])

        for disk_ref in disk_refs:
            if args.type:
                if disk_ref.Collection() == 'compute.disks':
                    type_ref = compute_holder.resources.Parse(
                        args.type,
                        collection='compute.diskTypes',
                        params={
                            'project': disk_ref.project,
                            'zone': disk_ref.zone
                        })
                elif disk_ref.Collection() == 'compute.regionDisks':
                    type_ref = compute_holder.resources.Parse(
                        args.type,
                        collection='compute.regionDiskTypes',
                        params={
                            'project': disk_ref.project,
                            'region': disk_ref.region
                        })
                type_uri = type_ref.SelfLink()
            else:
                type_uri = None

            if csek_keys:
                disk_key_or_none = csek_keys.LookupKey(
                    disk_ref, args.require_csek_key_create)
                disk_key_message_or_none = csek_utils.MaybeToMessage(
                    disk_key_or_none, client.apitools_client)
                kwargs = {
                    'diskEncryptionKey':
                    disk_key_message_or_none,
                    'sourceImageEncryptionKey':
                    project_to_source_image[disk_ref.project].keys[0],
                    'sourceSnapshotEncryptionKey':
                    project_to_source_image[disk_ref.project].keys[1]
                }
            else:
                kwargs = {}

            if disk_ref.Collection() == 'compute.disks':
                request = client.messages.ComputeDisksInsertRequest(
                    disk=client.messages.Disk(name=disk_ref.Name(),
                                              description=args.description,
                                              sizeGb=size_gb,
                                              sourceSnapshot=snapshot_uri,
                                              type=type_uri,
                                              **kwargs),
                    project=disk_ref.project,
                    sourceImage=project_to_source_image[disk_ref.project].uri,
                    zone=disk_ref.zone)
                if labels:
                    request.disk.labels = labels
                request = (client.apitools_client.disks, 'Insert', request)
            elif disk_ref.Collection() == 'compute.regionDisks':

                def SelfLink(zone, disk_ref):
                    return compute_holder.resources.Parse(
                        zone,
                        collection='compute.zones',
                        params={
                            'project': disk_ref.project
                        }).SelfLink()

                zones = [
                    SelfLink(zone, disk_ref) for zone in args.replica_zones
                ]
                request = client.messages.ComputeRegionDisksInsertRequest(
                    disk=client.messages.Disk(name=disk_ref.Name(),
                                              description=args.description,
                                              sizeGb=size_gb,
                                              sourceSnapshot=snapshot_uri,
                                              type=type_uri,
                                              replicaZones=zones,
                                              **kwargs),
                    project=disk_ref.project,
                    sourceImage=project_to_source_image[disk_ref.project].uri,
                    region=disk_ref.region)
                if labels:
                    request.disk.labels = labels

                request = (client.apitools_client.regionDisks, 'Insert',
                           request)

            requests.append(request)

        return client.MakeRequests(requests)
Exemple #8
0
    def CreateRequests(self, args):
        """Returns a list of requests necessary for adding disks."""
        size_gb = utils.BytesToGb(args.size)

        from_image = args.image or args.image_family
        if not size_gb and not args.source_snapshot and not from_image:
            if args.type and 'pd-ssd' in args.type:
                size_gb = constants.DEFAULT_SSD_DISK_SIZE_GB
            else:
                size_gb = constants.DEFAULT_STANDARD_DISK_SIZE_GB

        utils.WarnIfDiskSizeIsTooSmall(size_gb, args.type)

        requests = []
        disk_refs = disks_flags.DISKS_ARG.ResolveAsResource(
            args,
            self.resources,
            scope_lister=flags.GetDefaultScopeLister(self.compute_client,
                                                     self.project))

        # Check if the zone is deprecated or has maintenance coming.
        self.WarnForZonalCreation(disk_refs)

        if from_image:
            source_image_uri, _ = self.ExpandImageFlag(
                args, return_image_resource=False)
        else:
            source_image_uri = None

        snapshot_ref = disks_flags.SOURCE_SNAPSHOT_ARG.ResolveAsResource(
            args, self.resources)
        if snapshot_ref:
            snapshot_uri = snapshot_ref.SelfLink()
        else:
            snapshot_uri = None

        # This feature is only exposed in alpha/beta
        allow_rsa_encrypted = self.ReleaseTrack() in [
            base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA
        ]
        csek_keys = csek_utils.CsekKeyStore.FromArgs(args, allow_rsa_encrypted)

        image_key_message_or_none, snapshot_key_message_or_none = (
            csek_utils.MaybeLookupKeyMessagesByUri(
                csek_keys, self.resources, [source_image_uri, snapshot_uri],
                self.compute))

        for disk_ref in disk_refs:
            if args.type:
                type_ref = self.resources.Parse(args.type,
                                                collection='compute.diskTypes',
                                                params={'zone': disk_ref.zone})
                type_uri = type_ref.SelfLink()
            else:
                type_uri = None

            if csek_keys:
                disk_key_or_none = csek_keys.LookupKey(
                    disk_ref, args.require_csek_key_create)
                disk_key_message_or_none = csek_utils.MaybeToMessage(
                    disk_key_or_none, self.compute)
                kwargs = {
                    'diskEncryptionKey': disk_key_message_or_none,
                    'sourceImageEncryptionKey': image_key_message_or_none,
                    'sourceSnapshotEncryptionKey': snapshot_key_message_or_none
                }
            else:
                kwargs = {}

            request = self.messages.ComputeDisksInsertRequest(
                disk=self.messages.Disk(name=disk_ref.Name(),
                                        description=args.description,
                                        sizeGb=size_gb,
                                        sourceSnapshot=snapshot_uri,
                                        type=type_uri,
                                        **kwargs),
                project=self.project,
                sourceImage=source_image_uri,
                zone=disk_ref.zone)
            requests.append(request)

        return requests
def CreatePersistentCreateDiskMessages(compute_client,
                                       resources,
                                       csek_keys,
                                       create_disks,
                                       project,
                                       location,
                                       scope,
                                       holder,
                                       enable_kms=False,
                                       enable_snapshots=False,
                                       container_mount_disk=None,
                                       enable_source_snapshot_csek=False,
                                       enable_image_csek=False,
                                       support_replica_zones=False,
                                       use_disk_type_uri=True,
                                       support_multi_writer=False,
                                       support_image_family_scope=False):
  """Returns a list of AttachedDisk messages for newly creating disks.

  Args:
    compute_client: creates resources,
    resources: parser of resources,
    csek_keys: customer suplied encryption keys,
    create_disks: disk objects - contains following properties * name - the name
      of disk, * description - an optional description for the disk, * mode -
      'rw' (R/W), 'ro' (R/O) access mode, * disk-size - the size of the disk, *
      disk-type - the type of the disk (HDD or SSD), * image - the name of the
      image to initialize from, * image-csek-required - the name of the CSK
      protected image, * image-family - the image family name, * image-project -
      the project name that has the image, * auto-delete - whether disks is
      deleted when VM is deleted, * device-name - device name on VM, *
      source-snapshot - the snapshot to initialize from, *
      source-snapshot-csek-required - CSK protected snapshot, *
      disk-resource-policy - resource policies applied to disk. *
      enable_source_snapshot_csek - CSK file for snapshot, * enable_image_csek -
      CSK file for image
    project: Project of instance that will own the new disks.
    location: Location of the instance that will own the new disks.
    scope: Location type of the instance that will own the new disks.
    holder: Convenience class to hold lazy initialized client and resources.
    enable_kms: True if KMS keys are supported for the disk.
    enable_snapshots: True if snapshot initialization is supported for the disk.
    container_mount_disk: list of disks to be mounted to container, if any.
    enable_source_snapshot_csek: True if snapshot CSK files are enabled
    enable_image_csek: True if image CSK files are enabled
    support_replica_zones: True if we allow creation of regional disks
    use_disk_type_uri: True to use disk type URI, False if naked type.
    support_multi_writer: True if we allow multiple instances to write to disk.
    support_image_family_scope: True if the zonal image views are supported.

  Returns:
    list of API messages for attached disks
  """
  disks_messages = []

  messages = compute_client.messages
  compute = compute_client.apitools_client
  for disk in create_disks or []:
    name = disk.get('name')

    # Resolves the mode.
    mode_value = disk.get('mode', 'rw')
    if mode_value == 'rw':
      mode = messages.AttachedDisk.ModeValueValuesEnum.READ_WRITE
    else:
      mode = messages.AttachedDisk.ModeValueValuesEnum.READ_ONLY

    auto_delete = disk.get('auto-delete', True)
    disk_size_gb = utils.BytesToGb(disk.get('size'))
    disk_type = disk.get('type')
    if disk_type:
      if use_disk_type_uri:
        disk_type_ref = instance_utils.ParseDiskType(resources, disk_type,
                                                     project, location, scope)
        disk_type = disk_type_ref.SelfLink()
    else:
      disk_type = None

    img = disk.get('image')
    img_family = disk.get('image-family')
    img_project = disk.get('image-project')
    image_family_scope = disk.get('image_family_scope')

    image_uri = None
    if img or img_family:
      image_expander = image_utils.ImageExpander(compute_client, resources)
      image_uri, _ = image_expander.ExpandImageFlag(
          user_project=project,
          image=img,
          image_family=img_family,
          image_project=img_project,
          return_image_resource=False,
          image_family_scope=image_family_scope,
          support_image_family_scope=support_image_family_scope)

    image_key = None
    disk_key = None
    if csek_keys:
      image_key = csek_utils.MaybeLookupKeyMessagesByUri(
          csek_keys, resources, [image_uri], compute)
      if name:
        disk_ref = resources.Parse(
            name, collection='compute.disks', params={'zone': location})
        disk_key = csek_utils.MaybeLookupKeyMessage(csek_keys, disk_ref,
                                                    compute)

    if enable_kms:
      disk_key = kms_utils.MaybeGetKmsKeyFromDict(disk, messages, disk_key)

    initialize_params = messages.AttachedDiskInitializeParams(
        diskName=name,
        description=disk.get('description'),
        sourceImage=image_uri,
        diskSizeGb=disk_size_gb,
        diskType=disk_type,
        sourceImageEncryptionKey=image_key)

    replica_zones = disk.get('replica-zones')
    if support_replica_zones and replica_zones:
      normalized_zones = []
      for zone in replica_zones:
        zone_ref = holder.resources.Parse(
            zone, collection='compute.zones', params={'project': project})
        normalized_zones.append(zone_ref.SelfLink())
      initialize_params.replicaZones = normalized_zones

    if enable_snapshots:
      snapshot_name = disk.get('source-snapshot')
      attached_snapshot_uri = instance_utils.ResolveSnapshotURI(
          snapshot=snapshot_name,
          user_project=project,
          resource_parser=resources)
      if attached_snapshot_uri:
        initialize_params.sourceImage = None
        initialize_params.sourceSnapshot = attached_snapshot_uri

    policies = disk.get('disk-resource-policy')
    if policies:
      initialize_params.resourcePolicies = policies

    if enable_image_csek:
      image_key_file = disk.get('image_csek')
      if image_key_file:
        initialize_params.imageKeyFile = image_key_file

    if enable_source_snapshot_csek:
      snapshot_key_file = disk.get('source_snapshot_csek')
      if snapshot_key_file:
        initialize_params.snapshotKeyFile = snapshot_key_file
    boot = disk.get('boot', False)

    multi_writer = disk.get('multi-writer')
    if support_multi_writer and multi_writer:
      initialize_params.multiWriter = True

    provisioned_iops = disk.get('provisioned-iops')
    if provisioned_iops:
      initialize_params.provisionedIops = provisioned_iops

    device_name = instance_utils.GetDiskDeviceName(disk, name,
                                                   container_mount_disk)
    create_disk = messages.AttachedDisk(
        autoDelete=auto_delete,
        boot=boot,
        deviceName=device_name,
        initializeParams=initialize_params,
        mode=mode,
        type=messages.AttachedDisk.TypeValueValuesEnum.PERSISTENT,
        diskEncryptionKey=disk_key)
    disks_messages.append(create_disk)

  return disks_messages