github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/core/description/action.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package description
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/schema"
    11  )
    12  
    13  type actions struct {
    14  	Version  int       `yaml:"version"`
    15  	Actions_ []*action `yaml:"actions"`
    16  }
    17  
    18  type action struct {
    19  	Id_         string                 `yaml:"id"`
    20  	Receiver_   string                 `yaml:"receiver"`
    21  	Name_       string                 `yaml:"name"`
    22  	Parameters_ map[string]interface{} `yaml:"parameters"`
    23  	Enqueued_   time.Time              `yaml:"enqueued"`
    24  	// Can't use omitempty with time.Time, it just doesn't work
    25  	// (nothing is serialised), so use a pointer in the struct.
    26  	Started_   *time.Time             `yaml:"started,omitempty"`
    27  	Completed_ *time.Time             `yaml:"completed,omitempty"`
    28  	Status_    string                 `yaml:"status"`
    29  	Message_   string                 `yaml:"message"`
    30  	Results_   map[string]interface{} `yaml:"results"`
    31  }
    32  
    33  // Id implements Action.
    34  func (i *action) Id() string {
    35  	return i.Id_
    36  }
    37  
    38  // Receiver implements Action.
    39  func (i *action) Receiver() string {
    40  	return i.Receiver_
    41  }
    42  
    43  // Name implements Action.
    44  func (i *action) Name() string {
    45  	return i.Name_
    46  }
    47  
    48  // Parameters implements Action.
    49  func (i *action) Parameters() map[string]interface{} {
    50  	return i.Parameters_
    51  }
    52  
    53  // Enqueued implements Action.
    54  func (i *action) Enqueued() time.Time {
    55  	return i.Enqueued_
    56  }
    57  
    58  // Started implements Action.
    59  func (i *action) Started() time.Time {
    60  	var zero time.Time
    61  	if i.Started_ == nil {
    62  		return zero
    63  	}
    64  	return *i.Started_
    65  }
    66  
    67  // Completed implements Action.
    68  func (i *action) Completed() time.Time {
    69  	var zero time.Time
    70  	if i.Completed_ == nil {
    71  		return zero
    72  	}
    73  	return *i.Completed_
    74  }
    75  
    76  // Status implements Action.
    77  func (i *action) Status() string {
    78  	return i.Status_
    79  }
    80  
    81  // Message implements Action.
    82  func (i *action) Message() string {
    83  	return i.Message_
    84  }
    85  
    86  // Results implements Action.
    87  func (i *action) Results() map[string]interface{} {
    88  	return i.Results_
    89  }
    90  
    91  // ActionArgs is an argument struct used to create a
    92  // new internal action type that supports the Action interface.
    93  type ActionArgs struct {
    94  	Id         string
    95  	Receiver   string
    96  	Name       string
    97  	Parameters map[string]interface{}
    98  	Enqueued   time.Time
    99  	Started    time.Time
   100  	Completed  time.Time
   101  	Status     string
   102  	Message    string
   103  	Results    map[string]interface{}
   104  }
   105  
   106  func newAction(args ActionArgs) *action {
   107  	action := &action{
   108  		Receiver_:   args.Receiver,
   109  		Name_:       args.Name,
   110  		Parameters_: args.Parameters,
   111  		Enqueued_:   args.Enqueued,
   112  		Status_:     args.Status,
   113  		Message_:    args.Message,
   114  		Id_:         args.Id,
   115  		Results_:    args.Results,
   116  	}
   117  	if !args.Started.IsZero() {
   118  		value := args.Started
   119  		action.Started_ = &value
   120  	}
   121  	if !args.Completed.IsZero() {
   122  		value := args.Completed
   123  		action.Completed_ = &value
   124  	}
   125  	return action
   126  }
   127  
   128  func importActions(source map[string]interface{}) ([]*action, error) {
   129  	checker := versionedChecker("actions")
   130  	coerced, err := checker.Coerce(source, nil)
   131  	if err != nil {
   132  		return nil, errors.Annotatef(err, "actions version schema check failed")
   133  	}
   134  	valid := coerced.(map[string]interface{})
   135  
   136  	version := int(valid["version"].(int64))
   137  	importFunc, ok := actionDeserializationFuncs[version]
   138  	if !ok {
   139  		return nil, errors.NotValidf("version %d", version)
   140  	}
   141  	sourceList := valid["actions"].([]interface{})
   142  	return importActionList(sourceList, importFunc)
   143  }
   144  
   145  func importActionList(sourceList []interface{}, importFunc actionDeserializationFunc) ([]*action, error) {
   146  	result := make([]*action, 0, len(sourceList))
   147  	for i, value := range sourceList {
   148  		source, ok := value.(map[string]interface{})
   149  		if !ok {
   150  			return nil, errors.Errorf("unexpected value for action %d, %T", i, value)
   151  		}
   152  		action, err := importFunc(source)
   153  		if err != nil {
   154  			return nil, errors.Annotatef(err, "action %d", i)
   155  		}
   156  		result = append(result, action)
   157  	}
   158  	return result, nil
   159  }
   160  
   161  type actionDeserializationFunc func(map[string]interface{}) (*action, error)
   162  
   163  var actionDeserializationFuncs = map[int]actionDeserializationFunc{
   164  	1: importActionV1,
   165  }
   166  
   167  func importActionV1(source map[string]interface{}) (*action, error) {
   168  	fields := schema.Fields{
   169  		"receiver":   schema.String(),
   170  		"name":       schema.String(),
   171  		"parameters": schema.StringMap(schema.Any()),
   172  		"enqueued":   schema.Time(),
   173  		"started":    schema.Time(),
   174  		"completed":  schema.Time(),
   175  		"status":     schema.String(),
   176  		"message":    schema.String(),
   177  		"results":    schema.StringMap(schema.Any()),
   178  		"id":         schema.String(),
   179  	}
   180  	// Some values don't have to be there.
   181  	defaults := schema.Defaults{
   182  		"started":   time.Time{},
   183  		"completed": time.Time{},
   184  	}
   185  	checker := schema.FieldMap(fields, defaults)
   186  
   187  	coerced, err := checker.Coerce(source, nil)
   188  	if err != nil {
   189  		return nil, errors.Annotatef(err, "action v1 schema check failed")
   190  	}
   191  	valid := coerced.(map[string]interface{})
   192  	action := &action{
   193  		Id_:         valid["id"].(string),
   194  		Receiver_:   valid["receiver"].(string),
   195  		Name_:       valid["name"].(string),
   196  		Status_:     valid["status"].(string),
   197  		Message_:    valid["message"].(string),
   198  		Parameters_: valid["parameters"].(map[string]interface{}),
   199  		Enqueued_:   valid["enqueued"].(time.Time).UTC(),
   200  		Results_:    valid["results"].(map[string]interface{}),
   201  	}
   202  
   203  	started := valid["started"].(time.Time)
   204  	if !started.IsZero() {
   205  		started = started.UTC()
   206  		action.Started_ = &started
   207  	}
   208  	completed := valid["completed"].(time.Time)
   209  	if !started.IsZero() {
   210  		completed = completed.UTC()
   211  		action.Completed_ = &completed
   212  	}
   213  	return action, nil
   214  }