cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #02808
Re: [Merge] ~smoser/cloud-init:azure_run_local into cloud-init:master
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.
References