1
from collections import namedtuple
3
from string import ascii_lowercase
5
from juju.machine.constraints import register_conflicts, register_constraint
8
#======================================================================
9
# Generic (but not user-visible) constraints; always relevant
10
register_constraint("ubuntu-series", visible=False)
11
register_constraint("provider-type", visible=False)
14
#======================================================================
15
# Generic (user-visible) constraints; always relevant
17
_VALID_ARCHS = ("i386", "amd64", "arm")
20
_GIGABYTES = _MEGABYTES * 1024
21
_TERABYTES = _GIGABYTES * 1024
22
_MEM_SUFFIXES = {"M": _MEGABYTES, "G": _GIGABYTES, "T": _TERABYTES}
28
raise ValueError("unknown architecture")
35
raise ValueError("must be non-negative")
39
if s[-1] in _MEM_SUFFIXES:
40
value = float(s[:-1]) * _MEM_SUFFIXES[s[-1]]
45
raise ValueError("must be non-negative")
48
register_constraint("arch", converter=_convert_arch)
50
"mem", default="512M", converter=_convert_mem, comparer=operator.ge)
52
"cpu", default="1", converter=_convert_cpu, comparer=operator.ge)
55
#======================================================================
58
def _convert_orchestra_classes(s):
62
def _compare_orchestra_classes(candidate, benchmark):
63
return set(candidate) >= set(benchmark)
67
"orchestra-classes", converter=_convert_orchestra_classes,
68
comparer=_compare_orchestra_classes, provider="orchestra")
69
register_constraint("orchestra-name", provider="orchestra")
72
#======================================================================
75
# We don't actually know what's available in any given region
76
_PLAUSIBLE_EC2_ZONES = ascii_lowercase
78
# cost is measured in $/h in us-east-1
79
_InstanceType = namedtuple("_InstanceType", "arch cpu mem cost")
81
# t1.micro can be i386 or amd64, and this needs special handling; however,
82
# it doesn't seem worthwhile to add custom code for handling non-overlap
83
# of arch when there's already a mechanism for specifying the desired arch
84
# for a t1.micro (for example, "cpu=0 mem=0 arch=<whatever>").
85
EC2_T1_MICRO_ARCH = "?"
87
EC2_INSTANCE_TYPES = {
88
# t1.micro cpu is "up to 2", but in practice "very little"
89
"t1.micro": _InstanceType(EC2_T1_MICRO_ARCH, 0.1, 613, 0.02),
91
"m1.small": _InstanceType("i386", 1, 1740, 0.085),
92
"m1.large": _InstanceType("amd64", 4, 7680, 0.34),
93
"m1.xlarge": _InstanceType("amd64", 8, 15360, 0.68),
95
"m2.xlarge": _InstanceType("amd64", 6.5, 17510, 0.5),
96
"m2.2xlarge": _InstanceType("amd64", 13, 35020, 1),
97
"m2.4xlarge": _InstanceType("amd64", 26, 70040, 2),
99
"c1.medium": _InstanceType("i386", 5, 1740, 0.17),
100
"c1.xlarge": _InstanceType("amd64", 20, 7168, 0.68),
102
"cc1.4xlarge": _InstanceType("amd64", 33.5, 23552, 1.3),
103
"cc2.8xlarge": _InstanceType("amd64", 88, 61952, 2.4),
105
# also has fancy GPUs we can't currently describe
106
"cg1.4xlarge": _InstanceType("amd64", 33.5, 22528, 2.1)}
109
def _convert_ec2_zone(s):
110
if s not in _PLAUSIBLE_EC2_ZONES:
111
raise ValueError("expected lowercase ascii char")
115
def _convert_ec2_instance_type(s):
116
if s not in EC2_INSTANCE_TYPES:
117
raise ValueError("unknown instance type")
121
register_constraint("ec2-zone", converter=_convert_ec2_zone, provider="ec2")
123
"ec2-instance-type", converter=_convert_ec2_instance_type, provider="ec2")
126
#======================================================================
129
register_conflicts(["orchestra-name"], ["orchestra-classes"])
131
["ec2-instance-type", "orchestra-name"], ["arch", "cpu", "mem"])