watcher-tempest-plugin 3.7.0__tar.gz → 3.8.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/.zuul.yaml +15 -8
  2. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/AUTHORS +1 -0
  3. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/ChangeLog +10 -0
  4. {watcher_tempest_plugin-3.7.0/watcher_tempest_plugin.egg-info → watcher_tempest_plugin-3.8.0}/PKG-INFO +5 -1
  5. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/README.rst +4 -0
  6. watcher_tempest_plugin-3.8.0/releasenotes/notes/parametrize-promtool-write-url-path-3534f2b9.yaml +8 -0
  7. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/config.py +7 -0
  8. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/infra_optim_clients.py +1 -0
  9. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/metric/prometheus_client.py +43 -8
  10. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_execute_zone_migration.py +174 -44
  11. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0/watcher_tempest_plugin.egg-info}/PKG-INFO +5 -1
  12. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin.egg-info/SOURCES.txt +1 -0
  13. watcher_tempest_plugin-3.8.0/watcher_tempest_plugin.egg-info/pbr.json +1 -0
  14. watcher_tempest_plugin-3.7.0/watcher_tempest_plugin.egg-info/pbr.json +0 -1
  15. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/.coveragerc +0 -0
  16. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/.mailmap +0 -0
  17. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/.stestr.conf +0 -0
  18. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/.testr.conf +0 -0
  19. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/CONTRIBUTING.rst +0 -0
  20. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/HACKING.rst +0 -0
  21. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/LICENSE +0 -0
  22. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/doc/requirements.txt +0 -0
  23. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/doc/source/conf.py +0 -0
  24. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/doc/source/contributing.rst +0 -0
  25. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/doc/source/index.rst +0 -0
  26. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/doc/source/readme.rst +0 -0
  27. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/pyproject.toml +0 -0
  28. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/releasenotes/notes/.placeholder +0 -0
  29. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/releasenotes/notes/drop-py-2-7-eb1979587d237f5e.yaml +0 -0
  30. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/releasenotes/notes/drop-python38-support-eeb09a8bc0170ce2.yaml +0 -0
  31. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/releasenotes/source/_static/.placeholder +0 -0
  32. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/releasenotes/source/_templates/.placeholder +0 -0
  33. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/releasenotes/source/conf.py +0 -0
  34. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/releasenotes/source/index.rst +0 -0
  35. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/releasenotes/source/unreleased.rst +0 -0
  36. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/requirements.txt +0 -0
  37. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/setup.cfg +0 -0
  38. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/setup.py +0 -0
  39. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/test-requirements.txt +0 -0
  40. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/tox.ini +0 -0
  41. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/__init__.py +0 -0
  42. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/plugin.py +0 -0
  43. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/__init__.py +0 -0
  44. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/base.py +0 -0
  45. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/infra_optim/__init__.py +0 -0
  46. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/infra_optim/v1/__init__.py +0 -0
  47. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/infra_optim/v1/json/__init__.py +0 -0
  48. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/infra_optim/v1/json/api_microversion_fixture.py +0 -0
  49. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/infra_optim/v1/json/client.py +0 -0
  50. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/metric/__init__.py +0 -0
  51. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/metric/v1/__init__.py +0 -0
  52. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/metric/v1/json/__init__.py +0 -0
  53. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/services/metric/v1/json/client.py +0 -0
  54. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/__init__.py +0 -0
  55. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/__init__.py +0 -0
  56. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/__init__.py +0 -0
  57. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/base.py +0 -0
  58. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/test_action.py +0 -0
  59. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/test_action_plan.py +0 -0
  60. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/test_api_discovery.py +0 -0
  61. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/test_audit.py +0 -0
  62. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/test_audit_template.py +0 -0
  63. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/test_data_model.py +0 -0
  64. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/test_goal.py +0 -0
  65. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/test_scoring_engine.py +0 -0
  66. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/test_service.py +0 -0
  67. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/api/admin/test_strategy.py +0 -0
  68. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/client_functional/__init__.py +0 -0
  69. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/client_functional/v1/__init__.py +0 -0
  70. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/client_functional/v1/base.py +0 -0
  71. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/client_functional/v1/test_action.py +0 -0
  72. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/client_functional/v1/test_action_plan.py +0 -0
  73. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/client_functional/v1/test_audit.py +0 -0
  74. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/client_functional/v1/test_audit_template.py +0 -0
  75. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/client_functional/v1/test_goal.py +0 -0
  76. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/client_functional/v1/test_scoring_engine.py +0 -0
  77. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/client_functional/v1/test_service.py +0 -0
  78. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/client_functional/v1/test_strategy.py +0 -0
  79. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/common/__init__.py +0 -0
  80. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/common/base.py +0 -0
  81. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/__init__.py +0 -0
  82. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/base.py +0 -0
  83. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_continuous_audit.py +0 -0
  84. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_data_model.py +0 -0
  85. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_execute_actuator.py +0 -0
  86. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_execute_basic_optim.py +0 -0
  87. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_execute_dummy_optim.py +0 -0
  88. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_execute_host_maintenance.py +0 -0
  89. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_execute_node_resource_consolidation.py +0 -0
  90. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_execute_storage_balance.py +0 -0
  91. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_execute_strategies_real.py +0 -0
  92. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_execute_vm_workload_consolidation.py +0 -0
  93. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_execute_workload_balance.py +0 -0
  94. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/tests/scenario/test_execute_workload_stabilization.py +0 -0
  95. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin/utils.py +0 -0
  96. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin.egg-info/dependency_links.txt +0 -0
  97. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin.egg-info/entry_points.txt +0 -0
  98. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin.egg-info/not-zip-safe +0 -0
  99. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin.egg-info/requires.txt +0 -0
  100. {watcher_tempest_plugin-3.7.0 → watcher_tempest_plugin-3.8.0}/watcher_tempest_plugin.egg-info/top_level.txt +0 -0
