~gz/pyjuju/0.5_default_instance_backport

« back to all changes in this revision

Viewing changes to juju/providers/openstack/launch.py

  • Committer: Clint Byrum
  • Author(s): Kapil Thangavelu
  • Date: 2012-09-10 08:35:26 UTC
  • Revision ID: clint@ubuntu.com-20120910083526-04el6ce40gfeaise
OpenstackĀ providerĀ constraintsĀ support

Show diffs side-by-side

added added

removed removed

Lines of Context:
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.
16
14
 
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.
21
21
"""
22
22
 
23
23
from cStringIO import StringIO
24
24
 
25
 
from twisted.internet import (
26
 
    defer,
27
 
    reactor,
28
 
    )
 
25
from twisted.internet.defer import inlineCallbacks, returnValue
 
26
 
29
27
 
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
33
32
 
34
33
from .machine import machine_from_instance, get_server_status
35
34
 
41
40
 
42
41
    _DELAY_FOR_ADDRESSES = 5  # seconds
43
42
 
44
 
    @defer.inlineCallbacks
 
43
    @inlineCallbacks
45
44
    def start_machine(self, machine_id, zookeepers):
46
45
        """Actually launch an instance on Nova.
47
46
 
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()
 
62
 
63
63
        # Only the master is required to get its own instance id like this.
64
64
        if self._master:
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")
75
 
 
76
75
        security_groups = (
77
76
            yield self._provider.port_manager.ensure_groups(machine_id))
78
77
 
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,))
 
82
            log.warning(
 
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)
88
86
 
89
87
        server = yield self._provider.nova.run_server(
90
88
            name="juju %s instance %s" %
91
89
                (self._provider.environment_name, machine_id,),
92
90
            image_id=image_id,
93
 
            flavor_id=flavor_map[flavor_name],
 
91
            flavor_id=flavor_id,
94
92
            security_group_names=security_groups,
95
93
            user_data=user_data)
96
94
 
117
115
                server = yield self._provider.nova.get_server(server['id'])
118
116
            yield _assign_floating_ip(self._provider, server['id'])
119
117
 
120
 
        defer.returnValue([machine_from_instance(server)])
121
 
 
122
 
 
123
 
@defer.inlineCallbacks
 
118
        returnValue([machine_from_instance(server)])
 
119
 
 
120
 
 
121
def _solve_flavor(constraints, flavor_name, flavors):
 
122
    flavor_map, flavor_types = {}, {}
 
123
    for f in flavors:
 
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'])
 
128
 
 
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]
 
134
 
 
135
 
 
136
@inlineCallbacks
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: