~0x44/nova/bug838466

« back to all changes in this revision

Viewing changes to nova/virt/fake.py

  • Committer: Eric Day
  • Date: 2010-10-21 18:49:51 UTC
  • mto: This revision was merged to the branch mainline in revision 377.
  • Revision ID: eday@oddments.org-20101021184951-x0vs3s8y7mc0aeyy
PEP8 and pylint cleanup. There should be no functional changes here, just style changes to get violations down.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
#    under the License.
19
19
 
20
20
"""
21
 
A fake (in-memory) hypervisor+api.
22
 
 
23
 
Allows nova testing w/o a hypervisor.  This module also documents the
24
 
semantics of real hypervisor connections.
25
 
 
 
21
A fake (in-memory) hypervisor+api. Allows nova testing w/o a hypervisor.
 
22
This module also documents the semantics of real hypervisor connections.
26
23
"""
27
24
 
28
 
from nova import exception
29
 
from nova import log as logging
30
 
from nova import utils
 
25
import logging
 
26
 
 
27
from twisted.internet import defer
 
28
 
31
29
from nova.compute import power_state
32
 
from nova.virt import driver
33
 
 
34
 
 
35
 
LOG = logging.getLogger('nova.compute.disk')
36
30
 
37
31
 
38
32
def get_connection(_):
40
34
    return FakeConnection.instance()
41
35
 
42
36
 
43
 
class FakeInstance(object):
44
 
 
45
 
    def __init__(self, name, state):
46
 
        self.name = name
47
 
        self.state = state
48
 
 
49
 
 
50
 
class FakeConnection(driver.ComputeDriver):
51
 
    """Fake hypervisor driver"""
 
37
class FakeConnection(object):
 
38
    """
 
39
    The interface to this class talks in terms of 'instances' (Amazon EC2 and
 
40
    internal Nova terminology), by which we mean 'running virtual machine'
 
41
    (XenAPI terminology) or domain (Xen or libvirt terminology).
 
42
 
 
43
    An instance has an ID, which is the identifier chosen by Nova to represent
 
44
    the instance further up the stack.  This is unfortunately also called a
 
45
    'name' elsewhere.  As far as this layer is concerned, 'instance ID' and
 
46
    'instance name' are synonyms.
 
47
 
 
48
    Note that the instance ID or name is not human-readable or
 
49
    customer-controlled -- it's an internal ID chosen by Nova.  At the
 
50
    nova.virt layer, instances do not have human-readable names at all -- such
 
51
    things are only known higher up the stack.
 
52
 
 
53
    Most virtualization platforms will also have their own identity schemes,
 
54
    to uniquely identify a VM or domain.  These IDs must stay internal to the
 
55
    platform-specific layer, and never escape the connection interface.  The
 
56
    platform-specific layer is responsible for keeping track of which instance
 
57
    ID maps to which platform-specific ID, and vice versa.
 
58
 
 
59
    In contrast, the list_disks and list_interfaces calls may return
 
60
    platform-specific IDs.  These identify a specific virtual disk or specific
 
61
    virtual network interface, and these IDs are opaque to the rest of Nova.
 
62
 
 
63
    Some methods here take an instance of nova.compute.service.Instance.  This
 
64
    is the datastructure used by nova.compute to store details regarding an
 
65
    instance, and pass them into this layer.  This layer is responsible for
 
66
    translating that generic datastructure into terms that are specific to the
 
67
    virtualization platform.
 
68
    """
52
69
 
53
70
    def __init__(self):
54
71
        self.instances = {}
55
 
        self.host_status = {
56
 
          'host_name-description': 'Fake Host',
57
 
          'host_hostname': 'fake-mini',
58
 
          'host_memory_total': 8000000000,
59
 
          'host_memory_overhead': 10000000,
60
 
          'host_memory_free': 7900000000,
61
 
          'host_memory_free_computed': 7900000000,
62
 
          'host_other_config': {},
63
 
          'host_ip_address': '192.168.1.109',
64
 
          'host_cpu_info': {},
65
 
          'disk_available': 500000000000,
66
 
          'disk_total': 600000000000,
67
 
          'disk_used': 100000000000,
68
 
          'host_uuid': 'cedb9b39-9388-41df-8891-c5c9a0c0fe5f',
69
 
          'host_name_label': 'fake-mini'}
