Search This Blog

Monday, August 15, 2016

What's new with neutron-lib 0.3.0


OpenStack neutron-lib version 0.3.0 was recently released to PyPI  and contains a number of updates to API validators, constants and hacking checks.

The complete list of public API changes are summarized below (and can be viewed on github):
 New API Signatures  
 neutron_lib.api.validators.get_validator(validation_type, default=None)  
 neutron_lib.api.validators.validate_integer(data, valid_values=None)  
 neutron_lib.api.validators.validate_subports(data, valid_values=None)  
 neutron_lib.constants.DHCPV6_STATEFUL = dhcpv6-stateful  
 neutron_lib.constants.DHCPV6_STATELESS = dhcpv6-stateless  
 neutron_lib.constants.IPV6_MODES = [u'dhcpv6-stateful', u'dhcpv6-stateless', u'slaac']  
 neutron_lib.constants.IPV6_SLAAC = slaac  
 neutron_lib.constants.L3_AGENT_MODE = agent_mode  
 neutron_lib.constants.L3_AGENT_MODE_DVR = dvr  
 neutron_lib.constants.L3_AGENT_MODE_DVR_SNAT = dvr_snat  
 neutron_lib.constants.L3_AGENT_MODE_LEGACY = legacy  
 neutron_lib.hacking.translation_checks.check_log_warn_deprecated(logical_line, filename)  
 neutron_lib.hacking.translation_checks.check_raised_localized_exceptions(logical_line, filename)  
 neutron_lib.hacking.translation_checks.no_translate_debug_logs(logical_line, filename)  
 neutron_lib.hacking.translation_checks.validate_log_translations(logical_line, physical_line, filename)  
 Removed API Signatures  
 Changed API Signatures  

The above public API changes were generated using a new tool we're looking to include with neutron-lib and eventually perhaps in the change summary for each neutron-lib release.

API Validators

Two new validators were added in neutron-lib 0.3.0; validate_integer and validate_subports.

As expected, validate_integer ensures a value is in fact an integer. The implementation includes smarts to detect if the value is a str, float or bool; which are often missing in common integer validation functions. In addition, the function supports passing a list of valid_values to check for value inclusion.

As with other validator functions, validate_integer returns None if the value is valid and a str message otherwise. The string message for an invalid value is a user friendly message as to why the value is bad.

Here's a sample python snippet to showcase validate_integer

 from neutron_lib.api import validators  

 def test_validate(validator, val, valid_values=None):  
   result = validator(val, valid_values)  
   print("%s(%s, %s) --> %s" % (validator.__name__, val,  
                  valid_values, result))  

 print("Testing valid values...")  
 test_validate(validators.validate_integer, 1)  
 test_validate(validators.validate_integer, '-9')  
 test_validate(validators.validate_integer, 0)  
 test_validate(validators.validate_integer, 7, [9, 8, 7])  
 test_validate(validators.validate_integer, 7, [9, 8, 7])  

 print("\nTesting invalid values...")  
 test_validate(validators.validate_integer, True)  
 test_validate(validators.validate_integer, False)  
 test_validate(validators.validate_integer, '1.1')  
 test_validate(validators.validate_integer, -9.98933)  
 test_validate(validators.validate_integer, 7, [9, 8, 6])  

When run, it outputs:

 Testing valid values...  
 validate_integer(1, None) --> None  
 validate_integer(-9, None) --> None  
 validate_integer(0, None) --> None  
 validate_integer(7, [9, 8, 7]) --> None  
 validate_integer(7, [9, 8, 7]) --> None  
 Testing invalid values...  
 validate_integer(True, None) --> 'True' is not an integer:boolean  
 validate_integer(False, None) --> 'False' is not an integer:boolean  
 validate_integer(1.1, None) --> '1.1' is not an integer  
 validate_integer(-9.98933, None) --> '-9.98933' is not an integer  
 validate_integer(7, [9, 8, 6]) --> '7' is not in [9, 8, 6]  

The validate_subports validator is also new in neutron-lib 0.3.0. This validator is used as part of the vlan-aware-vms workstream currently under development. Rather than diving into the details on this one, we'll defer to blueprint and related change sets.

Finally in the API validators space, we have some work going on to remove direct access to the neutron_lib.api.validators.validators attribute. This attribute is a dict of the currently "registered" validators known to neutron_lib.

Today, consumers add a "local" (validator function defined outside of neutron-lib) validator by directly adding it to the dict.

For example:

validators.validators['type:my_validatable_type'] = my_validator_function

In general, this is bad practice and can cause complications if we ever decide to wrap API validator access with encapsulating logic. Consumers should now use the following accessors:

get_validator(validation_type, default=None)  
add_validator(validation_type, validator)

Both of which are defined in the neutron_lib.api.validators module. We've deprecated direct access to the validators dict and plan to remove it in the OpenStack "P" release.

For more information on related changes see review 350259.


The only thing overly interesting about the change in neutron_lib.constants, is the addition of the Sentinel class that allows you to create instances that don't change; even with deepcopy(). For example:

import copy

from neutron_lib.constants import Sentinel

singleton = Sentinel()
print("deepcopy() = %s" % (copy.deepcopy(singleton) == singleton))

When run outputs:

deepcopy() = True

Hacking checks

A handful of new translation hacking checks have been added in the 0.3.0 release:
[N532] Validate that LOG.warning is used instead of LOG.warn. The latter is deprecated.
[N534] Exception messages should be translated
[N533] Validate that debug level logs are not translated
[N531] Validate that LOG messages, except debug ones, have translations

The behavior of these hacking checks should be evident from the description shown above, so I won't belabor. These checks are all registered via neutron_lib.hacking.checks.factory() and therefore will be active by default if your project uses the neutron_lib factory function in it's tox.ini.

Looking forward in this space, we hope to further solidify the hacking check interface as well as the dev-ref for its intended usage. For example: 350723