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

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // Package metricsmanager contains the implementation of an api endpoint
     5  // for calling metrics functions in state.
     6  package metricsmanager
     7  
     8  import (
     9  	"github.com/juju/errors"
    10  	"github.com/juju/loggo"
    11  	"github.com/juju/utils/clock"
    12  	"gopkg.in/juju/names.v2"
    13  
    14  	"github.com/juju/juju/apiserver/common"
    15  	"github.com/juju/juju/apiserver/facade"
    16  	"github.com/juju/juju/apiserver/metricsender"
    17  	"github.com/juju/juju/apiserver/params"
    18  	"github.com/juju/juju/state"
    19  )
    20  
    21  var (
    22  	logger            = loggo.GetLogger("juju.apiserver.metricsmanager")
    23  	maxBatchesPerSend = metricsender.DefaultMaxBatchesPerSend()
    24  
    25  	sender = metricsender.DefaultMetricSender()
    26  )
    27  
    28  func init() {
    29  	common.RegisterStandardFacade("MetricsManager", 1, newMetricsManagerAPI)
    30  }
    31  
    32  // MetricsManager defines the methods on the metricsmanager API end point.
    33  type MetricsManager interface {
    34  	CleanupOldMetrics(arg params.Entities) (params.ErrorResults, error)
    35  	SendMetrics(args params.Entities) (params.ErrorResults, error)
    36  }
    37  
    38  // MetricsManagerAPI implements the metrics manager interface and is the concrete
    39  // implementation of the api end point.
    40  type MetricsManagerAPI struct {
    41  	state *state.State
    42  
    43  	accessEnviron common.GetAuthFunc
    44  	clock         clock.Clock
    45  }
    46  
    47  var _ MetricsManager = (*MetricsManagerAPI)(nil)
    48  
    49  // newMetricsManagerAPI wraps NewMetricsManagerAPI for RegisterStandardFacade.
    50  func newMetricsManagerAPI(
    51  	st *state.State,
    52  	resources facade.Resources,
    53  	authorizer facade.Authorizer,
    54  ) (*MetricsManagerAPI, error) {
    55  	return NewMetricsManagerAPI(st, resources, authorizer, clock.WallClock)
    56  }
    57  
    58  // NewMetricsManagerAPI creates a new API endpoint for calling metrics manager functions.
    59  func NewMetricsManagerAPI(
    60  	st *state.State,
    61  	resources facade.Resources,
    62  	authorizer facade.Authorizer,
    63  	clock clock.Clock,
    64  ) (*MetricsManagerAPI, error) {
    65  	if !(authorizer.AuthMachineAgent() && authorizer.AuthModelManager()) {
    66  		return nil, common.ErrPerm
    67  	}
    68  
    69  	// Allow access only to the current environment.
    70  	accessEnviron := func() (common.AuthFunc, error) {
    71  		return func(tag names.Tag) bool {
    72  			if tag == nil {
    73  				return false
    74  			}
    75  			return tag == st.ModelTag()
    76  		}, nil
    77  	}
    78  
    79  	return &MetricsManagerAPI{
    80  		state:         st,
    81  		accessEnviron: accessEnviron,
    82  		clock:         clock,
    83  	}, nil
    84  }
    85  
    86  // CleanupOldMetrics removes old metrics from the collection.
    87  // The single arg params is expected to contain and environment uuid.
    88  // Even though the call will delete all metrics across environments
    89  // it serves to validate that the connection has access to at least one environment.
    90  func (api *MetricsManagerAPI) CleanupOldMetrics(args params.Entities) (params.ErrorResults, error) {
    91  	result := params.ErrorResults{
    92  		Results: make([]params.ErrorResult, len(args.Entities)),
    93  	}
    94  	if len(args.Entities) == 0 {
    95  		return result, nil
    96  	}
    97  	canAccess, err := api.accessEnviron()
    98  	if err != nil {
    99  		return result, err
   100  	}
   101  	for i, arg := range args.Entities {
   102  		tag, err := names.ParseModelTag(arg.Tag)
   103  		if err != nil {
   104  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   105  			continue
   106  		}
   107  		if !canAccess(tag) {
   108  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   109  			continue
   110  		}
   111  		modelState := api.state
   112  		if tag != api.state.ModelTag() {
   113  			modelState, err = api.state.ForModel(tag)
   114  			if err != nil {
   115  				err = errors.Annotatef(err, "failed to access state for %s", tag)
   116  				result.Results[i].Error = common.ServerError(err)
   117  				continue
   118  			}
   119  		}
   120  
   121  		err = modelState.CleanupOldMetrics()
   122  		if err != nil {
   123  			err = errors.Annotatef(err, "failed to cleanup old metrics for %s", tag)
   124  			result.Results[i].Error = common.ServerError(err)
   125  		}
   126  	}
   127  	return result, nil
   128  }
   129  
   130  // SendMetrics will send any unsent metrics onto the metric collection service.
   131  func (api *MetricsManagerAPI) SendMetrics(args params.Entities) (params.ErrorResults, error) {
   132  	result := params.ErrorResults{
   133  		Results: make([]params.ErrorResult, len(args.Entities)),
   134  	}
   135  	if len(args.Entities) == 0 {
   136  		return result, nil
   137  	}
   138  	canAccess, err := api.accessEnviron()
   139  	if err != nil {
   140  		return result, err
   141  	}
   142  	for i, arg := range args.Entities {
   143  		tag, err := names.ParseModelTag(arg.Tag)
   144  		if err != nil {
   145  			result.Results[i].Error = common.ServerError(err)
   146  			continue
   147  		}
   148  		if !canAccess(tag) {
   149  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   150  			continue
   151  		}
   152  		modelState := api.state
   153  		if tag != api.state.ModelTag() {
   154  			modelState, err = api.state.ForModel(tag)
   155  			if err != nil {
   156  				err = errors.Annotatef(err, "failed to access state for %s", tag)
   157  				result.Results[i].Error = common.ServerError(err)
   158  				continue
   159  			}
   160  		}
   161  		txVendorMetrics, err := transmitVendorMetrics(modelState)
   162  		if err != nil {
   163  			result.Results[i].Error = common.ServerError(err)
   164  			continue
   165  		}
   166  		err = metricsender.SendMetrics(modelState, sender, api.clock, maxBatchesPerSend, txVendorMetrics)
   167  		if err != nil {
   168  			err = errors.Annotatef(err, "failed to send metrics for %s", tag)
   169  			logger.Warningf("%v", err)
   170  			result.Results[i].Error = common.ServerError(err)
   171  			continue
   172  		}
   173  	}
   174  	return result, nil
   175  }
   176  
   177  func transmitVendorMetrics(st *state.State) (bool, error) {
   178  	cfg, err := st.ModelConfig()
   179  	if err != nil {
   180  		return false, errors.Annotatef(err, "failed to get model config for %s", st.ModelTag())
   181  	}
   182  	return cfg.TransmitVendorMetrics(), nil
   183  }