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 }