Diff comments:
> diff --git a/cloudinit/cmd/main.py b/cloudinit/cmd/main.py > index ce3c10d..35d9a55 100644 > --- a/cloudinit/cmd/main.py > +++ b/cloudinit/cmd/main.py > @@ -372,6 +372,7 @@ def main_init(name, args): > LOG.debug("[%s] %s is in local mode, will apply init modules > now.", > mode, init.datasource) > > + init.setup_datasource() comment here about why: some datasources can only complete their setup *after* networking is up > # update fully realizes user-data (pulling in #include if necessary) > init.update() > # Stage 7 > diff --git a/cloudinit/sources/DataSourceAzure.py > b/cloudinit/sources/DataSourceAzure.py > index 4fe0d63..d9132d0 100644 > --- a/cloudinit/sources/DataSourceAzure.py > +++ b/cloudinit/sources/DataSourceAzure.py > @@ -331,6 +335,7 @@ class DataSourceAzureNet(sources.DataSource): > if asset_tag != AZURE_CHASSIS_ASSET_TAG: > LOG.debug("Non-Azure DMI asset tag '%s' discovered.", asset_tag) > return False > + whitespace damage > ddir = self.ds_cfg['data_dir'] > > candidates = [self.seed_dir] > @@ -389,6 +395,33 @@ class DataSourceAzureNet(sources.DataSource): > # the directory to be protected. > write_files(ddir, files, dirmode=0o700) > > + self.metadata['instance-id'] = util.read_dmi_data('system-uuid') > + > + return True > + > + def device_name_to_device(self, name): > + return self.ds_cfg['disk_aliases'].get(name) > + > + def get_config_obj(self): > + return self.cfg > + > + def check_instance_id(self, sys_cfg): > + # quickly (local check only) if self.instance_id is still valid > + return > sources.instance_id_matches_system_uuid(self.get_instance_id()) > + > + def setup(self, is_new_instance): kinda want to bikeshed on this name a bit; more of a register_instance_with_cloud or something. Do we have any other datasources that do something like this? > + if self._negotiated is False: > + LOG.debug("negotiating for %s", self.get_instance_id()) negotiating for instance-id %s Is this more like 'attempting register instance-id %s with azure network fabric' ? > + fabric_data = self._negotiate() > + LOG.debug("negotiating returned %s", fabric_data) We should probably document what we expect this fabric_data to look like, I still don't know what it is. > + if fabric_data: > + self.metadata.update(fabric_data) > + self._negotiated = True > + else: > + LOG.debug("negotiating already done for %s", > + self.get_instance_id()) > + > + def _negotiate(self): > if self.ds_cfg['agent_command'] == AGENT_START_BUILTIN: > self.bounce_network_with_azure_hostname() > > @@ -398,31 +431,64 @@ class DataSourceAzureNet(sources.DataSource): > else: > metadata_func = self.get_metadata_from_agent > > + LOG.debug("negotiating with fabric via %s", via 'agent_command' %s > + self.ds_cfg['agent_command']) > try: > fabric_data = metadata_func() > except Exception as exc: > LOG.info("Error communicating with Azure fabric; assume we > aren't" > " on Azure.", exc_info=True) > return False > - self.metadata['instance-id'] = util.read_dmi_data('system-uuid') > - self.metadata.update(fabric_data) > - > - return True > - > - def device_name_to_device(self, name): > - return self.ds_cfg['disk_aliases'].get(name) > > - def get_config_obj(self): > - return self.cfg > - > - def check_instance_id(self, sys_cfg): > - # quickly (local check only) if self.instance_id is still valid > - return > sources.instance_id_matches_system_uuid(self.get_instance_id()) > + return fabric_data > > def activate(self, cfg, is_new_instance): > address_ephemeral_resize(is_new_instance=is_new_instance) > return > > + @property > + def network_config(self): > + """Generate a network config like net.generate_fallback_network() > with > + the following execptions. > + > + 1. Probe the drivers of the net-devices present and inject them in > + the network configuration under params: driver: <driver> value > + 2. If the driver value is 'mlx4_core', the control mode should be > + set to manual. The device will be later used to build a bond, > + for now we want to ensure the device gets named but does not > + break any network configuration > + """ > + blacklist = ['mlx4_core'] we should set this as a default in the builtins ds configuration I think. > + if not self._network_config: > + LOG.debug('Azure: generating fallback configuration') > + # generate a network config, blacklist picking any mlx4_core devs > + netconfig = net.generate_fallback_config( > + blacklist_drivers=blacklist, config_driver=True) > + > + # if we have any blacklisted devices, update the network_config > to > + # include the device, mac, and driver values, but with no ip > + # config; this ensures udev rules are generated but won't affect > + # ip configuration > + bl_found = 0 > + for bl_dev in [dev for dev in net.get_devicelist() > + if net.device_driver(dev) in blacklist]: > + bl_found += 1 > + cfg = { > + 'type': 'physical', > + 'name': 'vf%d' % bl_found, > + 'mac_address': net.get_interface_mac(bl_dev), > + 'params': { > + 'driver': net.device_driver(bl_dev), > + 'device_id': net.device_devid(bl_dev), > + }, > + } > + netconfig['config'].append(cfg) > + > + # switch to network mode after generating a config drop this comment > + self._network_config = netconfig > + > + return self._network_config > + > > def _partitions_on_device(devpath, maxnum=16): > # return a list of tuples (ptnum, path) for each part on devpath > diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py > index c3ce36d..952caf3 100644 > --- a/cloudinit/sources/__init__.py > +++ b/cloudinit/sources/__init__.py > @@ -251,10 +251,23 @@ class DataSource(object): > def first_instance_boot(self): > return > > + def setup(self, is_new_instance): > + """setup(is_new_instance) > + > + This is called before user-data and vendor-data have been processed. > + > + Unless the datasource has set mode to 'local', then networking > + per 'fallback' or per 'network_config' will have been written and > + brought up the OS at this point. > + """ > + return We could assert those requirements, dsmode == DS_MODE_LOCAL and ds.network_config is not None > + > def activate(self, cfg, is_new_instance): > """activate(cfg, is_new_instance) > > - This is called before the init_modules will be called. > + This is called before the init_modules will be called but after > + the user-data and vendor-data have been fully processed. > + > The cfg is fully up to date config, it contains a merged view of > system config, datasource config, user config, vendor config. > It should be used rather than the sys_cfg passed to __init__. > diff --git a/tests/unittests/test_datasource/test_azure.py > b/tests/unittests/test_datasource/test_azure.py > index 7d33daf..2f7c1bb 100644 > --- a/tests/unittests/test_datasource/test_azure.py > +++ b/tests/unittests/test_datasource/test_azure.py > @@ -142,6 +142,10 @@ scbus-1 on xpt0 bus 0 > def _invoke_agent(cmd): > data['agent_invoked'] = cmd > > + def _get_dsmodes(config): > + # sources.DSMODE_NETWORK > + return 'net' > + drop this > def _wait_for_files(flist, _maxwait=None, _naplen=None): > data['waited'] = flist > return [] > @@ -171,6 +175,7 @@ scbus-1 on xpt0 bus 0 > self.apply_patches([ > (dsaz, 'list_possible_azure_ds_devs', dsdevs), > (dsaz, 'invoke_agent', _invoke_agent), > + (dsaz, 'get_dsmodes', _get_dsmodes), drop this > (dsaz, 'wait_for_files', _wait_for_files), > (dsaz, 'pubkeys_from_crt_files', _pubkeys_from_crt_files), > (dsaz, 'perform_hostname_bounce', mock.MagicMock()), > @@ -568,6 +651,9 @@ class TestAzureBounce(TestCase): > self.patches.enter_context( > mock.patch.object(dsaz, 'get_metadata_from_fabric', > mock.MagicMock(return_value={}))) > + self.patches.enter_context( > + mock.patch.object(dsaz, 'get_dsmodes', > + mock.MagicMock(return_value='net'))) drop this > > def _dmi_mocks(key): > if key == 'system-uuid': -- https://code.launchpad.net/~smoser/cloud-init/+git/cloud-init/+merge/326373 Your team cloud-init commiters is requested to review the proposed merge of ~smoser/cloud-init:azure_run_local 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