Skip to content

Commit 3b391e5

Browse files
authored
Allow management of project's default volume type (#262)
Allow optional specification and mangement of a project's default volume type. Signed-off-by: Jan Horstmann <horstmann@osism.tech>
1 parent d5f735e commit 3b391e5

4 files changed

Lines changed: 363 additions & 7 deletions

File tree

openstack_project_manager/create.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ def run(
166166
service_network_cidr: Annotated[
167167
str, typer.Option("--service-network-cidr", help="Service network CIDR")
168168
] = "",
169+
default_volume_type: Annotated[
170+
Optional[str],
171+
typer.Option(
172+
"--default-volume-type", help="Project-specific default volume type"
173+
),
174+
] = None,
169175
) -> None:
170176

171177
# Connect to the OpenStack environment
@@ -305,6 +311,12 @@ def run(
305311
# Set other parameters of the project
306312
keystone.projects.update(project=project.id, owner=owner)
307313

314+
# Set default volume type of the project
315+
if default_volume_type:
316+
keystone.projects.update(
317+
project=project.id, default_volume_type=default_volume_type
318+
)
319+
308320
# The network resources of the project should be created automatically
309321
if managed_network_resources:
310322
keystone.projects.update(

openstack_project_manager/manage.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,84 @@ def manage_private_volumetypes(
530530
configuration.os_cloud.block_storage.add_type_access(volume_type, project.id)
531531

532532

533+
def manage_default_volume_type(
534+
configuration: Configuration,
535+
project: openstack.identity.v3.project.Project,
536+
domain: openstack.identity.v3.domain.Domain,
537+
classes: str,
538+
) -> None:
539+
logger.info(f"{project.name} - managing default volume type")
540+
if "quotaclass" in project:
541+
quotaclass = get_quotaclass(classes, project.quotaclass)
542+
else:
543+
logger.warning(f"{project.name} - quotaclass not set --> use default")
544+
if domain.name.startswith("ok"):
545+
quotaclass = get_quotaclass(classes, "okeanos")
546+
else:
547+
quotaclass = get_quotaclass(classes, "basic")
548+
549+
if "default_volume_type" in project and project.default_volume_type:
550+
# NOTE: It is impossible to unset a project property, so we need to make sure it actually contains a value
551+
default_volume_type_name_or_id = project.default_volume_type
552+
elif quotaclass and "default_volume_type" in quotaclass:
553+
default_volume_type_name_or_id = quotaclass["default_volume_type"]
554+
else:
555+
default_volume_type_name_or_id = None
556+
557+
if default_volume_type_name_or_id:
558+
# NOTE: Find declared volume type in public and private types (find_type() does not search private types)
559+
default_volume_types = []
560+
for is_public in [True, False]:
561+
default_volume_types += [
562+
volume_type
563+
for volume_type in configuration.os_cloud.block_storage.types(
564+
is_public=is_public
565+
)
566+
if default_volume_type_name_or_id == volume_type.id
567+
or default_volume_type_name_or_id == volume_type.name
568+
]
569+
570+
if not default_volume_types:
571+
logger.error(
572+
f"{project.name} - default volume type {default_volume_type_name_or_id} not found"
573+
)
574+
return
575+
elif len(default_volume_types) > 1:
576+
logger.error(
577+
f"{project.name} - default volume type {default_volume_type_name_or_id} not unique, please use ID"
578+
)
579+
return
580+
else:
581+
default_volume_type = default_volume_types[0]
582+
583+
else:
584+
default_volume_type = None
585+
586+
try:
587+
current_default_type = configuration.os_cloud.block_storage.show_default_type(
588+
project
589+
)
590+
except openstack.exceptions.NotFoundException:
591+
current_default_type = None
592+
593+
if not default_volume_type and not current_default_type:
594+
return
595+
elif not default_volume_type and current_default_type:
596+
logger.info(
597+
f"{project.name} - Unsetting default volume type {current_default_type.volume_type_id}"
598+
)
599+
configuration.os_cloud.block_storage.unset_default_type(project)
600+
elif (
601+
default_volume_type and not current_default_type
602+
) or default_volume_type.id != current_default_type.volume_type_id:
603+
logger.info(
604+
f"{project.name} - Setting default volume type {default_volume_type.id} ({default_volume_type.name})"
605+
)
606+
configuration.os_cloud.block_storage.set_default_type(
607+
project, default_volume_type
608+
)
609+
610+
533611
def check_flavors(
534612
configuration: Configuration,
535613
project: openstack.identity.v3.project.Project,
@@ -1224,6 +1302,7 @@ def process_project(
12241302
manage_endpoints: bool,
12251303
manage_homeprojects: bool,
12261304
manage_privatevolumetypes: bool,
1305+
manage_defaultvolumetype: bool,
12271306
manage_privateflavors: bool,
12281307
) -> None:
12291308

@@ -1275,6 +1354,9 @@ def process_project(
12751354
if manage_privatevolumetypes:
12761355
manage_private_volumetypes(configuration, project, domain)
12771356

1357+
if manage_defaultvolumetype:
1358+
manage_default_volume_type(configuration, project, domain, classes)
1359+
12781360
check_flavors(configuration, project, domain, classes)
12791361

12801362
if manage_privateflavors:
@@ -1331,6 +1413,13 @@ def run(
13311413
help="Manage private volume types",
13321414
),
13331415
] = True,
1416+
manage_defaultvolumetype: Annotated[
1417+
bool,
1418+
typer.Option(
1419+
"--manage-defaultvolumetype/--nomanage-defaultvolumetype",
1420+
help="Manage default volume type",
1421+
),
1422+
] = True,
13341423
manage_privateflavors: Annotated[
13351424
bool,
13361425
typer.Option(
@@ -1384,6 +1473,7 @@ def run(
13841473
manage_endpoints,
13851474
manage_homeprojects,
13861475
manage_privatevolumetypes,
1476+
manage_defaultvolumetype,
13871477
manage_privateflavors,
13881478
)
13891479

@@ -1419,6 +1509,7 @@ def run(
14191509
manage_endpoints,
14201510
manage_homeprojects,
14211511
manage_privatevolumetypes,
1512+
manage_defaultvolumetype,
14221513
manage_privateflavors,
14231514
)
14241515

@@ -1444,6 +1535,7 @@ def run(
14441535
manage_endpoints,
14451536
manage_homeprojects,
14461537
manage_privatevolumetypes,
1538+
manage_defaultvolumetype,
14471539
manage_privateflavors,
14481540
)
14491541

@@ -1474,6 +1566,7 @@ def run(
14741566
manage_endpoints,
14751567
manage_homeprojects,
14761568
manage_privatevolumetypes,
1569+
manage_defaultvolumetype,
14771570
manage_privateflavors,
14781571
)
14791572

test/unit/test_create.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ def test_cli_13(self):
347347
"--name=othername",
348348
"--owner=otherowner",
349349
"--public-network=otherpublic",
350+
"--default-volume-type=othertype",
350351
],
351352
)
352353
self.assertEqual(result.exit_code, 0, (result, result.stdout))
@@ -366,6 +367,9 @@ def test_cli_13(self):
366367
self.mock_os_keystone.projects.update.assert_any_call(
367368
project=9012, owner="otherowner"
368369
)
370+
self.mock_os_keystone.projects.update.assert_any_call(
371+
project=9012, default_volume_type="othertype"
372+
)
369373
self.mock_os_cloud.identity.find_user.assert_called_once_with(
370374
"otherdomain-admin", domain_id=1234
371375
)

0 commit comments

Comments
 (0)