7
7
as EC2 doesn't support changing groups later, but OpenStack does.
8
8
* Needs to tell cloud-init how to get server id, currently in essex metadata
9
9
service gives i-08x style only, so cheat and use filestorage.
10
* Config must specify a flavor, as these vary between Openstack deployments.
11
Working out constraints should resolve this.
12
10
* Config must specify an image id, as there's no standard way of looking up
13
11
from distro series across clouds yet in essex.
14
12
* Would be really nice to put the service name in the server name, but it's
15
13
not passed down into LaunchMachine currently.
17
15
There are some race issues with the current setup:
18
* Storing of server id needs to complete before cloud-init does the lookup.
19
* A floating ip may be assigned to another server before the current one
20
finishes launching and can use the available ip itself.
16
* Storing of server id needs to complete before cloud-init does the lookup,
17
extremely unlikely (two successive api calls vs instance boot and running).
18
* for environments configured with floating-ips. A floating ip may be
19
assigned to another server before the current one finishes launching and
20
can use the available ip itself.
23
23
from cStringIO import StringIO
25
from twisted.internet import (
25
from twisted.internet.defer import inlineCallbacks, returnValue
30
28
from juju.errors import ProviderError, ProviderInteractionError
31
29
from juju.lib import twistutils
32
30
from juju.providers.common.launch import LaunchMachine
31
from juju.providers.common.instance_type import TypeSolver, InstanceType
34
33
from .machine import machine_from_instance, get_server_status
60
59
cloud_init = self._create_cloud_init(machine_id, zookeepers)
61
60
cloud_init.set_provider_type(self._provider.provider_type)
62
61
filestorage = self._provider.get_file_storage()
63
63
# Only the master is required to get its own instance id like this.
65
65
id_name = "juju_master_id"
72
72
image_id = self._provider.config.get("default-image-id")
73
73
if image_id is None:
74
74
raise ProviderError("Need to specify a default-image-id")
76
75
security_groups = (
77
76
yield self._provider.port_manager.ensure_groups(machine_id))
79
# Until constraints are implemented, need to a configured instance
80
# type and resolve it to a flavor id here.
78
# Find appropriate instance type for the given constraints. Warn
79
# if deprecated is instance-type is being used.
81
80
flavor_name = self._provider.config.get("default-instance-type")
82
81
if flavor_name is None:
83
raise ProviderError("Need to specify a default-instance-type")
84
flavors = yield self._provider.nova.list_flavors()
85
flavor_map = dict((f['name'], f['id']) for f in flavors)
86
if not flavor_name in flavor_map:
87
ProviderError("Unknown instance type given: %r" % (flavor_name,))
83
"default-instance-type is deprecated, use cli --constraints")
84
flavors = yield self._provider.nova.list_flavor_details()
85
flavor_id = _solve_flavor(self._constraints, flavor_name, flavors)
89
87
server = yield self._provider.nova.run_server(
90
88
name="juju %s instance %s" %
91
89
(self._provider.environment_name, machine_id,),
93
flavor_id=flavor_map[flavor_name],
94
92
security_group_names=security_groups,
95
93
user_data=user_data)
117
115
server = yield self._provider.nova.get_server(server['id'])
118
116
yield _assign_floating_ip(self._provider, server['id'])
120
defer.returnValue([machine_from_instance(server)])
123
@defer.inlineCallbacks
118
returnValue([machine_from_instance(server)])
121
def _solve_flavor(constraints, flavor_name, flavors):
122
flavor_map, flavor_types = {}, {}
124
flavor_map[f['name']] = f['id']
125
# Arch needs to be part of nova details.
126
flavor_types[f['name']] = InstanceType(
127
'amd64', f['vcpus'], f['ram'])
129
solver = TypeSolver(flavor_types)
130
flavor_name = solver.run(constraints)
131
if not flavor_name in flavor_map:
132
ProviderError("Unknown instance type given: %r" % (flavor_name,))
133
return flavor_map[flavor_name]
124
137
def _assign_floating_ip(provider, server_id):
125
138
floating_ips = yield provider.nova.list_floating_ips()
126
139
for floating_ip in floating_ips: