github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/apiserver/diskformatter/diskformatter.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package diskformatter
     5  
     6  import (
     7  	"github.com/juju/loggo"
     8  	"github.com/juju/names"
     9  
    10  	"github.com/juju/juju/apiserver/common"
    11  	"github.com/juju/juju/apiserver/params"
    12  	"github.com/juju/juju/state"
    13  	"github.com/juju/juju/state/watcher"
    14  	"github.com/juju/juju/storage"
    15  )
    16  
    17  func init() {
    18  	common.RegisterStandardFacade("DiskFormatter", 1, NewDiskFormatterAPI)
    19  }
    20  
    21  var logger = loggo.GetLogger("juju.apiserver.diskformatter")
    22  
    23  // DiskFormatterAPI provides access to the DiskFormatter API facade.
    24  type DiskFormatterAPI struct {
    25  	st          stateInterface
    26  	resources   *common.Resources
    27  	authorizer  common.Authorizer
    28  	getAuthFunc common.GetAuthFunc
    29  }
    30  
    31  // NewDiskFormatterAPI creates a new server-side DiskFormatter API facade.
    32  func NewDiskFormatterAPI(
    33  	st *state.State,
    34  	resources *common.Resources,
    35  	authorizer common.Authorizer,
    36  ) (*DiskFormatterAPI, error) {
    37  
    38  	if !authorizer.AuthUnitAgent() {
    39  		return nil, common.ErrPerm
    40  	}
    41  
    42  	getAuthFunc := func() (common.AuthFunc, error) {
    43  		return authorizer.AuthOwner, nil
    44  	}
    45  
    46  	return &DiskFormatterAPI{
    47  		st:          getState(st),
    48  		resources:   resources,
    49  		authorizer:  authorizer,
    50  		getAuthFunc: getAuthFunc,
    51  	}, nil
    52  }
    53  
    54  // WatchBlockDevices returns a StringsWatcher for observing changes
    55  // to block devices associated with the unit's machine.
    56  func (a *DiskFormatterAPI) WatchBlockDevices(args params.Entities) (params.StringsWatchResults, error) {
    57  	result := params.StringsWatchResults{
    58  		Results: make([]params.StringsWatchResult, len(args.Entities)),
    59  	}
    60  	canAccess, err := a.getAuthFunc()
    61  	if err != nil {
    62  		return params.StringsWatchResults{}, err
    63  	}
    64  	for i, entity := range args.Entities {
    65  		unit, err := names.ParseUnitTag(entity.Tag)
    66  		if err != nil {
    67  			result.Results[i].Error = common.ServerError(common.ErrPerm)
    68  			continue
    69  		}
    70  		err = common.ErrPerm
    71  		var watcherId string
    72  		var changes []string
    73  		if canAccess(unit) {
    74  			watcherId, changes, err = a.watchOneBlockDevices(unit)
    75  		}
    76  		result.Results[i].StringsWatcherId = watcherId
    77  		result.Results[i].Changes = changes
    78  		result.Results[i].Error = common.ServerError(err)
    79  	}
    80  	return result, nil
    81  }
    82  
    83  func (a *DiskFormatterAPI) watchOneBlockDevices(tag names.UnitTag) (string, []string, error) {
    84  	w, err := a.st.WatchUnitMachineBlockDevices(tag)
    85  	if err != nil {
    86  		return "", nil, err
    87  	}
    88  	// Consume the initial event. Technically, API
    89  	// calls to Watch 'transmit' the initial event
    90  	// in the Watch response.
    91  	if changes, ok := <-w.Changes(); ok {
    92  		return a.resources.Register(w), changes, nil
    93  	}
    94  	return "", nil, watcher.EnsureErr(w)
    95  }
    96  
    97  // BlockDevices returns details about each specified block device.
    98  func (a *DiskFormatterAPI) BlockDevices(args params.Entities) (params.BlockDeviceResults, error) {
    99  	result := params.BlockDeviceResults{
   100  		Results: make([]params.BlockDeviceResult, len(args.Entities)),
   101  	}
   102  	canAccess, err := a.getAuthFunc()
   103  	if err != nil {
   104  		return params.BlockDeviceResults{}, err
   105  	}
   106  	one := func(entity params.Entity) (storage.BlockDevice, error) {
   107  		blockDevice, _, err := a.oneBlockDevice(entity.Tag, canAccess)
   108  		if err != nil {
   109  			return storage.BlockDevice{}, err
   110  		}
   111  		return storageBlockDevice(blockDevice)
   112  	}
   113  	for i, entity := range args.Entities {
   114  		blockDevice, err := one(entity)
   115  		result.Results[i].Result = blockDevice
   116  		result.Results[i].Error = common.ServerError(err)
   117  	}
   118  	return result, nil
   119  }
   120  
   121  // BlockDeviceStorageInstances returns details of storage instances corresponding
   122  // to each specified block device.
   123  func (a *DiskFormatterAPI) BlockDeviceStorageInstances(args params.Entities) (params.StorageInstanceResults, error) {
   124  	result := params.StorageInstanceResults{
   125  		Results: make([]params.StorageInstanceResult, len(args.Entities)),
   126  	}
   127  	canAccess, err := a.getAuthFunc()
   128  	if err != nil {
   129  		return params.StorageInstanceResults{}, err
   130  	}
   131  	one := func(entity params.Entity) (storage.StorageInstance, error) {
   132  		_, storageInstance, err := a.oneBlockDevice(entity.Tag, canAccess)
   133  		if err != nil {
   134  			return storage.StorageInstance{}, err
   135  		}
   136  		return storageStorageInstance(storageInstance)
   137  	}
   138  	for i, entity := range args.Entities {
   139  		storageInstance, err := one(entity)
   140  		result.Results[i].Result = storageInstance
   141  		result.Results[i].Error = common.ServerError(err)
   142  	}
   143  	return result, nil
   144  }
   145  
   146  func (a *DiskFormatterAPI) oneBlockDevice(tag string, canAccess common.AuthFunc) (state.BlockDevice, state.StorageInstance, error) {
   147  	diskTag, err := names.ParseDiskTag(tag)
   148  	if err != nil {
   149  		return nil, nil, common.ErrPerm
   150  	}
   151  	blockDevice, err := a.st.BlockDevice(diskTag.Id())
   152  	if err != nil {
   153  		return nil, nil, common.ErrPerm
   154  	}
   155  	if !blockDevice.Attached() {
   156  		// ignore unattached block devices
   157  		return nil, nil, common.ErrPerm
   158  	}
   159  	storageInstanceId, ok := blockDevice.StorageInstance()
   160  	if !ok {
   161  		// not assigned to any storage instance
   162  		return nil, nil, common.ErrPerm
   163  	}
   164  	storageInstance, err := a.st.StorageInstance(storageInstanceId)
   165  	if err != nil || !canAccess(storageInstance.Owner()) {
   166  		return nil, nil, common.ErrPerm
   167  	}
   168  	return blockDevice, storageInstance, nil
   169  }
   170  
   171  // NOTE: purposefully not using field keys below, so
   172  // the code breaks if structures change.
   173  
   174  func storageBlockDevice(dev state.BlockDevice) (storage.BlockDevice, error) {
   175  	if dev == nil {
   176  		return storage.BlockDevice{}, nil
   177  	}
   178  	info, err := dev.Info()
   179  	if err != nil {
   180  		return storage.BlockDevice{}, err
   181  	}
   182  	return storage.BlockDevice{
   183  		dev.Name(),
   184  		"", // TODO(axw) ProviderId
   185  		info.DeviceName,
   186  		info.Label,
   187  		info.UUID,
   188  		info.Serial,
   189  		info.Size,
   190  		info.FilesystemType,
   191  		info.InUse,
   192  	}, nil
   193  }
   194  
   195  func storageStorageInstance(st state.StorageInstance) (storage.StorageInstance, error) {
   196  	if st == nil {
   197  		return storage.StorageInstance{}, nil
   198  	}
   199  	return storage.StorageInstance{
   200  		st.Id(),
   201  		storageStorageKind(st.Kind()),
   202  		"", // TODO(wallyworld) Location
   203  	}, nil
   204  }
   205  
   206  func storageStorageKind(k state.StorageKind) storage.StorageKind {
   207  	switch k {
   208  	case state.StorageKindBlock:
   209  		return storage.StorageKindBlock
   210  	case state.StorageKindFilesystem:
   211  		return storage.StorageKindFilesystem
   212  	default:
   213  		return storage.StorageKindUnknown
   214  	}
   215  }