github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/uniter/runner/jujuc/context.go (about) 1 // Copyright 2012, 2013, 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package jujuc 5 6 import ( 7 "fmt" 8 "strconv" 9 "strings" 10 "time" 11 12 "github.com/juju/errors" 13 "github.com/juju/names" 14 "gopkg.in/juju/charm.v6-unstable" 15 16 "github.com/juju/juju/apiserver/params" 17 "github.com/juju/juju/network" 18 "github.com/juju/juju/storage" 19 ) 20 21 // RebootPriority is the type used for reboot requests. 22 type RebootPriority int 23 24 const ( 25 // RebootSkip is a noop. 26 RebootSkip RebootPriority = iota 27 // RebootAfterHook means wait for current hook to finish before 28 // rebooting. 29 RebootAfterHook 30 // RebootNow means reboot immediately, killing and requeueing the 31 // calling hook 32 RebootNow 33 ) 34 35 // Context is the interface that all hook helper commands 36 // depend on to interact with the rest of the system. 37 type Context interface { 38 HookContext 39 relationHookContext 40 actionHookContext 41 } 42 43 // HookContext represents the information and functionality that is 44 // common to all charm hooks. 45 type HookContext interface { 46 ContextUnit 47 ContextStatus 48 ContextInstance 49 ContextNetworking 50 ContextLeadership 51 ContextMetrics 52 ContextStorage 53 ContextRelations 54 } 55 56 // UnitHookContext is the context for a unit hook. 57 type UnitHookContext interface { 58 HookContext 59 } 60 61 // RelationHookContext is the context for a relation hook. 62 type RelationHookContext interface { 63 HookContext 64 relationHookContext 65 } 66 67 type relationHookContext interface { 68 // HookRelation returns the ContextRelation associated with the executing 69 // hook if it was found, or an error if it was not found (or is not available). 70 HookRelation() (ContextRelation, error) 71 72 // RemoteUnitName returns the name of the remote unit the hook execution 73 // is associated with if it was found, and an error if it was not found or is not 74 // available. 75 RemoteUnitName() (string, error) 76 } 77 78 // ActionHookContext is the context for an action hook. 79 type ActionHookContext interface { 80 HookContext 81 actionHookContext 82 } 83 84 type actionHookContext interface { 85 // ActionParams returns the map of params passed with an Action. 86 ActionParams() (map[string]interface{}, error) 87 88 // UpdateActionResults inserts new values for use with action-set. 89 // The results struct will be delivered to the state server upon 90 // completion of the Action. 91 UpdateActionResults(keys []string, value string) error 92 93 // SetActionMessage sets a message for the Action. 94 SetActionMessage(string) error 95 96 // SetActionFailed sets a failure state for the Action. 97 SetActionFailed() error 98 } 99 100 // ContextUnit is the part of a hook context related to the unit. 101 type ContextUnit interface { 102 // UnitName returns the executing unit's name. 103 UnitName() string 104 105 // Config returns the current service configuration of the executing unit. 106 ConfigSettings() (charm.Settings, error) 107 } 108 109 // ContextStatus is the part of a hook context related to the unit's status. 110 type ContextStatus interface { 111 // UnitStatus returns the executing unit's current status. 112 UnitStatus() (*StatusInfo, error) 113 114 // SetUnitStatus updates the unit's status. 115 SetUnitStatus(StatusInfo) error 116 117 // ServiceStatus returns the executing unit's service status 118 // (including all units). 119 ServiceStatus() (ServiceStatusInfo, error) 120 121 // SetServiceStatus updates the status for the unit's service. 122 SetServiceStatus(StatusInfo) error 123 } 124 125 // ContextInstance is the part of a hook context related to the unit's intance. 126 type ContextInstance interface { 127 // AvailabilityZone returns the executing unit's availablilty zone or an error 128 // if it was not found (or is not available). 129 AvailabilityZone() (string, error) 130 131 // RequestReboot will set the reboot flag to true on the machine agent 132 RequestReboot(prio RebootPriority) error 133 } 134 135 // ContextNetworking is the part of a hook context related to network 136 // interface of the unit's instance. 137 type ContextNetworking interface { 138 // PublicAddress returns the executing unit's public address or an 139 // error if it is not available. 140 PublicAddress() (string, error) 141 142 // PrivateAddress returns the executing unit's private address or an 143 // error if it is not available. 144 PrivateAddress() (string, error) 145 146 // OpenPorts marks the supplied port range for opening when the 147 // executing unit's service is exposed. 148 OpenPorts(protocol string, fromPort, toPort int) error 149 150 // ClosePorts ensures the supplied port range is closed even when 151 // the executing unit's service is exposed (unless it is opened 152 // separately by a co- located unit). 153 ClosePorts(protocol string, fromPort, toPort int) error 154 155 // OpenedPorts returns all port ranges currently opened by this 156 // unit on its assigned machine. The result is sorted first by 157 // protocol, then by number. 158 OpenedPorts() []network.PortRange 159 } 160 161 // ContextLeadership is the part of a hook context related to the 162 // unit leadership. 163 type ContextLeadership interface { 164 // IsLeader returns true if the local unit is known to be leader for at 165 // least the next 30s. 166 IsLeader() (bool, error) 167 168 // LeaderSettings returns the current leader settings. Once leader settings 169 // have been read in a given context, they will not be updated other than 170 // via successful calls to WriteLeaderSettings. 171 LeaderSettings() (map[string]string, error) 172 173 // WriteLeaderSettings writes the supplied settings directly to state, or 174 // fails if the local unit is not the service's leader. 175 WriteLeaderSettings(map[string]string) error 176 } 177 178 // ContextMetrics is the part of a hook context related to metrics. 179 type ContextMetrics interface { 180 // AddMetric records a metric to return after hook execution. 181 AddMetric(string, string, time.Time) error 182 } 183 184 // ContextStorage is the part of a hook context related to storage 185 // resources associated with the unit. 186 type ContextStorage interface { 187 // StorageTags returns a list of tags for storage instances 188 // attached to the unit or an error if they are not available. 189 StorageTags() ([]names.StorageTag, error) 190 191 // Storage returns the ContextStorageAttachment with the supplied 192 // tag if it was found, and an error if it was not found or is not 193 // available to the context. 194 Storage(names.StorageTag) (ContextStorageAttachment, error) 195 196 // HookStorage returns the storage attachment associated 197 // the executing hook if it was found, and an error if it 198 // was not found or is not available. 199 HookStorage() (ContextStorageAttachment, error) 200 201 // AddUnitStorage saves storage constraints in the context. 202 AddUnitStorage(map[string]params.StorageConstraints) error 203 } 204 205 // ContextRelations exposes the relations associated with the unit. 206 type ContextRelations interface { 207 // Relation returns the relation with the supplied id if it was found, and 208 // an error if it was not found or is not available. 209 Relation(id int) (ContextRelation, error) 210 211 // RelationIds returns the ids of all relations the executing unit is 212 // currently participating in or an error if they are not available. 213 RelationIds() ([]int, error) 214 } 215 216 // ContextRelation expresses the capabilities of a hook with respect to a relation. 217 type ContextRelation interface { 218 219 // Id returns an integer which uniquely identifies the relation. 220 Id() int 221 222 // Name returns the name the locally executing charm assigned to this relation. 223 Name() string 224 225 // FakeId returns a string of the form "relation-name:123", which uniquely 226 // identifies the relation to the hook. In reality, the identification 227 // of the relation is the integer following the colon, but the composed 228 // name is useful to humans observing it. 229 FakeId() string 230 231 // Settings allows read/write access to the local unit's settings in 232 // this relation. 233 Settings() (Settings, error) 234 235 // UnitNames returns a list of the remote units in the relation. 236 UnitNames() []string 237 238 // ReadSettings returns the settings of any remote unit in the relation. 239 ReadSettings(unit string) (params.Settings, error) 240 } 241 242 // ContextStorageAttachment expresses the capabilities of a hook with 243 // respect to a storage attachment. 244 type ContextStorageAttachment interface { 245 246 // Tag returns a tag which uniquely identifies the storage attachment 247 // in the context of the unit. 248 Tag() names.StorageTag 249 250 // Kind returns the kind of the storage. 251 Kind() storage.StorageKind 252 253 // Location returns the location of the storage: the mount point for 254 // filesystem-kind stores, and the device path for block-kind stores. 255 Location() string 256 } 257 258 // Settings is implemented by types that manipulate unit settings. 259 type Settings interface { 260 Map() params.Settings 261 Set(string, string) 262 Delete(string) 263 } 264 265 // newRelationIdValue returns a gnuflag.Value for convenient parsing of relation 266 // ids in ctx. 267 func newRelationIdValue(ctx Context, result *int) (*relationIdValue, error) { 268 v := &relationIdValue{result: result, ctx: ctx} 269 id := -1 270 if r, err := ctx.HookRelation(); err == nil { 271 id = r.Id() 272 v.value = r.FakeId() 273 } else if !errors.IsNotFound(err) { 274 return nil, errors.Trace(err) 275 } 276 *result = id 277 return v, nil 278 } 279 280 // relationIdValue implements gnuflag.Value for use in relation commands. 281 type relationIdValue struct { 282 result *int 283 ctx Context 284 value string 285 } 286 287 // String returns the current value. 288 func (v *relationIdValue) String() string { 289 return v.value 290 } 291 292 // Set interprets value as a relation id, if possible, and returns an error 293 // if it is not known to the system. The parsed relation id will be written 294 // to v.result. 295 func (v *relationIdValue) Set(value string) error { 296 trim := value 297 if idx := strings.LastIndex(trim, ":"); idx != -1 { 298 trim = trim[idx+1:] 299 } 300 id, err := strconv.Atoi(trim) 301 if err != nil { 302 return fmt.Errorf("invalid relation id") 303 } 304 if _, err := v.ctx.Relation(id); err != nil { 305 return errors.Trace(err) 306 } 307 *v.result = id 308 v.value = value 309 return nil 310 } 311 312 // newStorageIdValue returns a gnuflag.Value for convenient parsing of storage 313 // ids in ctx. 314 func newStorageIdValue(ctx Context, result *names.StorageTag) (*storageIdValue, error) { 315 v := &storageIdValue{result: result, ctx: ctx} 316 if s, err := ctx.HookStorage(); err == nil { 317 *v.result = s.Tag() 318 } else if !errors.IsNotFound(err) { 319 return nil, errors.Trace(err) 320 } 321 return v, nil 322 } 323 324 // storageIdValue implements gnuflag.Value for use in storage commands. 325 type storageIdValue struct { 326 result *names.StorageTag 327 ctx Context 328 } 329 330 // String returns the current value. 331 func (v *storageIdValue) String() string { 332 if *v.result == (names.StorageTag{}) { 333 return "" 334 } 335 return v.result.Id() 336 } 337 338 // Set interprets value as a storage id, if possible, and returns an error 339 // if it is not known to the system. The parsed storage id will be written 340 // to v.result. 341 func (v *storageIdValue) Set(value string) error { 342 if !names.IsValidStorage(value) { 343 return errors.Errorf("invalid storage ID %q", value) 344 } 345 tag := names.NewStorageTag(value) 346 if _, err := v.ctx.Storage(tag); err != nil { 347 return errors.Trace(err) 348 } 349 *v.result = tag 350 return nil 351 }