@@ -10,26 +10,39 @@
10
10
  - watcher-tempest-aetos
11
11
  - watcher-tempest-gnocchi
12
12
  - watcher-tempest-prometheus
13
+ - watcher-tempest-aetos-2026-1
14
+ - watcher-tempest-gnocchi-2026-1
13
15
  - watcher-tempest-aetos-2025-2
14
16
  - watcher-tempest-gnocchi-2025-2
15
17
  - watcher-tempest-gnocchi-2025-1
16
18
  - watcher-tempest-prometheus-2025-1
17
- - watcher-tempest-gnocchi-2024-2
18
19
  gate:
19
20
  jobs:
20
21
  - watcher-tempest-aetos
21
22
  - watcher-tempest-gnocchi
22
23
  - watcher-tempest-prometheus
24
+ - watcher-tempest-aetos-2026-1
25
+ - watcher-tempest-gnocchi-2026-1
23
26
  - watcher-tempest-aetos-2025-2
24
27
  - watcher-tempest-gnocchi-2025-2
25
28
  - watcher-tempest-gnocchi-2025-1
26
29
  - watcher-tempest-prometheus-2025-1
27
- - watcher-tempest-gnocchi-2024-2
28
30
  experimental:
29
31
  jobs:
30
32
  - watcher-tempest-prometheus-realdata
31
33
  - watcher-tempest-aetos-realdata
32
34
 
35
+ # stable/2026.1 jobs
36
+ - job:
37
+ name: watcher-tempest-aetos-2026-1
38
+ parent: watcher-tempest-aetos
39
+ override-checkout: stable/2026.1
40
+
41
+ - job:
42
+ name: watcher-tempest-gnocchi-2026-1
43
+ parent: watcher-tempest-gnocchi
44
+ override-checkout: stable/2026.1
45
+
33
46
  # stable/2025.2 jobs
