github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/provider/gce/google/disk.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package google
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"google.golang.org/api/compute/v1"
     9  )
    10  
    11  // The different types of disk persistence supported by GCE.
    12  const (
    13  	diskPersistenceTypeScratch    = "SCRATCH"
    14  	diskPersistenceTypePersistent = "PERSISTENT"
    15  )
    16  
    17  type DiskType string
    18  
    19  // The types of disk supported by GCE
    20  const (
    21  	// persistent
    22  	DiskPersistentStandard DiskType = "pd-standard"
    23  	DiskPersistentSSD      DiskType = "pd-ssd"
    24  	// scratch
    25  	DiskLocalSSD DiskType = "local-ssd"
    26  )
    27  
    28  type DiskMode string
    29  
    30  // The different disk modes supported by GCE.
    31  const (
    32  	ModeRW DiskMode = "READ_WRITE"
    33  	ModeRO DiskMode = "READ_ONLY"
    34  )
    35  
    36  type DiskStatus string
    37  
    38  const (
    39  	StatusCreating  DiskStatus = "CREATING"
    40  	StatusFailed    DiskStatus = "FAILED"
    41  	StatusReady     DiskStatus = "READY"
    42  	StatusRestoring DiskStatus = "RESTORING"
    43  )
    44  
    45  // MinDiskSizeGB is the minimum/default size (in megabytes) for
    46  // GCE disks.
    47  //
    48  // Note: GCE does not currently have an official minimum disk size.
    49  // However, in testing we found the minimum size to be 10 GB due to
    50  // the image size. See gceapi messsage.
    51  //
    52  // gceapi: Requested disk size cannot be smaller than the image size (10 GB)
    53  const MinDiskSizeGB uint64 = 10
    54  
    55  // gibToMib converts gibibytes to mebibytes.
    56  func gibToMib(g int64) uint64 {
    57  	return uint64(g) * 1024
    58  }
    59  
    60  // DiskSpec holds all the data needed to request a new disk on GCE.
    61  // Some fields are used only for attached disks (i.e. in association
    62  // with instances).
    63  type DiskSpec struct {
    64  	// SizeHintGB is the requested disk size in Gigabytes. It must be
    65  	// greater than 0.
    66  	SizeHintGB uint64
    67  	// ImageURL is the location of the image to which the disk should
    68  	// be initialized.
    69  	ImageURL string
    70  	// Boot indicates that this is a boot disk. An instance may only
    71  	// have one boot disk. (attached only)
    72  	Boot bool
    73  	// Scratch indicates that the disk should be a "scratch" disk
    74  	// instead of a "persistent" disk (the default).
    75  	Scratch bool
    76  	// Readonly indicates that the disk should not support writes.
    77  	Readonly bool
    78  	// AutoDelete indicates that the attached disk should be removed
    79  	// when the instance to which it is attached is removed.
    80  	AutoDelete bool
    81  	// PersistenDiskType is exclusive to persistent disks and indicates which of the
    82  	// persistent types available this disk should be.
    83  	PersistentDiskType DiskType
    84  	// Name: Name of the resource; provided by the client when the resource
    85  	// is created. The name must be 1-63 characters long, and comply with
    86  	// RFC1035. Specifically, the name must be 1-63 characters long and
    87  	// match the regular expression [a-z]([-a-z0-9]*[a-z0-9])? which means
    88  	// the first character must be a lowercase letter, and all following
    89  	// characters must be a dash, lowercase letter, or digit, except the
    90  	// last character, which cannot be a dash.
    91  	Name string
    92  }
    93  
    94  // TooSmall checks the spec's size hint and indicates whether or not
    95  // it is smaller than the minimum disk size.
    96  func (ds *DiskSpec) TooSmall() bool {
    97  	return ds.SizeHintGB < MinDiskSizeGB
    98  }
    99  
   100  // SizeGB returns the disk size to use for a new disk. The size hint
   101  // is returned if it isn't too small (otherwise the min size is
   102  // returned).
   103  func (ds *DiskSpec) SizeGB() uint64 {
   104  	size := ds.SizeHintGB
   105  	if ds.TooSmall() {
   106  		size = MinDiskSizeGB
   107  	}
   108  	return size
   109  }
   110  
   111  // newAttached builds a compute.AttachedDisk using the information in
   112  // the disk spec and returns it.
   113  //
   114  // Note: Not all AttachedDisk fields are set.
   115  func (ds *DiskSpec) newAttached() *compute.AttachedDisk {
   116  	// TODO(ericsnow) Fail if SizeHintGB is 0?
   117  	diskType := diskPersistenceTypePersistent
   118  	if ds.Scratch {
   119  		diskType = diskPersistenceTypeScratch
   120  	}
   121  	mode := ModeRW
   122  	if ds.Readonly {
   123  		mode = ModeRO
   124  	}
   125  
   126  	disk := compute.AttachedDisk{
   127  		Type:       diskType,
   128  		Boot:       ds.Boot,
   129  		Mode:       string(mode),
   130  		AutoDelete: ds.AutoDelete,
   131  		InitializeParams: &compute.AttachedDiskInitializeParams{
   132  			// DiskName (defaults to instance name)
   133  			DiskSizeGb: int64(ds.SizeGB()),
   134  			// DiskType (defaults to pd-standard, pd-ssd, local-ssd)
   135  			SourceImage: ds.ImageURL,
   136  		},
   137  		// Interface (defaults to SCSI)
   138  		// DeviceName (GCE sets this, persistent disk only)
   139  	}
   140  	return &disk
   141  }
   142  
   143  // newDetached creates a new detached persistent disk representation,
   144  // this DOES NOT create a disk in gce, just creates the spec.
   145  // reference in https://cloud.google.com/compute/docs/reference/latest/disks#resource
   146  func (ds *DiskSpec) newDetached() (*compute.Disk, error) {
   147  	if ds.Scratch {
   148  		return nil, errors.New("cannot create scratch volumes detached")
   149  	}
   150  	if ds.PersistentDiskType == DiskLocalSSD {
   151  		return nil, errors.New("cannot create local ssd disks detached")
   152  	}
   153  	return &compute.Disk{
   154  		Name:        ds.Name,
   155  		SizeGb:      int64(ds.SizeGB()),
   156  		SourceImage: ds.ImageURL,
   157  		Type:        string(ds.PersistentDiskType),
   158  	}, nil
   159  }
   160  
   161  // AttachedDisk represents a disk that is attached to an instance.
   162  type AttachedDisk struct {
   163  	// VolumeName is the name of the volume that is attached, this is unique
   164  	// and used by gce as an identifier.
   165  	VolumeName string
   166  	// DeviceName is the name of the device in the instance, typycally
   167  	// is reflected into the /dev/disk/by-id/google-*
   168  	DeviceName string
   169  	// Mode is the read/write mode of the disk.
   170  	Mode DiskMode
   171  }
   172  
   173  // Disk represents a gce disk.
   174  type Disk struct {
   175  	// Id is an unique identifier google adds to the disk, it usually
   176  	// is not used in the API.
   177  	Id uint64
   178  	// Name is a unique identifier string for each disk.
   179  	Name string
   180  	// Size is the size in mbit.
   181  	Size uint64
   182  	// Type is one of the available disk types supported by
   183  	// gce (persistent or ephemeral).
   184  	Type DiskType
   185  	// Zone indicates the zone in which the disk lives.
   186  	Zone string
   187  	// DiskStatus holds the status of he aforementioned disk.
   188  	Status DiskStatus
   189  }
   190  
   191  func NewDisk(cd *compute.Disk) *Disk {
   192  	d := &Disk{
   193  		Id:     cd.Id,
   194  		Name:   cd.Name,
   195  		Size:   gibToMib(cd.SizeGb),
   196  		Type:   DiskType(cd.Type),
   197  		Zone:   cd.Zone,
   198  		Status: DiskStatus(cd.Status),
   199  	}
   200  	return d
   201  }