diff --git a/chaosoci/core/computemanagement/__init__.py b/chaosoci/core/computemanagement/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/chaosoci/core/computemanagement/actions.py b/chaosoci/core/computemanagement/actions.py new file mode 100644 index 0000000..8f1a521 --- /dev/null +++ b/chaosoci/core/computemanagement/actions.py @@ -0,0 +1,83 @@ +# coding: utf-8 +# Copyright 2020, Oracle Corporation and/or its affiliates. + +__all__ = ["stop_instance_pool_by_id", "stop_instance_pool_by_filters"] + +from random import choice +from typing import Any, Dict, List + +from chaoslib.exceptions import ActivityFailed +from chaoslib.types import Configuration, Secrets + +from chaosoci import oci_client +from chaosoci.types import OCIResponse +from chaosoci.util.constants import FILTER_ERR + +from logzero import logger + +from oci.config import from_file +from oci.core import ComputeManagementClient + +from .common import (get_instance_pools) + +from .filters import (filter_instance_pools) + + +def stop_instance_pool_by_id(instance_pool_id: str, force: bool = False, + configuration: Configuration = None, + secrets: Secrets = None) -> OCIResponse: + """ + Stops an instance pool using the instance pool id. + + Parameters: + Required: + - instance_pool_id: the id of the route table + """ + + client = oci_client(ComputeManagementClient, configuration, secrets, + skip_deserialization=True) + if not instance_pool_id: + raise ActivityFailed('An instance pool id is required.') + + ret = client.stop_instance_pool(instance_pool_id=instance_pool_id).data + logger.debug("Instance pool %s stopped", instance_pool_id) + return ret + + +def stop_instance_pool_by_filters(compartment_id: str, + filters: Dict[str, Any], force: bool = False, + configuration: Configuration = None, + secrets: Secrets = None) -> OCIResponse: + """ + Search for an instance pool using the specified filters and + then stops it. + + Parameters: + Required: + - compartment_id: the compartment id of the instance pool + - filters: the set of filters for the route table. + Please refer to + https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/core/models/oci.core.models.InstancePool.html#oci.core.models.InstancePool + for the route table filters. + """ + + client = oci_client(ComputeManagementClient, configuration, secrets, + skip_deserialization=False) + + if compartment_id is None: + raise ActivityFailed('A compartment id is required.') + else: + unfiltered = get_instance_pools(client, compartment_id) + + if filters is None: + raise ActivityFailed(FILTER_ERR) + else: + filtered = filter_instance_pools(unfiltered, filters) + + if (len(filtered) == 0): + raise ActivityFailed(FILTER_ERR) + else: + ret = client.stop_instance_pool(filtered[0].id).data + logger.debug("Instance pool %s stopped", + filtered[0].display_name) + return ret diff --git a/chaosoci/core/computemanagement/common.py b/chaosoci/core/computemanagement/common.py new file mode 100644 index 0000000..dc240ff --- /dev/null +++ b/chaosoci/core/computemanagement/common.py @@ -0,0 +1,33 @@ +# coding: utf-8 +# Copyright 2020, Oracle Corporation and/or its affiliates. + +__all__ = ["get_instance_pools"] + +from typing import Any, Dict, List + +from chaoslib.exceptions import ActivityFailed + +from logzero import logger + +from oci.core import ComputeManagementClient +from oci.core.models import (InstancePool) + + +def get_instance_pools(client: ComputeManagementClient = None, + compartment_id: str = None) -> List[InstancePool]: + """ + Returns a complete, unfiltered list of instance pools in the + compartment. + """ + + instance_pools = [] + instance_pools_raw = client.list_instance_pools( + compartment_id=compartment_id) + instance_pools.extend(instance_pools_raw.data) + while instance_pools_raw.has_next_page: + instance_pools_raw = client.list_instance_pools( + compartment_id=compartment_id, + page=instance_pools_raw.next_page) + instance_pools.extend(instance_pools_raw.data) + + return instance_pools diff --git a/chaosoci/core/computemanagement/filters.py b/chaosoci/core/computemanagement/filters.py new file mode 100644 index 0000000..fbe7423 --- /dev/null +++ b/chaosoci/core/computemanagement/filters.py @@ -0,0 +1,48 @@ +# coding: utf-8 +# Copyright 2020, Oracle Corporation and/or its affiliates. + +__all__ = ["filter_instance_pools"] + +from typing import Any, Dict, List + +from chaoslib.exceptions import ActivityFailed +from chaosoci.util.constants import FILTER_ERR + +from logzero import logger + +from oci.core import ComputeManagementClient +from oci.core.models import (InstancePool) + + +def filter_instance_pools(instance_pools: List[InstancePool] = None, + filters: Dict[str, Any] = None + ) -> List[InstancePool]: + """ + Return only those instance pools that match the filters provided. + """ + instance_pools = instance_pools or None + + if instance_pools is None: + raise ActivityFailed('No instance pools were found.') + + filters_set = {x for x in filters} + + available_filters_set = {x for x in instance_pools[0].attribute_map} + + # Partial filtering may return instance pools we do not want. We avoid it. + if not filters_set.issubset(available_filters_set): + raise ActivityFailed(FILTER_ERR) + + # Walk the instance pools and find those that match the given filters. + filtered = [] + for instance_pool in instance_pools: + sentinel = True + for attr, val in filters.items(): + if val != getattr(instance_pool, attr, None): + sentinel = False + break + + if sentinel: + filtered.append(instance_pool) + + return filtered diff --git a/chaosoci/core/computemanagement/probes.py b/chaosoci/core/computemanagement/probes.py new file mode 100644 index 0000000..c15fb64 --- /dev/null +++ b/chaosoci/core/computemanagement/probes.py @@ -0,0 +1,48 @@ +# coding: utf-8 +# Copyright 2020, Oracle Corporation and/or its affiliates. + +__all__ = ['count_instance_pools'] + +from typing import Any, Dict, List + +from chaoslib.exceptions import ActivityFailed +from chaoslib.types import Configuration, Secrets + +from chaosoci import oci_client + +from logzero import logger + +from oci.config import from_file +from oci.core import ComputeManagementClient + +from .common import (get_instance_pools) + +from .filters import (filter_instance_pools) + + +def count_instance_pools(filters: List[Dict[str, Any]], + compartment_id: str = None, + configuration: Configuration = None, + secrets: Secrets = None) -> int: + """ + Returns the number of Instance Pools in the compartment 'compartment_id' + and according to the given filters. + + Please refer to:https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/core/models/oci.core.models.InstancePool.html#oci.core.models.InstancePool + + for details on the available filters under the 'parameters' section. + """ # noqa: E501 + compartment_id = compartment_id or from_file().get('compartment') + + if compartment_id is None: + raise ActivityFailed('A valid compartment id is required.') + + client = oci_client(ComputeManagementClient, configuration, secrets, + skip_deserialization=False) + + filters = filters or None + instance_pools = get_instance_pools(client, compartment_id) + if filters is not None: + return len(filter_instance_pools(instance_pools, filters=filters)) + else: + return len(instance_pools) diff --git a/chaosoci/core/computemanagement/rollbacks.py b/chaosoci/core/computemanagement/rollbacks.py new file mode 100644 index 0000000..1e6d57d --- /dev/null +++ b/chaosoci/core/computemanagement/rollbacks.py @@ -0,0 +1,22 @@ +# coding: utf-8 +# Copyright 2020, Oracle Corporation and/or its affiliates. + +__all__ = ["delete_nat_rollback"] + +from random import choice +from typing import Any, Dict, List + +from chaoslib.exceptions import ActivityFailed +from chaoslib.types import Configuration, Secrets + +from chaosoci import oci_client +from chaosoci.types import OCIResponse + +from logzero import logger + +from oci.config import from_file +from oci.core import ComputeManagementClient + +from .common import (get_instance_pools) + +from .filters import (filter_instance_pools) diff --git a/tests/core/computemanagement/test_actions.py b/tests/core/computemanagement/test_actions.py new file mode 100644 index 0000000..017e6d4 --- /dev/null +++ b/tests/core/computemanagement/test_actions.py @@ -0,0 +1,58 @@ +# coding: utf-8 +# Copyright 2020, Oracle Corporation and/or its affiliates. + +import pytest + +from unittest.mock import MagicMock, patch + +from chaoslib.exceptions import ActivityFailed + +from chaosoci.core.computemanagement.actions import (stop_instance_pool_by_id, + stop_instance_pool_by_filters) +from chaosoci.util.constants import FILTER_ERR + +@patch('chaosoci.core.computemanagement.actions.oci_client', autospec=True) +def test_stop_instance_pool_by_id(oci_client): + compute_management_client = MagicMock() + oci_client.return_value = compute_management_client + instance_pool_id = "ocid1.instancepool.oc1.phx.aawnm2cdxq3naniep5dsiixtchqjuypcx7l7" + instance_pool_ids = [instance_pool_id, ""] + for id in instance_pool_ids: + if id == instance_pool_id: + stop_instance_pool_by_id(id) + compute_management_client.stop_instance_pool.assert_called_with(instance_pool_id=id) + else: + with pytest.raises(ActivityFailed) as f: + stop_instance_pool_by_id(id) + assert 'An instance pool id is required.' + +@patch('chaosoci.core.computemanagement.actions.filter_instance_pools', autospec=True) +@patch('chaosoci.core.computemanagement.actions.get_instance_pools', autospec=True) +@patch('chaosoci.core.computemanagement.actions.oci_client', autospec=True) +def test_stop_instance_pool_by_filters(oci_client, get_instance_pools, + filter_instance_pools): + compute_management_client = MagicMock() + oci_client.return_value = compute_management_client + + c_id = "ocid1.compartment.oc1..oadsocmof6r6ksovxmda44ikwxje7xxu" + + c_ids = [c_id, None] + filters = [[{'display_name': 'random_name', 'region': 'uk-london-1'}], + None] + + for c in c_ids: + for f in filters: + if c is None : + with pytest.raises(ActivityFailed) as c_failed: + stop_instance_pool_by_filters(c, f) + assert 'A compartment id or vcn id is required.' + elif f is None: + with pytest.raises(ActivityFailed) as f_failed: + stop_instance_pool_by_filters(c, f) + assert FILTER_ERR + else: + with pytest.raises(ActivityFailed) as rt_failed: + stop_instance_pool_by_filters(c, f) + cdcdcompute_management_client.stop_instance_pool.assert_called_with( + filter_instance_pools(route_tables=get_instance_pools( + oci_client, c), filters=f)[0].id) diff --git a/tests/core/computemanagement/test_probes.py b/tests/core/computemanagement/test_probes.py new file mode 100644 index 0000000..5068690 --- /dev/null +++ b/tests/core/computemanagement/test_probes.py @@ -0,0 +1,35 @@ +# coding: utf-8 +# Copyright 2020, Oracle Corporation and/or its affiliates. + +import pytest + +from unittest import TestCase as T +from unittest.mock import MagicMock, patch + +from chaoslib.exceptions import ActivityFailed + +from chaosoci.core.computemanagement.probes import (count_instance_pools, + filter_instance_pools) + +@patch('chaosoci.core.computemanagement.probes.filter_instance_pools', autospec=True) +@patch('chaosoci.core.computemanagement.probes.get_instance_pools', autospec=True) +@patch('chaosoci.core.computemanagement.probes.oci_client', autospec=True) +def test_count_instance_pools(oci_client, get_instance_pools, filter_instance_pools): + compute_management_client = MagicMock() + oci_client.return_value = compute_management_client + + c_id = "ocid1.compartment.oc1..oadsocmof6r6ksovxmda44ikwxje7xxu" + filters = [{'display_name': 'random_name', 'region': 'uk-london-1'}] + + c_ids = [c_id] + + for id in c_ids: + if id == c_id: + count_instance_pools(filters=filters, compartment_id=id) + filter_instance_pools.assert_called_with( + instance_pools=get_instance_pools( + oci_client, id), filters=filters) + else: + with pytest.raises(ActivityFailed) as f: + count_instance_pools(filters=filters, compartment_id=id) + assert 'A valid compartment id is required.' diff --git a/tests/core/computemanagement/test_rollbacks.py b/tests/core/computemanagement/test_rollbacks.py new file mode 100644 index 0000000..7be5e9e --- /dev/null +++ b/tests/core/computemanagement/test_rollbacks.py @@ -0,0 +1,10 @@ +# coding: utf-8 +# Copyright 2020, Oracle Corporation and/or its affiliates. + +import pytest + +from unittest.mock import MagicMock, patch + +from oci.exceptions import ServiceError + +from chaoslib.exceptions import ActivityFailed diff --git a/tests/core/networking/test_networking_actions.py b/tests/core/networking/test_networking_actions.py index 11f974e..bff6fc7 100644 --- a/tests/core/networking/test_networking_actions.py +++ b/tests/core/networking/test_networking_actions.py @@ -10,7 +10,6 @@ from chaosoci.core.networking.actions import (delete_route_table_by_id, delete_route_table_by_filters) from chaosoci.util.constants import FILTER_ERR -# FILTER_ERR = 'Some of the chosen filters were not found, we cannot continue.' @patch('chaosoci.core.networking.actions.oci_client', autospec=True) def test_delete_route_table_by_id(oci_client):