34
47
  - job:
35
48
  name: watcher-tempest-aetos-2025-2
@@ -51,9 +64,3 @@
51
64
  name: watcher-tempest-prometheus-2025-1
52
65
  parent: watcher-tempest-prometheus
53
66
  override-checkout: stable/2025.1
54
-
55
- # stable/2024.2 jobs
56
- - job:
57
- name: watcher-tempest-gnocchi-2024-2
58
- parent: watcher-tempest-gnocchi
59
- override-checkout: stable/2024.2
@@ -14,6 +14,7 @@ Ghanshyam Mann <gmann@ghanshyammann.com>
14
14
  Gábor Antal <antal@inf.u-szeged.hu>
15
15
  Hervé Beraud <hberaud@redhat.com>
16
16
  Hidekazu Nakamura <hid-nakamura@vf.jp.nec.com>
17
+ Ivan Anfimov <lazekteam@gmail.com>
17
18
  Jaewoo Park <jp655p@att.com>
18
19
  Jaromir Wysoglad <jwysogla@redhat.com>
19
20
  Ken'ichi Ohmichi <ken-oomichi@wx.jp.nec.com>
@@ -1,10 +1,20 @@
1
1
  CHANGES
2
2
  =======
3
3
 
4
+ 3.8.0
5
+ -----
6
+
7
+ * Remove 2024.2 jobs from the zuul gates
8
+ * Add stable/2026.1 job
9
+ * Parametrize promtool write URL path
10
+ * Add extra checks to zone migration retype test
11
+ * Test zone migration volume and compute migrations
12
+
4
13
  3.7.0
5
14
  -----
6
15
 
7
16
  * Add test for volume migrate with zone migration
17
+ * Add project badge
8
18
  * Consolidate and improve Zuul CI jobs for stable branches
9
19
  * Fix unsupported operand types in internal methods
10
20
  * Refresh the state of the actionplan before asserting status
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: watcher-tempest-plugin
3
- Version: 3.7.0
3
+ Version: 3.8.0
4
4
  Summary: Tempest plugin watcher-tempest-plugin
5
5
  Home-page: https://docs.openstack.org/watcher/latest/
6
6
  Author: OpenStack
@@ -39,6 +39,10 @@ Dynamic: summary
39
39
  watcher-tempest-plugin
40
40
  ======================
41
41
 
42
+ .. image:: https://governance.openstack.org/tc/badges/watcher-tempest-plugin.svg
43
+
44
+ .. Change things from this point on
45
+
42
46
  This repository contains a `Tempest`_ `test plugin`_ to verify the
43
47
  functionality of the `Watcher`_ service.
44
48
 
@@ -2,6 +2,10 @@
2
2
  watcher-tempest-plugin
3
3
  ======================
4
4
 
5
+ .. image:: https://governance.openstack.org/tc/badges/watcher-tempest-plugin.svg
6
+
7
+ .. Change things from this point on
8
+
5
9
  This repository contains a `Tempest`_ `test plugin`_ to verify the
6
10
  functionality of the `Watcher`_ service.
7
11
 
@@ -0,0 +1,8 @@
1
+ ---
2
+ features:
3
+ - |
4
+ Added a new ``prometheus_write_path`` configuration option under the
5
+ ``[optimize]`` section to allow customizing the URL path appended to the
6
+ Prometheus base URL for remote write operations. The default value is
7
+ ``/api/v1/write``, preserving the existing behavior. Set it to an empty
8
+ string if the base URL already includes the full write endpoint.
@@ -96,6 +96,13 @@ OptimizationGroup = [
96
96
  help="The label that Prometheus uses to store the fqdn of "
97
97
  "exporters.",
98
98
  ),
99
+ cfg.StrOpt(
100
+ "prometheus_write_path",
101
+ default="/api/v1/write",
102
+ help="The URL path to append to the Prometheus base URL for "
103
+ "remote write operations. Set to an empty string if the "
104
+ "base URL already includes the full write endpoint.",
105
+ ),
99
106
  # Podified control plane configuration
