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