40
34
return FakeConnection.instance()
43
class FakeInstance(object):
45
def __init__(self, name, state):
50
class FakeConnection(driver.ComputeDriver):
51
"""Fake hypervisor driver"""
37
class FakeConnection(object):
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).
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.
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.
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.
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.
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.
53
70
def __init__(self):
54
71
self.instances = {}
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',
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'}
75
76
cls._instance = cls()
76
77
return cls._instance
78
def init_host(self, host):
81
79
def list_instances(self):
81
Return the names of all the instances known to the virtualization
82
84
return self.instances.keys()
84
def _map_to_instance_info(self, instance):
85
instance = utils.check_isinstance(instance, FakeInstance)
86
info = driver.InstanceInfo(instance.name, instance.state)
89
def list_instances_detail(self):
91
for instance in self.instances.values():
92
info_list.append(self._map_to_instance_info(instance))
95
def spawn(self, context, instance,
96
network_info=None, block_device_info=None):
98
state = power_state.RUNNING
99
fake_instance = FakeInstance(name, state)
100
self.instances[name] = fake_instance
102
def snapshot(self, context, instance, name):
103
if not instance['name'] in self.instances:
104
raise exception.InstanceNotRunning()
106
def reboot(self, instance, network_info):
109
def get_host_ip_addr(self):
112
def resize(self, instance, flavor):
115
def set_admin_password(self, instance, new_pass):
118
def inject_file(self, instance, b64_path, b64_contents):
121
def agent_update(self, instance, url, md5hash):
124
def rescue(self, context, instance, callback, network_info):
127
def unrescue(self, instance, callback, network_info):
130
def poll_rescued_instances(self, timeout):
133
def migrate_disk_and_power_off(self, instance, dest):
136
def pause(self, instance, callback):
139
def unpause(self, instance, callback):
142
def suspend(self, instance, callback):
145
def resume(self, instance, callback):
148
def destroy(self, instance, network_info, cleanup=True):
149
key = instance['name']
150
if key in self.instances:
151
del self.instances[key]
153
LOG.warning("Key '%s' not in instances '%s'" %
154
(key, self.instances))
86
def spawn(self, instance):
88
Create a new instance/VM/domain on the virtualization platform.
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
94
The work will be done asynchronously. This function returns a
95
Deferred that allows the caller to detect when it is complete.
97
Once this successfully completes, the instance should be
98
running (power_state.RUNNING).
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.
105
fake_instance = FakeInstance()
106
self.instances[instance.name] = fake_instance
107
fake_instance._state = power_state.RUNNING
108
return defer.succeed(None)
110
def reboot(self, instance):
112
Reboot the specified instance.
114
The given parameter is an instance of nova.compute.service.Instance,
115
and so the instance is being specified as instance.name.
117
The work will be done asynchronously. This function returns a
118
Deferred that allows the caller to detect when it is complete.
120
return defer.succeed(None)
122
def destroy(self, instance):
124
Destroy (shutdown and delete) the specified instance.
126
The given parameter is an instance of nova.compute.service.Instance,
127
and so the instance is being specified as instance.name.
129
The work will be done asynchronously. This function returns a
130
Deferred that allows the caller to detect when it is complete.
132
del self.instances[instance.name]
133
return defer.succeed(None)
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"""
162
139
def detach_volume(self, instance_name, mountpoint):
164
del self._mounts[instance_name][mountpoint]
140
"""Detach the disk attached to the instance at mountpoint"""
169
143
def get_info(self, instance_name):
170
if instance_name not in self.instances:
171
raise exception.InstanceNotFound(instance_id=instance_name)
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.
172
152
i = self.instances[instance_name]
173
return {'state': i.state,
153
return {'state': i._state,
179
def get_diagnostics(self, instance_name):
182
159
def list_disks(self, instance_name):
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.
166
Note that this function takes an instance ID, not a
167
compute.service.Instance, so that it can be called by compute.monitor.
183
169
return ['A_DISK']
185
171
def list_interfaces(self, instance_name):
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
179
Note that this function takes an instance ID, not a
180
compute.service.Instance, so that it can be called by compute.monitor.
188
184
def block_stats(self, instance_name, disk_id):
189
return [0L, 0L, 0L, 0L, None]
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
193
All counters are long integers.
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
200
Note that this function takes an instance ID, not a
201
compute.service.Instance, so that it can be called by compute.monitor.
203
return [0L, 0L, 0L, 0L, null]
191
205
def interface_stats(self, instance_name, iface_id):
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.
214
All counters are long integers.
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
221
Note that this function takes an instance ID, not a
222
compute.service.Instance, so that it can be called by compute.monitor.
192
224
return [0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L]
194
226
def get_console_output(self, instance):
195
return 'FAKE CONSOLE\xffOUTPUT'
197
def get_ajax_console(self, instance):
198
return {'token': 'FAKETOKEN',
199
'host': 'fakeajaxconsole.com',
202
def get_vnc_console(self, instance):
203
return {'token': 'FAKETOKEN',
204
'host': 'fakevncconsole.com',
207
def get_console_pool_info(self, console_type):
208
return {'address': '127.0.0.1',
209
'username': 'fakeuser',
210
'password': 'fakepassword'}
212
def refresh_security_group_rules(self, security_group_id):
215
def refresh_security_group_members(self, security_group_id):
218
def refresh_provider_fw_rules(self):
221
def update_available_resource(self, ctxt, host):
222
"""This method is supported only by libvirt."""
225
def compare_cpu(self, xml):
226
"""This method is supported only by libvirt."""
227
raise NotImplementedError('This method is supported only by libvirt.')
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.')
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."""
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.')
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)
246
def update_host_status(self):
247
"""Return fake Host Status of ram, disk, network."""
248
return self.host_status
250
def get_host_stats(self, refresh=False):
251
"""Return fake Host Status of ram, disk, network."""
252
return self.host_status
254
def host_power_action(self, host, action):
255
"""Reboots, shuts down or powers up the host."""
258
def set_host_enabled(self, host, enabled):
259
"""Sets the specified host's ability to accept new instances."""
227
return 'FAKE CONSOLE OUTPUT'
229
class FakeInstance(object):
231
self._state = power_state.NOSTATE