100
107
  cfg.StrOpt(
101
108
  "podified_kubeconfig_path",
@@ -55,6 +55,7 @@ class BaseManager(clients.Manager, metaclass=abc.ABCMeta):
55
55
  podified_kubeconfig=CONF.optimize.podified_kubeconfig_path,
56
56
  prometheus_ssl_cert=CONF.optimize.prometheus_ssl_cert_dir,
57
57
  prometheus_fqdn_label=CONF.optimize.prometheus_fqdn_label,
58
+ write_url_path=CONF.optimize.prometheus_write_path,
58
59
  )
59
60
 
60
61
 
@@ -13,9 +13,9 @@
13
13
  # under the License.
14
14
 
15
15
  import json
16
+ from urllib import parse
16
17
 
17
18
  from oslo_log import log
18
- from urllib.parse import quote
19
19
 
20
20
  from watcher_tempest_plugin.services import base
21
21
 
@@ -31,8 +31,32 @@ class PromtoolClient:
31
31
  proxy_host_pkey=None, proxy_host_pkey_type='rsa',
32
32
  podified_ns=None, podified_kubeconfig=None,
33
33
  prometheus_ssl_cert=None,
34
- prometheus_fqdn_label="fqdn"):
35
-
34
+ prometheus_fqdn_label="fqdn",
35
+ write_url_path=None):
36
+ """Initialize PromtoolClient.
37
+
38
+ :param url: Base URL of the Prometheus server (e.g.
39
+ 'http://host:9090').
40
+ :param promtool_path: Path to the promtool binary.
41
+ :param openstack_type: Deployment type; use 'podified' for
42
+ Podified Control Plane deployments, 'devstack' otherwise.
43
+ :param proxy_host_address: Optional SSH proxy host address. When
44
+ provided together with proxy_host_user, commands are executed
45
+ over SSH instead of locally.
46
+ :param proxy_host_user: SSH username for the proxy host.
47
+ :param proxy_host_pkey: Path to the SSH private key file.
48
+ :param proxy_host_pkey_type: Type of the SSH private key
49
+ (default: 'rsa').
50
+ :param podified_ns: Kubernetes namespace for podified deployments.
51
+ :param podified_kubeconfig: Path to the kubeconfig file for
52
+ podified deployments.
53
+ :param prometheus_ssl_cert: Directory containing SSL certificates
54
+ used when connecting to Prometheus over HTTPS.
55
+ :param prometheus_fqdn_label: Prometheus label used to identify
56
+ host FQDNs in target metadata (default: 'fqdn').
57
+ :param write_url_path: URL path for the remote-write endpoint
58
+ (default: '/api/v1/write').
59
+ """
36
60
  # Podified Control Plane
37
61
  self.is_podified = ("podified" == openstack_type)
