github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/dependency/resource.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package dependency
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  
    11  	"github.com/juju/juju/worker"
    12  )
    13  
    14  // resourceGetter encapsulates a snapshot of workers and output funcs and exposes
    15  // a getResource method that can be used as a GetResourceFunc.
    16  type resourceGetter struct {
    17  
    18  	// clientName is the name of the manifold for whose convenience this exists.
    19  	clientName string
    20  
    21  	// expired is closed when the resourceGetter should no longer be used.
    22  	expired chan struct{}
    23  
    24  	// workers holds the snapshot of manifold workers.
    25  	workers map[string]worker.Worker
    26  
    27  	// outputs holds the snapshot of manifold output funcs.
    28  	outputs map[string]OutputFunc
    29  
    30  	// accessLog holds the names and types of resource requests, and any error
    31  	// encountered. It does not include requests made after expiry.
    32  	accessLog []resourceAccess
    33  }
    34  
    35  // expire closes the expired channel. Calling it more than once will panic.
    36  func (rg *resourceGetter) expire() {
    37  	close(rg.expired)
    38  }
    39  
    40  // getResource is intended for use as the GetResourceFunc passed into the Start
    41  // func of the client manifold.
    42  func (rg *resourceGetter) getResource(resourceName string, out interface{}) error {
    43  	logger.Tracef("%q manifold requested %q resource", rg.clientName, resourceName)
    44  	select {
    45  	case <-rg.expired:
    46  		return errors.New("expired resourceGetter: cannot be used outside Start func")
    47  	default:
    48  		err := rg.rawAccess(resourceName, out)
    49  		rg.accessLog = append(rg.accessLog, resourceAccess{
    50  			name: resourceName,
    51  			as:   fmt.Sprintf("%T", out),
    52  			err:  err,
    53  		})
    54  		return err
    55  	}
    56  }
    57  
    58  // rawAccess is a GetResourceFunc that neither checks enpiry nor records access.
    59  func (rg *resourceGetter) rawAccess(resourceName string, out interface{}) error {
    60  	input := rg.workers[resourceName]
    61  	if input == nil {
    62  		// No worker running (or not declared).
    63  		return ErrMissing
    64  	}
    65  	convert := rg.outputs[resourceName]
    66  	if convert == nil {
    67  		// No conversion func available...
    68  		if out != nil {
    69  			// ...and the caller wants a resource.
    70  			return ErrMissing
    71  		}
    72  		// ...but it's ok, because the caller depends on existence only.
    73  		return nil
    74  	}
    75  	return convert(input, out)
    76  }
    77  
    78  // resourceAccess describes a call made to (*resourceGetter).getResource.
    79  type resourceAccess struct {
    80  
    81  	// name is the name of the resource requested.
    82  	name string
    83  
    84  	// as is the string representation of the type of the out param.
    85  	as string
    86  
    87  	// err is any error returned from rawAccess.
    88  	err error
    89  }
    90  
    91  // report returns a convenient representation of ra.
    92  func (ra resourceAccess) report() map[string]interface{} {
    93  	return map[string]interface{}{
    94  		KeyName:  ra.name,
    95  		KeyType:  ra.as,
    96  		KeyError: ra.err,
    97  	}
    98  }
    99  
   100  // resourceLogReport returns a convenient representation of accessLog.
   101  func resourceLogReport(accessLog []resourceAccess) []map[string]interface{} {
   102  	result := make([]map[string]interface{}, len(accessLog))
   103  	for i, access := range accessLog {
   104  		result[i] = access.report()
   105  	}
   106  	return result
   107  }