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

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package charms
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/utils/set"
     9  	"gopkg.in/juju/charm.v6-unstable"
    10  	"gopkg.in/juju/charm.v6-unstable/resource"
    11  
    12  	"github.com/juju/juju/apiserver/common"
    13  	"github.com/juju/juju/apiserver/facade"
    14  	"github.com/juju/juju/apiserver/params"
    15  	"github.com/juju/juju/permission"
    16  	"github.com/juju/juju/state"
    17  )
    18  
    19  func init() {
    20  	common.RegisterStandardFacade("Charms", 2, NewAPI)
    21  }
    22  
    23  var getState = func(st *state.State) charmsAccess {
    24  	return stateShim{st}
    25  }
    26  
    27  // Charms defines the methods on the charms API end point.
    28  type Charms interface {
    29  	List(args params.CharmsList) (params.CharmsListResult, error)
    30  	CharmInfo(args params.CharmURL) (params.CharmInfo, error)
    31  	IsMetered(args params.CharmURL) (bool, error)
    32  }
    33  
    34  // API implements the charms interface and is the concrete
    35  // implementation of the api end point.
    36  type API struct {
    37  	access     charmsAccess
    38  	authorizer facade.Authorizer
    39  }
    40  
    41  func (a *API) checkCanRead() error {
    42  	canRead, err := a.authorizer.HasPermission(permission.ReadAccess, a.access.ModelTag())
    43  	if err != nil {
    44  		return errors.Trace(err)
    45  	}
    46  	if !canRead {
    47  		return common.ErrPerm
    48  	}
    49  	return nil
    50  }
    51  
    52  // NewAPI returns a new charms API facade.
    53  func NewAPI(
    54  	st *state.State,
    55  	resources facade.Resources,
    56  	authorizer facade.Authorizer,
    57  ) (*API, error) {
    58  
    59  	if !authorizer.AuthClient() {
    60  		return nil, common.ErrPerm
    61  	}
    62  
    63  	return &API{
    64  		access:     getState(st),
    65  		authorizer: authorizer,
    66  	}, nil
    67  }
    68  
    69  // CharmInfo returns information about the requested charm.
    70  // NOTE: thumper 2016-06-29, this is not a bulk call and probably should be.
    71  func (a *API) CharmInfo(args params.CharmURL) (params.CharmInfo, error) {
    72  	if err := a.checkCanRead(); err != nil {
    73  		return params.CharmInfo{}, errors.Trace(err)
    74  	}
    75  
    76  	curl, err := charm.ParseURL(args.URL)
    77  	if err != nil {
    78  		return params.CharmInfo{}, errors.Trace(err)
    79  	}
    80  	aCharm, err := a.access.Charm(curl)
    81  	if err != nil {
    82  		return params.CharmInfo{}, errors.Trace(err)
    83  	}
    84  	info := params.CharmInfo{
    85  		Revision: aCharm.Revision(),
    86  		URL:      curl.String(),
    87  		Config:   convertCharmConfig(aCharm.Config()),
    88  		Meta:     convertCharmMeta(aCharm.Meta()),
    89  		Actions:  convertCharmActions(aCharm.Actions()),
    90  		Metrics:  convertCharmMetrics(aCharm.Metrics()),
    91  	}
    92  	return info, nil
    93  }
    94  
    95  // List returns a list of charm URLs currently in the state.
    96  // If supplied parameter contains any names, the result will be filtered
    97  // to return only the charms with supplied names.
    98  func (a *API) List(args params.CharmsList) (params.CharmsListResult, error) {
    99  	if err := a.checkCanRead(); err != nil {
   100  		return params.CharmsListResult{}, errors.Trace(err)
   101  	}
   102  
   103  	charms, err := a.access.AllCharms()
   104  	if err != nil {
   105  		return params.CharmsListResult{}, errors.Annotatef(err, " listing charms ")
   106  	}
   107  
   108  	names := set.NewStrings(args.Names...)
   109  	checkName := !names.IsEmpty()
   110  	charmURLs := []string{}
   111  	for _, aCharm := range charms {
   112  		charmURL := aCharm.URL()
   113  		if checkName {
   114  			if !names.Contains(charmURL.Name) {
   115  				continue
   116  			}
   117  		}
   118  		charmURLs = append(charmURLs, charmURL.String())
   119  	}
   120  	return params.CharmsListResult{CharmURLs: charmURLs}, nil
   121  }
   122  
   123  // IsMetered returns whether or not the charm is metered.
   124  func (a *API) IsMetered(args params.CharmURL) (params.IsMeteredResult, error) {
   125  	if err := a.checkCanRead(); err != nil {
   126  		return params.IsMeteredResult{}, errors.Trace(err)
   127  	}
   128  
   129  	curl, err := charm.ParseURL(args.URL)
   130  	if err != nil {
   131  		return params.IsMeteredResult{false}, errors.Trace(err)
   132  	}
   133  	aCharm, err := a.access.Charm(curl)
   134  	if err != nil {
   135  		return params.IsMeteredResult{false}, errors.Trace(err)
   136  	}
   137  	if aCharm.Metrics() != nil && len(aCharm.Metrics().Metrics) > 0 {
   138  		return params.IsMeteredResult{true}, nil
   139  	}
   140  	return params.IsMeteredResult{false}, nil
   141  }
   142  
   143  func convertCharmConfig(config *charm.Config) map[string]params.CharmOption {
   144  	if config == nil {
   145  		return nil
   146  	}
   147  	result := make(map[string]params.CharmOption)
   148  	for key, value := range config.Options {
   149  		result[key] = convertCharmOption(value)
   150  	}
   151  	return result
   152  }
   153  
   154  func convertCharmOption(opt charm.Option) params.CharmOption {
   155  	return params.CharmOption{
   156  		Type:        opt.Type,
   157  		Description: opt.Description,
   158  		Default:     opt.Default,
   159  	}
   160  }
   161  
   162  func convertCharmMeta(meta *charm.Meta) *params.CharmMeta {
   163  	if meta == nil {
   164  		return nil
   165  	}
   166  	result := &params.CharmMeta{
   167  		Name:           meta.Name,
   168  		Summary:        meta.Summary,
   169  		Description:    meta.Description,
   170  		Subordinate:    meta.Subordinate,
   171  		Provides:       convertCharmRelationMap(meta.Provides),
   172  		Requires:       convertCharmRelationMap(meta.Requires),
   173  		Peers:          convertCharmRelationMap(meta.Peers),
   174  		ExtraBindings:  convertCharmExtraBindingMap(meta.ExtraBindings),
   175  		Categories:     meta.Categories,
   176  		Tags:           meta.Tags,
   177  		Series:         meta.Series,
   178  		Storage:        convertCharmStorageMap(meta.Storage),
   179  		PayloadClasses: convertCharmPayloadClassMap(meta.PayloadClasses),
   180  		Resources:      convertCharmResourceMetaMap(meta.Resources),
   181  		Terms:          meta.Terms,
   182  		MinJujuVersion: meta.MinJujuVersion.String(),
   183  	}
   184  
   185  	return result
   186  }
   187  
   188  func convertCharmRelationMap(relations map[string]charm.Relation) map[string]params.CharmRelation {
   189  	if len(relations) == 0 {
   190  		return nil
   191  	}
   192  	result := make(map[string]params.CharmRelation)
   193  	for key, value := range relations {
   194  		result[key] = convertCharmRelation(value)
   195  	}
   196  	return result
   197  }
   198  
   199  func convertCharmRelation(relation charm.Relation) params.CharmRelation {
   200  	return params.CharmRelation{
   201  		Name:      relation.Name,
   202  		Role:      string(relation.Role),
   203  		Interface: relation.Interface,
   204  		Optional:  relation.Optional,
   205  		Limit:     relation.Limit,
   206  		Scope:     string(relation.Scope),
   207  	}
   208  }
   209  
   210  func convertCharmStorageMap(storage map[string]charm.Storage) map[string]params.CharmStorage {
   211  	if len(storage) == 0 {
   212  		return nil
   213  	}
   214  	result := make(map[string]params.CharmStorage)
   215  	for key, value := range storage {
   216  		result[key] = convertCharmStorage(value)
   217  	}
   218  	return result
   219  }
   220  
   221  func convertCharmStorage(storage charm.Storage) params.CharmStorage {
   222  	return params.CharmStorage{
   223  		Name:        storage.Name,
   224  		Description: storage.Description,
   225  		Type:        string(storage.Type),
   226  		Shared:      storage.Shared,
   227  		ReadOnly:    storage.ReadOnly,
   228  		CountMin:    storage.CountMin,
   229  		CountMax:    storage.CountMax,
   230  		MinimumSize: storage.MinimumSize,
   231  		Location:    storage.Location,
   232  		Properties:  storage.Properties,
   233  	}
   234  }
   235  
   236  func convertCharmPayloadClassMap(payload map[string]charm.PayloadClass) map[string]params.CharmPayloadClass {
   237  	if len(payload) == 0 {
   238  		return nil
   239  	}
   240  	result := make(map[string]params.CharmPayloadClass)
   241  	for key, value := range payload {
   242  		result[key] = convertCharmPayloadClass(value)
   243  	}
   244  	return result
   245  }
   246  
   247  func convertCharmPayloadClass(payload charm.PayloadClass) params.CharmPayloadClass {
   248  	return params.CharmPayloadClass{
   249  		Name: payload.Name,
   250  		Type: payload.Type,
   251  	}
   252  }
   253  
   254  func convertCharmResourceMetaMap(resources map[string]resource.Meta) map[string]params.CharmResourceMeta {
   255  	if len(resources) == 0 {
   256  		return nil
   257  	}
   258  	result := make(map[string]params.CharmResourceMeta)
   259  	for key, value := range resources {
   260  		result[key] = convertCharmResourceMeta(value)
   261  	}
   262  	return result
   263  }
   264  
   265  func convertCharmResourceMeta(meta resource.Meta) params.CharmResourceMeta {
   266  	return params.CharmResourceMeta{
   267  		Name:        meta.Name,
   268  		Type:        meta.Type.String(),
   269  		Path:        meta.Path,
   270  		Description: meta.Description,
   271  	}
   272  }
   273  
   274  func convertCharmActions(actions *charm.Actions) *params.CharmActions {
   275  	if actions == nil {
   276  		return nil
   277  	}
   278  	result := &params.CharmActions{
   279  		ActionSpecs: convertCharmActionSpecMap(actions.ActionSpecs),
   280  	}
   281  
   282  	return result
   283  }
   284  
   285  func convertCharmActionSpecMap(specs map[string]charm.ActionSpec) map[string]params.CharmActionSpec {
   286  	if len(specs) == 0 {
   287  		return nil
   288  	}
   289  	result := make(map[string]params.CharmActionSpec)
   290  	for key, value := range specs {
   291  		result[key] = convertCharmActionSpec(value)
   292  	}
   293  	return result
   294  }
   295  
   296  func convertCharmActionSpec(spec charm.ActionSpec) params.CharmActionSpec {
   297  	return params.CharmActionSpec{
   298  		Description: spec.Description,
   299  		Params:      spec.Params,
   300  	}
   301  }
   302  
   303  func convertCharmMetrics(metrics *charm.Metrics) *params.CharmMetrics {
   304  	if metrics == nil {
   305  		return nil
   306  	}
   307  	return &params.CharmMetrics{
   308  		Metrics: convertCharmMetricMap(metrics.Metrics),
   309  		Plan:    convertCharmPlan(metrics.Plan),
   310  	}
   311  }
   312  
   313  func convertCharmPlan(plan *charm.Plan) params.CharmPlan {
   314  	if plan == nil {
   315  		return params.CharmPlan{Required: false}
   316  	}
   317  	return params.CharmPlan{Required: plan.Required}
   318  }
   319  
   320  func convertCharmMetricMap(metrics map[string]charm.Metric) map[string]params.CharmMetric {
   321  	if len(metrics) == 0 {
   322  		return nil
   323  	}
   324  	result := make(map[string]params.CharmMetric)
   325  	for key, value := range metrics {
   326  		result[key] = convertCharmMetric(value)
   327  	}
   328  	return result
   329  }
   330  
   331  func convertCharmMetric(metric charm.Metric) params.CharmMetric {
   332  	return params.CharmMetric{
   333  		Type:        string(metric.Type),
   334  		Description: metric.Description,
   335  	}
   336  }
   337  
   338  func convertCharmExtraBindingMap(bindings map[string]charm.ExtraBinding) map[string]string {
   339  	if len(bindings) == 0 {
   340  		return nil
   341  	}
   342  	result := make(map[string]string)
   343  	for key, value := range bindings {
   344  		result[key] = value.Name
   345  	}
   346  	return result
   347  }