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  }