'Attach a volume to a node.
If volume is None, an ex_source URL must be provided.
:param  node: The node to attach the volume to
:type   node: :class:`Node` or ``None``
:param  volume: The volume to attach.
:type   volume: :class:`StorageVolume` or ``None``
:keyword  device: The device name to attach the volume as. Defaults to
volume name.
:type     device: ``str``
:keyword  ex_mode: Either \'READ_WRITE\' or \'READ_ONLY\'
:type     ex_mode: ``str``
:keyword  ex_boot: If true, disk will be attached as a boot disk
:type     ex_boot: ``bool``
:keyword  ex_type: Specify either \'PERSISTENT\' (default) or \'SCRATCH\'.
:type     ex_type: ``str``
:keyword  ex_source: URL (full or partial) of disk source. Must be
present if not using an existing StorageVolume.
:type     ex_source: ``str`` or ``None``
:keyword  ex_auto_delete: If set, the disk will be auto-deleted
if the parent node/instance is deleted.
:type     ex_auto_delete: ``bool`` or ``None``
:keyword  ex_initialize_params: Allow user to pass in full JSON
struct of `initializeParams` as
documented in GCE\'s API.
:type     ex_initialize_params: ``dict`` or ``None``
:keyword  ex_licenses: List of strings representing licenses
associated with the volume/disk.
:type     ex_licenses: ``list`` of ``str``
:keyword  ex_interface: User can specify either \'SCSI\' (default) or
\'NVME\'.
:type     ex_interface: ``str`` or ``None``
:return:  True if successful
:rtype:   ``bool``'

def attach_volume(self, node, volume, device=None, ex_mode=None, ex_boot=False, ex_type=None, ex_source=None, ex_auto_delete=None, ex_initialize_params=None, ex_licenses=None, ex_interface=None):

    if ((volume is None) and (ex_source is None)):
        raise ValueError('Must    supply    either    a    StorageVolume    or    set    `ex_source`    URL    for    an    existing    disk.')
    if ((volume is None) and (device is None)):
        raise ValueError('Must    supply    either    a    StorageVolume    or    set    `device`    name.')
    volume_data = {}
    if ex_source:
        volume_data['source'] = ex_source
    if ex_initialize_params:
        volume_data['initialzeParams'] = ex_initialize_params
    if ex_licenses:
        volume_data['licenses'] = ex_licenses
    if ex_interface:
        volume_data['interface'] = ex_interface
    if ex_type:
        volume_data['type'] = ex_type
    if ex_auto_delete:
        volume_data['autoDelete'] = ex_auto_delete
    volume_data['source'] = (ex_source or volume.extra['selfLink'])
    volume_data['mode'] = (ex_mode or 'READ_WRITE')
    if device:
        volume_data['deviceName'] = device
    else:
        volume_data['deviceName'] = volume.name
    volume_data['boot'] = ex_boot
    request = ('/zones/%s/instances/%s/attachDisk' % (node.extra['zone'].name, node.name))
    self.connection.async_request(request, method='POST', data=volume_data)
    return True
