forked from keephq/keep
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into feat-add-last-updated-timestamp-to-mappings
- Loading branch information
Showing
13 changed files
with
549 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
--- | ||
title: "Kubernetes" | ||
description: "Kubernetes provider to perform rollout restart or list pods action." | ||
--- | ||
|
||
## Inputs | ||
|
||
- **action** (required): Determines the which action to perform (`rollout_restart`, `list_pods`). | ||
- **kind** (required): Kind of the object to perform rollout restart action. | ||
- **object_name** (required): Name of the object to perform rollout restart action. | ||
- **namespace** (required): Namespace of the object to perform rollout restart or list pods action. | ||
- **labels** (optional): Labels to filter the pods while performing list pods action and also filters before performing rollout restart. | ||
|
||
## 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 Kubernetes cluster. | ||
- **token** (required): The token of your service account to authenticate with Kubernetes. | ||
- **insecure** (optional): If you want to skip the certificate verification, set this to `True` (default: True). | ||
|
||
## Connecting with the Provider | ||
|
||
To connect to Kubernetes, follow below steps: | ||
|
||
1. Create a service account on Kubernetes. | ||
2. Create role/clusterrole and bind to service account using rolebinding/clusterrolebinding. | ||
3. Get the token of service account. | ||
|
||
## Notes | ||
|
||
- This provider allows you to interact with Kubernetes to perform rollout restart or pods listing actions. | ||
|
||
## Useful Links | ||
|
||
- [Access Kubernetes Cluster](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
203 changes: 203 additions & 0 deletions
203
keep/providers/kubernetes_provider/kubernetes_provider.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
import pydantic | ||
import dataclasses | ||
|
||
from kubernetes import client | ||
from kubernetes.client.rest import ApiException | ||
import datetime | ||
|
||
from keep.contextmanager.contextmanager import ContextManager | ||
from keep.providers.base.base_provider import BaseProvider | ||
from keep.providers.models.provider_config import ProviderScope, ProviderConfig | ||
|
||
|
||
@pydantic.dataclasses.dataclass | ||
class KubernetesProviderAuthConfig: | ||
"""Kubernetes authentication configuration.""" | ||
|
||
api_server: str = dataclasses.field( | ||
default=None, | ||
metadata={ | ||
"name": "api_server", | ||
"description": "The kubernetes api server url", | ||
"required": True, | ||
"sensitive": False, | ||
}, | ||
) | ||
token: str = dataclasses.field( | ||
default=None, | ||
metadata={ | ||
"name": "token", | ||
"description": "Bearer token to access kubernetes", | ||
"required": True, | ||
"sensitive": True, | ||
}, | ||
) | ||
insecure: bool = dataclasses.field( | ||
default=True, | ||
metadata={ | ||
"name": "insecure", | ||
"description": "Whether to skip tls verification (default: True)", | ||
"required": False, | ||
"sensitive": False, | ||
}, | ||
) | ||
|
||
|
||
class KubernetesProvider(BaseProvider): | ||
"""Perform actions like rollout restart objects or list pods on Kubernetes.""" | ||
|
||
provider_id: str | ||
PROVIDER_DISPLAY_NAME = "Kubernetes" | ||
|
||
PROVIDER_SCOPES = [ | ||
ProviderScope( | ||
name="connect_to_kubernetes", | ||
description="Check if the provided token can connect to the kubernetes server", | ||
mandatory=True, | ||
alias="Connect to the kubernetes", | ||
) | ||
] | ||
|
||
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): | ||
""" | ||
Validate the required configuration for the Kubernetes provider. | ||
""" | ||
if self.config.authentication is None: | ||
self.config.authentication = {} | ||
self.authentication_config = KubernetesProviderAuthConfig(**self.config.authentication) | ||
|
||
def __create_k8s_client(self): | ||
""" | ||
Create a Kubernetes client. | ||
""" | ||
client_configuration = client.Configuration() | ||
|
||
client_configuration.host = self.authentication_config.api_server | ||
client_configuration.verify_ssl = not self.authentication_config.insecure | ||
client_configuration.api_key = {"authorization": "Bearer " + self.authentication_config.token} | ||
|
||
return client.ApiClient(client_configuration) | ||
|
||
def validate_scopes(self): | ||
""" | ||
Validate that the provided token has the required scopes to use the provider. | ||
""" | ||
self.logger.info("Validating scopes for Kubernetes provider") | ||
try: | ||
self.__create_k8s_client() | ||
self.logger.info("Successfully connected to the Kubernetes server") | ||
scopes = { | ||
"connect_to_kubernetes": True, | ||
} | ||
except Exception as e: | ||
self.logger.error(f"Failed to connect to the Kubernetes server: {str(e)}") | ||
scopes = { | ||
"connect_to_kubernetes": str(e), | ||
} | ||
|
||
return scopes | ||
|
||
def _notify(self, action: str, kind: str, object_name: str, namespace: str, labels: str, **kwargs): | ||
if labels is None: | ||
labels = [] | ||
if action == "rollout_restart": | ||
self.__rollout_restart(kind=kind, name=object_name, namespace=namespace, labels=labels) | ||
elif action == "list_pods": | ||
self.__list_pods(namespace=namespace, labels=labels) | ||
else: | ||
raise NotImplementedError(f"Action {action} is not implemented") | ||
|
||
def __rollout_restart(self, kind, name, namespace, labels): | ||
api_client = self.__create_k8s_client() | ||
self.logger.info(f"Performing rollout restart for {kind} {name} using kubernetes provider") | ||
now = datetime.datetime.now(datetime.timezone.utc) | ||
now = str(now.isoformat("T") + "Z") | ||
body = { | ||
'spec': { | ||
'template': { | ||
'metadata': { | ||
'annotations': { | ||
'kubectl.kubernetes.io/restartedAt': now | ||
} | ||
} | ||
} | ||
} | ||
} | ||
apps_v1 = client.AppsV1Api(api_client) | ||
try: | ||
if kind == "deployment": | ||
deployment_list = apps_v1.list_namespaced_deployment(namespace=namespace, label_selector=labels) | ||
if not deployment_list.items: | ||
raise ValueError(f"Deployment with labels {labels} not found in namespace {namespace}") | ||
apps_v1.patch_namespaced_deployment(name=name, namespace=namespace, body=body) | ||
elif kind == "statefulset": | ||
statefulset_list = apps_v1.list_namespaced_stateful_set(namespace=namespace, label_selector=labels) | ||
if not statefulset_list.items: | ||
raise ValueError(f"StatefulSet with labels {labels} not found in namespace {namespace}") | ||
apps_v1.patch_namespaced_stateful_set(name=name, namespace=namespace, body=body) | ||
elif kind == "daemonset": | ||
daemonset_list = apps_v1.list_namespaced_daemon_set(namespace=namespace, label_selector=labels) | ||
if not daemonset_list.items: | ||
raise ValueError(f"DaemonSet with labels {labels} not found in namespace {namespace}") | ||
apps_v1.patch_namespaced_daemon_set(name=name, namespace=namespace, body=body) | ||
else: | ||
raise ValueError(f"Unsupported kind {kind} to perform rollout restart") | ||
except ApiException as e: | ||
self.logger.error(f"Error performing rollout restart for {kind} {name}: {e}") | ||
raise Exception(f"Error performing rollout restart for {kind} {name}: {e}") | ||
|
||
self.logger.info(f"Successfully performed rollout restart for {kind} {name}") | ||
|
||
def __list_pods(self, namespace, labels): | ||
api_client = self.__create_k8s_client() | ||
core_v1 = client.CoreV1Api(api_client) | ||
if namespace is None: | ||
namespace = "default" | ||
self.logger.info(f"Listing pods in namespace {namespace} with labels {labels}") | ||
try: | ||
core_v1.list_namespaced_pod(namespace=namespace, label_selector=labels) | ||
except ApiException as e: | ||
self.logger.error(f"Error listing pods in namespace {namespace} with labels {labels}: {e}") | ||
raise Exception(f"Error listing pods in namespace {namespace} with labels {labels}: {e}") | ||
|
||
self.logger.info(f"Successfully listed pods in namespace {namespace} with labels {labels}") | ||
|
||
|
||
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("KUBERNETES_URL") | ||
token = os.environ.get("KUBERNETES_TOKEN") | ||
insecure = os.environ.get("KUBERNETES_INSECURE", "false").lower() == "true" | ||
context_manager = ContextManager( | ||
tenant_id="singletenant", | ||
workflow_id="test", | ||
) | ||
config = ProviderConfig( | ||
authentication={ | ||
"api_server": url, | ||
"token": token, | ||
"insecure": insecure, | ||
}, | ||
) | ||
|
||
kubernetes_provider = KubernetesProvider(context_manager, "kubernetes_keephq", config) | ||
|
||
result = kubernetes_provider.notify("rollout_restart", "deployment", "nginx", "default", {"app": "nginx"}) | ||
print(result) |
Empty file.
Oops, something went wrong.