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  }