Diff comments:
> diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py > index d1740e5..8745ee7 100644 > --- a/cloudinit/net/__init__.py > +++ b/cloudinit/net/__init__.py > @@ -557,6 +558,67 @@ def get_interfaces(): > return ret > > > +class EphemeralIPv4Network(object): > + """Context manager which sets up temporary static network configuration. > + > + No operations are performed if the provided interface is already > connected. > + If unconnected, bring up the interface with valid ip, prefix and > broadcast. > + If router is provided setup a default route for that interface. Upon > + context exit, tear down the interface leaving no configuration behind. > + """ > + > + def __init__(self, interface, ip, prefix_or_mask, broadcast, > router=None): > + """Setup context manager and validate call signature. > + > + @param interface: Name of the network interface to bring up. > + @param ip: IP address to assign to the interface. > + @param prefix_or_mask: Either netmask of the format X.X.X.X or an int > + prefix. > + @param broadcast: Broadcast address for the IPv4 network. > + @param route: Optionally the default gatway IP. > + """ > + if not all([interface, ip, prefix_or_mask, broadcast]): > + raise ValueError( > + 'Cannot init network on {0} with {1}/{2} and bcast > {3}'.format( > + interface, ip, prefix_or_mask, broadcast)) > + try: > + self.prefix = mask_to_net_prefix(prefix_or_mask) > + except ValueError as e: > + raise ValueError( > + 'Cannot setup network: {0}'.format(e)) > + self.interface = interface > + self.ip = ip > + self.broadcast = broadcast > + self.router = router > + self.network_teardown = True > + > + def __enter__(self): > + """Perform ephemeral network setup if interface is not connected.""" > + if is_up(self.interface): Dropped this and reworked it to check existing ip information via a get_ip_info() utility function. > + LOG.debug( > + "Skipping ephemeral network setup. %s is connected.", > + self.interface) > + self.network_teardown = False > + return > + util.subp([ > + 'ip', '-family', 'inet', 'addr', 'add', > + '%s/%s' % (self.ip, self.prefix), 'broadcast', self.broadcast, > + 'dev', self.interface], capture=True) > + util.subp( > + ['ip', '-family', 'inet', 'link', 'set', 'dev', self.interface, > + 'up'], capture=True) > + if self.router: > + util.subp( > + ['ip', '-4', 'route', 'add', 'default', 'via', self.router, > + 'dev', self.interface], capture=True) > + > + def __exit__(self, excp_type, excp_value, excp_traceback): > + if self.network_teardown: > + util.subp( > + ['ip', 'link', 'set', 'dev', self.interface, 'down'], > + capture=True) Added proper cleanup commands based on what was setup initially. > + > + > class RendererNotFoundError(RuntimeError): > pass > > diff --git a/tox.ini b/tox.ini > index 1140f9b..0bf9ee8 100644 > --- a/tox.ini > +++ b/tox.ini > @@ -21,7 +21,11 @@ setenv = > LC_ALL = en_US.utf-8 > > [testenv:pylint] > -deps = pylint==1.7.1 Good question, without it, we get import errors on mock. I'll dig into why that's the case. > +deps = > + # requirements > + pylint==1.7.1 > + # test-requirements > + mock==1.3.0 > commands = {envpython} -m pylint {posargs:cloudinit} > > [testenv:py3] -- https://code.launchpad.net/~chad.smith/cloud-init/+git/cloud-init/+merge/327827 Your team cloud-init commiters is requested to review the proposed merge of ~chad.smith/cloud-init:unittests-in-cloudinit-package into cloud-init:master. _______________________________________________ Mailing list: https://launchpad.net/~cloud-init-dev Post to : cloud-init-dev@lists.launchpad.net Unsubscribe : https://launchpad.net/~cloud-init-dev More help : https://help.launchpad.net/ListHelp