Integrating custom code with Nova using hooks
Would you like to run some custom Python code when Nova creates and destroys virtual instances on your compute hosts? This is possible using Nova’s support for hooks, but the existing documentation is somewhat short on examples, so I’ve spent some time trying to get things working.
The demo_nova_hooks repository contains a working example of the techniques discussed in this article.
What’s a hook?⌗
A Nova “hook” is a mechanism that allows you to attach a class of your
own design to a particular function or method call in Nova. Your
class should define a pre
method (that will be called before the
method is called) and post
function (that will be called after the
method is called):
class YourHookClass(object):
def pre(self, *args, **kwargs):
....
def post(self, rv, *args, **kwargs):
....
The pre
method will be called with the positional and keyword
arguments being passed to the hooked function. The post
method
receives the return value of the called method in addition to the
positional and keyword arguments.
You connect your code to available hooks using Setuptools entry
points. For example, assuming that the above code lived in
module named your_package.hooks
, you might have the following in the
corresponding setup.py
file:
entry_points = {
'nova.hooks': [
'create_instance=your_package.hooks:YourHookClass',
]
},
What hooks are available?⌗
The Nova code (as of 81b1bab) defines three hooks:
create_instance
delete_instances
instance_network_info
create_instance⌗
The create_instance
hook is attached to the Nova API create
function, and will receive the following arguments:
def create(self, context, instance_type,
image_href, kernel_id=None, ramdisk_id=None,
min_count=None, max_count=None,
display_name=None, display_description=None,
key_name=None, key_data=None, security_group=None,
availability_zone=None, user_data=None, metadata=None,
injected_files=None, admin_password=None,
block_device_mapping=None, access_ip_v4=None,
access_ip_v6=None, requested_networks=None, config_drive=None,
auto_disk_config=None, scheduler_hints=None, legacy_bdm=True,
shutdown_terminate=False, check_server_group_quota=False):
When called, self
is a nova.compute.api.API
object, context
is a
nova.context.RequestContext
object, instance_type
is a dictionary
containing information about the selected flavor, and image_href
is
an image UUID.
During my testing, the instance_type
dictionary looked like this…
{'created_at': None,
'deleted': 0L,
'deleted_at': None,
'disabled': False,
'ephemeral_gb': 0L,
'extra_specs': {},
'flavorid': u'2',
'id': 5L,
'is_public': True,
'memory_mb': 2048L,
'name': u'm1.small',
'root_gb': 20L,
'rxtx_factor': 1.0,
'swap': 0L,
'updated_at': None,
'vcpu_weight': None,
'vcpus': 1L}
…corresponding to the m1.small
flavor on my system.
delete_instance⌗
The delete_instance
hook is attached to the _delete_instance
method in the nova.compute.manager.ComputeManager
class, which is
called whenever Nova needs to delete an instance. The hook will
receive the following arguments:
def _delete_instance(self, context, instance, bdms, quotas):
Where:
self
is anova.compute.manager.ComputeManager
object,context
is anova.context.RequestContext
,instance
is anova.objects.instance.Instance
objectbdms
is anova.objects.block_device.BlockDeviceMappingList
object, andquotas
is anova.objects.quotas.Quotas
object
instance_network_info⌗
The instance_network_info
hook is attached to the
update_instance_cache_with_nw_info
function in
nova.network.base_api.py
. The hook will receive the following
arguments:
def update_instance_cache_with_nw_info(impl, context, instance,
nw_info=None, update_cells=True):
I am not running Nova Network in my environment, so I have not examined this hook in any additional detail.
A working example⌗
The demo_nova_hooks repository implements simple logging-only
implementations of create_instance
and delete_instance
hooks. You
can install this code, restart Nova services, boot an instances, and
verify that the code has executed by looking at the logs generated in
/var/log/nova
.