github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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 "gopkg.in/juju/charm.v6-unstable" 14 "gopkg.in/juju/names.v2" 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 ContextComponents 54 ContextRelations 55 ContextVersion 56 } 57 58 // UnitHookContext is the context for a unit hook. 59 type UnitHookContext interface { 60 HookContext 61 } 62 63 // RelationHookContext is the context for a relation hook. 64 type RelationHookContext interface { 65 HookContext 66 relationHookContext 67 } 68 69 type relationHookContext interface { 70 // HookRelation returns the ContextRelation associated with the executing 71 // hook if it was found, or an error if it was not found (or is not available). 72 HookRelation() (ContextRelation, error) 73 74 // RemoteUnitName returns the name of the remote unit the hook execution 75 // is associated with if it was found, and an error if it was not found or is not 76 // available. 77 RemoteUnitName() (string, error) 78 } 79 80 // ActionHookContext is the context for an action hook. 81 type ActionHookContext interface { 82 HookContext 83 actionHookContext 84 } 85 86 type actionHookContext interface { 87 // ActionParams returns the map of params passed with an Action. 88 ActionParams() (map[string]interface{}, error) 89 90 // UpdateActionResults inserts new values for use with action-set. 91 // The results struct will be delivered to the controller upon 92 // completion of the Action. 93 UpdateActionResults(keys []string, value string) error 94 95 // SetActionMessage sets a message for the Action. 96 SetActionMessage(string) error 97 98 // SetActionFailed sets a failure state for the Action. 99 SetActionFailed() error 100 } 101 102 // ContextUnit is the part of a hook context related to the unit. 103 type ContextUnit interface { 104 // UnitName returns the executing unit's name. 105 UnitName() string 106 107 // Config returns the current service configuration of the executing unit. 108 ConfigSettings() (charm.Settings, error) 109 } 110 111 // ContextStatus is the part of a hook context related to the unit's status. 112 type ContextStatus interface { 113 // UnitStatus returns the executing unit's current status. 114 UnitStatus() (*StatusInfo, error) 115 116 // SetUnitStatus updates the unit's status. 117 SetUnitStatus(StatusInfo) error 118 119 // ApplicationStatus returns the executing unit's service status 120 // (including all units). 121 ApplicationStatus() (ApplicationStatusInfo, error) 122 123 // SetApplicationStatus updates the status for the unit's service. 124 SetApplicationStatus(StatusInfo) error 125 } 126 127 // ContextInstance is the part of a hook context related to the unit's instance. 128 type ContextInstance interface { 129 // AvailabilityZone returns the executing unit's availability zone or an error 130 // if it was not found (or is not available). 131 AvailabilityZone() (string, error) 132 133 // RequestReboot will set the reboot flag to true on the machine agent 134 RequestReboot(prio RebootPriority) error 135 } 136 137 // ContextNetworking is the part of a hook context related to network 138 // interface of the unit's instance. 139 type ContextNetworking interface { 140 // PublicAddress returns the executing unit's public address or an 141 // error if it is not available. 142 PublicAddress() (string, error) 143 144 // PrivateAddress returns the executing unit's private address or an 145 // error if it is not available. 146 PrivateAddress() (string, error) 147 148 // OpenPorts marks the supplied port range for opening when the 149 // executing unit's service is exposed. 150 OpenPorts(protocol string, fromPort, toPort int) error 151 152 // ClosePorts ensures the supplied port range is closed even when 153 // the executing unit's service is exposed (unless it is opened 154 // separately by a co- located unit). 155 ClosePorts(protocol string, fromPort, toPort int) error 156 157 // OpenedPorts returns all port ranges currently opened by this 158 // unit on its assigned machine. The result is sorted first by 159 // protocol, then by number. 160 OpenedPorts() []network.PortRange 161 162 // NetworkConfig returns the network configuration for the unit and the 163 // given bindingName. 164 // 165 // TODO(dimitern): Currently, only the Address is populated, add the 166 // rest later. 167 // 168 // LKK Card: https://canonical.leankit.com/Boards/View/101652562/119258804 169 NetworkConfig(bindingName string) ([]params.NetworkConfig, error) 170 } 171 172 // ContextLeadership is the part of a hook context related to the 173 // unit leadership. 174 type ContextLeadership interface { 175 // IsLeader returns true if the local unit is known to be leader for at 176 // least the next 30s. 177 IsLeader() (bool, error) 178 179 // LeaderSettings returns the current leader settings. Once leader settings 180 // have been read in a given context, they will not be updated other than 181 // via successful calls to WriteLeaderSettings. 182 LeaderSettings() (map[string]string, error) 183 184 // WriteLeaderSettings writes the supplied settings directly to state, or 185 // fails if the local unit is not the service's leader. 186 WriteLeaderSettings(map[string]string) error 187 } 188 189 // ContextMetrics is the part of a hook context related to metrics. 190 type ContextMetrics interface { 191 // AddMetric records a metric to return after hook execution. 192 AddMetric(string, string, time.Time) error 193 } 194 195 // ContextStorage is the part of a hook context related to storage 196 // resources associated with the unit. 197 type ContextStorage interface { 198 // StorageTags returns a list of tags for storage instances 199 // attached to the unit or an error if they are not available. 200 StorageTags() ([]names.StorageTag, error) 201 202 // Storage returns the ContextStorageAttachment with the supplied 203 // tag if it was found, and an error if it was not found or is not 204 // available to the context. 205 Storage(names.StorageTag) (ContextStorageAttachment, error) 206 207 // HookStorage returns the storage attachment associated 208 // the executing hook if it was found, and an error if it 209 // was not found or is not available. 210 HookStorage() (ContextStorageAttachment, error) 211 212 // AddUnitStorage saves storage constraints in the context. 213 AddUnitStorage(map[string]params.StorageConstraints) error 214 } 215 216 // ContextComponents exposes modular Juju components as they relate to 217 // the unit in the context of the hook. 218 type ContextComponents interface { 219 // Component returns the ContextComponent with the supplied name if 220 // it was found. 221 Component(name string) (ContextComponent, error) 222 } 223 224 // ContextRelations exposes the relations associated with the unit. 225 type ContextRelations interface { 226 // Relation returns the relation with the supplied id if it was found, and 227 // an error if it was not found or is not available. 228 Relation(id int) (ContextRelation, error) 229 230 // RelationIds returns the ids of all relations the executing unit is 231 // currently participating in or an error if they are not available. 232 RelationIds() ([]int, error) 233 } 234 235 // ContextComponent is a single modular Juju component as it relates to 236 // the current unit and hook. Components should implement this interfaces 237 // in a type-safe way. Ensuring checked type-conversions are preformed on 238 // the result and value interfaces. You will use the runner.RegisterComponentFunc 239 // to register a your components concrete ContextComponent implementation. 240 // 241 // See: process/context/context.go for an implementation example. 242 // 243 type ContextComponent interface { 244 // Flush pushes the component's data to Juju state. 245 // In the Flush implementation, call your components API. 246 Flush() error 247 } 248 249 // ContextRelation expresses the capabilities of a hook with respect to a relation. 250 type ContextRelation interface { 251 252 // Id returns an integer which uniquely identifies the relation. 253 Id() int 254 255 // Name returns the name the locally executing charm assigned to this relation. 256 Name() string 257 258 // FakeId returns a string of the form "relation-name:123", which uniquely 259 // identifies the relation to the hook. In reality, the identification 260 // of the relation is the integer following the colon, but the composed 261 // name is useful to humans observing it. 262 FakeId() string 263 264 // Settings allows read/write access to the local unit's settings in 265 // this relation. 266 Settings() (Settings, error) 267 268 // UnitNames returns a list of the remote units in the relation. 269 UnitNames() []string 270 271 // ReadSettings returns the settings of any remote unit in the relation. 272 ReadSettings(unit string) (params.Settings, error) 273 } 274 275 // ContextStorageAttachment expresses the capabilities of a hook with 276 // respect to a storage attachment. 277 type ContextStorageAttachment interface { 278 279 // Tag returns a tag which uniquely identifies the storage attachment 280 // in the context of the unit. 281 Tag() names.StorageTag 282 283 // Kind returns the kind of the storage. 284 Kind() storage.StorageKind 285 286 // Location returns the location of the storage: the mount point for 287 // filesystem-kind stores, and the device path for block-kind stores. 288 Location() string 289 } 290 291 // ContextVersion expresses the parts of a hook context related to 292 // reporting workload versions. 293 type ContextVersion interface { 294 295 // UnitWorkloadVersion returns the currently set workload version for 296 // the unit. 297 UnitWorkloadVersion() (string, error) 298 299 // SetUnitWorkloadVersion updates the workload version for the unit. 300 SetUnitWorkloadVersion(string) error 301 } 302 303 // Settings is implemented by types that manipulate unit settings. 304 type Settings interface { 305 Map() params.Settings 306 Set(string, string) 307 Delete(string) 308 } 309 310 // newRelationIdValue returns a gnuflag.Value for convenient parsing of relation 311 // ids in ctx. 312 func newRelationIdValue(ctx Context, result *int) (*relationIdValue, error) { 313 v := &relationIdValue{result: result, ctx: ctx} 314 id := -1 315 if r, err := ctx.HookRelation(); err == nil { 316 id = r.Id() 317 v.value = r.FakeId() 318 } else if !errors.IsNotFound(err) { 319 return nil, errors.Trace(err) 320 } 321 *result = id 322 return v, nil 323 } 324 325 // relationIdValue implements gnuflag.Value for use in relation commands. 326 type relationIdValue struct { 327 result *int 328 ctx Context 329 value string 330 } 331 332 // String returns the current value. 333 func (v *relationIdValue) String() string { 334 return v.value 335 } 336 337 // Set interprets value as a relation id, if possible, and returns an error 338 // if it is not known to the system. The parsed relation id will be written 339 // to v.result. 340 func (v *relationIdValue) Set(value string) error { 341 trim := value 342 if idx := strings.LastIndex(trim, ":"); idx != -1 { 343 trim = trim[idx+1:] 344 } 345 id, err := strconv.Atoi(trim) 346 if err != nil { 347 return fmt.Errorf("invalid relation id") 348 } 349 if _, err := v.ctx.Relation(id); err != nil { 350 return errors.Trace(err) 351 } 352 *v.result = id 353 v.value = value 354 return nil 355 } 356 357 // newStorageIdValue returns a gnuflag.Value for convenient parsing of storage 358 // ids in ctx. 359 func newStorageIdValue(ctx Context, result *names.StorageTag) (*storageIdValue, error) { 360 v := &storageIdValue{result: result, ctx: ctx} 361 if s, err := ctx.HookStorage(); err == nil { 362 *v.result = s.Tag() 363 } else if !errors.IsNotFound(err) { 364 return nil, errors.Trace(err) 365 } 366 return v, nil 367 } 368 369 // storageIdValue implements gnuflag.Value for use in storage commands. 370 type storageIdValue struct { 371 result *names.StorageTag 372 ctx Context 373 } 374 375 // String returns the current value. 376 func (v *storageIdValue) String() string { 377 if *v.result == (names.StorageTag{}) { 378 return "" 379 } 380 return v.result.Id() 381 } 382 383 // Set interprets value as a storage id, if possible, and returns an error 384 // if it is not known to the system. The parsed storage id will be written 385 // to v.result. 386 func (v *storageIdValue) Set(value string) error { 387 if !names.IsValidStorage(value) { 388 return errors.Errorf("invalid storage ID %q", value) 389 } 390 tag := names.NewStorageTag(value) 391 if _, err := v.ctx.Storage(tag); err != nil { 392 return errors.Trace(err) 393 } 394 *v.result = tag 395 return nil 396 }