github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/core/description/constraints.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  	"github.com/juju/errors"
     8  	"github.com/juju/schema"
     9  )
    10  
    11  // ConstraintsArgs is an argument struct to construct Constraints.
    12  type ConstraintsArgs struct {
    13  	Architecture string
    14  	Container    string
    15  	CpuCores     uint64
    16  	CpuPower     uint64
    17  	InstanceType string
    18  	Memory       uint64
    19  	RootDisk     uint64
    20  
    21  	Spaces []string
    22  	Tags   []string
    23  }
    24  
    25  func newConstraints(args ConstraintsArgs) *constraints {
    26  	// If the ConstraintsArgs are all empty, then we return
    27  	// nil to indicate that there are no constraints.
    28  	if args.empty() {
    29  		return nil
    30  	}
    31  
    32  	tags := make([]string, len(args.Tags))
    33  	copy(tags, args.Tags)
    34  	spaces := make([]string, len(args.Spaces))
    35  	copy(spaces, args.Spaces)
    36  	return &constraints{
    37  		Version:       1,
    38  		Architecture_: args.Architecture,
    39  		Container_:    args.Container,
    40  		CpuCores_:     args.CpuCores,
    41  		CpuPower_:     args.CpuPower,
    42  		InstanceType_: args.InstanceType,
    43  		Memory_:       args.Memory,
    44  		RootDisk_:     args.RootDisk,
    45  		Spaces_:       spaces,
    46  		Tags_:         tags,
    47  	}
    48  }
    49  
    50  type constraints struct {
    51  	Version int `yaml:"version"`
    52  
    53  	Architecture_ string `yaml:"architecture,omitempty"`
    54  	Container_    string `yaml:"container,omitempty"`
    55  	CpuCores_     uint64 `yaml:"cpu-cores,omitempty"`
    56  	CpuPower_     uint64 `yaml:"cpu-power,omitempty"`
    57  	InstanceType_ string `yaml:"instance-type,omitempty"`
    58  	Memory_       uint64 `yaml:"memory,omitempty"`
    59  	RootDisk_     uint64 `yaml:"root-disk,omitempty"`
    60  
    61  	Spaces_ []string `yaml:"spaces,omitempty"`
    62  	Tags_   []string `yaml:"tags,omitempty"`
    63  }
    64  
    65  // Architecture implements Constraints.
    66  func (c *constraints) Architecture() string {
    67  	return c.Architecture_
    68  }
    69  
    70  // Container implements Constraints.
    71  func (c *constraints) Container() string {
    72  	return c.Container_
    73  }
    74  
    75  // CpuCores implements Constraints.
    76  func (c *constraints) CpuCores() uint64 {
    77  	return c.CpuCores_
    78  }
    79  
    80  // CpuPower implements Constraints.
    81  func (c *constraints) CpuPower() uint64 {
    82  	return c.CpuPower_
    83  }
    84  
    85  // InstanceType implements Constraints.
    86  func (c *constraints) InstanceType() string {
    87  	return c.InstanceType_
    88  }
    89  
    90  // Memory implements Constraints.
    91  func (c *constraints) Memory() uint64 {
    92  	return c.Memory_
    93  }
    94  
    95  // RootDisk implements Constraints.
    96  func (c *constraints) RootDisk() uint64 {
    97  	return c.RootDisk_
    98  }
    99  
   100  // Spaces implements Constraints.
   101  func (c *constraints) Spaces() []string {
   102  	var spaces []string
   103  	if count := len(c.Spaces_); count > 0 {
   104  		spaces = make([]string, count)
   105  		copy(spaces, c.Spaces_)
   106  	}
   107  	return spaces
   108  }
   109  
   110  // Tags implements Constraints.
   111  func (c *constraints) Tags() []string {
   112  	var tags []string
   113  	if count := len(c.Tags_); count > 0 {
   114  		tags = make([]string, count)
   115  		copy(tags, c.Tags_)
   116  	}
   117  	return tags
   118  }
   119  
   120  func importConstraints(source map[string]interface{}) (*constraints, error) {
   121  	version, err := getVersion(source)
   122  	if err != nil {
   123  		return nil, errors.Annotate(err, "constraints version schema check failed")
   124  	}
   125  
   126  	importFunc, ok := constraintsDeserializationFuncs[version]
   127  	if !ok {
   128  		return nil, errors.NotValidf("version %d", version)
   129  	}
   130  
   131  	return importFunc(source)
   132  }
   133  
   134  type constraintsDeserializationFunc func(map[string]interface{}) (*constraints, error)
   135  
   136  var constraintsDeserializationFuncs = map[int]constraintsDeserializationFunc{
   137  	1: importConstraintsV1,
   138  }
   139  
   140  func importConstraintsV1(source map[string]interface{}) (*constraints, error) {
   141  	fields := schema.Fields{
   142  		"architecture":  schema.String(),
   143  		"container":     schema.String(),
   144  		"cpu-cores":     schema.Uint(),
   145  		"cpu-power":     schema.Uint(),
   146  		"instance-type": schema.String(),
   147  		"memory":        schema.Uint(),
   148  		"root-disk":     schema.Uint(),
   149  
   150  		"spaces": schema.List(schema.String()),
   151  		"tags":   schema.List(schema.String()),
   152  	}
   153  	// Some values don't have to be there.
   154  	defaults := schema.Defaults{
   155  		"architecture":  "",
   156  		"container":     "",
   157  		"cpu-cores":     uint64(0),
   158  		"cpu-power":     uint64(0),
   159  		"instance-type": "",
   160  		"memory":        uint64(0),
   161  		"root-disk":     uint64(0),
   162  
   163  		"spaces": schema.Omit,
   164  		"tags":   schema.Omit,
   165  	}
   166  	checker := schema.FieldMap(fields, defaults)
   167  
   168  	coerced, err := checker.Coerce(source, nil)
   169  	if err != nil {
   170  		return nil, errors.Annotatef(err, "constraints v1 schema check failed")
   171  	}
   172  	valid := coerced.(map[string]interface{})
   173  	// From here we know that the map returned from the schema coercion
   174  	// contains fields of the right type.
   175  
   176  	return &constraints{
   177  		Version:       1,
   178  		Architecture_: valid["architecture"].(string),
   179  		Container_:    valid["container"].(string),
   180  		CpuCores_:     valid["cpu-cores"].(uint64),
   181  		CpuPower_:     valid["cpu-power"].(uint64),
   182  		InstanceType_: valid["instance-type"].(string),
   183  		Memory_:       valid["memory"].(uint64),
   184  		RootDisk_:     valid["root-disk"].(uint64),
   185  
   186  		Spaces_: convertToStringSlice(valid["spaces"]),
   187  		Tags_:   convertToStringSlice(valid["tags"]),
   188  	}, nil
   189  }
   190  
   191  func addConstraintsSchema(fields schema.Fields, defaults schema.Defaults) {
   192  	fields["constraints"] = schema.StringMap(schema.Any())
   193  	defaults["constraints"] = schema.Omit
   194  }
   195  
   196  func (c ConstraintsArgs) empty() bool {
   197  	return c.Architecture == "" &&
   198  		c.Container == "" &&
   199  		c.CpuCores == 0 &&
   200  		c.CpuPower == 0 &&
   201  		c.InstanceType == "" &&
   202  		c.Memory == 0 &&
   203  		c.RootDisk == 0 &&
   204  		c.Spaces == nil &&
   205  		c.Tags == nil
   206  }