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_instancedelete_instancesinstance_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:
selfis anova.compute.manager.ComputeManagerobject,contextis anova.context.RequestContext,instanceis anova.objects.instance.Instanceobjectbdmsis anova.objects.block_device.BlockDeviceMappingListobject, andquotasis anova.objects.quotas.Quotasobject
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.