github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/diskmanager/diskmanager.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package diskmanager
     5  
     6  import (
     7  	"gopkg.in/juju/names.v2"
     8  
     9  	"github.com/juju/juju/apiserver/common"
    10  	"github.com/juju/juju/apiserver/facade"
    11  	"github.com/juju/juju/apiserver/params"
    12  	"github.com/juju/juju/state"
    13  	"github.com/juju/juju/storage"
    14  )
    15  
    16  func init() {
    17  	common.RegisterStandardFacade("DiskManager", 2, NewDiskManagerAPI)
    18  }
    19  
    20  // DiskManagerAPI provides access to the DiskManager API facade.
    21  type DiskManagerAPI struct {
    22  	st          stateInterface
    23  	authorizer  facade.Authorizer
    24  	getAuthFunc common.GetAuthFunc
    25  }
    26  
    27  var getState = func(st *state.State) stateInterface {
    28  	return stateShim{st}
    29  }
    30  
    31  // NewDiskManagerAPI creates a new server-side DiskManager API facade.
    32  func NewDiskManagerAPI(
    33  	st *state.State,
    34  	resources facade.Resources,
    35  	authorizer facade.Authorizer,
    36  ) (*DiskManagerAPI, error) {
    37  
    38  	if !authorizer.AuthMachineAgent() {
    39  		return nil, common.ErrPerm
    40  	}
    41  
    42  	authEntityTag := authorizer.GetAuthTag()
    43  	getAuthFunc := func() (common.AuthFunc, error) {
    44  		return func(tag names.Tag) bool {
    45  			// A machine agent can always access its own machine.
    46  			return tag == authEntityTag
    47  		}, nil
    48  	}
    49  
    50  	return &DiskManagerAPI{
    51  		st:          getState(st),
    52  		authorizer:  authorizer,
    53  		getAuthFunc: getAuthFunc,
    54  	}, nil
    55  }
    56  
    57  func (d *DiskManagerAPI) SetMachineBlockDevices(args params.SetMachineBlockDevices) (params.ErrorResults, error) {
    58  	result := params.ErrorResults{
    59  		Results: make([]params.ErrorResult, len(args.MachineBlockDevices)),
    60  	}
    61  	canAccess, err := d.getAuthFunc()
    62  	if err != nil {
    63  		return result, err
    64  	}
    65  	for i, arg := range args.MachineBlockDevices {
    66  		tag, err := names.ParseMachineTag(arg.Machine)
    67  		if err != nil {
    68  			result.Results[i].Error = common.ServerError(common.ErrPerm)
    69  			continue
    70  		}
    71  		if !canAccess(tag) {
    72  			err = common.ErrPerm
    73  		} else {
    74  			// TODO(axw) create volumes for block devices without matching
    75  			// volumes, if and only if the block device has a serial. Under
    76  			// the assumption of unique (to a machine) serial IDs, this
    77  			// gives us a guaranteed *persistently* unique way of identifying
    78  			// the volume.
    79  			//
    80  			// NOTE: we must predicate the above on there being no unprovisioned
    81  			// volume attachments for the machine, otherwise we would have
    82  			// a race between the volume attachment info being recorded and
    83  			// the diskmanager publishing block devices and erroneously creating
    84  			// volumes.
    85  			err = d.st.SetMachineBlockDevices(tag.Id(), stateBlockDeviceInfo(arg.BlockDevices))
    86  			// TODO(axw) set volume/filesystem attachment info.
    87  		}
    88  		result.Results[i].Error = common.ServerError(err)
    89  	}
    90  	return result, nil
    91  }
    92  
    93  func stateBlockDeviceInfo(devices []storage.BlockDevice) []state.BlockDeviceInfo {
    94  	result := make([]state.BlockDeviceInfo, len(devices))
    95  	for i, dev := range devices {
    96  		result[i] = state.BlockDeviceInfo{
    97  			dev.DeviceName,
    98  			dev.DeviceLinks,
    99  			dev.Label,
   100  			dev.UUID,
   101  			dev.HardwareId,
   102  			dev.BusAddress,
   103  			dev.Size,
   104  			dev.FilesystemType,
   105  			dev.InUse,
   106  			dev.MountPoint,
   107  		}
   108  	}
   109  	return result
   110  }