From 150635d7436a252fa18071abf4e5232f87500e5b Mon Sep 17 00:00:00 2001 From: anish-mudaraddi Date: Tue, 17 Dec 2024 11:16:24 +0000 Subject: [PATCH] remove old code remove old actions, rules and sensors that aren't being used or are broken --- actions/jupyter.server.start.yaml | 32 --- actions/jupyter.server.stop.yaml | 32 --- actions/jupyter.user.create.yaml | 32 --- actions/jupyter.user.delete.yaml | 32 --- actions/src/jupyter.py | 80 ------ actions/workflow.jupyter.user.prepare.yaml | 27 -- actions/workflows/jupyter.user.prepare.yaml | 27 -- lib/amphorae.py | 20 -- lib/{jupyter_api => enums/icinga}/__init__.py | 0 .../jupyter => lib/icinga_api}/__init__.py | 0 lib/jupyter_api/api_endpoints.py | 5 - lib/jupyter_api/get_token.py | 22 -- lib/jupyter_api/user_api.py | 165 ------------ lib/openstack_action.py | 53 ---- lib/openstack_query_api/__init__.py | 0 lib/post_ticket.py | 34 --- lib/ssh_api/__init__.py | 0 lib/structs/icinga/__init__.py | 0 lib/structs/jira/__init__.py | 0 lib/structs/ssh/__init__.py | 0 rules/jupyter.prune_inactive.yaml | 22 -- rules/openstack.deletedmachines.rule.yaml | 15 -- rules/openstack.loadbalancers.rule.yaml | 15 -- sensors/jupyter.inactive_users.yaml | 16 -- sensors/openstack.deletingmachines.yaml | 10 - sensors/openstack.loadbalancers.yaml | 10 - sensors/src/deleting_machines_sensor.py | 94 ------- sensors/src/hypervisor_state_sensor.py | 7 +- sensors/src/jupyter_inactive_user_sensor.py | 76 ------ sensors/src/loadbalancer_sensor.py | 162 ------------ tests/actions/test_jupyter_actions.py | 70 ----- tests/lib/jupyter/test_server_api.py | 162 ------------ tests/lib/jupyter/test_user_api.py | 246 ------------------ tests/lib/ssh_api/__init__.py | 0 tests/sensors/__init__.py | 0 todo/actions/email.image.users.yaml | 132 ---------- todo/actions/email.server.users.yaml | 135 ---------- todo/actions/hypervisor.list.yaml | 78 ------ todo/actions/image.list.yaml | 88 ------- todo/actions/project.list.yaml | 79 ------ todo/actions/server.list.yaml | 90 ------- todo/actions/user.list.yaml | 76 ------ .../workflow.email.errored.server.users.yaml | 39 --- .../workflow.email.shutoff.server.users.yaml | 39 --- .../workflows/email.errored.server.users.yaml | 43 --- .../workflows/email.shutoff.server.users.yaml | 41 --- ...bitmq.hypervisor.disable.service.rule.yaml | 18 -- ...bbitmq.hypervisor.enable.service.rule.yaml | 18 -- .../rabbitmq.hypervisor.reboot.rule.yaml | 20 -- ...ypervisor.remove.icinga.downtime.rule.yaml | 18 -- ...ervisor.schedule.icinga.downtime.rule.yaml | 18 -- todo/rules/rabbitmq.server.create.rule.yaml | 18 -- todo/rules/rabbitmq.server.delete.rule.yaml | 18 -- todo/rules/rabbitmq.server.reboot.rule.yaml | 18 -- todo/rules/rabbitmq.server.restart.rule.yaml | 18 -- todo/rules/rabbitmq.server.shutdown.rule.yaml | 18 -- 56 files changed, 3 insertions(+), 2485 deletions(-) delete mode 100644 actions/jupyter.server.start.yaml delete mode 100644 actions/jupyter.server.stop.yaml delete mode 100644 actions/jupyter.user.create.yaml delete mode 100644 actions/jupyter.user.delete.yaml delete mode 100644 actions/src/jupyter.py delete mode 100644 actions/workflow.jupyter.user.prepare.yaml delete mode 100644 actions/workflows/jupyter.user.prepare.yaml delete mode 100644 lib/amphorae.py rename lib/{jupyter_api => enums/icinga}/__init__.py (100%) rename {tests/lib/jupyter => lib/icinga_api}/__init__.py (100%) delete mode 100644 lib/jupyter_api/api_endpoints.py delete mode 100644 lib/jupyter_api/get_token.py delete mode 100644 lib/jupyter_api/user_api.py delete mode 100644 lib/openstack_action.py create mode 100644 lib/openstack_query_api/__init__.py delete mode 100644 lib/post_ticket.py create mode 100644 lib/ssh_api/__init__.py create mode 100644 lib/structs/icinga/__init__.py create mode 100644 lib/structs/jira/__init__.py create mode 100644 lib/structs/ssh/__init__.py delete mode 100644 rules/jupyter.prune_inactive.yaml delete mode 100644 rules/openstack.deletedmachines.rule.yaml delete mode 100644 rules/openstack.loadbalancers.rule.yaml delete mode 100644 sensors/jupyter.inactive_users.yaml delete mode 100644 sensors/openstack.deletingmachines.yaml delete mode 100644 sensors/openstack.loadbalancers.yaml delete mode 100644 sensors/src/deleting_machines_sensor.py delete mode 100644 sensors/src/jupyter_inactive_user_sensor.py delete mode 100644 sensors/src/loadbalancer_sensor.py delete mode 100644 tests/actions/test_jupyter_actions.py delete mode 100644 tests/lib/jupyter/test_server_api.py delete mode 100644 tests/lib/jupyter/test_user_api.py create mode 100644 tests/lib/ssh_api/__init__.py create mode 100644 tests/sensors/__init__.py delete mode 100644 todo/actions/email.image.users.yaml delete mode 100644 todo/actions/email.server.users.yaml delete mode 100644 todo/actions/hypervisor.list.yaml delete mode 100644 todo/actions/image.list.yaml delete mode 100644 todo/actions/project.list.yaml delete mode 100644 todo/actions/server.list.yaml delete mode 100644 todo/actions/user.list.yaml delete mode 100644 todo/actions/workflow.email.errored.server.users.yaml delete mode 100644 todo/actions/workflow.email.shutoff.server.users.yaml delete mode 100644 todo/actions/workflows/email.errored.server.users.yaml delete mode 100644 todo/actions/workflows/email.shutoff.server.users.yaml delete mode 100644 todo/rules/rabbitmq.hypervisor.disable.service.rule.yaml delete mode 100644 todo/rules/rabbitmq.hypervisor.enable.service.rule.yaml delete mode 100644 todo/rules/rabbitmq.hypervisor.reboot.rule.yaml delete mode 100644 todo/rules/rabbitmq.hypervisor.remove.icinga.downtime.rule.yaml delete mode 100644 todo/rules/rabbitmq.hypervisor.schedule.icinga.downtime.rule.yaml delete mode 100644 todo/rules/rabbitmq.server.create.rule.yaml delete mode 100644 todo/rules/rabbitmq.server.delete.rule.yaml delete mode 100644 todo/rules/rabbitmq.server.reboot.rule.yaml delete mode 100644 todo/rules/rabbitmq.server.restart.rule.yaml delete mode 100644 todo/rules/rabbitmq.server.shutdown.rule.yaml diff --git a/actions/jupyter.server.start.yaml b/actions/jupyter.server.start.yaml deleted file mode 100644 index aba27f6b9..000000000 --- a/actions/jupyter.server.start.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: jupyter.server.start -description: Starts servers for the given list of users - -enabled: true -entry_point: src/jupyter.py -runner_type: python-script - -parameters: - submodule: - default: server_start - immutable: true - type: string - jupyter_env: - description: The environment to start servers from - required: true - type: string - enum: - - dev - - prod - - training - user: - description: The users to start servers for, or base name of the users without the hyphen (e.g. "jupyter") - required: true - type: string - first_index: - description: The index of the first user server to start - required: false - type: integer - last_index: - description: The index of the last user server to start (inclusive) - required: false - type: integer diff --git a/actions/jupyter.server.stop.yaml b/actions/jupyter.server.stop.yaml deleted file mode 100644 index cdfc561ad..000000000 --- a/actions/jupyter.server.stop.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: jupyter.server.stop -description: Stops servers for the given list of users - -enabled: true -entry_point: src/jupyter.py -runner_type: python-script - -parameters: - submodule: - default: server_stop - immutable: true - type: string - jupyter_env: - description: The environment to stop servers from - required: true - type: string - enum: - - dev - - prod - - training - user: - description: The users to stop servers for, or base name of the users without the hyphen (e.g. "jupyter") - required: true - type: string - first_index: - description: The index of the first user server to stop - required: false - type: integer - last_index: - description: The index of the last user server to stop (inclusive) - required: false - type: integer diff --git a/actions/jupyter.user.create.yaml b/actions/jupyter.user.create.yaml deleted file mode 100644 index 597e8fb3a..000000000 --- a/actions/jupyter.user.create.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: jupyter.user.create -description: Creates the given list of users - -enabled: true -entry_point: src/jupyter.py -runner_type: python-script - -parameters: - submodule: - default: user_create - immutable: true - type: string - jupyter_env: - description: The environment to create users from - required: true - type: string - enum: - - dev - - prod - - training - user: - description: The users to create, or base name of the users to create without the hyphen (e.g. "jupyter") - required: true - type: string - first_index: - description: The index of the first user to create - required: false - type: integer - last_index: - description: The index of the last user to create (inclusive) - required: false - type: integer diff --git a/actions/jupyter.user.delete.yaml b/actions/jupyter.user.delete.yaml deleted file mode 100644 index db822075e..000000000 --- a/actions/jupyter.user.delete.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: jupyter.user.delete -description: Removes the given list of users. This implicitly deletes any running pods the user has started. - -enabled: true -entry_point: src/jupyter.py -runner_type: python-script - -parameters: - submodule: - default: user_delete - immutable: true - type: string - jupyter_env: - description: The environment to remove users from - required: true - type: string - enum: - - dev - - prod - - training - user: - description: The users to remove, or base name of the users to remove without the hyphen (e.g. "jupyter") - required: true - type: string - first_index: - description: The index of the first user to remove - required: false - type: integer - last_index: - description: The index of the last user to remove (inclusive). - required: false - type: integer diff --git a/actions/src/jupyter.py b/actions/src/jupyter.py deleted file mode 100644 index 7dc2aaa60..000000000 --- a/actions/src/jupyter.py +++ /dev/null @@ -1,80 +0,0 @@ -from typing import Dict, Callable, Optional - -from jupyter_api.user_api import UserApi -from jupyter_api.get_token import get_token -from st2common.runners.base_action import Action -from structs.jupyter_users import JupyterUsers - - -class Jupyter(Action): - def __init__(self, *args, config: Dict = None, **kwargs): - """constructor class""" - super().__init__(*args, config=config, **kwargs) - self._api: UserApi = config.get("user_api", UserApi()) - - def run(self, submodule: str, **kwargs): - """ - Dynamically dispatches to the method wanted - """ - func: Callable = getattr(self, submodule) - return func(**kwargs) - - def user_delete( - self, - jupyter_env: str, - user: str, - first_index: Optional[int] = None, - last_index: Optional[int] = None, - ): - """ - Delete users from the given environment - """ - jupyter_keys = self.config["jupyter"] - token = get_token(jupyter_env, jupyter_keys) - user_details = JupyterUsers(user, first_index, last_index) - self._api.delete_users(jupyter_env, token, user_details) - - def user_create( - self, - jupyter_env: str, - user: str, - first_index: Optional[int] = None, - last_index: Optional[int] = None, - ): - """ - Create users from the given environment - """ - jupyter_keys = self.config["jupyter"] - token = get_token(jupyter_env, jupyter_keys) - user_details = JupyterUsers(user, first_index, last_index) - self._api.create_users(jupyter_env, token, user_details) - - def server_start( - self, - jupyter_env: str, - user: str, - first_index: Optional[int] = None, - last_index: Optional[int] = None, - ): - """ - Start servers for users from the given environment - """ - jupyter_keys = self.config["jupyter"] - token = get_token(jupyter_env, jupyter_keys) - user_details = JupyterUsers(user, first_index, last_index) - self._api.start_servers(jupyter_env, token, user_details) - - def server_stop( - self, - jupyter_env: str, - user: str, - first_index: Optional[int] = None, - last_index: Optional[int] = None, - ): - """ - Stop servers for users from the given environment - """ - jupyter_keys = self.config["jupyter"] - token = get_token(jupyter_env, jupyter_keys) - user_details = JupyterUsers(user, first_index, last_index) - self._api.stop_servers(jupyter_env, token, user_details) diff --git a/actions/workflow.jupyter.user.prepare.yaml b/actions/workflow.jupyter.user.prepare.yaml deleted file mode 100644 index f30cc5b42..000000000 --- a/actions/workflow.jupyter.user.prepare.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: workflow.jupyter.user.prepare -description: Creates a list of JupyterHub users, and starts up servers for each user -enabled: true -entry_point: workflows/jupyter.user.prepare.yaml -runner_type: orquesta - -parameters: - jupyter_env: - description: The Jupyter environment to prepare users on - required: true - type: string - enum: - - prod - - dev - - training - user_base_name: - description: The users to prepare, or base name of the users to prepare without the hyphen (e.g. "jupyter") - required: true - type: string - first_index: - description: The index of the first user to prepare - required: false - type: integer - last_index: - description: The index of the last user to prepare (inclusive). - required: false - type: integer diff --git a/actions/workflows/jupyter.user.prepare.yaml b/actions/workflows/jupyter.user.prepare.yaml deleted file mode 100644 index cd29a5314..000000000 --- a/actions/workflows/jupyter.user.prepare.yaml +++ /dev/null @@ -1,27 +0,0 @@ -version: 1.0 -description: Creates a list of JupyterHub users, and starts up servers for each user - -input: - - jupyter_env - - user_base_name - - first_index - - last_index - -tasks: - create_jupyter_users: - action: stackstorm_openstack.jupyter.user.create - user=<% ctx(user_base_name) %> - first_index=<% ctx(first_index) %> - last_index=<% ctx(last_index) %> - jupyter_env=<% ctx(jupyter_env) %> - next: - - when: <% succeeded() %> - do: - - start_jupyter_servers - - start_jupyter_servers: - action: stackstorm_openstack.jupyter.server.start - user=<% ctx(user_base_name) %> - first_index=<% ctx(first_index) %> - last_index=<% ctx(last_index) %> - jupyter_env=<% ctx(jupyter_env) %> diff --git a/lib/amphorae.py b/lib/amphorae.py deleted file mode 100644 index 63123afb2..000000000 --- a/lib/amphorae.py +++ /dev/null @@ -1,20 +0,0 @@ -from openstack_api.openstack_connection import OpenstackConnection -import requests - - -DEV_URL = "https://dev-openstack.nubes.rl.ac.uk:9876/v2/octavia/amphorae" -PROD_URL = "https://openstack.nubes.rl.ac.uk:9876/v2/octavia/amphorae" - - -def get_amphorae(cloud_account: str): - """ - Method to get list of amphorae in openstack project - """ - - url = DEV_URL if "dev".casefold() in cloud_account.casefold() else PROD_URL - with OpenstackConnection(cloud_name=cloud_account) as conn: - return requests.get( - url, - headers={"X-Auth-Token": conn.auth_token}, - timeout=300, - ) diff --git a/lib/jupyter_api/__init__.py b/lib/enums/icinga/__init__.py similarity index 100% rename from lib/jupyter_api/__init__.py rename to lib/enums/icinga/__init__.py diff --git a/tests/lib/jupyter/__init__.py b/lib/icinga_api/__init__.py similarity index 100% rename from tests/lib/jupyter/__init__.py rename to lib/icinga_api/__init__.py diff --git a/lib/jupyter_api/api_endpoints.py b/lib/jupyter_api/api_endpoints.py deleted file mode 100644 index 66029c896..000000000 --- a/lib/jupyter_api/api_endpoints.py +++ /dev/null @@ -1,5 +0,0 @@ -API_ENDPOINTS = { - "dev": "https://test.jupyter.stfc.ac.uk", - "training": "https://training.jupyter.stfc.ac.uk", - "prod": "https://jupyter.stfc.ac.uk", -} diff --git a/lib/jupyter_api/get_token.py b/lib/jupyter_api/get_token.py deleted file mode 100644 index 25d232155..000000000 --- a/lib/jupyter_api/get_token.py +++ /dev/null @@ -1,22 +0,0 @@ -def get_token( - jupyter_env: str, - jupyter_keys: str, -) -> str: - """ - Returns the appropriate API token based on the Jupyter environment - :param jupyter_env: The Jupyter environment name - :param jupyter_keys: Dictionary of Jupyter API tokens - """ - key_name = None - env = jupyter_env.casefold() - if env == "prod".casefold(): - key_name = "prod_token" - if env == "training".casefold(): - key_name = "training_token" - if env == "dev".casefold(): - key_name = "dev_token" - if not key_name: - raise KeyError("Unknown Jupyter environment") - - token = jupyter_keys[key_name] - return token diff --git a/lib/jupyter_api/user_api.py b/lib/jupyter_api/user_api.py deleted file mode 100644 index bbf6869bd..000000000 --- a/lib/jupyter_api/user_api.py +++ /dev/null @@ -1,165 +0,0 @@ -from datetime import datetime -from typing import List, Dict - -import pytz -import requests -from dateutil import parser -from dateutil.relativedelta import relativedelta - -from jupyter_api.api_endpoints import API_ENDPOINTS -from structs.jupyter_last_used import JupyterLastUsed -from structs.jupyter_users import JupyterUsers - - -class UserApi: - def get_inactive_users( - self, endpoint: str, auth_token: str, threshold: relativedelta - ) -> List[JupyterLastUsed]: - """ - Polls the given endpoint for users and returns the list of users - """ - try: - users = self.get_users(endpoint, auth_token) - except RuntimeError: - return [] - - return self._filter_inactive(users, threshold) - - def get_users(self, endpoint: str, auth_token: str) -> List[JupyterLastUsed]: - """ - Gets the list of all users from the JupyterHub API - """ - result = requests.get( - url=API_ENDPOINTS[endpoint] + "/hub/api/users", - headers={"Authorization": f"token {auth_token}"}, - timeout=300, - ) - - if result.status_code == 200: - return self._pack_users(result.json()) - if result.status_code == 204: - return [] - raise RuntimeError(f"Failed to get users error was:\n{result.text}") - - def delete_users(self, endpoint: str, auth_token: str, users: JupyterUsers) -> None: - """ - Removes the given user(s) from the JupyterHub API - """ - user_list = self._get_user_list(users) - for user in user_list: - self._delete_single_user(endpoint, auth_token, user) - - def _delete_single_user(self, endpoint: str, auth_token: str, user: str): - result = requests.delete( - url=API_ENDPOINTS[endpoint] + f"/hub/api/users/{user}", - headers={"Authorization": f"token {auth_token}"}, - timeout=300, - ) - - if result.status_code != 204: - raise RuntimeError(f"Failed to remove user {user}: {result.text}") - - def create_users(self, endpoint: str, auth_token: str, users: JupyterUsers) -> None: - """ - Creates the given user(s) from the JupyterHub API - """ - user_list = self._get_user_list(users) - for user in user_list: - self._create_single_user(endpoint, auth_token, user) - - def _create_single_user(self, endpoint: str, auth_token: str, user: str): - result = requests.post( - url=API_ENDPOINTS[endpoint] + f"/hub/api/users/{user}", - headers={"Authorization": f"token {auth_token}"}, - timeout=60, - ) - - if result.status_code != 201: - raise RuntimeError(f"Failed to create user {user}: {result.text}") - - def start_servers( - self, endpoint: str, auth_token: str, users: JupyterUsers - ) -> None: - """ - Starts servers for the given user(s) from the JupyterHub API - """ - user_list = self._get_user_list(users) - for user in user_list: - self._start_single_server(endpoint, auth_token, user) - - def _start_single_server(self, endpoint: str, auth_token: str, user: str): - result = requests.post( - url=API_ENDPOINTS[endpoint] + f"/hub/api/users/{user}/server", - headers={"Authorization": f"token {auth_token}"}, - timeout=60, - ) - - if result.status_code not in (201, 202): - raise RuntimeError( - f"Failed to request server for user {user}: {result.text}" - ) - - def stop_servers(self, endpoint: str, auth_token: str, users: JupyterUsers) -> None: - """ - Stops servers for the given user(s) from the JupyterHub API - """ - user_list = self._get_user_list(users) - for user in user_list: - self._stop_single_server(endpoint, auth_token, user) - - def _stop_single_server(self, endpoint: str, auth_token: str, user: str): - result = requests.delete( - url=API_ENDPOINTS[endpoint] + f"/hub/api/users/{user}/server", - headers={"Authorization": f"token {auth_token}"}, - timeout=60, - ) - - if result.status_code not in (202, 204): - raise RuntimeError(f"Failed to stop server for user {user}: {result.text}") - - @staticmethod - def _get_user_list(users: JupyterUsers) -> List[str]: - """ - Creates list of users from name and indices - """ - if users.start_index or users.end_index: - if not (users.start_index and users.end_index): - raise RuntimeError("Both start_index and end_index must be provided") - if users.start_index > users.end_index: - raise RuntimeError("start_index must be less than end_index") - - user_list = ( - [f"{users.name}-{i}" for i in range(users.start_index, users.end_index + 1)] - if users.start_index - else [users.name] - ) - return user_list - - @staticmethod - def _pack_users(users: List[Dict]) -> List[JupyterLastUsed]: - """ - Deserializes the JSON into a bespoke struct for easier processing - """ - to_return = [] - for user in users: - last_used = parser.parse( - user["last_activity"] if user["last_activity"] else user["created"] - ) - to_return.append((user["name"], last_used)) - return to_return - - def _filter_inactive( - self, users: List[JupyterLastUsed], threshold: relativedelta - ) -> List[JupyterLastUsed]: - """ - Filters inactive users from the list of all users - """ - return [user for user in users if self._is_inactive(user, threshold)] - - @staticmethod - def _is_inactive(user: JupyterLastUsed, threshold: relativedelta) -> bool: - """ - Test if a user is inactive after a given length of time - """ - # Force UTC timezone - return user[1] < pytz.utc.localize(datetime.now() - threshold) diff --git a/lib/openstack_action.py b/lib/openstack_action.py deleted file mode 100644 index f8f7d3a14..000000000 --- a/lib/openstack_action.py +++ /dev/null @@ -1,53 +0,0 @@ -from abc import ABC -from typing import Dict - -import openstack - -from st2common.runners.base_action import Action - - -def connect_to_openstack(): - """ - Connect to openstack - :return: openstack connection object - """ - return openstack.connect() - - -class OpenstackAction(Action, ABC): - def __init__(self, config=None, action_service=None): - super().__init__(config, action_service) - self.conn = None - # Abstract method - self.func: Dict - - def run(self, **kwargs): - """ - function that is run openstack_resource stackstorm when an action is invoked - :param kwargs: arguments for openstack actions - :return: (Status (Bool), Output <*>): tuple of action status (succeeded(T)/failed(F)) and the output - """ - self.conn = connect_to_openstack() - - function = self.func.get(kwargs["submodule"]) - return function( - **{ - k: v - for k, v in kwargs.items() - if v not in [None, ["NULL"]] and k not in ["submodule"] - } - ) - - @staticmethod - def find_resource_id(identifier, openstack_func, **kwargs): - """ - helper to find the ID of a openstack resource - :param identifier: Associated Name of the openstack resource - :param openstack_func: Openstack function to find the resource - :param kwargs: Arguments to pass into Openstack function - :return: (String/None): ID of resource (or None if not found) - """ - resource = openstack_func(identifier, **kwargs) - if not resource: - return None - return resource.get("id", None) diff --git a/lib/openstack_query_api/__init__.py b/lib/openstack_query_api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lib/post_ticket.py b/lib/post_ticket.py deleted file mode 100644 index ad5ec4763..000000000 --- a/lib/post_ticket.py +++ /dev/null @@ -1,34 +0,0 @@ -import requests -from requests.auth import HTTPBasicAuth - - -# pylint: disable=too-many-arguments -def post_ticket( - tickets_info, ticket_details, service_desk_id, request_type_id, email, api_key -): - """ - Returns a requests that has created a ticket in atlassian - :param dict tickets_info: Basic data that is needed to create the ticket - :param str service_desk_id: The service desk to send the ticket to - :param str request_type_id: The type of ticket to create - """ - - return requests.post( - "https://stfc.atlassian.net/rest/servicedeskapi/request", - auth=HTTPBasicAuth(email, api_key), - headers={ - "Accept": "application/json", - "Content-Type": "application/json", - }, - json={ - "requestFieldValues": { - "summary": tickets_info["title"].format(p=ticket_details["dataTitle"]), - "description": tickets_info["body"].format( - p=ticket_details["dataBody"] - ), - }, - "serviceDeskId": service_desk_id, # Point this at relevant service desk - "requestTypeId": request_type_id, - }, - timeout=300, - ) diff --git a/lib/ssh_api/__init__.py b/lib/ssh_api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lib/structs/icinga/__init__.py b/lib/structs/icinga/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lib/structs/jira/__init__.py b/lib/structs/jira/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lib/structs/ssh/__init__.py b/lib/structs/ssh/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/rules/jupyter.prune_inactive.yaml b/rules/jupyter.prune_inactive.yaml deleted file mode 100644 index c7b36a3be..000000000 --- a/rules/jupyter.prune_inactive.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: "jupyter.prune_inactive" -pack: "stackstorm_openstack" -description: "Triggers the cleanup of inactive users in JupyterHub" -enabled: true - -criteria: - trigger.env: - type: incontains - # Disable on prod until we migrate JupyterHub - # this is an additional safety net. Before you enable this - # ensure the threshold in the sensors is changed from 1 day to the desired value. - pattern: prod - -trigger: - type: "stackstorm_openstack.jupyter.inactiveusers" - -action: - ref: "stackstorm_openstack.jupyter.user.delete" - parameters: - jupyter_env: "{{ trigger.env }}" - users: "{{ trigger.inactive_users }}" diff --git a/rules/openstack.deletedmachines.rule.yaml b/rules/openstack.deletedmachines.rule.yaml deleted file mode 100644 index ef993800f..000000000 --- a/rules/openstack.deletedmachines.rule.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: "openstack.deletedmachines" -pack: "stackstorm_openstack" -description: "Rule to trigger createTickets when sensor picks up issue" -enabled: true - -trigger: - type: "stackstorm_openstack.openstack.deletingmachines" -action: - ref: "stackstorm_openstack.atlassian.create.tickets" - parameters: - tickets_info: "{{ trigger }}" - email: "{{ st2kv.system.jsm_email }}" - api_key: "{{ st2kv.system.jsm_key }}" - servicedesk_id: "12" #StackstormTest - requesttype_id: "167" #Report a problem diff --git a/rules/openstack.loadbalancers.rule.yaml b/rules/openstack.loadbalancers.rule.yaml deleted file mode 100644 index d574f88bb..000000000 --- a/rules/openstack.loadbalancers.rule.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: "openstack.loadbalancers" -pack: "stackstorm_openstack" -description: "Rule to trigger createTickets when sensor picks up issue" -enabled: true - -trigger: - type: "stackstorm_openstack.openstack.loadbalancer" -action: - ref: "stackstorm_openstack.atlassian.create.tickets" - parameters: - tickets_info: "{{ trigger }}" - email: "{{ st2kv.system.jsm_email }}" - api_key: "{{ st2kv.system.jsm_key }}" - servicedesk_id: "12" #StackstormTest - requesttype_id: "167" #Report a problem diff --git a/sensors/jupyter.inactive_users.yaml b/sensors/jupyter.inactive_users.yaml deleted file mode 100644 index be11ff4dd..000000000 --- a/sensors/jupyter.inactive_users.yaml +++ /dev/null @@ -1,16 +0,0 @@ -class_name: "JupyterInactiveUserSensor" -entry_point: "src/jupyter_inactive_user_sensor.py" -description: "Sensor the detects inactive users in JupyterHub" -poll_interval: 300 # Every 10 hours #TODO -trigger_types: - - name: "jupyter.inactiveusers" - description: "Trigger for JupyterHub inactive users that match are older than the given expiry" - payload_schema: - type: "object" - properties: - env: - type: "string" - description: "The environment to run the sensor in" - inactive_users: - type: "array" - description: "The list of inactive user names" diff --git a/sensors/openstack.deletingmachines.yaml b/sensors/openstack.deletingmachines.yaml deleted file mode 100644 index f1f47de9f..000000000 --- a/sensors/openstack.deletingmachines.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -class_name: "DeletingMachinesSensor" -entry_point: "src/deleting_machines_sensor.py" -description: "Check for machines stuck in deleting state for longer than 10m" -poll_interval: 604800 -trigger_types: - - name: "openstack.deletingmachines" - description: "Trigger for problems with deleting machines" - payload_schema: - type: "object" diff --git a/sensors/openstack.loadbalancers.yaml b/sensors/openstack.loadbalancers.yaml deleted file mode 100644 index a4c831415..000000000 --- a/sensors/openstack.loadbalancers.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -class_name: "LoadbalancerSensor" -entry_point: "src/loadbalancer_sensor.py" -description: "Check for amphorae with an error status and find out if it is an issue with the amphora or loadbalancer" -poll_interval: 604800 -trigger_types: - - name: "openstack.loadbalancer" - description: "Trigger for problems with loadbalancers." - payload_schema: - type: "object" diff --git a/sensors/src/deleting_machines_sensor.py b/sensors/src/deleting_machines_sensor.py deleted file mode 100644 index 4c40c44c7..000000000 --- a/sensors/src/deleting_machines_sensor.py +++ /dev/null @@ -1,94 +0,0 @@ -from datetime import datetime -from st2reactor.sensor.base import PollingSensor -from st2reactor.container.sensor_wrapper import SensorService -from openstack_api.openstack_connection import OpenstackConnection - - -class DeletingMachinesSensor(PollingSensor): - def __init__(self, sensor_service: SensorService, config, poll_interval): - # pylint: disable=super-with-arguments - super(DeletingMachinesSensor, self).__init__( - sensor_service=sensor_service, config=config, poll_interval=poll_interval - ) - self.sensor_service: SensorService = sensor_service - self._logger = self.sensor_service.get_logger(name=self.__class__.__name__) - - # pylint: disable=missing-function-docstring - def add_trigger(self, trigger): - pass - - def update_trigger(self, trigger): - pass - - def cleanup(self): - pass - - def remove_trigger(self, trigger): - pass - - def setup(self): - pass - - def poll(self, cloud_account: str = "dev-admin"): - """ - Action to check for machines that are stuck deleting for more than 10mins - Outputs a suitable dictionary to pass into create_tickets - """ - output = { - "title": "Server {p[id]} has not been updated in more than 10 minutes during {p[action]}", - "body": "The following information may be useful\nHost id: {p[id]}", - "server_list": [], - } - - with OpenstackConnection(cloud_name=cloud_account) as conn: - projects = conn.list_projects() - for project in projects: - deleted = self._check_deleted(project=project["id"], cloud=cloud_account) - print(output["server_list"]) - output["server_list"].extend(deleted) - print(output["server_list"]) - if output["server_list"]: - self.sensor_service.dispatch_with_context( - payload=output, - trigger="stackstorm_openstack.openstack.deletingmachines", - ) - return output - - print("checks complete, no servers found") - print(output) - return output - - @staticmethod - def _check_deleted(cloud: str, project: str): - """ - Runs the check for deleting machines on a per-project basis - """ - output = [] - - print("Checking project", project) - with OpenstackConnection(cloud_name=cloud) as conn: - server_list = conn.compute.servers(all_tenants=True, project_id=project) - - # Loop through each server in the project/list - for i in server_list: - server = conn.compute.get_server(i["id"]) - # Take current time and check difference between updated time - since_update = datetime.utcnow() - datetime.strptime( - server.updated_at, "%Y-%m-%dT%H:%M:%Sz" - ) - # Check if server has been stuck in deleting for too long. - # (uses the last updated time so if changes have been made - # to the server while deleting the check may not work.) - if server.status == "DELETING" and since_update.total_seconds() >= 600: - # Append data to output array - output.append( - { - "dataTitle": { - "id": str(server.id), - "action": str(server.status), - }, - "dataBody": {"id": server.id}, - } - ) - print(output) - return output diff --git a/sensors/src/hypervisor_state_sensor.py b/sensors/src/hypervisor_state_sensor.py index 5f0675408..f7c9a1249 100644 --- a/sensors/src/hypervisor_state_sensor.py +++ b/sensors/src/hypervisor_state_sensor.py @@ -56,10 +56,9 @@ def poll(self): trigger="stackstorm_openstack.hypervisor.state_change", payload=payload, ) - - self.sensor_service.set_value( - name=hypervisor["hypervisor_name"], value=current_state.name - ) + self.sensor_service.set_value( + name=hypervisor["hypervisor_name"], value=current_state.name + ) def cleanup(self): """ diff --git a/sensors/src/jupyter_inactive_user_sensor.py b/sensors/src/jupyter_inactive_user_sensor.py deleted file mode 100644 index aad27f187..000000000 --- a/sensors/src/jupyter_inactive_user_sensor.py +++ /dev/null @@ -1,76 +0,0 @@ -from dateutil.relativedelta import relativedelta - -from jupyter_api.api_endpoints import API_ENDPOINTS -from jupyter_api.user_api import UserApi -from st2reactor.sensor.base import PollingSensor - -THRESHOLD = relativedelta(days=90) - - -class JupyterInactiveUserSensor(PollingSensor): - """ - Polls for accounts that have not logged in for a given amount of time - """ - - def __init__(self, sensor_service, config=None, poll_interval=5): - """ - Init to prep injected vars - """ - super().__init__(sensor_service, config, poll_interval) - self._log = self._sensor_service.get_logger(__name__) - self._api: UserApi = UserApi() - self._credentials = {"dev": None, "prod": None, "training": None} - - def poll(self): - """ - Polls for inactive users and dispatches triggers if any are found - """ - for endpoint in API_ENDPOINTS.keys(): - inactive_users = self._api.get_inactive_users( - endpoint, auth_token=self._credentials[endpoint], threshold=THRESHOLD - ) - if not inactive_users: - continue - - self._log.info(f"Found {len(inactive_users)} inactive users on {endpoint}") - self._log.info(f"Inactive users: {inactive_users}") - - inactive_usernames = [user[0] for user in inactive_users] - self.sensor_service.dispatch( - trigger="stackstorm_openstack.jupyter.inactiveusers", - payload={"env": endpoint, "inactive_users": inactive_usernames}, - ) - - def setup(self): - """ - Sets up the sensor - """ - self._credentials["prod"] = self.sensor_service.get_value( - "jupyter.prod_token", local=False, decrypt=True - ) - self._credentials["dev"] = self.sensor_service.get_value( - "jupyter.dev_token", local=False, decrypt=True - ) - self._credentials["training"] = self.sensor_service.get_value( - "jupyter.training_token", local=False, decrypt=True - ) - - def cleanup(self): - """ - Stub - """ - - def add_trigger(self, trigger): - """ - Stub - """ - - def update_trigger(self, trigger): - """ - Stub - """ - - def remove_trigger(self, trigger): - """ - Stub - """ diff --git a/sensors/src/loadbalancer_sensor.py b/sensors/src/loadbalancer_sensor.py deleted file mode 100644 index 9590b1476..000000000 --- a/sensors/src/loadbalancer_sensor.py +++ /dev/null @@ -1,162 +0,0 @@ -import subprocess -import logging -import requests -from st2reactor.sensor.base import Sensor -from st2reactor.container.sensor_wrapper import SensorService -from amphorae import get_amphorae - - -# pylint: disable=abstract-method -class LoadbalancerSensor(Sensor): - def __init__(self, sensor_service: SensorService, config): - # pylint: disable=super-with-arguments - super(LoadbalancerSensor, self).__init__( - sensor_service=sensor_service, config=config - ) - self.sensor_service: SensorService = sensor_service - self._logger = self.sensor_service.get_logger(name=self.__class__.__name__) - - def run( - self, - cloud_account: str = "dev-admin", - ): - """ - Action to check loadbalancer and amphorae status - output suitable to be passed to create_tickets - """ - - amphorae = get_amphorae(cloud_account) - - amph_json = self._check_amphora_status(amphorae) - # pylint: disable=line-too-long - output = { - "title": "{p[title_text]}", - "body": "The loadbalance ping test result was: {p[lb_status]}\nThe status of the amphora was: {p[amp_status]}\nThe amphora id is: {p[amp_id]}\nThe loadbalancer id is: {p[lb_id]}", - "server_list": [], - } - if amphorae.status_code != 200: - # Notes problem with accessing api if anything other than 403 or 200 returned - logging.critical("We encountered a problem accessing the API") - logging.critical("The status code was: %s ", str(amphorae.status_code)) - logging.critical("The JSON response was: \n %s", str(amph_json)) - - # Gets list of amphorae and iterates through it to check the loadbalancer and amphora status. - for i in amph_json["amphorae"]: - status = self._check_status(i) - ping_result = self._ping_lb(i["lb_network_ip"]) - # This section builds out the ticket for each one with an error - if status[0].lower() == "error" and ping_result.lower() == "error": - output["server_list"].append( - { - "dataTitle": { - "title_text": "Issue with loadbalancer " - + str(i["loadbalancer_id"] or "null") - + " and amphora " - + str(i["id"] or "null"), - "lb_id": str(i["loadbalancer_id"] or "null"), - "amp_id": str(i["id"] or "null"), - }, - "dataBody": { - "lb_status": str(ping_result or "null"), - "amp_status": str(status[1] or "null"), - "lb_id": str(i["loadbalancer_id"] or "null"), - "amp_id": str(i["id"] or "null"), - }, - } - ) - if status[0].lower() == "error" and ping_result.lower() != "error": - output["server_list"].append( - { - "dataTitle": { - "title_text": "Issue with loadbalancer " - + str(i["loadbalancer_id"] or "null"), - "lb_id": str(i["loadbalancer_id"] or "null"), - }, - "dataBody": { - "lb_status": str(ping_result or "null"), - "amp_status": str(status[1] or "null"), - "lb_id": str(i["loadbalancer_id"] or "null"), - "amp_id": str(i["id"] or "null"), - }, - } - ) - if status[0].lower() != "error" and ping_result.lower() == "error": - output["server_list"].append( - { - "dataTitle": { - "title_text": "Issue with amphora " - + str(i["id"] or "null"), - "amp_id": str(i["id"] or "null"), - }, - "dataBody": { - "lb_status": str(ping_result or "null"), - "amp_status": str(status[1] or "null"), - "lb_id": str(i["loadbalancer_id"] or "null"), - "amp_id": str(i["id"] or "null"), - }, - } - ) - else: - logging.info("%s is fine.", i["id"]) - if len(output["server_list"]) > 0: - self.sensor_service.dispatch( - trigger="stackstorm_openstack.openstack.loadbalancer", payload=output - ) - - @staticmethod - def _check_amphora_status(amphorae): - try: - amph_json = amphorae.json() - return amph_json - except requests.exceptions.JSONDecodeError: - logging.critical( - msg="There was no JSON response \nThe status code was: " - + str(amphorae.status_code) - + "\nThe body was: \n" - + str(amphorae.content) - ) - # pylint: disable=line-too-long - return ( - "There was no JSON response \nThe status code was: " - + str(amphorae.status_code) - + "\nThe body was: \n" - + str(amphorae.content) - ) - - # pylint: disable=missing-function-docstring - @staticmethod - def _check_status(amphora): - # Extracts the status of the amphora and returns relevant info - status = amphora["status"] - if status.upper() in ("ALLOCATED", "BOOTING", "READY"): - return ["ok", status] - - return ["error", status] - - # pylint: disable=invalid-name - @staticmethod - def _ping_lb(ip): - # Runs the ping command to check that loadbalancer is up - response = subprocess.run(["ping", "-q", "-c", "1", ip], check=False) - # Checks output of ping command - if response.returncode == 0: - logging.info(msg="Successfully pinged " + ip) - return "success" - - logging.info(msg=ip + " is down") - return "error" - - def add_trigger(self, trigger): - pass - - def cleanup(self): - pass - - def remove_trigger(self, trigger): - pass - - def setup(self): - pass - - def update_trigger(self, trigger): - pass diff --git a/tests/actions/test_jupyter_actions.py b/tests/actions/test_jupyter_actions.py deleted file mode 100644 index 341a0cb4a..000000000 --- a/tests/actions/test_jupyter_actions.py +++ /dev/null @@ -1,70 +0,0 @@ -from unittest.mock import create_autospec, Mock, NonCallableMock, NonCallableMagicMock - -from nose.tools import raises -from parameterized import parameterized - -from jupyter_api.user_api import UserApi -from src.jupyter import Jupyter -from structs.jupyter_users import JupyterUsers -from tests.actions.openstack_action_test_base import OpenstackActionTestBase - - -class TestJupyterActions(OpenstackActionTestBase): - """ - Unit tests for the Jupyter.* actions - """ - - action_cls = Jupyter - - # pylint: disable=invalid-name - def setUp(self): - """ - Prepares the mock API and injects it into a new instance - """ - super().setUp() - self.user_mock: UserApi = create_autospec(UserApi) - self.jupyter_keys = NonCallableMagicMock() - config = {"user_api": self.user_mock, "jupyter": self.jupyter_keys} - self.action: Jupyter = self.get_action_instance(config=config) - - @parameterized.expand(["prod", "dev", "training"]) - def test_user_delete_gets_correct_key(self, endpoint): - token = self.jupyter_keys[endpoint] - - users, start_index, end_index = ( - NonCallableMock(), - NonCallableMock(), - NonCallableMock(), - ) - expected = JupyterUsers(users, start_index, end_index) - self.action.action_service.get_value = Mock() - self.action.user_delete(endpoint, users, start_index, end_index) - - self.user_mock.delete_users.assert_called_once_with( - endpoint=endpoint, auth_token=token, users=expected - ) - - @raises(KeyError) - def test_user_delete_throws_unknown_env(self): - self.action.user_delete("unknown", NonCallableMock()) - - @parameterized.expand(["prod", "dev", "training"]) - def test_user_create_gets_correct_key(self, endpoint): - token = self.jupyter_keys[endpoint] - - users, start_index, end_index = ( - NonCallableMock(), - NonCallableMock(), - NonCallableMock(), - ) - expected = JupyterUsers(users, start_index, end_index) - self.action.action_service.get_value = Mock() - self.action.user_create(endpoint, users, start_index, end_index) - - self.user_mock.create_users.assert_called_once_with( - endpoint=endpoint, auth_token=token, users=expected - ) - - @raises(KeyError) - def test_user_create_throws_unknown_env(self): - self.action.user_create("unknown", NonCallableMock()) diff --git a/tests/lib/jupyter/test_server_api.py b/tests/lib/jupyter/test_server_api.py deleted file mode 100644 index 983b3560e..000000000 --- a/tests/lib/jupyter/test_server_api.py +++ /dev/null @@ -1,162 +0,0 @@ -import unittest -from unittest.mock import patch, NonCallableMock, call - - -from jupyter_api.api_endpoints import API_ENDPOINTS -from jupyter_api.user_api import UserApi -from structs.jupyter_users import JupyterUsers - - -@patch("jupyter_api.user_api.requests") -class UserApiTests(unittest.TestCase): - """ - Tests for the API class handling user creation and deletion - """ - - def setUp(self) -> None: - """ - Creates a new instance of the API class for each test - """ - self.api = UserApi() - - def test_start_servers_single_user(self, requests): - """ - Tests that the start_servers method calls the correct endpoint - """ - token = NonCallableMock() - user_names = JupyterUsers(name="test", start_index=None, end_index=None) - requests.post.return_value.status_code = 201 - - self.api.start_servers("dev", token, user_names) - requests.post.assert_called_once_with( - url=API_ENDPOINTS["dev"] + "/hub/api/users/test/server", - headers={"Authorization": f"token {token}"}, - timeout=60, - ) - - def test_start_servers_multiple_users(self, requests): - """ - Tests that the start_servers method calls the correct endpoint - and usernames - """ - token = NonCallableMock() - start_index, end_index = 1, 10 - user_names = JupyterUsers( - name="test", start_index=start_index, end_index=end_index - ) - requests.post.return_value.status_code = 201 - - self.api.start_servers("dev", token, user_names) - for i, user_index in enumerate(range(start_index, end_index + 1)): - assert requests.post.call_args_list[i] == call( - url=API_ENDPOINTS["dev"] + f"/hub/api/users/test-{user_index}/server", - headers={"Authorization": f"token {token}"}, - timeout=60, - ) - assert requests.post.call_count == (end_index - start_index + 1) - - def test_start_servers_missing_start_index(self, _): - """ - Tests that the start_servers method raises an error if the start_index is not provided - """ - user_names = JupyterUsers(name="test", start_index=None, end_index=1) - with self.assertRaises(RuntimeError): - self.api.start_servers("dev", "token", user_names) - - def test_start_servers_missing_end_index(self, _): - """ - Tests that the start_servers method raises an error if the end_index is not provided - """ - user_names = JupyterUsers(name="test", start_index=1, end_index=None) - with self.assertRaises(RuntimeError): - self.api.start_servers("dev", "token", user_names) - - def test_start_servers_incorrect_order(self, _): - """ - Tests that the start_servers method raises an error if the end_index is greater than start - """ - user_names = JupyterUsers(name="test", start_index=2, end_index=1) - with self.assertRaisesRegex(RuntimeError, "must be less than"): - self.api.start_servers("dev", "token", user_names) - - def test_start_servers_handles_error(self, requests): - """ - Tests that the start_servers method logs an error if the request fails - """ - token = NonCallableMock() - user_names = JupyterUsers(name="test", start_index=None, end_index=None) - requests.post.return_value.status_code = 500 - - with self.assertRaisesRegex(RuntimeError, "Failed to request server"): - self.api.start_servers("dev", token, user_names) - - def test_stop_servers_single_user(self, requests): - """ - Tests that the stop_servers method calls the correct endpoint - """ - token = NonCallableMock() - user_names = JupyterUsers(name="test", start_index=None, end_index=None) - requests.delete.return_value.status_code = 204 - - self.api.stop_servers("dev", token, user_names) - requests.delete.assert_called_once_with( - url=API_ENDPOINTS["dev"] + "/hub/api/users/test/server", - headers={"Authorization": f"token {token}"}, - timeout=60, - ) - - def test_stop_servers_multiple_users(self, requests): - """ - Tests that the stop_servers method calls the correct endpoint - and usernames - """ - token = NonCallableMock() - start_index, end_index = 1, 10 - user_names = JupyterUsers( - name="test", start_index=start_index, end_index=end_index - ) - requests.delete.return_value.status_code = 204 - - self.api.stop_servers("dev", token, user_names) - for i, user_index in enumerate(range(start_index, end_index + 1)): - assert requests.delete.call_args_list[i] == call( - url=API_ENDPOINTS["dev"] + f"/hub/api/users/test-{user_index}/server", - headers={"Authorization": f"token {token}"}, - timeout=60, - ) - assert requests.delete.call_count == (end_index - start_index + 1) - - def test_stop_servers_missing_start_index(self, _): - """ - Tests that the stop_servers method raises an error if the start_index is not provided - """ - user_names = JupyterUsers(name="test", start_index=None, end_index=1) - with self.assertRaises(RuntimeError): - self.api.stop_servers("dev", "token", user_names) - - def test_stop_servers_missing_end_index(self, _): - """ - Tests that the stop_servers method raises an error if the end_index is not provided - """ - user_names = JupyterUsers(name="test", start_index=1, end_index=None) - with self.assertRaises(RuntimeError): - self.api.stop_servers("dev", "token", user_names) - - def test_stop_servers_incorrect_order(self, _): - """ - Tests that the stop_servers method raises an error if the end_index is greater than start - """ - user_names = JupyterUsers(name="test", start_index=2, end_index=1) - with self.assertRaisesRegex(RuntimeError, "must be less than"): - self.api.stop_servers("dev", "token", user_names) - - def test_stop_servers_handles_error(self, requests): - """ - Tests that the stop_servers method logs an error if the request fails - """ - token = NonCallableMock() - user_names = JupyterUsers(name="test", start_index=None, end_index=None) - requests.delete.return_value.status_code = 500 - - with self.assertRaisesRegex(RuntimeError, "Failed to stop server"): - self.api.stop_servers("dev", token, user_names) diff --git a/tests/lib/jupyter/test_user_api.py b/tests/lib/jupyter/test_user_api.py deleted file mode 100644 index e70bfe3dc..000000000 --- a/tests/lib/jupyter/test_user_api.py +++ /dev/null @@ -1,246 +0,0 @@ -from datetime import datetime -from unittest.mock import patch, NonCallableMock, Mock, call - -import pytest -import pytz -from dateutil import parser -from dateutil.relativedelta import relativedelta - -from jupyter_api.api_endpoints import API_ENDPOINTS -from jupyter_api.user_api import UserApi -from structs.jupyter_users import JupyterUsers - - -@pytest.fixture(name="patch_requests", scope="function", autouse=True) -def patch_requests_fixture(): - """ - Returns a patched instance of the requests library, this is scoped - for the duration of the test instance - """ - with patch("jupyter_api.user_api.requests") as mock_patch_requests: - yield mock_patch_requests - - -@pytest.fixture(name="api") -def api_fixture(): - """ - Returns a new instance of the UserApi class for each test - """ - return UserApi() - - -@pytest.mark.parametrize("endpoint", ["dev", "prod"]) -def test_get_users(endpoint, api, patch_requests): - """ - Tests that the get_users method calls the correct endpoint - and serialises the JSON correctly - """ - token = NonCallableMock() - expected_name = "test" - expected_time = "2020-01-01T00:00:00Z" - - patch_requests.get.return_value.status_code = 200 - patch_requests.get.return_value.json.return_value = [ - {"name": expected_name, "last_activity": expected_time} - ] - - returned = api.get_users(endpoint, token) - - patch_requests.get.assert_called_once_with( - url=API_ENDPOINTS[endpoint] + "/hub/api/users", - headers={"Authorization": f"token {token}"}, - timeout=300, - ) - assert len(returned) == 1 - assert returned[0][0] == expected_name - assert returned[0][1] == parser.parse(expected_time) - - -@pytest.mark.parametrize("endpoint", ["dev", "prod"]) -def test_get_users_no_users(endpoint, api, patch_requests): - """ - Tests that the get_users method returns an empty list if no users are found - """ - token = NonCallableMock() - - patch_requests.get.return_value.status_code = 204 - patch_requests.get.return_value.json.return_value = [] - - returned = api.get_users(endpoint, token) - - patch_requests.get.assert_called_once_with( - url=API_ENDPOINTS[endpoint] + "/hub/api/users", - headers={"Authorization": f"token {token}"}, - timeout=300, - ) - assert len(returned) == 0 - - -def test_get_users_handles_error(patch_requests, api): - """ - Tests that the get_users method logs an error if the request fails - """ - patch_requests.get.return_value.status_code = 500 - patch_requests.get.return_value.json.return_value = [] - - with pytest.raises(RuntimeError, match="Failed to get users"): - api.get_users("dev", "token") - - -def test_get_inactive_users(api): - """ - Tests the get_inactive_users filters out active users - correctly - """ - # Patch get_users to return a list of users - threshold = relativedelta(seconds=1) - active_user = ("test", pytz.utc.localize(datetime.now())) - inactive_user = ( - "test2", - pytz.utc.localize(datetime.now() - relativedelta(seconds=2)), - ) - - api.get_users = Mock(return_value=[active_user, inactive_user]) - returned = api.get_inactive_users("dev", "token", threshold) - - api.get_users.assert_called_once_with("dev", "token") - - assert len(returned) == 1 - assert returned[0] == inactive_user - - -def test_get_inactive_users_no_users(api): - """ - Tests the get_inactive_users method returns an empty list if no users are found - """ - api.get_users = Mock(return_value=[]) - returned = api.get_inactive_users("dev", "token", relativedelta(seconds=1)) - - api.get_users.assert_called_once_with("dev", "token") - assert not returned - - -def test_remove_users_single_user(patch_requests, api): - """ - Tests that the delete_users method calls the correct endpoint - """ - token = NonCallableMock() - user_names = JupyterUsers(name="test", start_index=None, end_index=None) - patch_requests.delete.return_value.status_code = 204 - - api.delete_users("dev", token, user_names) - patch_requests.delete.assert_called_once_with( - url=API_ENDPOINTS["dev"] + "/hub/api/users/test", - headers={"Authorization": f"token {token}"}, - timeout=300, - ) - - -def test_remove_users_multiple_users(patch_requests, api): - """ - Tests that the delete_users method calls the correct endpoint - and usernames - """ - token = NonCallableMock() - start_index, end_index = 1, 10 - user_names = JupyterUsers(name="test", start_index=start_index, end_index=end_index) - patch_requests.delete.return_value.status_code = 204 - - api.delete_users("dev", token, user_names) - for i, user_index in enumerate(range(start_index, end_index + 1)): - assert patch_requests.delete.call_args_list[i] == call( - url=API_ENDPOINTS["dev"] + f"/hub/api/users/test-{user_index}", - headers={"Authorization": f"token {token}"}, - timeout=300, - ) - assert patch_requests.delete.call_count == (end_index - start_index + 1) - - -def test_remove_users_missing_start_index(api): - """ - Tests that the delete_users method raises an error if the start_index is not provided - """ - user_names = JupyterUsers(name="test", start_index=None, end_index=1) - with pytest.raises(RuntimeError): - api.delete_users("dev", "token", user_names) - - -def test_remove_users_missing_end_index(api): - """ - Tests that the delete_users method raises an error if the end_index is not provided - """ - user_names = JupyterUsers(name="test", start_index=1, end_index=None) - with pytest.raises(RuntimeError): - api.delete_users("dev", "token", user_names) - - -def test_remove_users_incorrect_order(api): - """ - Tests that the delete_users method raises an error if the end_index is greater than start - """ - user_names = JupyterUsers(name="test", start_index=2, end_index=1) - with pytest.raises(RuntimeError, match="must be less than"): - api.delete_users("dev", "token", user_names) - - -def test_create_users_single_user(patch_requests, api): - """ - Tests that the create_users method calls the correct endpoint - """ - token = NonCallableMock() - user_names = JupyterUsers(name="test", start_index=None, end_index=None) - patch_requests.post.return_value.status_code = 201 - - api.create_users("dev", token, user_names) - patch_requests.post.assert_called_once_with( - url=API_ENDPOINTS["dev"] + "/hub/api/users/test", - headers={"Authorization": f"token {token}"}, - timeout=60, - ) - - -def test_create_users_multiple_users(patch_requests, api): - """ - Tests that the create_users method calls the correct endpoint - and usernames - """ - token = NonCallableMock() - start_index, end_index = 1, 10 - user_names = JupyterUsers(name="test", start_index=start_index, end_index=end_index) - patch_requests.post.return_value.status_code = 201 - - api.create_users("dev", token, user_names) - for i, user_index in enumerate(range(start_index, end_index + 1)): - assert patch_requests.post.call_args_list[i] == call( - url=API_ENDPOINTS["dev"] + f"/hub/api/users/test-{user_index}", - headers={"Authorization": f"token {token}"}, - timeout=60, - ) - assert patch_requests.post.call_count == (end_index - start_index + 1) - - -def test_create_users_missing_start_index(api): - """ - Tests that the create_users method raises an error if the start_index is not provided - """ - user_names = JupyterUsers(name="test", start_index=None, end_index=1) - with pytest.raises(RuntimeError): - api.create_users("dev", "token", user_names) - - -def test_create_users_missing_end_index(api): - """ - Tests that the create_users method raises an error if the end_index is not provided - """ - user_names = JupyterUsers(name="test", start_index=1, end_index=None) - with pytest.raises(RuntimeError): - api.create_users("dev", "token", user_names) - - -def test_create_users_incorrect_order(api): - """ - Tests that the create_users method raises an error if the end_index is greater than start - """ - user_names = JupyterUsers(name="test", start_index=2, end_index=1) - with pytest.raises(RuntimeError, match="must be less than"): - api.create_users("dev", "token", user_names) diff --git a/tests/lib/ssh_api/__init__.py b/tests/lib/ssh_api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/sensors/__init__.py b/tests/sensors/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/todo/actions/email.image.users.yaml b/todo/actions/email.image.users.yaml deleted file mode 100644 index fefe08a0b..000000000 --- a/todo/actions/email.image.users.yaml +++ /dev/null @@ -1,132 +0,0 @@ ---- -description: Sends email notifications to image project contacts based on a given query. -enabled: true -entry_point: src/email_actions.py -name: email.image.users -parameters: - timeout: - default: 5400 - submodule: - default: email_image_users - immutable: true - type: string - cloud_account: - description: "The clouds.yaml account to use whilst performing this action" - type: string - required: true - default: "dev" - enum: - - "dev" - - "prod" - project_identifier: - type: string - description: "Project (Name or ID) to search in - leave empty for all projects" - required: false - default: "" - query_preset: - description: "Name of a preset query - e.g images_older_than: list all images older than" - type: string - default: "images_older_than" - enum: - - "all_images" - - "images_older_than" - - "images_younger_than" - - "images_last_updated_before" - - "images_last_updated_after" - - "images_id_in" - - "images_id_not_in" - - "images_name_in" - - "images_name_not_in" - - "images_name_contains" - - "images_name_not_contains" - - "images_non_existent_project" - required: true - properties_to_select: - type: array - description: "Properties to display for images, must include project_email" - required: true - default: - - "id" - - "name" - - "status" - - "updated_at" - - "project_name" - - "project_email" - email_from: - type: string - description: "Email address to send email from" - required: true - default: "cloud-support@stfc.ac.uk" - immutable: true - email_cc: - description: "Email Addresses to Cc in (comma separated)" - required: false - type: array - header: - type: string - description: "Email Header filepath" - required: true - default: "/opt/stackstorm/packs/stackstorm_openstack/email_templates/header.html" - message: - type: string - description: "Email message to put in the body" - required: true - footer: - type: string - description: "Email footer filepath" - required: true - default: "/opt/stackstorm/packs/stackstorm_openstack/email_templates/footer.html" - attachment_filepaths: - description: "Filepaths to email attachments (comma separated)" - required: false - type: array - subject: - type: string - description: "Email subject" - required: true - default: "Test Message" - smtp_account: - type: string - description: "SMTP Account to use. Must be configured in in the pack settings." - required: true - default: "default" - send_as_html: - type: boolean - description: "Send email body as HTML" - required: true - default: true - test_override: - type: boolean - description: "Overrides email sending to a single address for testing purposes (Will only send a subset of emails if there are lots of them)" - required: true - default: false - test_override_email: - type: array - description: "Email to send the output to if test_override is checked" - required: true - default: - - "" - names: - type: array - description: "Names to search openstack_resource (ignored unless query_preset=name_in, or name_contains etc)" - required: true - default: - - "" - ids: - type: array - description: "ID to search openstack_resource (ignored unless query_preset=id_in etc)" - required: true - default: - - "" - name_snippets: - type: array - description: "Name snippets to search openstack_resource (ignored unless query_preset=name_contains etc)" - required: true - default: - - "" - days: - type: integer - description: "Number of days threshold for selecting images ips (ignored unless submodule=images_older_than or images_younger_than" - required: true - default: 60 -runner_type: python-script diff --git a/todo/actions/email.server.users.yaml b/todo/actions/email.server.users.yaml deleted file mode 100644 index dacbd9bb2..000000000 --- a/todo/actions/email.server.users.yaml +++ /dev/null @@ -1,135 +0,0 @@ ---- -description: Sends email notifications to VM owners based on a given query. -enabled: true -entry_point: src/email_actions.py -name: email.server.users -parameters: - timeout: - default: 5400 - submodule: - default: email_server_users - immutable: true - type: string - cloud_account: - description: "The clouds.yaml account to use whilst performing this action" - type: string - required: true - default: "dev" - enum: - - "dev" - - "prod" - project_identifier: - type: string - description: Project (Name or ID) to search in - leave empty for all projects - required: false - default: "" - query_preset: - description: "Name of a preset query - e.g servers_older_than: list all servers older than" - type: string - default: "servers_older_than" - enum: - - "all_servers" - - "servers_older_than" - - "servers_younger_than" - - "servers_last_updated_before" - - "servers_last_updated_after" - - "servers_id_in" - - "servers_id_not_in" - - "servers_name_in" - - "servers_name_not_in" - - "servers_name_contains" - - "servers_name_not_contains" - - "servers_errored" - - "servers_shutoff" - - "servers_errored_and_shutoff" - - "servers_shutoff_before" - required: true - properties_to_select: - type: array - description: "Properties to display for servers, must include user_email" - required: true - default: - - "id" - - "name" - - "status" - - "updated" - - "user_name" - - "user_email" - email_from: - type: string - description: "Email address to send email from" - required: true - default: "cloud-support@stfc.ac.uk" - immutable: true - email_cc: - description: "Email Addresses to Cc in (comma separated)" - required: false - type: array - header: - type: string - description: "Email Header filepath" - required: true - default: "/opt/stackstorm/packs/stackstorm_openstack/email_templates/header.html" - message: - type: string - description: "Email message to put in the body" - required: true - footer: - type: string - description: "Email footer filepath" - required: true - default: "/opt/stackstorm/packs/stackstorm_openstack/email_templates/footer.html" - attachment_filepaths: - description: "Filepaths to email attachments (comma separated)" - required: false - type: array - subject: - type: string - description: "Email subject" - required: true - default: "Test Message" - smtp_account: - type: string - description: "SMTP Account to use. Must be configured in in the pack settings." - required: true - default: "default" - send_as_html: - type: boolean - description: "Send email body as HTML" - required: true - default: true - test_override: - type: boolean - description: "Overrides email sending to a single address for testing purposes (Will only send a subset of emails if there are lots of them)" - required: true - default: false - test_override_email: - type: array - description: "Email to send the output to if test_override is checked" - required: true - default: - - "" - names: - type: array - description: Names to search openstack_resource (ignored unless query_preset=name_in, or name_contains etc) - required: true - default: - - "" - ids: - type: array - description: ID to search openstack_resource (ignored unless query_preset=id_in etc) - required: true - default: - - "" - name_snippets: - type: array - description: Name snippets to search openstack_resource (ignored unless query_preset=name_contains etc) - required: true - default: - - "" - days: - type: integer - description: Number of days threshold for selecting servers (ignored unless submodule=server_older_than(_per_user) or server_younger_than(_per_user) - required: true - default: 60 -runner_type: python-script diff --git a/todo/actions/hypervisor.list.yaml b/todo/actions/hypervisor.list.yaml deleted file mode 100644 index 08976cc96..000000000 --- a/todo/actions/hypervisor.list.yaml +++ /dev/null @@ -1,78 +0,0 @@ ---- -description: List hypervisors -enabled: true -entry_point: src/hypervisor_actions.py -name: hypervisor.list -parameters: - timeout: - default: 5400 - submodule: - default: hypervisor_list - type: string - immutable: true - cloud_account: - description: "The clouds.yaml account to use whilst performing this action" - required: true - type: string - default: "dev" - enum: - - "dev" - - "prod" - query_preset: - type: string - description: "Name of a preset query - e.g hvs_older_than: list all hvs older than" - default: hvs_up - enum: - - "all_hvs" - - "hvs_id_in" - - "hvs_id_not_in" - - "hvs_name_in" - - "hvs_name_not_in" - - "hvs_name_contains" - - "hvs_name_not_contains" - - "hvs_down" - - "hvs_up" - - "hvs_disabled" - - "hvs_enabled" - required: true - properties_to_select: - default: - - "id" - - "hypervisor_hostname" - - "state" - - "running_vms" - - "vcpu_usage" - - "memory_mb_usage" - - "local_gb_usage" - type: array - description: "Properties to display for the hvs that match the chosen query" - required: true - group_by: - description: "Property to group the selected resources by e.g. vcpus. Leave empty for no grouping." - type: string - default: "" - required: false - return_html: - default: false - description: "If True, get HTML" - required: true - type: boolean - names: - description: "Names to search openstack_resource (ignored unless query_preset=name_in, or name_contains etc)" - type: array - default: - - "" - required: true - ids: - description: "ID to search openstack_resource (ignored unless query_preset=id_in etc)" - type: array - default: - - "" - required: true - name_snippets: - description: "Name snippets to search openstack_resource (ignored unless query_preset=name_contains etc)" - type: array - default: - - "" - required: true -runner_type: python-script diff --git a/todo/actions/image.list.yaml b/todo/actions/image.list.yaml deleted file mode 100644 index 4faf12f43..000000000 --- a/todo/actions/image.list.yaml +++ /dev/null @@ -1,88 +0,0 @@ ---- -description: List images -enabled: true -entry_point: src/image_actions.py -name: image.list -parameters: - timeout: - default: 5400 - submodule: - default: image_list - type: string - immutable: true - cloud_account: - description: "The clouds.yaml account to use whilst performing this action" - required: true - type: string - default: "dev" - enum: - - "dev" - - "prod" - project_identifier: - type: string - description: "Project (Name or ID) to search in - leave empty for all projects" - required: false - default: "" - query_preset: - type: string - description: "Name of a preset query - e.g images_older_than: list all images older than" - default: images_older_than - enum: - - "all_images" - - "images_older_than" - - "images_younger_than" - - "images_last_updated_before" - - "images_last_updated_after" - - "images_id_in" - - "images_id_not_in" - - "images_name_in" - - "images_name_not_in" - - "images_name_contains" - - "images_name_not_contains" - - "images_non_existent_project" - required: true - properties_to_select: - default: - - "id" - - "name" - - "status" - - "updated_at" - - "project_name" - - "project_email" - type: array - description: "Properties to display for the images that match the chosen query" - required: true - group_by: - description: "Property to group the selected resources by e.g. project_email. Leave empty for no grouping." - type: string - default: "" - required: false - return_html: - default: false - description: "If True, get HTML" - required: true - type: boolean - names: - description: "Names to search openstack_resource (ignored unless query_preset=name_in, or name_contains etc)" - type: array - default: - - "" - required: true - ids: - description: "ID to search openstack_resource (ignored unless query_preset=id_in etc)" - type: array - default: - - "" - required: true - name_snippets: - description: "Name snippets to search openstack_resource (ignored unless query_preset=name_contains etc)" - type: array - default: - - "" - required: true - days: - description: "Number of days threshold for selecting images (ignored unless query_preset=images_older_than or images_last_updated_before etc)" - type: integer - default: 60 - required: true -runner_type: python-script diff --git a/todo/actions/project.list.yaml b/todo/actions/project.list.yaml deleted file mode 100644 index 1a5364e8c..000000000 --- a/todo/actions/project.list.yaml +++ /dev/null @@ -1,79 +0,0 @@ ---- -description: List projects -enabled: true -entry_point: src/project_actions.py -name: project.list -parameters: - timeout: - default: 99999 - submodule: - default: project_list - type: string - immutable: true - cloud_account: - description: The clouds.yaml account to use whilst performing this action - required: true - type: string - default: "dev" - enum: - - "dev" - - "prod" - query_preset: - type: string - description: "Name of a preset query - e.g project_name_contains: list all projects with particular strings in their name" - default: all_projects - enum: - - "all_projects" - - "projects_id_in" - - "projects_id_not_in" - - "projects_name_in" - - "projects_name_not_in" - - "projects_name_contains" - - "projects_name_not_contains" - - "projects_description_contains" - - "projects_description_not_contains" - - "projects_without_email" - properties_to_select: - default: - - "id" - - "name" - - "description" - - "email" - type: array - description: "Properties to display for the projects that match the chosen query" - required: true - group_by: - description: "Property to group the selected resources by e.g. email. Leave empty for no grouping." - type: string - default: "" - required: false - return_html: - default: false - description: "If True, get HTML" - required: true - type: boolean - names: - description: "Names to search openstack_resource (ignored unless query_preset=name_in etc)" - type: array - default: - - "" - required: true - ids: - description: "ID to search openstack_resource (ignored unless query_preset=id_in etc)" - type: array - default: - - "" - required: true - name_snippets: - description: "Name snippets to search openstack_resource (ignored unless query_preset=name_contains etc)" - type: array - default: - - "" - required: true - description_snippets: - description: "Description snippets to search openstack_resource (ignored unless query_preset=description_contains etc)" - type: array - default: - - "" - required: true -runner_type: python-script diff --git a/todo/actions/server.list.yaml b/todo/actions/server.list.yaml deleted file mode 100644 index 753276d80..000000000 --- a/todo/actions/server.list.yaml +++ /dev/null @@ -1,90 +0,0 @@ ---- -description: List servers -enabled: true -entry_point: src/server_actions.py -name: server.list -parameters: - timeout: - default: 5400 - submodule: - default: server_list - type: string - immutable: true - cloud_account: - description: The clouds.yaml account to use whilst performing this action - required: true - type: string - default: "dev" - enum: - - "dev" - - "prod" - project_identifier: - type: string - description: Project (Name or ID) to search in - leave empty for all projects - required: false - default: "" - query_preset: - type: string - description: "Name of a preset query - e.g server_older_than: list all servers older than" - default: servers_older_than - enum: - - "all_servers" - - "servers_older_than" - - "servers_younger_than" - - "servers_last_updated_before" - - "servers_last_updated_after" - - "servers_id_in" - - "servers_id_not_in" - - "servers_name_in" - - "servers_name_not_in" - - "servers_name_contains" - - "servers_name_not_contains" - - "servers_errored" - - "servers_shutoff" - - "servers_errored_and_shutoff" - - "servers_shutoff_before" - required: true - properties_to_select: - default: - - "id" - - "name" - - "status" - - "user_name" - - "user_email" - type: array - description: "Properties to display for the servers that match the chosen query" - required: true - group_by: - description: "Property to group the selected resources by e.g. user_email. Leave empty for no grouping." - type: string - default: "" - required: false - return_html: - default: false - description: "If True, get HTML" - required: true - type: boolean - names: - description: "Names to search openstack_resource (ignored unless query_preset=name_in etc)" - type: array - default: - - "" - required: true - ids: - description: "ID to search openstack_resource (ignored unless query_preset=id_in etc)" - type: array - default: - - "" - required: true - name_snippets: - description: "Name snippets to search openstack_resource (ignored unless query_preset=name_contains etc)" - type: array - default: - - "" - required: true - days: - description: "Number of days threshold for selecting servers (ignored unless query_preset=server_older_than or server_last_updated_before etc)" - type: integer - default: 60 - required: true -runner_type: python-script diff --git a/todo/actions/user.list.yaml b/todo/actions/user.list.yaml deleted file mode 100644 index 28fa1cf4d..000000000 --- a/todo/actions/user.list.yaml +++ /dev/null @@ -1,76 +0,0 @@ ---- -description: List users -enabled: true -entry_point: src/user_actions.py -name: user.list -parameters: - timeout: - default: 5400 - submodule: - default: user_list - type: string - immutable: true - cloud_account: - description: The clouds.yaml account to use whilst performing this action - required: true - type: string - default: "dev" - enum: - - "dev" - - "prod" - user_domain: - type: string - description: "Domain (Name or ID) to search in" - required: true - default: "default" - query_preset: - type: string - description: "Name of a preset query - e.g users_name_contains: list all users with a name containing" - default: all_users - enum: - - "all_users" - - "users_id_in" - - "users_id_not_in" - - "users_name_in" - - "users_name_not_in" - - "users_name_contains" - - "users_name_not_contains" - required: true - properties_to_select: - default: - - "id" - - "name" - - "email" - - "description" - type: array - description: "Properties to display for the users that match the chosen query" - required: true - group_by: - description: "Property to group the selected resources by e.g. project_email. Leave empty for no grouping." - type: string - default: "" - required: false - return_html: - default: false - description: "If True, get HTML" - required: true - type: boolean - names: - description: "Names to search openstack_resource (ignored unless query_preset=name_in, or name_contains etc)" - type: array - default: - - "" - required: true - ids: - description: "ID to search openstack_resource (ignored unless query_preset=id_in etc)" - type: array - default: - - "" - required: true - name_snippets: - description: "Name snippets to search openstack_resource (ignored unless query_preset=name_contains etc)" - type: array - default: - - "" - required: true -runner_type: python-script diff --git a/todo/actions/workflow.email.errored.server.users.yaml b/todo/actions/workflow.email.errored.server.users.yaml deleted file mode 100644 index b3789a952..000000000 --- a/todo/actions/workflow.email.errored.server.users.yaml +++ /dev/null @@ -1,39 +0,0 @@ -description: Emails users of errored VMs -enabled: true -entry_point: workflows/email.errored.server.users.yaml -name: workflow.email.errored.server.users -parameters: - cloud_account: - description: The clouds.yaml account to use whilst performing this action - required: true - type: string - default: "dev" - enum: - - "dev" - - "prod" - project_id: - description: "Project (Name or ID) to search in - leave empty for all projects" - default: "" - required: false - type: string - email_cc: - description: "Email Addresses to Cc in (comma separated)" - required: false - type: array - smtp_account: - type: string - description: "SMTP Account to use. Must be configured in in the pack settings." - required: true - default: "default" - test_override: - type: boolean - description: "Overrides email sending to a single address for testing purposes (Will only send a subset of emails if there are lots of them)" - required: true - default: false - test_override_email: - type: array - description: "Email to send the output to if test_override is checked" - required: true - default: - - "" -runner_type: orquesta diff --git a/todo/actions/workflow.email.shutoff.server.users.yaml b/todo/actions/workflow.email.shutoff.server.users.yaml deleted file mode 100644 index 7276010dd..000000000 --- a/todo/actions/workflow.email.shutoff.server.users.yaml +++ /dev/null @@ -1,39 +0,0 @@ -description: Emails users of shutoff VMs -enabled: true -entry_point: workflows/email.shutoff.server.users.yaml -name: workflow.email.shutoff.server.users -parameters: - cloud_account: - description: The clouds.yaml account to use whilst performing this action - required: true - type: string - default: "dev" - enum: - - "dev" - - "prod" - project_id: - description: "Project (Name or ID) to search in - leave empty for all projects" - default: "" - required: false - type: string - email_cc: - description: "Email Addresses to Cc in (comma separated)" - required: false - type: array - smtp_account: - type: string - description: "SMTP Account to use. Must be configured in in the pack settings." - required: true - default: "default" - test_override: - type: boolean - description: "Overrides email sending to a single address for testing purposes (Will only send a subset of emails if there are lots of them)" - required: true - default: false - test_override_email: - type: array - description: "Email to send the output to if test_override is checked" - required: true - default: - - "" -runner_type: orquesta diff --git a/todo/actions/workflows/email.errored.server.users.yaml b/todo/actions/workflows/email.errored.server.users.yaml deleted file mode 100644 index 2c2090b37..000000000 --- a/todo/actions/workflows/email.errored.server.users.yaml +++ /dev/null @@ -1,43 +0,0 @@ -version: 1.0 - -description: Executes the email.server.users action for errored VMs to informing users about them - -input: - - cloud_account - - project_id - - email_cc - - smtp_account - - test_override - - test_override_email - -vars: - - stdout: null - - stderr: null - - result: null - -output: - - result: <% ctx().result %> - -tasks: - send_emails: - action: stackstorm_openstack.email.server.users - cloud_account=<% ctx().cloud_account %> - project_identifier=<% ctx().project_id %> - email_cc=<% ctx().email_cc %> - smtp_account=<% ctx().smtp_account %> - test_override=<% ctx().test_override %> - test_override_email=<% ctx().test_override_email %> - query_preset=<% 'servers_errored' %> - properties_to_select=<% ['id', 'name', 'status', 'updated', 'user_name', 'user_email'] %> - header=<% '/opt/stackstorm/packs/stackstorm_openstack/email_templates/header.html' %> - message=<% 'The following VMs are in an errored state. Please submit a ticket to cloud-support@stfc.ac.uk if they are needed or delete them if they are not.' %> - footer=<% '/opt/stackstorm/packs/stackstorm_openstack/email_templates/footer.html' %> - subject=<% 'Errored VMs' %> - send_as_html=<% true %> - names=<% [] %> - name_snippets=<% [] %> - days=0 - next: - - when: <% succeeded() %> - publish: - - result: <% task(send_multiple_emails).result %> diff --git a/todo/actions/workflows/email.shutoff.server.users.yaml b/todo/actions/workflows/email.shutoff.server.users.yaml deleted file mode 100644 index db7b62239..000000000 --- a/todo/actions/workflows/email.shutoff.server.users.yaml +++ /dev/null @@ -1,41 +0,0 @@ -version: 1.0 - -description: Executes the email.server.users action for shutoff VMs to informing users about them - -input: - - cloud_account - - project_id - - email_cc - - smtp_account - - test_override - - test_override_email - -vars: - - result: null - -output: - - result: <% ctx().result %> - -tasks: - send_emails: - action: stackstorm_openstack.email.server.users - cloud_account=<% ctx().cloud_account %> - project_identifier=<% ctx().project_id %> - email_cc=<% ctx().email_cc %> - smtp_account=<% ctx().smtp_account %> - test_override=<% ctx().test_override %> - test_override_email=<% ctx().test_override_email %> - query_preset=<% 'servers_shutoff' %> - properties_to_select=<% ['id', 'name', 'status', 'updated', 'user_name', 'user_email'] %> - header=<% '/opt/stackstorm/packs/stackstorm_openstack/email_templates/header.html' %> - message=<% 'The following VMs are shutoff. As these VMs still take up resources while shutoff, please consider whether they are needed and delete them if they are not.' %> - footer=<% '/opt/stackstorm/packs/stackstorm_openstack/email_templates/footer.html' %> - subject=<% 'Shutoff VMs' %> - send_as_html=<% true %> - names=<% [] %> - name_snippets=<% [] %> - days=0 - next: - - when: <% succeeded() %> - publish: - - result: <% task(send_multiple_emails).result %> diff --git a/todo/rules/rabbitmq.hypervisor.disable.service.rule.yaml b/todo/rules/rabbitmq.hypervisor.disable.service.rule.yaml deleted file mode 100644 index 8bc55df97..000000000 --- a/todo/rules/rabbitmq.hypervisor.disable.service.rule.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: "rabbitmq.hypervisor.disable.service.rule" -pack: "stackstorm_openstack" -description: "Handles incoming trigger \"rabbit_message\" with message_type HYPERVISOR_DISABLE_SERVICE" -enabled: true -trigger: - type: stackstorm_send_notifications.rabbit_message - -criteria: - trigger.message_type: - type: "iequals" - pattern: "HYPERVISOR_DISABLE_SERVICE" - -action: - ref: stackstorm_send_notifications.rabbit.execute - parameters: - action_inputs: "{{ trigger.args }}" - dynamic_action: "stackstorm_openstack.hypervisor.service.disable" diff --git a/todo/rules/rabbitmq.hypervisor.enable.service.rule.yaml b/todo/rules/rabbitmq.hypervisor.enable.service.rule.yaml deleted file mode 100644 index 8a9e74d89..000000000 --- a/todo/rules/rabbitmq.hypervisor.enable.service.rule.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: "rabbitmq.hypervisor.enable.service.rule" -pack: "stackstorm_openstack" -description: "Handles incoming trigger \"rabbit_message\" with message_type HYPERVISOR_ENABLE_SERVICE" -enabled: true -trigger: - type: stackstorm_send_notifications.rabbit_message - -criteria: - trigger.message_type: - type: "iequals" - pattern: "HYPERVISOR_ENABLE_SERVICE" - -action: - ref: stackstorm_send_notifications.rabbit.execute - parameters: - action_inputs: "{{ trigger.args }}" - dynamic_action: "stackstorm_openstack.hypervisor.service.enable" diff --git a/todo/rules/rabbitmq.hypervisor.reboot.rule.yaml b/todo/rules/rabbitmq.hypervisor.reboot.rule.yaml deleted file mode 100644 index a9044c239..000000000 --- a/todo/rules/rabbitmq.hypervisor.reboot.rule.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: "rabbitmq.hypervisor.reboot.rule" -pack: "stackstorm_openstack" -description: "Handles incoming trigger \"rabbit_reply_message\" with message_type HYPERVISOR_REBOOT" -enabled: true -trigger: - type: stackstorm_send_notifications.rabbit_reply_message - -criteria: - trigger.message_type: - type: "iequals" - pattern: "HYPERVISOR_REBOOT" - -action: - ref: stackstorm_send_notifications.rabbit.execute.and.reply - parameters: - action_inputs: "{{ trigger.args }}" - dynamic_action: "stackstorm_openstack.hypervisor.reboot" - routing_key: "{{trigger.routing_key}}" - exchange: "" diff --git a/todo/rules/rabbitmq.hypervisor.remove.icinga.downtime.rule.yaml b/todo/rules/rabbitmq.hypervisor.remove.icinga.downtime.rule.yaml deleted file mode 100644 index 40d23c306..000000000 --- a/todo/rules/rabbitmq.hypervisor.remove.icinga.downtime.rule.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: "rabbitmq.hypervisor.remove.icinga.downtime.rule" -pack: "stackstorm_openstack" -description: "Handles incoming trigger \"rabbit_message\" with message_type HYPERVISOR_REMOVE_ICINGA_DOWNTIME" -enabled: true -trigger: - type: stackstorm_send_notifications.rabbit_message - -criteria: - trigger.message_type: - type: "iequals" - pattern: "HYPERVISOR_REMOVE_ICINGA_DOWNTIME" - -action: - ref: stackstorm_send_notifications.rabbit.execute - parameters: - action_inputs: "{{ trigger.args }}" - dynamic_action: "stackstorm_openstack.hypervisor.remove.icinga.downtime" diff --git a/todo/rules/rabbitmq.hypervisor.schedule.icinga.downtime.rule.yaml b/todo/rules/rabbitmq.hypervisor.schedule.icinga.downtime.rule.yaml deleted file mode 100644 index 1d9fbded6..000000000 --- a/todo/rules/rabbitmq.hypervisor.schedule.icinga.downtime.rule.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: "rabbitmq.hypervisor.schedule.icinga.downtime.rule" -pack: "stackstorm_openstack" -description: "Handles incoming trigger \"rabbit_message\" with message_type HYPERVISOR_SCHEDULE_ICINGA_DOWNTIME" -enabled: true -trigger: - type: stackstorm_send_notifications.rabbit_message - -criteria: - trigger.message_type: - type: "iequals" - pattern: "HYPERVISOR_SCHEDULE_ICINGA_DOWNTIME" - -action: - ref: stackstorm_send_notifications.rabbit.execute - parameters: - action_inputs: "{{ trigger.args }}" - dynamic_action: "stackstorm_openstack.hypervisor.remove.icinga.downtime" diff --git a/todo/rules/rabbitmq.server.create.rule.yaml b/todo/rules/rabbitmq.server.create.rule.yaml deleted file mode 100644 index 544941491..000000000 --- a/todo/rules/rabbitmq.server.create.rule.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: "rabbitmq.server.create.rule" -pack: "stackstorm_openstack" -description: "Handles incoming trigger \"rabbit_message\" with message_type CREATE_VM" -enabled: true -trigger: - type: stackstorm_send_notifications.rabbit_message - -criteria: - trigger.message_type: - type: "iequals" - pattern: "CREATE_VM" - -action: - ref: stackstorm_send_notifications.rabbit.execute - parameters: - action_inputs: "{{ trigger.args }}" - dynamic_action: "stackstorm_openstack.server.create" diff --git a/todo/rules/rabbitmq.server.delete.rule.yaml b/todo/rules/rabbitmq.server.delete.rule.yaml deleted file mode 100644 index 604743193..000000000 --- a/todo/rules/rabbitmq.server.delete.rule.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: "rabbitmq.server.delete.rule" -pack: "stackstorm_openstack" -description: "Handles incoming trigger \"rabbit_message\" with message_type DELETE_VM" -enabled: true -trigger: - type: stackstorm_send_notifications.rabbit_message - -criteria: - trigger.message_type: - type: "iequals" - pattern: "DELETE_VM" - -action: - ref: stackstorm_send_notifications.rabbit.execute - parameters: - action_inputs: "{{ trigger.args }}" - dynamic_action: "stackstorm_openstack.server.delete" diff --git a/todo/rules/rabbitmq.server.reboot.rule.yaml b/todo/rules/rabbitmq.server.reboot.rule.yaml deleted file mode 100644 index 233f5b02c..000000000 --- a/todo/rules/rabbitmq.server.reboot.rule.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: "rabbitmq.server.reboot.rule" -pack: "stackstorm_openstack" -description: "Handles incoming trigger \"rabbit_message\" with message_type REBOOT_VM" -enabled: true -trigger: - type: stackstorm_send_notifications.rabbit_message - -criteria: - trigger.message_type: - type: "iequals" - pattern: "REBOOT_VM" - -action: - ref: stackstorm_send_notifications.rabbit.execute - parameters: - action_inputs: "{{ trigger.args }}" - dynamic_action: "stackstorm_openstack.server.reboot" diff --git a/todo/rules/rabbitmq.server.restart.rule.yaml b/todo/rules/rabbitmq.server.restart.rule.yaml deleted file mode 100644 index a818682fa..000000000 --- a/todo/rules/rabbitmq.server.restart.rule.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: "rabbitmq.server.restart.rule" -pack: "stackstorm_openstack" -description: "Handles incoming trigger \"rabbit_message\" with message_type RESTART_VM" -enabled: true -trigger: - type: stackstorm_send_notifications.rabbit_message - -criteria: - trigger.message_type: - type: "iequals" - pattern: "RESTART_VM" - -action: - ref: stackstorm_send_notifications.rabbit.execute - parameters: - action_inputs: "{{ trigger.args }}" - dynamic_action: "stackstorm_openstack.server.restart" diff --git a/todo/rules/rabbitmq.server.shutdown.rule.yaml b/todo/rules/rabbitmq.server.shutdown.rule.yaml deleted file mode 100644 index 3642be658..000000000 --- a/todo/rules/rabbitmq.server.shutdown.rule.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: "rabbitmq.server.shutdown.rule" -pack: "stackstorm_openstack" -description: "Handles incoming trigger \"rabbit_message\" with message_type SHUTDOWN_VM" -enabled: true -trigger: - type: stackstorm_send_notifications.rabbit_message - -criteria: - trigger.message_type: - type: "iequals" - pattern: "SHUTDOWN_VM" - -action: - ref: stackstorm_send_notifications.rabbit.execute - parameters: - action_inputs: "{{ trigger.args }}" - dynamic_action: "stackstorm_openstack.server.shutdown"