constraints
roger peppe
rogpeppe at gmail.com
Wed Feb 6 19:29:39 UTC 2013
There seems to be a desire to be able to specify constraints both in a
portable way (for example by specifying a required amount of RAM), and
in a provider-specific way (for example by specifying an instance type).
Part of the complexity of getting this to work well comes, I think,
from the fact that we're trying to allow both kinds of constraint in
the same constraint set. That means that we can get arbitrary semantic
overlap between provider-specific constraints and portable constraints -
the constraint attributes are not orthogonal.
I *think* that by explicitly separating portable constraints from
provider-specific constraints, the implementation can become simpler
because concerns are better isolated, and the user-facing behaviour
more predictable because all the attributes in a given constraint
can be designed to work coherently with one another.
In the proposal below, a provider can decide on a constraints language that
maps closely to the model of the underlying provider, but nowhere do we
need to combine constraints from this model with constraints from the
portable model.
Here's my straw man top-to-bottom overview of my proposal.
Please knock it down as appropriate!
At command level, constraints can be specified with juju portable
constraints *or* provider-specific constraints, but not both.
juju deploy --constraints 'cpu=8 mem=32G' mysql
or
juju deploy --provider-constraints 'instance-type=m1.small' mysql
>From here on, we'll refer to portable (normal) constraints as "n-constraints"
and provider-specific constraints as "p-constraints".
All constraints are evaluated inside the environment, not by the client.
They are associated, in their originally specified form, with the
appropriate state entity (the service or the environment).
The resolved constraints that apply to a newly started machine are determined
by combining environment-level and service-level constraints.
The combination rules are as follows:
- p-constraints do not combine with n-constraints -
either will override the other if specified at different levels.
- Otherwise, constraints are combined by concatenating the two sets
of constraints (environment first, service second), and treating later
constraint attributes as overriding earlier ones.
Example:
juju bootstrap --constraints 'cpu=8'
juju deploy --provider-constraints 'instance-type=m1.small' mysql
gives a resolved constraint for the mysql service of
p-constraint='-instance-type=m1.small'
Example:
juju bootstrap --provider-constraints 'instance-type=m1.small'
juju deploy --constraints 'cpu=8' mysql
gives a resolved constraint for units of mysql of
n-constraint='-cpu=8'
Example:
juju bootstrap --provider-constraints 'instance-type=m1.small'
juju deploy --provider-constraints 'zone=us-east-1a' mysql
gives a resolved constraint for units of mysql of
p-constraint='instance-type=m1.small zone=us-east-1a'
Example:
juju bootstrap --constraints 'cpu=8 mem=32G'
juju deploy --constraints 'mem=8G' mysql
gives a resolved constraint for units of mysql of
n-constraint='cpu=8 mem=8G'
When a new unit is added, the assigner worker (as yet unimplemented)
sees it and tries to assign it to a Machine. It looks through all
existing machines to see if the unit's service's resolved constraints
are *compatible* with the specifications of that machine. The machine
specifications are defined by both a p-constraint (the constraint
passed to StartInstance) and an n-constraint, acquired by querying the
environment about the started instance.
The rules for constraint compatibility are as follows:
- If the resolved constraint, C, is an n-constraint:
it is compatible with a machine M if each attribute in C is
present with the same or numerically more restrictive value in
M's n-constraint.
- Otherwise (C is a p-constraint)
- it is compatible with a machine M if each attribute in C is
present with the same or numerically more restrictive value in
M's p-constraint.
Example:
We have machines as follows:
Machine 1:
p-constraint: instance-type=m1.small arch=amd64
n-constraint: mem=1.7G arch=amd64
Machine-2:
p-constraint: instance-type=m1.medium arch=i386
n-constraint: mem=3.75G arch=i386
Machine-3:
p-constraint: instance-type=m1.medium
n-constraint: mem=2G
The following table has some constraints and the set of machines
that would satisfy them:
p-constraint='instance-type=m1.medium'
-> {2, 3}
n-constraint='mem=1G'
-> {1,2,3}
n-constraint='mem=3.75G instance-type=m1.small'
-> invalid constraint, because instance types are not defined in
n-constraints.
If the assigner worker finds an appropriate machine, it assigns the new
unit to that machine without further ado. If not, then it creates a new
Machine associated with the service's resolved constraints.
The provisioner worker sees the new machine, and tries to allocate a new
instance using Environ.StartInstance, which is now has a p-constraint
argument. If the machine has only an n-constraint, the provisioner asks
the Environ to translate it into a p-constraint first.
(This requires a new entry point in the environs package:
Environ.Constraints(portableConstraints *state.Constraints)
(*state.ProviderConstraints, error)
)
The Machine is then tagged, if necessary, with the provider-specific
constraints and the Environ is asked for the specification of the new instance
in n-constraint format. When available, this is stored in the Machine
(it is by definition more restrictive than the originally specified constraints)
(This requires a new new entry point in the environs package:
Instance.Specification() (*state.Constraints, error)
)
This last means that even if we launch a machine with provider-specific
constraints, we can later match it with a set of portable constraints.
An initial approach to implementing the above proposal
would be to implement n-constraints only and ignore p-constraints
entirely for the time being.
cheers,
rog.
More information about the Juju-dev
mailing list