github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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.v5" 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 type EntityId struct { 35 Kind string 36 Id interface{} 37 } 38 39 // Delta holds details of a change to the environment. 40 type Delta struct { 41 // If Removed is true, the entity has been removed; 42 // otherwise it has been created or changed. 43 Removed bool 44 // Entity holds data about the entity that has changed. 45 Entity EntityInfo 46 } 47 48 // MarshalJSON implements json.Marshaler. 49 func (d *Delta) MarshalJSON() ([]byte, error) { 50 b, err := json.Marshal(d.Entity) 51 if err != nil { 52 return nil, err 53 } 54 var buf bytes.Buffer 55 buf.WriteByte('[') 56 c := "change" 57 if d.Removed { 58 c = "remove" 59 } 60 fmt.Fprintf(&buf, "%q,%q,", d.Entity.EntityId().Kind, c) 61 buf.Write(b) 62 buf.WriteByte(']') 63 return buf.Bytes(), nil 64 } 65 66 // UnmarshalJSON implements json.Unmarshaler. 67 func (d *Delta) UnmarshalJSON(data []byte) error { 68 var elements []json.RawMessage 69 if err := json.Unmarshal(data, &elements); err != nil { 70 return err 71 } 72 if len(elements) != 3 { 73 return fmt.Errorf( 74 "Expected 3 elements in top-level of JSON but got %d", 75 len(elements)) 76 } 77 var entityKind, operation string 78 if err := json.Unmarshal(elements[0], &entityKind); err != nil { 79 return err 80 } 81 if err := json.Unmarshal(elements[1], &operation); err != nil { 82 return err 83 } 84 if operation == "remove" { 85 d.Removed = true 86 } else if operation != "change" { 87 return fmt.Errorf("Unexpected operation %q", operation) 88 } 89 switch entityKind { 90 case "machine": 91 d.Entity = new(MachineInfo) 92 case "service": 93 d.Entity = new(ServiceInfo) 94 case "unit": 95 d.Entity = new(UnitInfo) 96 case "relation": 97 d.Entity = new(RelationInfo) 98 case "annotation": 99 d.Entity = new(AnnotationInfo) 100 case "block": 101 d.Entity = new(BlockInfo) 102 default: 103 return fmt.Errorf("Unexpected entity name %q", entityKind) 104 } 105 return json.Unmarshal(elements[2], &d.Entity) 106 } 107 108 // When remote units leave scope, their ids will be noted in the 109 // Departed field, and no further events will be sent for those units. 110 type RelationUnitsChange struct { 111 Changed map[string]UnitSettings 112 Departed []string 113 } 114 115 // UnitSettings holds information about a service unit's settings 116 // within a relation. 117 type UnitSettings struct { 118 Version int64 119 } 120 121 // MachineInfo holds the information about a Machine 122 // that is watched by StateMultiwatcher. 123 type MachineInfo struct { 124 Id string `bson:"_id"` 125 InstanceId string 126 Status Status 127 StatusInfo string 128 StatusData map[string]interface{} 129 Life Life 130 Series string 131 SupportedContainers []instance.ContainerType 132 SupportedContainersKnown bool 133 HardwareCharacteristics *instance.HardwareCharacteristics `json:",omitempty"` 134 Jobs []MachineJob 135 Addresses []network.Address 136 HasVote bool 137 WantsVote bool 138 } 139 140 func (i *MachineInfo) EntityId() EntityId { 141 return EntityId{ 142 Kind: "machine", 143 Id: i.Id, 144 } 145 } 146 147 type StatusInfo struct { 148 Err error 149 Current Status 150 Message string 151 Since *time.Time 152 Version string 153 Data map[string]interface{} 154 } 155 156 type ServiceInfo struct { 157 Name string `bson:"_id"` 158 Exposed bool 159 CharmURL string 160 OwnerTag string 161 Life Life 162 MinUnits int 163 Constraints constraints.Value 164 Config map[string]interface{} 165 Subordinate bool 166 Status StatusInfo 167 } 168 169 func (i *ServiceInfo) EntityId() EntityId { 170 return EntityId{ 171 Kind: "service", 172 Id: i.Name, 173 } 174 } 175 176 type UnitInfo struct { 177 Name string `bson:"_id"` 178 Service string 179 Series string 180 CharmURL string 181 PublicAddress string 182 PrivateAddress string 183 MachineId string 184 Ports []network.Port 185 PortRanges []network.PortRange 186 Subordinate bool 187 // The following 3 status values are deprecated. 188 Status Status 189 StatusInfo string 190 StatusData map[string]interface{} 191 // Workload and agent state are modelled separately. 192 WorkloadStatus StatusInfo 193 AgentStatus StatusInfo 194 } 195 196 func (i *UnitInfo) EntityId() EntityId { 197 return EntityId{ 198 Kind: "unit", 199 Id: i.Name, 200 } 201 } 202 203 type ActionInfo struct { 204 Id string `bson:"_id"` 205 Receiver string `bson:"receiver"` 206 Name string `bson:"name"` 207 Parameters map[string]interface{} `bson:"parameters"` 208 Status string `bson:"status"` 209 Message string `bson:"message"` 210 Results map[string]interface{} `bson:"results"` 211 Enqueued time.Time `bson:"enqueued"` 212 Started time.Time `bson:"started"` 213 Completed time.Time `bson:"completed"` 214 } 215 216 func (i *ActionInfo) EntityId() EntityId { 217 return EntityId{ 218 Kind: "action", 219 Id: i.Id, 220 } 221 } 222 223 type RelationInfo struct { 224 Key string `bson:"_id"` 225 Id int 226 Endpoints []Endpoint 227 } 228 229 func (i *RelationInfo) EntityId() EntityId { 230 return EntityId{ 231 Kind: "relation", 232 Id: i.Key, 233 } 234 } 235 236 type AnnotationInfo struct { 237 Tag string 238 Annotations map[string]string 239 } 240 241 func (i *AnnotationInfo) EntityId() EntityId { 242 return EntityId{ 243 Kind: "annotation", 244 Id: i.Tag, 245 } 246 } 247 248 type Endpoint struct { 249 ServiceName string 250 Relation charm.Relation 251 } 252 253 // MachineJob values define responsibilities that machines may be 254 // expected to fulfil. 255 type MachineJob string 256 257 const ( 258 JobHostUnits MachineJob = "JobHostUnits" 259 JobManageEnviron MachineJob = "JobManageEnviron" 260 JobManageNetworking MachineJob = "JobManageNetworking" 261 262 // Deprecated in 1.18 263 JobManageStateDeprecated MachineJob = "JobManageState" 264 ) 265 266 // NeedsState returns true if the job requires a state connection. 267 func (job MachineJob) NeedsState() bool { 268 return job == JobManageEnviron 269 } 270 271 // AnyJobNeedsState returns true if any of the provided jobs 272 // require a state connection. 273 func AnyJobNeedsState(jobs ...MachineJob) bool { 274 for _, j := range jobs { 275 if j.NeedsState() { 276 return true 277 } 278 } 279 return false 280 } 281 282 // BlockInfo holds the information about blocks 283 // in this environment that are watched. 284 type BlockInfo struct { 285 Id string `bson:"_id"` 286 Type BlockType `bson:"type"` 287 Message string `bson:"message,omitempty"` 288 Tag string `bson:"tag"` 289 } 290 291 // EntityId returns block id. 292 func (i *BlockInfo) EntityId() EntityId { 293 return EntityId{ 294 Kind: "block", 295 Id: i.Id, 296 } 297 } 298 299 // BlockType values define environment block type. 300 type BlockType string 301 302 const ( 303 // BlockDestroy type identifies destroy blocks. 304 BlockDestroy BlockType = "BlockDestroy" 305 306 // BlockRemove type identifies remove blocks. 307 BlockRemove BlockType = "BlockRemove" 308 309 // BlockChange type identifies change blocks. 310 BlockChange BlockType = "BlockChange" 311 )