diff --git a/README.md b/README.md index 56cfadc684..1ff34bf7b2 100644 --- a/README.md +++ b/README.md @@ -190,7 +190,10 @@ Workflow triggers can either be executed manually when an alert is activated or           

- +

Container Orchestration platforms

+

+ +

## Getting Started ### Overview diff --git a/docs/mint.json b/docs/mint.json index 4cb35e36a9..1e2fd1c517 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -101,6 +101,7 @@ "providers/documentation/mock-provider", "providers/documentation/mysql-provider", "providers/documentation/new-relic-provider", + "providers/documentation/openshift-provider", "providers/documentation/opsgenie-provider", "providers/documentation/pagerduty-provider", "providers/documentation/pingdom-provider", diff --git a/docs/providers/documentation/openshift-provider.mdx b/docs/providers/documentation/openshift-provider.mdx new file mode 100644 index 0000000000..f097c97095 --- /dev/null +++ b/docs/providers/documentation/openshift-provider.mdx @@ -0,0 +1,34 @@ +--- +title: "Openshift" +description: "Openshift provider to perform rollout restart action on specific resources." +--- + +## Inputs + +- **kind** (required): Kind of the object which will be run rollout restart action run (`deployments`, `statefulset`, `daemonset`). +- **name** (required): Name of the object which will be run rollout restart action run. + +## Outputs + +- **message**: Message for the action performed. + +## Authentication Parameters + +This provider offers you to authenticate with Openshift using: api_server, token and insecure. + +- **api_server** (required): The api server url of your Openshift cluster. +- **token** (required): The token of your user to authenticate with Openshift. +- **insecure** (optional): If you want to skip the certificate verification, set this to `True`. + +## Connecting with the Provider + +To connect to Openshift, follow below steps: + +1. Log in to your Openshift cluster and create a new service account with required roles. +2. Get the token of the service account. +3. Use the token to authenticate with Openshift. + +## Notes + +- This provider allows you to interact with Openshift to perform rollout restart actions. + diff --git a/keep-ui/public/icons/openshift-icon.png b/keep-ui/public/icons/openshift-icon.png new file mode 100644 index 0000000000..1d20d2217f Binary files /dev/null and b/keep-ui/public/icons/openshift-icon.png differ diff --git a/keep/providers/openshift_provider/__init__.py b/keep/providers/openshift_provider/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/keep/providers/openshift_provider/openshift_provider.py b/keep/providers/openshift_provider/openshift_provider.py new file mode 100644 index 0000000000..acfd90f6f1 --- /dev/null +++ b/keep/providers/openshift_provider/openshift_provider.py @@ -0,0 +1,163 @@ +import pydantic +import openshift_client as oc +from openshift_client import OpenShiftPythonException, Context +import dataclasses +import traceback + +from keep.contextmanager.contextmanager import ContextManager +from keep.providers.base.base_provider import BaseProvider +from keep.providers.models.provider_config import ProviderConfig, ProviderScope + + +@pydantic.dataclasses.dataclass +class OpenshiftProviderAuthConfig: + """Openshift authentication configuration.""" + + api_server: str = dataclasses.field( + default=None, + metadata={ + "name": "api_server", + "description": "The openshift api server url", + "required": True, + "sensitive": False, + }, + ) + token: str = dataclasses.field( + default=None, + metadata={ + "name": "token", + "description": "The openshift token", + "required": True, + "sensitive": True, + }, + ) + insecure: bool = dataclasses.field( + default=False, + metadata={ + "name": "insecure", + "description": "Whether to skip tls verification", + "required": False, + "sensitive": False, + }, + ) + + +class OpenshiftProvider(BaseProvider): + """Perform rollout restart actions on Openshift.""" + + provider_id: str + PROVIDER_DISPLAY_NAME = "Openshift" + + PROVIDER_SCOPES = [ + ProviderScope( + name="connect_to_openshift", + description="Check if the provided token can connect to the openshift server", + mandatory=True, + alias="Connect to the openshift", + ) + ] + + def __init__( + self, context_manager, provider_id: str, config: ProviderConfig + ): + super().__init__(context_manager, provider_id, config) + self.authentication_config = None + self.validate_config() + + def dispose(self): + """Dispose the provider.""" + pass + + def validate_config(self): + """ + Validates required configuration for Openshift provider. + """ + + if self.config.authentication is None: + self.config.authentication = {} + self.authentication_config = OpenshiftProviderAuthConfig( + **self.config.authentication + ) + + def __get_ocp_client(self): + """Get the Openshift client.""" + oc_context = Context() + oc_context.api_server = self.authentication_config.api_server + oc_context.token = self.authentication_config.token + oc_context.insecure = self.authentication_config.insecure + return oc_context + + def validate_scopes(self): + """ + Validates that the provided token has the required scopes to use the provider. + """ + try: + client = self.__get_ocp_client() + with oc.timeout(60 * 30), oc.tracking() as t, client: + if oc.get_config_context() is None: + try: + oc.invoke('login') + except OpenShiftPythonException: + traceback.print_exc() + self.logger.error(f'Tracking:\n{t.get_result().as_json(redact_streams=False)}\n\n') + self.logger.error("Error logging into the API server") + raise Exception("Error logging into the API server") + scopes = { + "connect_to_openshift": True, + } + except Exception as e: + self.logger.exception("Error validating scopes") + scopes = { + "connect_to_openshift": str(e), + } + return scopes + + def _notify(self, kind: str, name: str, project_name: str): + """Rollout restart the specified kind.""" + client = self.__get_ocp_client() + client.project_name = project_name + self.logger.info(f"Performing rollout restart for {kind} {name} using openshift provider") + with oc.timeout(60 * 30), oc.tracking() as t, client: + if oc.get_config_context() is None: + self.logger.error(f'Current context not set! Logging into API server: {client.api_server}\n') + try: + oc.invoke('login') + except OpenShiftPythonException: + self.logger.error('error occurred logging into API Server') + traceback.print_exc() + self.logger.error(f'Tracking:\n{t.get_result().as_json(redact_streams=False)}\n\n') + raise Exception("Error logging into the API server") + try: + oc.invoke('rollout', ['restart', kind, name]) + except OpenShiftPythonException: + self.logger.error(f"Error restarting {kind} {name}") + raise Exception(f"Error restarting {kind} {name}") + + self.logger.info(f"Restarted {kind} {name}") + + +if __name__ == "__main__": + # Output debug messages + import logging + + logging.basicConfig(level=logging.DEBUG, handlers=[logging.StreamHandler()]) + + # Load environment variables + import os + + url = os.environ.get("OPENSHIFT_URL") + token = os.environ.get("OPENSHIFT_TOKEN") + context_manager = ContextManager( + tenant_id="singletenant", + workflow_id="test", + ) + config = ProviderConfig( + authentication={ + "api_server": url, + "token": token, + } + ) + openshift_provider = OpenshiftProvider(context_manager, "openshift-keephq", config) + + restart = openshift_provider.notify("deployment", "nginx") + print(restart)