70
 
        self._mounts = {}
71
72
 
72
73
    @classmethod
73
74
    def instance(cls):
75
76
            cls._instance = cls()
76
77
        return cls._instance
77
78
 
78
 
    def init_host(self, host):
79
 
        return
80
 
 
81
79
    def list_instances(self):
 
80
        """
 
81
        Return the names of all the instances known to the virtualization
 
82
        layer, as a list.
 
83
        """
82
84
        return self.instances.keys()
83
85
 
84
 
    def _map_to_instance_info(self, instance):
85
 
        instance = utils.check_isinstance(instance, FakeInstance)
86
 
        info = driver.InstanceInfo(instance.name, instance.state)
87
 
        return info
88
 
 
89
 
    def list_instances_detail(self):
90
 
        info_list = []
91
 
        for instance in self.instances.values():
92
 
            info_list.append(self._map_to_instance_info(instance))
93
 
        return info_list
94
 
 
95
 
    def spawn(self, context, instance,
96
 
              network_info=None, block_device_info=None):
97
 
        name = instance.name
98
 
        state = power_state.RUNNING
99
 
        fake_instance = FakeInstance(name, state)
100
 
        self.instances[name] = fake_instance
101
 
 
102
 
    def snapshot(self, context, instance, name):
103
 
        if not instance['name'] in self.instances:
104
 
            raise exception.InstanceNotRunning()
105
 
 
106
 
    def reboot(self, instance, network_info):
107
 
        pass
108
 
 
109
 
    def get_host_ip_addr(self):
110
 
        return '192.168.0.1'
111
 
 
112
 
    def resize(self, instance, flavor):
113
 
        pass
114
 
 
115
 
    def set_admin_password(self, instance, new_pass):
116
 
        pass
117
 
 
118
 
    def inject_file(self, instance, b64_path, b64_contents):
119
 
        pass
120
 
 
121
 
    def agent_update(self, instance, url, md5hash):
122
 
        pass
123
 
 
124
 
    def rescue(self, context, instance, callback, network_info):
125
 
        pass
126
 
 
127
 
    def unrescue(self, instance, callback, network_info):
128
 
        pass
129
 
 
130
 
    def poll_rescued_instances(self, timeout):
131
 
        pass
132
 
 
133
 
    def migrate_disk_and_power_off(self, instance, dest):
134
 
        pass
135
 
 
136
 
    def pause(self, instance, callback):
137
 
        pass
138
 
 
139
 
    def unpause(self, instance, callback):
140
 
        pass
141
 
 
142
 
    def suspend(self, instance, callback):
143
 
        pass
144
 
 
145
 
    def resume(self, instance, callback):
146
 
        pass
147
 
 
148
 
    def destroy(self, instance, network_info, cleanup=True):
149
 
        key = instance['name']
150
 
        if key in self.instances:
151
 
            del self.instances[key]
152
 
        else:
153
 
            LOG.warning("Key '%s' not in instances '%s'" %
154
 
                        (key, self.instances))
 
86
    def spawn(self, instance):
 
87
        """
 
88
        Create a new instance/VM/domain on the virtualization platform.
 
89
 
 
90
        The given parameter is an instance of nova.compute.service.Instance.
 
91
        This function should use the data there to guide the creation of
 
92
        the new instance.
 
93
 
 
94
        The work will be done asynchronously.  This function returns a
 
95
        Deferred that allows the caller to detect when it is complete.
 
96
 
 
97
        Once this successfully completes, the instance should be
 
98
        running (power_state.RUNNING).
 
99
 
 
100
        If this fails, any partial instance should be completely
 
101
        cleaned up, and the virtualization platform should be in the state
 
102
        that it was before this call began.
 
103
        """
 
104
 
 
105
        fake_instance = FakeInstance()
 
106
        self.instances[instance.name] = fake_instance
 
107
        fake_instance._state = power_state.RUNNING
 
108
        return defer.succeed(None)
 
109
 
 
110
    def reboot(self, instance):
 
111
        """
 
112
        Reboot the specified instance.
 
113
 
 
114
        The given parameter is an instance of nova.compute.service.Instance,
 
115
        and so the instance is being specified as instance.name.
 
116
 
 
117
        The work will be done asynchronously.  This function returns a
 
118
        Deferred that allows the caller to detect when it is complete.
 
119
        """
 