38
62
  LOG.debug(f"Configuring PromtoolClient for {openstack_type} "
@@ -61,12 +85,23 @@ class PromtoolClient:
61
85
  cmd_prefix = self.oc_cmd + ["rsh", self.prometheus_pod]
62
86
  self.client.cmd_prefix = " ".join(cmd_prefix)
63
87
 
88
+ # We keep the raw URL for reference/labels
64
89
  self.prometheus_url = url
65
- self.prometheus_write_url = url + "/api/v1/write"
66
- self.prometheus_delete_series_url = (
67
- url + "/api/v1/admin/tsdb/delete_series")
90
+
91
+ # Internal base_url ensuring a trailing slash for reliable joining
92
+ base_url = url if url.endswith('/') else url + '/'
93
+
94
+ # Handle write_url_path: handles None/Empty and leading slash issues
95
+ clean_write_path = (write_url_path or "").lstrip('/')
96
+ self.prometheus_write_url = parse.urljoin(base_url, clean_write_path)
97
+
98
+ self.prometheus_delete_series_url = parse.urljoin(
99
+ base_url, "api/v1/admin/tsdb/delete_series"
100
+ )
68
101
  # active targets
69
- self.prometheus_targets_url = url + "/api/v1/targets?state=active"
102
+ self.prometheus_targets_url = parse.urljoin(
103
+ base_url, "api/v1/targets?state=active"
104
+ )
70
105
  self.prometheus_fqdn_label = prometheus_fqdn_label
71
106
  self.promtool_cmd = [promtool_path]
72
107
  if prometheus_ssl_cert:
@@ -137,7 +172,7 @@ class PromtoolClient:
137
172
  # with double quotes both on direct command and
138
173
  # ssh command so using url encoding
139
174
 
140
- quoted_expr = quote(expr)
175
+ quoted_expr = parse.quote(expr)
141
176
 
142
177
  cmd = ['curl', '-s', '-k', '-X', 'POST', '-g',
143
178
  self.prometheus_delete_series_url + '?match[]=' + quoted_expr]
@@ -167,20 +167,57 @@ class TestExecuteZoneMigrationStrategyVolume(TestZoneMigrationStrategyBase):
167
167
  f"test volume migration, {len(pools)} found"
168
168
  )
169
169
 
170
+ def calculate_dst_pools(self, src_pool1, src_pool2):
171
+ """Check which should be the destination pool of the volumes
172
+
173
+ Calculate which should be the destination pool for each volume
174
+ according to where they were scheduled.
175
+ """
176
+ if src_pool1 == src_pool2:
177
+ # if both volumes are scheduled in the same storage host we only
178
+ # need one entry in the input parameters, it's enough picking one
179
+ # pool that is different than the source pool
180
+ all_pools = self.get_pool_names()
181
+ other_pools = all_pools - {src_pool1}
182
+ if not other_pools:
183
+ self.fail(
184
+ "could not find a destination pool for volumes "
185
+ f"in {src_pool1}"
186
+ )
187
+ dst_pool1 = dst_pool2 = other_pools.pop()
188
+ else:
189
+ dst_pool1 = src_pool2
190
+ dst_pool2 = src_pool1
191
+ return dst_pool1, dst_pool2
192
+
170
193
  @decorators.attr(type=['strategy', 'zone_migration', 'volume_migration'])
171
194
  @decorators.idempotent_id('f8f4d551-d892-4111-ab92-5b6b5523e5dc')
172
195
  def test_execute_zone_migration_volume_retype(self):
173
196
  self.check_min_enabled_compute_nodes(2)
174
197
  self.addCleanup(self.wait_delete_instances_from_model)
175
198
 
176
- # create second volume type
177
- volume_type = self.create_volume_type()
199
+ src_volume_type = self.create_volume_type()
200
+ src_type = src_volume_type["name"]
201
+
202
+ dst_volume_type = self.create_volume_type()
203
+ dst_type = dst_volume_type["name"]
204
+
205
+ # create additional volume type, with a volume
206
+ # associated. The test will use the src_type parameter to filter the
207
+ # volumes being retyped, and at the end of the test we will check the
208
+ # volume with this extra_volume_type was not changed as a result of the
209
+ # action plan.
210
+ extra_volume_type = self.create_volume_type()
211
+ extra_volume = self.create_volume(
212
+ name="extra_volume_retype",
213
+ volume_type=extra_volume_type["name"]
214
+ )
178
215
 
179
216
  # create a free volume
180
217
  free_volume = self.create_volume(
181
218
  name="free_volume_retype",
219
+ volume_type=src_type
182
220
  )
183
- src_type = free_volume['volume_type']
184
221
 
185
222
  # create a volume and attach it to an instance
186
223
  instance = self.create_server(
@@ -190,6 +227,7 @@ class TestExecuteZoneMigrationStrategyVolume(TestZoneMigrationStrategyBase):
190
227
  )
