-
Notifications
You must be signed in to change notification settings - Fork 9
hooks: defer internal OVS startup until charm has configured identity #168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1543,6 +1543,9 @@ def test_internal_ovs_not_ready_defers_ovs_configuration(self, mocker, snap): | |||||||||||||||||||||||||||||||
| "_ensure_internal_ovs_services", | ||||||||||||||||||||||||||||||||
| side_effect=lambda *_: order.append("ensure"), | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
| # Simulate charm already configured (real identity URL) so the OVS | ||||||||||||||||||||||||||||||||
| # startup guard does not interfere with what this test is checking. | ||||||||||||||||||||||||||||||||
| snap.config.get_options.return_value.get.return_value = "http://10.0.0.1:5000/v3" | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| hooks.configure(snap) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
@@ -1581,6 +1584,9 @@ def test_internal_ovs_ready_runs_configuration(self, mocker, snap): | |||||||||||||||||||||||||||||||
| "_ensure_internal_ovs_services", | ||||||||||||||||||||||||||||||||
| side_effect=lambda *_: order.append("ensure"), | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
| # Simulate charm already configured (real identity URL) so the OVS | ||||||||||||||||||||||||||||||||
| # startup guard does not interfere with what this test is checking. | ||||||||||||||||||||||||||||||||
| snap.config.get_options.return_value.get.return_value = "http://10.0.0.1:5000/v3" | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| hooks.configure(snap) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
@@ -1660,6 +1666,141 @@ def test_external_ovs_ready_check_uses_socket_path(self, mocker, snap, tmp_path) | |||||||||||||||||||||||||||||||
| socket_file.touch() | ||||||||||||||||||||||||||||||||
| assert hooks._external_ovs_ready(snap) is True | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| def test_internal_ovs_not_started_on_unconfigured_first_run(self, mocker, snap): | ||||||||||||||||||||||||||||||||
| """Internal OVS services must NOT be started while identity is unconfigured. | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Snapd fires a configure hook automatically right after 'snap install', and | ||||||||||||||||||||||||||||||||
| again when the charm calls ``snap set network.ovs-managed-by=auto`` in its | ||||||||||||||||||||||||||||||||
| own install hook — both times before any real Keystone URL has been provided. | ||||||||||||||||||||||||||||||||
| The snap detects this by checking that ``identity.auth-url`` still equals the | ||||||||||||||||||||||||||||||||
| placeholder default. In that state ``_ensure_internal_ovs_services`` must be | ||||||||||||||||||||||||||||||||
| skipped to avoid creating ``system@ovs-system`` before microovn installs. | ||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||
| snap.services.list.return_value = {} | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_mkdirs") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_update_default_config") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_setup_secrets") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_detect_compute_flavors") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_get_configure_context", return_value={"network": {}}) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_get_exclude_services", return_value=[]) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "OVSCli", return_value=mock.Mock()) | ||||||||||||||||||||||||||||||||
| # OVS mode is 'auto' (default from conftest) and plug is not connected | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "is_ovs_external", return_value=False) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_internal_ovs_ready", return_value=True) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "RestartOnChange", return_value=nullcontext()) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_render_templates") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_webdav_apache") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_tls") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_networking") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_kvm") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_monitoring_services") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_ceph") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_masakari_services") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_sriov_agent_service") | ||||||||||||||||||||||||||||||||
| mock_ensure = mocker.patch.object(hooks, "_ensure_internal_ovs_services") | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| # Simulate snap not yet configured by the charm: identity URL is the placeholder | ||||||||||||||||||||||||||||||||
| # AND username has not been set yet (None). Both conditions must hold for the | ||||||||||||||||||||||||||||||||
| # guard to defer OVS startup. | ||||||||||||||||||||||||||||||||
| def unconfigured_identity_get(key, default=None): | ||||||||||||||||||||||||||||||||
| if key == "identity.auth-url": | ||||||||||||||||||||||||||||||||
| return hooks.DEFAULT_CONFIG["identity.auth-url"] | ||||||||||||||||||||||||||||||||
| if key == "identity.username": | ||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||
| return default | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| snap.config.get_options.return_value.get.side_effect = unconfigured_identity_get | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| hooks.configure(snap) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| # _ensure_internal_ovs_services must NOT have been called — starting | ||||||||||||||||||||||||||||||||
| # ovs-vswitchd here would create system@ovs-system and block microovn. | ||||||||||||||||||||||||||||||||
| mock_ensure.assert_not_called() | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| def test_internal_ovs_started_when_managed_by_hypervisor_with_default_identity( | ||||||||||||||||||||||||||||||||
| self, mocker, snap | ||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||
| """Internal OVS must start when explicitly managed by 'hypervisor'. | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Even if ``identity.auth-url`` is still at the placeholder default and | ||||||||||||||||||||||||||||||||
| ``identity.username`` has not been set (i.e. the charm hasn't configured | ||||||||||||||||||||||||||||||||
| identity yet), setting ``network.ovs-managed-by`` to ``'hypervisor'`` must | ||||||||||||||||||||||||||||||||
| bypass the guard and ensure internal OVS services are started. | ||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||
| snap.services.list.return_value = {} | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_mkdirs") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_update_default_config") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_setup_secrets") | ||||||||||||||||||||||||||||||||
| # Force OVS mode to 'hypervisor' (simulates charm explicitly setting it). | ||||||||||||||||||||||||||||||||
| mocker.patch.object( | ||||||||||||||||||||||||||||||||
| hooks, | ||||||||||||||||||||||||||||||||
| "_set_ovs_managed_by", | ||||||||||||||||||||||||||||||||
| side_effect=lambda _: setattr( | ||||||||||||||||||||||||||||||||
| hooks, "_OVS_MANAGED_BY", hooks.OVS_MANAGED_BY_HYPERVISOR | ||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_detect_compute_flavors") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_get_configure_context", return_value={"network": {}}) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_get_exclude_services", return_value=[]) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "OVSCli", return_value=mock.Mock()) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "is_ovs_external", return_value=False) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_internal_ovs_ready", return_value=True) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "RestartOnChange", return_value=nullcontext()) | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_render_templates") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_webdav_apache") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_tls") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_networking") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_kvm") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_monitoring_services") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_ceph") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_masakari_services") | ||||||||||||||||||||||||||||||||
| mocker.patch.object(hooks, "_configure_sriov_agent_service") | ||||||||||||||||||||||||||||||||
| mock_ensure = mocker.patch.object(hooks, "_ensure_internal_ovs_services") | ||||||||||||||||||||||||||||||||
| # Identity is still unconfigured (placeholder URL, no username) — the guard | ||||||||||||||||||||||||||||||||
| # must be bypassed because mode is explicitly 'hypervisor'. | ||||||||||||||||||||||||||||||||
| snap.config.get_options.return_value.get.return_value = hooks.DEFAULT_CONFIG[ | ||||||||||||||||||||||||||||||||
| "identity.auth-url" | ||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
Comment on lines
+1761
to
+1764
|
||||||||||||||||||||||||||||||||
| snap.config.get_options.return_value.get.return_value = hooks.DEFAULT_CONFIG[ | |
| "identity.auth-url" | |
| ] | |
| identity_opts = snap.config.get_options.return_value | |
| def _identity_get_side_effect(option, default=None): | |
| if option == "identity.auth-url": | |
| # Still at the placeholder default. | |
| return hooks.DEFAULT_CONFIG["identity.auth-url"] | |
| if option == "identity.username": | |
| # Username has not been configured yet. | |
| return None | |
| return default | |
| identity_opts.get.side_effect = _identity_get_side_effect |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This docstring says the snap defers startup by checking only that
identity.auth-urlequals the placeholder default, but the actual guard inconfigure()also requiresidentity.usernameto be unset. Please update the docstring to reflect the real condition (auth-url placeholder AND username unset) so the test description matches the behavior under test.