120
        return defer.succeed(None)
 
121
 
 
122
    def destroy(self, instance):
 
123
        """
 
124
        Destroy (shutdown and delete) the specified instance.
 
125
 
 
126
        The given parameter is an instance of nova.compute.service.Instance,
 
127
        and so the instance is being specified as instance.name.
 
128
 
 
129
        The work will be done asynchronously.  This function returns a
 
130
        Deferred that allows the caller to detect when it is complete.
 
131
        """
 
132
        del self.instances[instance.name]
 
133
        return defer.succeed(None)
155
134
 
156
135
    def attach_volume(self, instance_name, device_path, mountpoint):
157
 
        if not instance_name in self._mounts:
158
 
            self._mounts[instance_name] = {}
159
 
        self._mounts[instance_name][mountpoint] = device_path
 
136
        """Attach the disk at device_path to the instance at mountpoint"""
160
137
        return True
161
138
 
162
139
    def detach_volume(self, instance_name, mountpoint):
163
 
        try:
164
 
            del self._mounts[instance_name][mountpoint]
165
 
        except KeyError:
166
 
            pass
 
140
        """Detach the disk attached to the instance at mountpoint"""
167
141
        return True
168
142
 
169
143
    def get_info(self, instance_name):
170
 
        if instance_name not in self.instances:
171
 
            raise exception.InstanceNotFound(instance_id=instance_name)
 
144
        """
 
145
        Get a block of information about the given instance.  This is returned
 
146
        as a dictionary containing 'state': The power_state of the instance,
 
147
        'max_mem': The maximum memory for the instance, in KiB, 'mem': The
 
148
        current memory the instance has, in KiB, 'num_cpu': The current number
 
149
        of virtual CPUs the instance has, 'cpu_time': The total CPU time used
 
150
        by the instance, in nanoseconds.
 
151
        """
172
152
        i = self.instances[instance_name]