191
228
  vm_volume = self.create_volume(
192
229
  name="attached_volume_retype",
230
+ volume_type=src_type
193
231
  )
194
232
  self.nova_volume_attach(
195
233
  instance, vm_volume, servers_client=self.os_primary.servers_client
@@ -203,9 +241,13 @@ class TestExecuteZoneMigrationStrategyVolume(TestZoneMigrationStrategyBase):
203
241
  }
204
242
 
205
243
  audit_parameters = {
244
+ # add the parameter to detect any possible regression on
245
+ # https://bugs.launchpad.net/watcher/+bug/2111429, for this test
246
+ # the parameter should have no impact
247
+ "with_attached_volume": True,
206
248
  "storage_pools": [
207
249
  {"src_pool": src_pool, "src_type": src_type,
208
- "dst_type": volume_type['name']}
250
+ "dst_type": dst_type}
209
251
  for src_pool in src_pools
210
252
  ]
211
253
  }
@@ -226,15 +268,25 @@ class TestExecuteZoneMigrationStrategyVolume(TestZoneMigrationStrategyBase):
226
268
 
227
269
  # check that the available volume was retyped
228
270
  self.assertEqual(
229
- self.get_type_for_volume(free_volume['id']), volume_type['name']
271
+ self.get_type_for_volume(free_volume['id']), dst_type
272
+ )
273
+ self.assertEqual(
274
+ self.get_type_for_volume(vm_volume['id']), dst_type
230
275
  )
276
+ # check that extra_volume was not retyped as a result of the audit,
277
+ # meaning that the volume was ignored due to the value of src_type,
278
+ # this should serve to detect a possible regression on
279
+ # https://bugs.launchpad.net/watcher/+bug/2111507
231
280
  self.assertEqual(
232
- self.get_type_for_volume(vm_volume['id']), volume_type['name']
281
+ self.get_type_for_volume(extra_volume['id']),
282
+ extra_volume_type['name']
233
283
  )
234
284
 
235
285
  @decorators.attr(type=['strategy', 'zone_migration', 'volume_migration'])
236
286
  @decorators.idempotent_id('2287000d-6f0e-4275-8741-cfeb38090307')
237
287
  def test_execute_zone_migration_volume_migrate(self):
288
+ """Test zone migration strategy with volume migrations."""
289
+
238
290
  # check that there are multiple cinder pools configured
239
291
  # to be able to test migrations between them
240
292
  self.check_multiple_pools()
@@ -267,49 +319,31 @@ class TestExecuteZoneMigrationStrategyVolume(TestZoneMigrationStrategyBase):
267
319
 
268
320
  src_pool_free_volume = self.get_host_for_volume(free_volume['id'])
269
321
  src_pool_vm_volume = self.get_host_for_volume(vm_volume['id'])
270
- if src_pool_free_volume == src_pool_vm_volume:
271
- # if both volumes are scheduled in the same storage host we only
272
- # need one entry in the input parameters, it's enough picking one
273
- # pool that is different than the source pool
274
- all_pools = self.get_pool_names()
275
- other_pools = all_pools - {src_pool_free_volume}
276
- if not other_pools:
277
- self.fail(
278
- "could not find a destination pool for volumes "
279
- f"in {src_pool_free_volume}"
280
- )
281
- dst_pool_free_volume = dst_pool_vm_volume = other_pools.pop()
282
- audit_parameters = {
283
- 'storage_pools': [
284
- {
285
- 'src_pool': src_pool_free_volume,
286
- 'src_type': volume_type['name'],
287
- 'dst_pool': dst_pool_free_volume
288
- }
289
- ]
290
- }
291
- else:
322
+ dst_pool_free_volume, dst_pool_vm_volume = self.calculate_dst_pools(
323
+ src_pool_free_volume, src_pool_vm_volume
324
+ )
325
+ audit_parameters = {
326
+ 'storage_pools': [
327
+ {
328
+ 'src_pool': src_pool_free_volume,
329
+ 'src_type': volume_type['name'],
330
+ 'dst_pool': dst_pool_free_volume
331
+ }
332
+ ]
333
+ }
334
+ if dst_pool_free_volume != dst_pool_vm_volume:
292
335
  # if the two volumes are scheduled in different hosts, we need to
