Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions actions/project.add.flavor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
description: Add an existing flavor to a project
enabled: true
entry_point: src/openstack_actions.py
name: project.add.flavor
parameters:
lib_entry_point:
default: apis.openstack_api.openstack_project.add_flavor_to_project
immutable: true
type: string
requires_openstack:
default: true
immutable: true
type: boolean
cloud_account:
description: The clouds.yaml account to use whilst performing this action
required: true
type: string
default: "dev"
enum:
- "dev"
- "prod"
project_identifier:
description: Project Name or ID to add the flavor to
required: true
type: string
flavor_identifier:
description: Flavor Name or ID to add
required: true
type: string
runner_type: python-script
16 changes: 16 additions & 0 deletions lib/apis/openstack_api/openstack_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,22 @@ def delete_project(conn: Connection, project_identifier: str) -> bool:
return result is None # Where None == success


def add_flavor_to_project(
conn: Connection, project_identifier: str, flavor_identifier: str
) -> bool:
"""
Add a flavor to the given project
:param conn: openstack connection object
:param project_identifier: The name or Openstack ID for the project
:param flavor_identifier: The name or Openstack ID for the flavor
:return:
"""
project = conn.identity.find_project(project_identifier, ignore_missing=False)
flavor = conn.compute.find_flavor(flavor_identifier, ignore_missing=False)
res = conn.compute.flavor_add_tenant_access(flavor, project)
return res is None


def _is_project_safe_to_delete(project: Project) -> bool:
"""
Returns true if the project is safe to delete - avoid deleting admin project for instance
Expand Down
56 changes: 55 additions & 1 deletion tests/lib/apis/openstack_api/test_openstack_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

from meta.exceptions.missing_mandatory_param_error import MissingMandatoryParamError
from openstack.exceptions import ConflictException
from apis.openstack_api.openstack_project import create_project, delete_project
from apis.openstack_api.openstack_project import (
create_project,
delete_project,
add_flavor_to_project,
)


def test_create_project_name_missing_throws():
Expand Down Expand Up @@ -204,3 +208,53 @@ def test_delete_protected_project_fails(protected_project_id):
mock_project_identifier, ignore_missing=False
)
mock_conn.identity.delete_project.assert_not_called()


def test_add_flavor_to_project_success():
"""tests that add flavor to project calls appropriate API functions with correct args"""
mock_conn = MagicMock()
mock_project_identifier = NonCallableMock()
mock_flavor_identifier = NonCallableMock()

res = add_flavor_to_project(
mock_conn, mock_project_identifier, mock_flavor_identifier
)

mock_conn.identity.find_project.assert_called_once_with(
mock_project_identifier, ignore_missing=False
)
mock_conn.compute.find_flavor.assert_called_once_with(
mock_flavor_identifier, ignore_missing=False
)
mock_conn.compute.flavor_add_tenant_access(
mock_conn.compute.find_flavor.return_value,
mock_conn.compute.find_project.return_value,
)
assert res is False # mock is not None


def test_add_flavor_to_project_fail():
"""tests that add flavor to project calls appropriate API functions with correct args"""
mock_conn = MagicMock()
mock_project_identifier = NonCallableMock()
mock_flavor_identifier = NonCallableMock()

mock_conn.compute.flavor_add_tenant_access.return_value = (
None # to mock failure of adding flavor to project
)

res = add_flavor_to_project(
mock_conn, mock_project_identifier, mock_flavor_identifier
)

mock_conn.identity.find_project.assert_called_once_with(
mock_project_identifier, ignore_missing=False
)
mock_conn.compute.find_flavor.assert_called_once_with(
mock_flavor_identifier, ignore_missing=False
)
mock_conn.compute.flavor_add_tenant_access(
mock_conn.compute.find_flavor.return_value,
mock_conn.compute.find_project.return_value,
)
assert res is True # mock is not None