github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/state/blockdevices.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"reflect"
     8  
     9  	"github.com/juju/errors"
    10  	jujutxn "github.com/juju/txn"
    11  	"gopkg.in/juju/names.v2"
    12  	"gopkg.in/mgo.v2"
    13  	"gopkg.in/mgo.v2/bson"
    14  	"gopkg.in/mgo.v2/txn"
    15  )
    16  
    17  // BlockDevice represents the state of a block device in the model.
    18  type BlockDevice interface {
    19  	// Machine returns the ID of the machine the block device is attached to.
    20  	Machine() string
    21  
    22  	// Info returns the block device's BlockDeviceInfo.
    23  	Info() BlockDeviceInfo
    24  }
    25  
    26  // blockDevicesDoc records information about a machine's block devices.
    27  type blockDevicesDoc struct {
    28  	DocID        string            `bson:"_id"`
    29  	ModelUUID    string            `bson:"model-uuid"`
    30  	Machine      string            `bson:"machineid"`
    31  	BlockDevices []BlockDeviceInfo `bson:"blockdevices"`
    32  }
    33  
    34  // BlockDeviceInfo describes information about a block device.
    35  type BlockDeviceInfo struct {
    36  	DeviceName     string   `bson:"devicename"`
    37  	DeviceLinks    []string `bson:"devicelinks,omitempty"`
    38  	Label          string   `bson:"label,omitempty"`
    39  	UUID           string   `bson:"uuid,omitempty"`
    40  	HardwareId     string   `bson:"hardwareid,omitempty"`
    41  	BusAddress     string   `bson:"busaddress,omitempty"`
    42  	Size           uint64   `bson:"size"`
    43  	FilesystemType string   `bson:"fstype,omitempty"`
    44  	InUse          bool     `bson:"inuse"`
    45  	MountPoint     string   `bson:"mountpoint,omitempty"`
    46  }
    47  
    48  // WatchBlockDevices returns a new NotifyWatcher watching for
    49  // changes to block devices associated with the specified machine.
    50  func (st *State) WatchBlockDevices(machine names.MachineTag) NotifyWatcher {
    51  	return newBlockDevicesWatcher(st, machine.Id())
    52  }
    53  
    54  // BlockDevices returns the BlockDeviceInfo for the specified machine.
    55  func (st *State) BlockDevices(machine names.MachineTag) ([]BlockDeviceInfo, error) {
    56  	return getBlockDevices(st, machine.Id())
    57  }
    58  
    59  func getBlockDevices(st modelBackend, machineId string) ([]BlockDeviceInfo, error) {
    60  	coll, cleanup := st.getCollection(blockDevicesC)
    61  	defer cleanup()
    62  
    63  	var d blockDevicesDoc
    64  	err := coll.FindId(machineId).One(&d)
    65  	if err == mgo.ErrNotFound {
    66  		return nil, errors.NotFoundf("block devices not found for machine %q", machineId)
    67  	} else if err != nil {
    68  		return nil, errors.Annotate(err, "cannot get block device details")
    69  	}
    70  	return d.BlockDevices, nil
    71  }
    72  
    73  // setMachineBlockDevices updates the blockdevices collection with the
    74  // currently attached block devices. Previously recorded block devices
    75  // not in the list will be removed.
    76  func setMachineBlockDevices(st *State, machineId string, newInfo []BlockDeviceInfo) error {
    77  	buildTxn := func(attempt int) ([]txn.Op, error) {
    78  		oldInfo, err := getBlockDevices(st, machineId)
    79  		if err != nil {
    80  			return nil, errors.Trace(err)
    81  		}
    82  		if !blockDevicesChanged(oldInfo, newInfo) {
    83  			return nil, jujutxn.ErrNoOperations
    84  		}
    85  		ops := []txn.Op{{
    86  			C:      machinesC,
    87  			Id:     machineId,
    88  			Assert: isAliveDoc,
    89  		}, {
    90  			C:      blockDevicesC,
    91  			Id:     machineId,
    92  			Assert: txn.DocExists,
    93  			Update: bson.D{{"$set", bson.D{{"blockdevices", newInfo}}}},
    94  		}}
    95  		return ops, nil
    96  	}
    97  	return st.run(buildTxn)
    98  }
    99  
   100  func createMachineBlockDevicesOp(machineId string) txn.Op {
   101  	return txn.Op{
   102  		C:      blockDevicesC,
   103  		Id:     machineId,
   104  		Insert: &blockDevicesDoc{Machine: machineId},
   105  		Assert: txn.DocMissing,
   106  	}
   107  }
   108  
   109  func removeMachineBlockDevicesOp(machineId string) txn.Op {
   110  	return txn.Op{
   111  		C:      blockDevicesC,
   112  		Id:     machineId,
   113  		Remove: true,
   114  	}
   115  }
   116  
   117  func blockDevicesChanged(oldDevices, newDevices []BlockDeviceInfo) bool {
   118  	if len(oldDevices) != len(newDevices) {
   119  		return true
   120  	}
   121  	for _, o := range oldDevices {
   122  		var found bool
   123  		for _, n := range newDevices {
   124  			if reflect.DeepEqual(o, n) {
   125  				found = true
   126  				break
   127  			}
   128  		}
   129  		if !found {
   130  			return true
   131  		}
   132  	}
   133  	return false
   134  }