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