github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/state/multiwatcher/multiwatcher.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package multiwatcher 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "fmt" 10 "time" 11 12 "gopkg.in/juju/charm.v6-unstable" 13 14 "github.com/juju/juju/constraints" 15 "github.com/juju/juju/instance" 16 "github.com/juju/juju/network" 17 ) 18 19 // Life describes the lifecycle state of an entity ("alive", "dying" 20 // or "dead"). 21 type Life string 22 23 // Status represents the status of an entity. 24 // It could be a service, unit, machine or its agent. 25 type Status string 26 27 // EntityInfo is implemented by all entity Info types. 28 type EntityInfo interface { 29 // EntityId returns an identifier that will uniquely 30 // identify the entity within its kind 31 EntityId() EntityId 32 } 33 34 // EntityId uniquely identifies an entity being tracked by the 35 // multiwatcherStore. 36 type EntityId struct { 37 Kind string 38 EnvUUID string 39 Id string 40 } 41 42 // Delta holds details of a change to the environment. 43 type Delta struct { 44 // If Removed is true, the entity has been removed; 45 // otherwise it has been created or changed. 46 Removed bool 47 // Entity holds data about the entity that has changed. 48 Entity EntityInfo 49 } 50 51 // MarshalJSON implements json.Marshaler. 52 func (d *Delta) MarshalJSON() ([]byte, error) { 53 b, err := json.Marshal(d.Entity) 54 if err != nil { 55 return nil, err 56 } 57 var buf bytes.Buffer 58 buf.WriteByte('[') 59 c := "change" 60 if d.Removed { 61 c = "remove" 62 } 63 fmt.Fprintf(&buf, "%q,%q,", d.Entity.EntityId().Kind, c) 64 buf.Write(b) 65 buf.WriteByte(']') 66 return buf.Bytes(), nil 67 } 68 69 // UnmarshalJSON implements json.Unmarshaler. 70 func (d *Delta) UnmarshalJSON(data []byte) error { 71 var elements []json.RawMessage 72 if err := json.Unmarshal(data, &elements); err != nil { 73 return err 74 } 75 if len(elements) != 3 { 76 return fmt.Errorf( 77 "Expected 3 elements in top-level of JSON but got %d", 78 len(elements)) 79 } 80 var entityKind, operation string 81 if err := json.Unmarshal(elements[0], &entityKind); err != nil { 82 return err 83 } 84 if err := json.Unmarshal(elements[1], &operation); err != nil { 85 return err 86 } 87 if operation == "remove" { 88 d.Removed = true 89 } else if operation != "change" { 90 return fmt.Errorf("Unexpected operation %q", operation) 91 } 92 switch entityKind { 93 case "environment": 94 d.Entity = new(EnvironmentInfo) 95 case "machine": 96 d.Entity = new(MachineInfo) 97 case "service": 98 d.Entity = new(ServiceInfo) 99 case "unit": 100 d.Entity = new(UnitInfo) 101 case "relation": 102 d.Entity = new(RelationInfo) 103 case "annotation": 104 d.Entity = new(AnnotationInfo) 105 case "block": 106 d.Entity = new(BlockInfo) 107 case "action": 108 d.Entity = new(ActionInfo) 109 default: 110 return fmt.Errorf("Unexpected entity name %q", entityKind) 111 } 112 return json.Unmarshal(elements[2], &d.Entity) 113 } 114 115 // When remote units leave scope, their ids will be noted in the 116 // Departed field, and no further events will be sent for those units. 117 type RelationUnitsChange struct { 118 Changed map[string]UnitSettings 119 Departed []string 120 } 121 122 // UnitSettings holds information about a service unit's settings 123 // within a relation. 124 type UnitSettings struct { 125 Version int64 126 } 127 128 // MachineInfo holds the information about a machine 129 // that is tracked by multiwatcherStore. 130 type MachineInfo struct { 131 EnvUUID string 132 Id string 133 InstanceId string 134 Status Status 135 StatusInfo string 136 StatusData map[string]interface{} 137 Life Life 138 Series string 139 SupportedContainers []instance.ContainerType 140 SupportedContainersKnown bool 141 HardwareCharacteristics *instance.HardwareCharacteristics `json:",omitempty"` 142 Jobs []MachineJob 143 Addresses []network.Address 144 HasVote bool 145 WantsVote bool 146 } 147 148 // EntityId returns a unique identifier for a machine across 149 // environments. 150 func (i *MachineInfo) EntityId() EntityId { 151 return EntityId{ 152 Kind: "machine", 153 EnvUUID: i.EnvUUID, 154 Id: i.Id, 155 } 156 } 157 158 // StatusInfo holds the unit and machine status information. It is 159 // used by ServiceInfo and UnitInfo. 160 type StatusInfo struct { 161 Err error 162 Current Status 163 Message string 164 Since *time.Time 165 Version string 166 Data map[string]interface{} 167 } 168 169 // ServiceInfo holds the information about a service that is tracked 170 // by multiwatcherStore. 171 type ServiceInfo struct { 172 EnvUUID string 173 Name string 174 Exposed bool 175 CharmURL string 176 OwnerTag string 177 Life Life 178 MinUnits int 179 Constraints constraints.Value 180 Config map[string]interface{} 181 Subordinate bool 182 Status StatusInfo 183 } 184 185 // EntityId returns a unique identifier for a service across 186 // environments. 187 func (i *ServiceInfo) EntityId() EntityId { 188 return EntityId{ 189 Kind: "service", 190 EnvUUID: i.EnvUUID, 191 Id: i.Name, 192 } 193 } 194 195 // UnitInfo holds the information about a unit 196 // that is tracked by multiwatcherStore. 197 type UnitInfo struct { 198 EnvUUID string 199 Name string 200 Service string 201 Series string 202 CharmURL string 203 PublicAddress string 204 PrivateAddress string 205 MachineId string 206 Ports []network.Port 207 PortRanges []network.PortRange 208 Subordinate bool 209 // The following 3 status values are deprecated. 210 Status Status 211 StatusInfo string 212 StatusData map[string]interface{} 213 // Workload and agent state are modelled separately. 214 WorkloadStatus StatusInfo 215 AgentStatus StatusInfo 216 } 217 218 // EntityId returns a unique identifier for a unit across 219 // environments. 220 func (i *UnitInfo) EntityId() EntityId { 221 return EntityId{ 222 Kind: "unit", 223 EnvUUID: i.EnvUUID, 224 Id: i.Name, 225 } 226 } 227 228 // ActionInfo holds the information about a action that is tracked by 229 // multiwatcherStore. 230 type ActionInfo struct { 231 EnvUUID string 232 Id string 233 Receiver string 234 Name string 235 Parameters map[string]interface{} 236 Status string 237 Message string 238 Results map[string]interface{} 239 Enqueued time.Time 240 Started time.Time 241 Completed time.Time 242 } 243 244 // EntityId returns a unique identifier for an action across 245 // environments. 246 func (i *ActionInfo) EntityId() EntityId { 247 return EntityId{ 248 Kind: "action", 249 EnvUUID: i.EnvUUID, 250 Id: i.Id, 251 } 252 } 253 254 // RelationInfo holds the information about a relation that is tracked 255 // by multiwatcherStore. 256 type RelationInfo struct { 257 EnvUUID string 258 Key string 259 Id int 260 Endpoints []Endpoint 261 } 262 263 // Endpoint holds a service-relation pair. 264 type Endpoint struct { 265 ServiceName string 266 Relation charm.Relation 267 } 268 269 // EntityId returns a unique identifier for a relation across 270 // environments. 271 func (i *RelationInfo) EntityId() EntityId { 272 return EntityId{ 273 Kind: "relation", 274 EnvUUID: i.EnvUUID, 275 Id: i.Key, 276 } 277 } 278 279 // AnnotationInfo holds the information about an annotation that is 280 // tracked by multiwatcherStore. 281 type AnnotationInfo struct { 282 EnvUUID string 283 Tag string 284 Annotations map[string]string 285 } 286 287 // EntityId returns a unique identifier for an annotation across 288 // environments. 289 func (i *AnnotationInfo) EntityId() EntityId { 290 return EntityId{ 291 Kind: "annotation", 292 EnvUUID: i.EnvUUID, 293 Id: i.Tag, 294 } 295 } 296 297 // MachineJob values define responsibilities that machines may be 298 // expected to fulfil. 299 type MachineJob string 300 301 const ( 302 JobHostUnits MachineJob = "JobHostUnits" 303 JobManageEnviron MachineJob = "JobManageEnviron" 304 JobManageNetworking MachineJob = "JobManageNetworking" 305 306 // Deprecated in 1.18 307 JobManageStateDeprecated MachineJob = "JobManageState" 308 ) 309 310 // NeedsState returns true if the job requires a state connection. 311 func (job MachineJob) NeedsState() bool { 312 return job == JobManageEnviron 313 } 314 315 // AnyJobNeedsState returns true if any of the provided jobs 316 // require a state connection. 317 func AnyJobNeedsState(jobs ...MachineJob) bool { 318 for _, j := range jobs { 319 if j.NeedsState() { 320 return true 321 } 322 } 323 return false 324 } 325 326 // BlockInfo holds the information about a block that is tracked by 327 // multiwatcherStore. 328 type BlockInfo struct { 329 EnvUUID string 330 Id string 331 Type BlockType 332 Message string 333 Tag string 334 } 335 336 // EntityId returns a unique identifier for a block across 337 // environments. 338 func (i *BlockInfo) EntityId() EntityId { 339 return EntityId{ 340 Kind: "block", 341 EnvUUID: i.EnvUUID, 342 Id: i.Id, 343 } 344 } 345 346 // BlockType values define environment block type. 347 type BlockType string 348 349 const ( 350 // BlockDestroy type identifies destroy blocks. 351 BlockDestroy BlockType = "BlockDestroy" 352 353 // BlockRemove type identifies remove blocks. 354 BlockRemove BlockType = "BlockRemove" 355 356 // BlockChange type identifies change blocks. 357 BlockChange BlockType = "BlockChange" 358 ) 359 360 // EnvironmentInfo holds the information about an environment that is 361 // tracked by multiwatcherStore. 362 type EnvironmentInfo struct { 363 EnvUUID string 364 Name string 365 Life Life 366 Owner string 367 ServerUUID string 368 } 369 370 // EntityId returns a unique identifier for an environment. 371 func (i *EnvironmentInfo) EntityId() EntityId { 372 return EntityId{ 373 Kind: "environment", 374 EnvUUID: i.EnvUUID, 375 Id: i.EnvUUID, 376 } 377 }