github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/apiserver/common/setstatus.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/names"
    11  
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/state"
    14  )
    15  
    16  // ServiceStatusSetter implements a SetServiceStatus method to be
    17  // used by facades that can change a service status.
    18  type ServiceStatusSetter struct {
    19  	st           state.EntityFinder
    20  	getCanModify GetAuthFunc
    21  }
    22  
    23  // NewServiceStatusSetter returns a ServiceStatusSetter.
    24  func NewServiceStatusSetter(st state.EntityFinder, getCanModify GetAuthFunc) *ServiceStatusSetter {
    25  	return &ServiceStatusSetter{
    26  		st:           st,
    27  		getCanModify: getCanModify,
    28  	}
    29  }
    30  
    31  // SetStatus sets the status on the service given by the unit in args if the unit is the leader.
    32  func (s *ServiceStatusSetter) SetStatus(args params.SetStatus) (params.ErrorResults, error) {
    33  	return serviceSetStatus(s, args, serviceFromUnitTag, isLeader)
    34  }
    35  
    36  func serviceSetStatus(s *ServiceStatusSetter, args params.SetStatus, getService serviceGetter, isLeaderCheck isLeaderFunc) (params.ErrorResults, error) {
    37  	result := params.ErrorResults{
    38  		Results: make([]params.ErrorResult, len(args.Entities)),
    39  	}
    40  	if len(args.Entities) == 0 {
    41  		return result, nil
    42  	}
    43  	canModify, err := s.getCanModify()
    44  	if err != nil {
    45  		return params.ErrorResults{}, err
    46  	}
    47  	for i, arg := range args.Entities {
    48  		leader, err := isLeaderCheck(s.st, arg.Tag)
    49  		if err != nil {
    50  			result.Results[i].Error = ServerError(err)
    51  			continue
    52  		}
    53  		if !leader {
    54  			result.Results[i].Error = ServerError(ErrIsNotLeader)
    55  			continue
    56  		}
    57  		service, err := getService(s.st, arg.Tag)
    58  		if err != nil {
    59  			result.Results[i].Error = ServerError(err)
    60  			continue
    61  		}
    62  
    63  		if !canModify(service.Tag()) {
    64  			result.Results[i].Error = ServerError(ErrPerm)
    65  			continue
    66  		}
    67  
    68  		if err := service.SetStatus(state.Status(arg.Status), arg.Info, arg.Data); err != nil {
    69  			result.Results[i].Error = ServerError(err)
    70  		}
    71  
    72  	}
    73  	return result, nil
    74  }
    75  
    76  // StatusSetter implements a common SetStatus method for use by
    77  // various facades.
    78  type StatusSetter struct {
    79  	st           state.EntityFinder
    80  	getCanModify GetAuthFunc
    81  }
    82  
    83  // NewStatusSetter returns a new StatusSetter. The GetAuthFunc will be
    84  // used on each invocation of SetStatus to determine current
    85  // permissions.
    86  func NewStatusSetter(st state.EntityFinder, getCanModify GetAuthFunc) *StatusSetter {
    87  	return &StatusSetter{
    88  		st:           st,
    89  		getCanModify: getCanModify,
    90  	}
    91  }
    92  
    93  func (s *StatusSetter) setEntityStatus(tag names.Tag, status params.Status, info string, data map[string]interface{}) error {
    94  	entity, err := s.st.FindEntity(tag)
    95  	if err != nil {
    96  		return err
    97  	}
    98  	switch entity := entity.(type) {
    99  	case state.StatusSetter:
   100  		return entity.SetStatus(state.Status(status), info, data)
   101  	default:
   102  		return NotSupportedError(tag, fmt.Sprintf("setting status, %T", entity))
   103  	}
   104  }
   105  
   106  // SetStatus sets the status of each given entity.
   107  func (s *StatusSetter) SetStatus(args params.SetStatus) (params.ErrorResults, error) {
   108  	result := params.ErrorResults{
   109  		Results: make([]params.ErrorResult, len(args.Entities)),
   110  	}
   111  	if len(args.Entities) == 0 {
   112  		return result, nil
   113  	}
   114  	canModify, err := s.getCanModify()
   115  	if err != nil {
   116  		return params.ErrorResults{}, err
   117  	}
   118  	for i, arg := range args.Entities {
   119  		tag, err := names.ParseTag(arg.Tag)
   120  		if err != nil {
   121  			result.Results[i].Error = ServerError(ErrPerm)
   122  			continue
   123  		}
   124  		err = ErrPerm
   125  		if canModify(tag) {
   126  			err = s.setEntityStatus(tag, arg.Status, arg.Info, arg.Data)
   127  		}
   128  		result.Results[i].Error = ServerError(err)
   129  	}
   130  	return result, nil
   131  }
   132  
   133  func (s *StatusSetter) updateEntityStatusData(tag names.Tag, data map[string]interface{}) error {
   134  	entity0, err := s.st.FindEntity(tag)
   135  	if err != nil {
   136  		return err
   137  	}
   138  	statusGetter, ok := entity0.(state.StatusGetter)
   139  	if !ok {
   140  		return NotSupportedError(tag, "getting status")
   141  	}
   142  	existingStatusInfo, err := statusGetter.Status()
   143  	if err != nil {
   144  		return err
   145  	}
   146  	newData := existingStatusInfo.Data
   147  	if newData == nil {
   148  		newData = data
   149  	} else {
   150  		for k, v := range data {
   151  			newData[k] = v
   152  		}
   153  	}
   154  	entity, ok := entity0.(state.StatusSetter)
   155  	if !ok {
   156  		return NotSupportedError(tag, "updating status")
   157  	}
   158  	if len(newData) > 0 && existingStatusInfo.Status != state.StatusError {
   159  		return fmt.Errorf("%s is not in an error state", names.ReadableString(tag))
   160  	}
   161  	return entity.SetStatus(existingStatusInfo.Status, existingStatusInfo.Message, newData)
   162  }
   163  
   164  // UpdateStatus updates the status data of each given entity.
   165  func (s *StatusSetter) UpdateStatus(args params.SetStatus) (params.ErrorResults, error) {
   166  	result := params.ErrorResults{
   167  		Results: make([]params.ErrorResult, len(args.Entities)),
   168  	}
   169  	if len(args.Entities) == 0 {
   170  		return result, nil
   171  	}
   172  	canModify, err := s.getCanModify()
   173  	if err != nil {
   174  		return params.ErrorResults{}, errors.Trace(err)
   175  	}
   176  	for i, arg := range args.Entities {
   177  		tag, err := names.ParseTag(arg.Tag)
   178  		if err != nil {
   179  			result.Results[i].Error = ServerError(ErrPerm)
   180  			continue
   181  		}
   182  		err = ErrPerm
   183  		if canModify(tag) {
   184  			err = s.updateEntityStatusData(tag, arg.Data)
   185  		}
   186  		result.Results[i].Error = ServerError(err)
   187  	}
   188  	return result, nil
   189  }