293
336
  # add both source hosts to the input parameters. Each volume is
294
337
  # then migrated to the other's source pool and the 'src_type'
295
338
  # parameter is set to the volume type created in the test to ensure
296
339
  # no other volumes are migrated
297
- dst_pool_free_volume = src_pool_vm_volume
298
- dst_pool_vm_volume = src_pool_free_volume
299
- audit_parameters = {
300
- 'storage_pools': [
301
- {
302
- 'src_pool': src_pool_free_volume,
303
- 'src_type': volume_type['name'],
304
- 'dst_pool': dst_pool_free_volume
305
- },
306
- {
307
- 'src_pool': src_pool_vm_volume,
308
- 'src_type': volume_type['name'],
309
- 'dst_pool': dst_pool_vm_volume
310
- }
311
- ]
312
- }
340
+ audit_parameters['storage_pools'].append(
341
+ {
342
+ 'src_pool': src_pool_vm_volume,
343
+ 'src_type': volume_type['name'],
344
+ 'dst_pool': dst_pool_vm_volume
345
+ }
346
+ )
313
347
 
314
348
  audit_kwargs = {'parameters': audit_parameters}
315
349
 
@@ -332,3 +366,99 @@ class TestExecuteZoneMigrationStrategyVolume(TestZoneMigrationStrategyBase):
332
366
  vm_volume_host = self.get_host_for_volume(vm_volume['id'])
333
367
  self.assertEqual(vm_volume_host, dst_pool_vm_volume)
334
368
  self.assertNotEqual(vm_volume_host, src_pool_vm_volume)
