github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/gce/google/conn_disks.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package google
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/juju/errors"
    11  	"google.golang.org/api/compute/v1"
    12  )
    13  
    14  // CreateDisks implements storage section of gceConnection.
    15  func (gce *Connection) CreateDisks(zone string, disks []DiskSpec) ([]*Disk, error) {
    16  	results := make([]*Disk, len(disks))
    17  	for i, disk := range disks {
    18  		d, err := disk.newDetached()
    19  		if err != nil {
    20  			return []*Disk{}, errors.Annotate(err, "cannot create disk spec")
    21  		}
    22  		if err := gce.createDisk(zone, d); err != nil {
    23  			return []*Disk{}, errors.Annotatef(err, "cannot create disk %q", disk.Name)
    24  		}
    25  		results[i] = NewDisk(d)
    26  	}
    27  	return results, nil
    28  }
    29  
    30  func (gce *Connection) createDisk(zone string, disk *compute.Disk) error {
    31  	return gce.raw.CreateDisk(gce.projectID, zone, disk)
    32  }
    33  
    34  // Disks implements storage section of gceConnection.
    35  func (gce *Connection) Disks() ([]*Disk, error) {
    36  	computeDisks, err := gce.raw.ListDisks(gce.projectID)
    37  	if err != nil {
    38  		return nil, errors.Annotate(err, "cannot list disks")
    39  	}
    40  	disks := make([]*Disk, len(computeDisks))
    41  	for i, disk := range computeDisks {
    42  		disks[i] = NewDisk(disk)
    43  	}
    44  	return disks, nil
    45  }
    46  
    47  // RemoveDisk implements storage section of gceConnection.
    48  // TODO(perrito666) handle non existing disk, perhaps catch 404.
    49  func (gce *Connection) RemoveDisk(zone, name string) error {
    50  	return gce.raw.RemoveDisk(gce.projectID, zone, name)
    51  }
    52  
    53  // Disk implements storage section of gceConnection.
    54  func (gce *Connection) Disk(zone, name string) (*Disk, error) {
    55  	d, err := gce.raw.GetDisk(gce.projectID, zone, name)
    56  	if err != nil {
    57  		return nil, errors.Annotatef(err, "cannot get disk %q in zone %q", name, zone)
    58  	}
    59  	return NewDisk(d), nil
    60  }
    61  
    62  // SetDiskLabels implements storage section of gceConnection.
    63  func (gce *Connection) SetDiskLabels(zone, name, labelFingerprint string, labels map[string]string) error {
    64  	err := gce.raw.SetDiskLabels(gce.projectID, zone, name, labelFingerprint, labels)
    65  	return errors.Annotatef(err, "cannot update labels for disk %q in zone %q", name, zone)
    66  }
    67  
    68  // deviceName will generate a device name from the passed
    69  // <zone> and <diskId>, the device name must not be confused
    70  // with the volume name, as it is used mainly to name the
    71  // disk when attached to a linux OS.
    72  func deviceName(zone string, diskId uint64) string {
    73  	return fmt.Sprintf("%s-%d", zone, diskId)
    74  }
    75  
    76  // AttachDisk implements storage section of gceConnection.
    77  func (gce *Connection) AttachDisk(zone, volumeName, instanceId string, mode DiskMode) (*AttachedDisk, error) {
    78  	disk, err := gce.raw.GetDisk(gce.projectID, zone, volumeName)
    79  	if err != nil {
    80  		return nil, errors.Annotatef(err, "cannot obtain disk %q to attach it", volumeName)
    81  	}
    82  	attachedDisk := &compute.AttachedDisk{
    83  		// Specifies a unique device name of your choice that
    84  		// is reflected into the /dev/disk/by-id/google-*
    85  		DeviceName: deviceName(zone, disk.Id),
    86  		Source:     disk.SelfLink,
    87  		Mode:       string(mode),
    88  	}
    89  	err = gce.raw.AttachDisk(gce.projectID, zone, instanceId, attachedDisk)
    90  	if err != nil {
    91  		return nil, errors.Annotate(err, "cannot attach disk")
    92  	}
    93  	return &AttachedDisk{
    94  		VolumeName: volumeName,
    95  		DeviceName: attachedDisk.DeviceName,
    96  		Mode:       mode,
    97  	}, nil
    98  }
    99  
   100  // DetachDisk implements storage section of gceConnection.
   101  // disk existence is checked but not instance nor is attachment.
   102  func (gce *Connection) DetachDisk(zone, instanceId, volumeName string) error {
   103  	disk, err := gce.raw.GetDisk(gce.projectID, zone, volumeName)
   104  	if err != nil {
   105  		return errors.Annotatef(err, "cannot obtain disk %q to detach it", volumeName)
   106  	}
   107  	dn := deviceName(zone, disk.Id)
   108  	err = gce.raw.DetachDisk(gce.projectID, zone, instanceId, dn)
   109  	if err != nil {
   110  		return errors.Annotatef(err, "cannot detach %q from %q", dn, instanceId)
   111  	}
   112  	return nil
   113  }
   114  
   115  // sourceToVolumeName will return the disk Name part of a
   116  // source URL for a compute disk, compute is a bit inconsistent
   117  // on its handling of disk resources, when used in requests it will
   118  // take the disk.Name but when used as a parameter it will take
   119  // the source url.
   120  // The source url (short) format is:
   121  // /projects/project/zones/zone/disks/disk
   122  // the relevant part is disk.
   123  func sourceToVolumeName(source string) string {
   124  	if source == "" {
   125  		return ""
   126  	}
   127  	parts := strings.Split(source, "/")
   128  	if len(parts) == 1 {
   129  		return source
   130  	}
   131  	lastItem := len(parts) - 1
   132  	return parts[lastItem]
   133  }
   134  
   135  // InstanceDisks implements storage section of gceConnection.
   136  func (gce *Connection) InstanceDisks(zone, instanceId string) ([]*AttachedDisk, error) {
   137  	disks, err := gce.raw.InstanceDisks(gce.projectID, zone, instanceId)
   138  	if err != nil {
   139  		return nil, errors.Annotatef(err, "cannot get disks from instance")
   140  	}
   141  	att := make([]*AttachedDisk, len(disks))
   142  	for i, disk := range disks {
   143  		att[i] = &AttachedDisk{
   144  			VolumeName: sourceToVolumeName(disk.Source),
   145  			DeviceName: disk.DeviceName,
   146  			Mode:       DiskMode(disk.Mode),
   147  		}
   148  	}
   149  	return att, nil
   150  }