diff --git a/config.yaml b/config.yaml index 98213773..483f0441 100644 --- a/config.yaml +++ b/config.yaml @@ -886,3 +886,19 @@ options: . This option doesn't have any effect on clouds running a release < Rocky. + block-device-allocate-retries: + type: int + default: 300 + description: | + Number of times to check for a volume to be available before + attaching it during server create. The timeout is calculated with + block-device-allocate-retries-interval(default: 3s) so the default + timeout with the charm is 15 minutes (300 retries at 3-seconds + interval). + block-device-allocate-retries-interval: + type: int + default: + description: | + Seconds between block device allocation retries. The default value + is 3. Please refer to the description of the + "block-device-allocate-retries" config for more details. diff --git a/hooks/nova_compute_context.py b/hooks/nova_compute_context.py index 360106b5..bfd08381 100644 --- a/hooks/nova_compute_context.py +++ b/hooks/nova_compute_context.py @@ -323,6 +323,15 @@ class NovaComputeLibvirtContext(context.OSContextGenerator): # -2 means disable the injection of data ctxt['inject_partition'] = -1 if config('inject-password') else -2 + if config("block-device-allocate-retries"): + ctxt["block_device_allocate_retries"] = config( + "block-device-allocate-retries" + ) + if config("block-device-allocate-retries-interval"): + ctxt["block_device_allocate_retries_interval"] = config( + "block-device-allocate-retries-interval" + ) + return ctxt diff --git a/templates/queens/nova.conf b/templates/queens/nova.conf index bef0f21d..06372819 100644 --- a/templates/queens/nova.conf +++ b/templates/queens/nova.conf @@ -16,6 +16,12 @@ ec2_private_dns_show_ip=True enabled_apis=osapi_compute,metadata my_ip = {{ host_ip }} force_raw_images = {{ force_raw_images }} +{% if block_device_allocate_retries -%} +block_device_allocate_retries = {{ block_device_allocate_retries }} +{% endif -%} +{% if block_device_allocate_retries_interval -%} +block_device_allocate_retries_interval = {{ block_device_allocate_retries_interval }} +{% endif -%} {% if debug -%} default_log_levels = "amqp=WARN, amqplib=WARN, boto=WARN, qpid=WARN, sqlalchemy=WARN, suds=INFO, oslo.messaging=INFO, oslo_messaging=DEBUG, iso8601=WARN, requests.packages.urllib3.connectionpool=WARN, urllib3.connectionpool=WARN, websocket=WARN, requests.packages.urllib3.util.retry=WARN, urllib3.util.retry=WARN, keystonemiddleware=WARN, routes.middleware=WARN, stevedore=WARN, taskflow=WARN, keystoneauth=WARN, oslo.cache=INFO, dogpile.core.dogpile=INFO" diff --git a/templates/rocky/nova.conf b/templates/rocky/nova.conf index f179367d..df8d4009 100644 --- a/templates/rocky/nova.conf +++ b/templates/rocky/nova.conf @@ -16,6 +16,12 @@ ec2_private_dns_show_ip=True enabled_apis=osapi_compute,metadata my_ip = {{ host_ip }} force_raw_images = {{ force_raw_images }} +{% if block_device_allocate_retries -%} +block_device_allocate_retries = {{ block_device_allocate_retries }} +{% endif -%} +{% if block_device_allocate_retries_interval -%} +block_device_allocate_retries_interval = {{ block_device_allocate_retries_interval }} +{% endif -%} {% if debug -%} default_log_levels = "amqp=WARN, amqplib=WARN, boto=WARN, qpid=WARN, sqlalchemy=WARN, suds=INFO, oslo.messaging=INFO, oslo_messaging=DEBUG, iso8601=WARN, requests.packages.urllib3.connectionpool=WARN, urllib3.connectionpool=WARN, websocket=WARN, requests.packages.urllib3.util.retry=WARN, urllib3.util.retry=WARN, keystonemiddleware=WARN, routes.middleware=WARN, stevedore=WARN, taskflow=WARN, keystoneauth=WARN, oslo.cache=INFO, dogpile.core.dogpile=INFO, glanceclient=WARN, oslo.privsep.daemon=INFO" diff --git a/templates/stein/nova.conf b/templates/stein/nova.conf index 79f468cc..aabce112 100644 --- a/templates/stein/nova.conf +++ b/templates/stein/nova.conf @@ -16,6 +16,12 @@ ec2_private_dns_show_ip=True enabled_apis=osapi_compute,metadata my_ip = {{ host_ip }} force_raw_images = {{ force_raw_images }} +{% if block_device_allocate_retries -%} +block_device_allocate_retries = {{ block_device_allocate_retries }} +{% endif -%} +{% if block_device_allocate_retries_interval -%} +block_device_allocate_retries_interval = {{ block_device_allocate_retries_interval }} +{% endif -%} {% if use_fqdn_hint and host_fqdn -%} host = {{ host_fqdn }} diff --git a/templates/train/nova.conf b/templates/train/nova.conf index de6f58f1..c80eebc5 100644 --- a/templates/train/nova.conf +++ b/templates/train/nova.conf @@ -19,6 +19,12 @@ ec2_private_dns_show_ip=True enabled_apis=osapi_compute,metadata my_ip = {{ host_ip }} force_raw_images = {{ force_raw_images }} +{% if block_device_allocate_retries -%} +block_device_allocate_retries = {{ block_device_allocate_retries }} +{% endif -%} +{% if block_device_allocate_retries_interval -%} +block_device_allocate_retries_interval = {{ block_device_allocate_retries_interval }} +{% endif -%} {% if use_fqdn_hint and host_fqdn -%} host = {{ host_fqdn }} diff --git a/unit_tests/test_nova_compute_contexts.py b/unit_tests/test_nova_compute_contexts.py index ee5eccc4..2aafa9ff 100644 --- a/unit_tests/test_nova_compute_contexts.py +++ b/unit_tests/test_nova_compute_contexts.py @@ -376,6 +376,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'default_ephemeral_format': 'ext4', 'reserved_host_disk': 0, 'reserved_host_memory': 512}, libvirt()) @@ -398,6 +399,32 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': True, 'inject_partition': -1, + 'block_device_allocate_retries': 300, + 'default_ephemeral_format': 'ext4', + 'reserved_host_disk': 0, + 'reserved_host_memory': 512}, libvirt()) + + def test_libvirt_context_block_device_allocate_retries(self): + self.lsb_release.return_value = {'DISTRIB_CODENAME': 'focal'} + self.os_release.return_value = 'ussuri' + self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid}) + self.test_config.set('block-device-allocate-retries', 120) + self.test_config.set('block-device-allocate-retries-interval', 5) + libvirt = context.NovaComputeLibvirtContext() + + self.assertEqual( + {'libvirtd_opts': '', + 'libvirt_user': 'libvirt', + 'arch': platform.machine(), + 'ksm': 'AUTO', + 'kvm_hugepages': 0, + 'listen_tls': 0, + 'host_uuid': self.host_uuid, + 'force_raw_images': True, + 'inject_password': False, + 'inject_partition': -2, + 'block_device_allocate_retries': 120, + 'block_device_allocate_retries_interval': 5, 'default_ephemeral_format': 'ext4', 'reserved_host_disk': 0, 'reserved_host_memory': 512}, libvirt()) @@ -420,6 +447,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'default_ephemeral_format': 'ext4', 'reserved_host_disk': 0, 'reserved_host_memory': 512, @@ -445,6 +473,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'default_ephemeral_format': 'ext4', 'reserved_host_disk': 0, 'reserved_host_memory': 512, @@ -468,6 +497,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'default_ephemeral_format': 'ext4', 'reserved_host_disk': 0, 'reserved_host_memory': 512}, libvirt()) @@ -497,6 +527,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'reserved_host_disk': 0, 'reserved_host_memory': 512}, libvirt()) @@ -559,6 +590,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'default_ephemeral_format': 'ext4', 'reserved_host_disk': 0, 'reserved_host_memory': 512}, libvirt()) @@ -589,6 +621,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'reserved_host_disk': 0, 'reserved_host_memory': 512}, libvirt()) @@ -610,6 +643,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'default_ephemeral_format': 'ext4', 'reserved_host_disk': 0, 'reserved_host_memory': 512}, libvirt()) @@ -633,6 +667,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'default_ephemeral_format': 'ext4', 'reserved_host_disk': 0, 'reserved_host_memory': 512}, libvirt()) @@ -655,6 +690,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': False, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'default_ephemeral_format': 'ext4', 'reserved_host_disk': 0, 'reserved_host_memory': 512}, libvirt()) @@ -769,6 +805,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'pci_passthrough_whitelist': 'mypcidevices', 'virtio_net_tx_queue_size': 512, 'virtio_net_rx_queue_size': 1024, @@ -797,6 +834,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'default_ephemeral_format': 'ext4'}, libvirt()) def test_cpu_dedicated_set(self): @@ -820,6 +858,7 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'default_ephemeral_format': 'ext4'} self.assertEqual(expected, libvirt()) @@ -1106,6 +1145,7 @@ class SerialConsoleContextTests(CharmTestCase): 'force_raw_images': True, 'inject_password': False, 'inject_partition': -2, + 'block_device_allocate_retries': 300, 'default_ephemeral_format': 'ext4', 'reserved_host_disk': 0, 'reserved_host_memory': 512}, libvirt())