369
+
370
+ @decorators.attr(type=['strategy', 'zone_migration', 'volume_migration'])
371
+ @decorators.idempotent_id('9ceff861-d6cd-4a88-8a8f-0a5d659b7b38')
372
+ def test_execute_zone_migration_with_volume_and_compute_migration(self):
373
+ """Test zone migration strategy with volume and compute migrations."""
374
+
375
+ # check that there are multiple cinder pools configured
376
+ # to be able to test migrations between them
377
+ self.check_multiple_pools()
378
+
379
+ self.check_min_enabled_compute_nodes(2)
380
+ self.addCleanup(self.wait_delete_instances_from_model)
381
+
382
+ volume_type = self.create_volume_type()
383
+
384
+ # create a free volume
385
+ free_volume = self.create_volume(
386
+ name='free_volume_migrate', volume_type=volume_type['name']
387
+ )
388
+
389
+ # create a volume and attach it to an instance
390
+ instance = self.create_server(
391
+ image_id=CONF.compute.image_ref,
392
+ wait_until='SSHABLE',
393
+ clients=self.os_primary,
394
+ )
395
+
396
+ vm_volume = self.create_volume(
397
+ name='attached_volume_migrate', volume_type=volume_type['name']
398
+ )
399
+ self.nova_volume_attach(
400
+ instance, vm_volume, servers_client=self.os_primary.servers_client
401
+ )
402
+ # wait for compute model updates
403
+ self.wait_for_instances_in_model([instance])
404
+
405
+ src_pool_free_volume = self.get_host_for_volume(free_volume['id'])
406
+ src_pool_vm_volume = self.get_host_for_volume(vm_volume['id'])
407
+ dst_pool_free_volume, dst_pool_vm_volume = self.calculate_dst_pools(
408
+ src_pool_free_volume, src_pool_vm_volume
409
+ )
410
+ audit_parameters = {
411
+ 'storage_pools': [
412
+ {
413
+ 'src_pool': src_pool_free_volume,
414
+ 'src_type': volume_type['name'],
415
+ 'dst_pool': dst_pool_free_volume
416
+ }
417
+ ]
418
+ }
419
+ if dst_pool_free_volume != dst_pool_vm_volume:
420
+ # if the two volumes are scheduled in different hosts, we need to
421
+ # add both source hosts to the input parameters. Each volume is
422
+ # then migrated to the other's source pool and the 'src_type'
423
+ # parameter is set to the volume type created in the test to ensure
424
+ # no other volumes are migrated
425
+ audit_parameters['storage_pools'].append(
426
+ {
427
+ 'src_pool': src_pool_vm_volume,
428
+ 'src_type': volume_type['name'],
429
+ 'dst_pool': dst_pool_vm_volume
430
+ }
431
+ )
432
+
433
+ src_node = self.get_host_for_server(instance['id'])
434
+ dst_node = self.get_host_other_than(instance['id'])
435
+ audit_parameters['compute_nodes'] = [
436
+ {'src_node': src_node, 'dst_node': dst_node}
437
+ ]
438
+
439
+ audit_kwargs = {'parameters': audit_parameters}
440
+
441
+ audit_template = self.create_audit_template_for_strategy()
442
+
443
+ audit = self.create_audit_and_wait(
444
+ audit_template['uuid'], **audit_kwargs)
445
+
446
+ action_plan, _ = self.get_action_plan_and_validate_actions(
447
+ audit['uuid'], ['volume_migrate', 'migrate'])
448
+
449
+ self.assertEqual('RECOMMENDED', action_plan['state'])
450
+
451
+ self.execute_action_plan_and_validate_states(action_plan['uuid'])
452
+
453
+ free_volume_host = self.get_host_for_volume(free_volume['id'])
454
+ self.assertEqual(free_volume_host, dst_pool_free_volume)
455
+ self.assertNotEqual(free_volume_host, src_pool_free_volume)
456
+
457
+ vm_volume_host = self.get_host_for_volume(vm_volume['id'])
458
+ self.assertEqual(vm_volume_host, dst_pool_vm_volume)
459
+ self.assertNotEqual(vm_volume_host, src_pool_vm_volume)
460
+
461
+ self.assertEqual(
462
+ self.get_host_for_server(instance['id']),
463
+ dst_node
464
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: watcher-tempest-plugin
3
- Version: 3.7.0
3
+ Version: 3.8.0
4
4
  Summary: Tempest plugin watcher-tempest-plugin
5
5
  Home-page: https://docs.openstack.org/watcher/latest/
6
6
  Author: OpenStack
@@ -39,6 +39,10 @@ Dynamic: summary
39
39
  watcher-tempest-plugin
40
40
  ======================
41
41
 
42
+ .. image:: https://governance.openstack.org/tc/badges/watcher-tempest-plugin.svg
43
+
44
+ .. Change things from this point on
45
+
42
46
  This repository contains a `Tempest`_ `test plugin`_ to verify the
43
47
  functionality of the `Watcher`_ service.
44
48
 
@@ -23,6 +23,7 @@ doc/source/readme.rst
23
23
  releasenotes/notes/.placeholder
24
24
  releasenotes/notes/drop-py-2-7-eb1979587d237f5e.yaml
25
25
  releasenotes/notes/drop-python38-support-eeb09a8bc0170ce2.yaml
26
+ releasenotes/notes/parametrize-promtool-write-url-path-3534f2b9.yaml
26
27
  releasenotes/source/conf.py
27
28
  releasenotes/source/index.rst
28
29
  releasenotes/source/unreleased.rst
@@ -0,0 +1 @@
1
+ {"git_version": "b69f7ed", "is_release": true}
@@ -1 +0,0 @@
1
- {"git_version": "49e68f7", "is_release": true}