173
 
        return {'state': i.state,
 
153
        return {'state': i._state,
174
154
                'max_mem': 0,
175
155
                'mem': 0,
176
156
                'num_cpu': 2,
177
157
                'cpu_time': 0}
178
158
 
179
 
    def get_diagnostics(self, instance_name):
180
 
        return {}
181
 
 
182
159
    def list_disks(self, instance_name):
 
160
        """
 
161
        Return the IDs of all the virtual disks attached to the specified
 
162
        instance, as a list.  These IDs are opaque to the caller (they are
 
163
        only useful for giving back to this layer as a parameter to
 
164
        disk_stats).  These IDs only need to be unique for a given instance.
 
165
 
 
166
        Note that this function takes an instance ID, not a
 
167
        compute.service.Instance, so that it can be called by compute.monitor.
 
168
        """
183
169
        return ['A_DISK']
184
170
 
185
171
    def list_interfaces(self, instance_name):
 
172
        """
 
173
        Return the IDs of all the virtual network interfaces attached to the
 
174
        specified instance, as a list.  These IDs are opaque to the caller
 
175
        (they are only useful for giving back to this layer as a parameter to
 
176
        interface_stats).  These IDs only need to be unique for a given
 
177
        instance.
 
178
 
 
179
        Note that this function takes an instance ID, not a
 
180
        compute.service.Instance, so that it can be called by compute.monitor.
 
181
        """
186
182
        return ['A_VIF']
187
183
 
188
184
    def block_stats(self, instance_name, disk_id):
189
 
        return [0L, 0L, 0L, 0L, None]
 
185
        """
 
186
        Return performance counters associated with the given disk_id on the
 
187
        given instance_name.  These are returned as [rd_req, rd_bytes, wr_req,
 
188
        wr_bytes, errs], where rd indicates read, wr indicates write, req is
 
189
        the total number of I/O requests made, bytes is the total number of
 
190
        bytes transferred, and errs is the number of requests held up due to a
 
191
        full pipeline.
 
192
 
 
193
        All counters are long integers.
 
194
 
 
195
        This method is optional.  On some platforms (e.g. XenAPI) performance
 
196
        statistics can be retrieved directly in aggregate form, without Nova
 
197
        having to do the aggregation.  On those platforms, this method is
 
198
        unused.
 
199
 
 
200
        Note that this function takes an instance ID, not a
 
201
        compute.service.Instance, so that it can be called by compute.monitor.
 
202
        """
 
203
        return [0L, 0L, 0L, 0L, null]
190
204
 
191
205
    def interface_stats(self, instance_name, iface_id):
 
206
        """
 
207
        Return performance counters associated with the given iface_id on the
 
208
        given instance_id.  These are returned as [rx_bytes, rx_packets,
 
209
        rx_errs, rx_drop, tx_bytes, tx_packets, tx_errs, tx_drop], where rx
 
210
        indicates receive, tx indicates transmit, bytes and packets indicate
 
211
        the total number of bytes or packets transferred, and errs and dropped
 
212
        is the total number of packets failed / dropped.
 
213
 
 
214
        All counters are long integers.
 
215
 
 
216
        This method is optional.  On some platforms (e.g. XenAPI) performance
 
217
        statistics can be retrieved directly in aggregate form, without Nova
 
218
        having to do the aggregation.  On those platforms, this method is
 
219
        unused.
 
220
 
 
221
        Note that this function takes an instance ID, not a
 
222
        compute.service.Instance, so that it can be called by compute.monitor.
 
223
        """
192
224
        return [0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L]
193
225
 
194
226
    def get_console_output(self, instance):
195
 
        return 'FAKE CONSOLE\xffOUTPUT'
196
 
 
197
 
    def get_ajax_console(self, instance):
198
 
        return {'token': 'FAKETOKEN',
199
 
                'host': 'fakeajaxconsole.com',
200
 
                'port': 6969}
201
 
 
202
 
    def get_vnc_console(self, instance):
203
 
        return {'token': 'FAKETOKEN',
204
 
                'host': 'fakevncconsole.com',
205
 
                'port': 6969}
206
 
 
207
 
    def get_console_pool_info(self, console_type):
208
 
        return  {'address': '127.0.0.1',
209
 
                 'username': 'fakeuser',
210
 
                 'password': 'fakepassword'}
211
 
 
212
 
    def refresh_security_group_rules(self, security_group_id):
213
 
        return True
214
 
 
215
 
    def refresh_security_group_members(self, security_group_id):
216
 
        return True
217
 
 
218
 
    def refresh_provider_fw_rules(self):
219
 
        pass
220
 
 
221
 
    def update_available_resource(self, ctxt, host):
222
 
        """This method is supported only by libvirt."""
223
 
        return
224
 
 
225
 
    def compare_cpu(self, xml):
226
 
        """This method is supported only by libvirt."""
227
 
        raise NotImplementedError('This method is supported only by libvirt.')
228
 
 
229
 
    def ensure_filtering_rules_for_instance(self, instance_ref, network_info):
230
 
        """This method is supported only by libvirt."""
231
 
        raise NotImplementedError('This method is supported only by libvirt.')
232
 
 
233
 
    def live_migration(self, context, instance_ref, dest,
234
 
                       post_method, recover_method, block_migration=False):
235
 
        """This method is supported only by libvirt."""
236
 
        return
237
 
 
238
 
    def unfilter_instance(self, instance_ref, network_info):
239
 
        """This method is supported only by libvirt."""
240
 
        raise NotImplementedError('This method is supported only by libvirt.')
241
 
 
242
 
    def test_remove_vm(self, instance_name):
243
 
        """ Removes the named VM, as if it crashed. For testing"""
244
 
        self.instances.pop(instance_name)
245
 
 
246
 
    def update_host_status(self):
247
 
        """Return fake Host Status of ram, disk, network."""
248
 
        return self.host_status
249
 
 
250
 
    def get_host_stats(self, refresh=False):
251
 
        """Return fake Host Status of ram, disk, network."""
252
 
        return self.host_status
253
 
 
254
 
    def host_power_action(self, host, action):
255
 
        """Reboots, shuts down or powers up the host."""
256
 
        pass
257
 
 
258
 
    def set_host_enabled(self, host, enabled):
259
 
        """Sets the specified host's ability to accept new instances."""
260
 
        pass
 
227
        return 'FAKE CONSOLE OUTPUT'
 
228
 
 
229
class FakeInstance(object):
 
230
    def __init__(self):
 
231
        self._state = power_state.NOSTATE