diff --git a/incubating/argocd-app-status/Dockerfile b/incubating/argocd-app-status/Dockerfile new file mode 100644 index 000000000..a1b36553c --- /dev/null +++ b/incubating/argocd-app-status/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.11.2-slim-buster +WORKDIR /app +COPY requirements.txt requirements.txt +RUN pip3 install -r requirements.txt +COPY queries queries/ +COPY argocd_app_status.py argocd_app_status.py +CMD [ "python3", "argocd_app_status.py"] diff --git a/incubating/argocd-app-status/argocd_app_status.py b/incubating/argocd-app-status/argocd_app_status.py new file mode 100644 index 000000000..7ea2c06fc --- /dev/null +++ b/incubating/argocd-app-status/argocd_app_status.py @@ -0,0 +1,100 @@ +from gql import Client, gql +from gql.transport.requests import RequestsHTTPTransport +import os +import logging + +RUNTIME = os.getenv('RUNTIME') +APPLICATION = os.getenv('APPLICATION') + +CF_URL = os.getenv('CF_URL', 'https://g.codefresh.io') +CF_API_KEY = os.getenv('CF_API_KEY') +CF_STEP_NAME= os.getenv('CF_STEP_NAME', 'STEP_NAME') +LOG_LEVEL = os.getenv('LOG_LEVEL', "info") + +####################################################################### + + +def main(): + log_format = "%(asctime)s:%(levelname)s:%(name)s.%(funcName)s: %(message)s" + logging.basicConfig(format = log_format, level = LOG_LEVEL.upper()) + + get_app_status() + + ## Generating link to the Apps Dashboard + CF_OUTPUT_URL_VAR = CF_STEP_NAME + '_CF_OUTPUT_URL' + link_to_app = get_link_to_apps_dashboard() + export_variable(CF_OUTPUT_URL_VAR, link_to_app) + + +####################################################################### + +def get_query(query_name): + ## To do: get query content from a variable, failback to a file + with open('queries/'+query_name+'.graphql', 'r') as file: + query_content = file.read() + return gql(query_content) + +def get_runtime(): + transport = RequestsHTTPTransport( + url = CF_URL + '/2.0/api/graphql', + headers={'authorization': CF_API_KEY}, + verify=True, + retries=3, + ) + client = Client(transport=transport, fetch_schema_from_transport=False) + query = get_query('getRuntime') ## gets gql query + variables = { + "runtime": RUNTIME + } + runtime = client.execute(query, variable_values=variables) + return runtime + +def get_runtime_ns(): + runtime = get_runtime() + runtime_ns = runtime['runtime']['metadata']['namespace'] + logging.debug("Runtime Namespace: %", runtime_ns) + return runtime_ns + +def get_link_to_apps_dashboard(): + runtime_ns= get_runtime_ns() + url_to_app = CF_URL+'/2.0/applications-dashboard/'+RUNTIME+'/'+runtime_ns+'/'+APPLICATION+'/timeline' + return url_to_app + +def get_app_status(): + gql_api_endpoint = CF_URL + '/2.0/api/graphql' + transport = RequestsHTTPTransport( + url=gql_api_endpoint, + headers={'authorization': CF_API_KEY}, + verify=True, + retries=3, + ) + client = Client(transport=transport, fetch_schema_from_transport=False) + query = get_query('get_app_status') ## gets gql query + variables = { + "runtime": RUNTIME, + "name": APPLICATION, + "namespace": get_runtime_ns() + } + result = client.execute(query, variable_values=variables) + + health = result['application']['healthStatus'] + sync = result['application']['syncStatus'] + export_variable('HEALTH_STATUS', health) + export_variable('SYNC_STATUS', sync) + + +def export_variable(var_name, var_value): + path = os.getenv('CF_VOLUME_PATH') if os.getenv('CF_VOLUME_PATH') != None else './' + with open(path+'/env_vars_to_export', 'a') as a_writer: + a_writer.write(var_name + "=" + var_value+'\n') + + if os.getenv('CF_VOLUME_PATH') == None: os.mkdir('/meta') + with open('/meta/env_vars_to_export', 'a') as a_writer: + a_writer.write(var_name + "=" + var_value+'\n') + + logging.info("Exporting variable: %s=%s", var_name, var_value) + +############################################################## + +if __name__ == "__main__": + main() diff --git a/incubating/argocd-app-status/env_vars_to_export b/incubating/argocd-app-status/env_vars_to_export new file mode 100644 index 000000000..eb68d6b2a --- /dev/null +++ b/incubating/argocd-app-status/env_vars_to_export @@ -0,0 +1,6 @@ +HEALTH_STATUS=HEALTHY +SYNC_STATUS=SYNCED +STEP_NAME_CF_OUTPUT_URL=https://g.codefresh.io/2.0/applications-dashboard/csdp/csdp/color-dev/timeline +HEALTH_STATUS=HEALTHY +SYNC_STATUS=SYNCED +STEP_NAME_CF_OUTPUT_URL=https://g.codefresh.io/2.0/applications-dashboard/csdp/csdp/color-dev/timeline diff --git a/incubating/argocd-app-status/queries/getRuntime.graphql b/incubating/argocd-app-status/queries/getRuntime.graphql new file mode 100644 index 000000000..b2929e44b --- /dev/null +++ b/incubating/argocd-app-status/queries/getRuntime.graphql @@ -0,0 +1,10 @@ +query getRuntime( + $runtime: String!) { + runtime(name: $runtime) { + metadata { + name + namespace + } + ingressHost + } +} \ No newline at end of file diff --git a/incubating/argocd-app-status/queries/get_app_status.graphql b/incubating/argocd-app-status/queries/get_app_status.graphql new file mode 100644 index 000000000..348fb3419 --- /dev/null +++ b/incubating/argocd-app-status/queries/get_app_status.graphql @@ -0,0 +1,161 @@ +fragment ApplicationShortOperationStateFragment on ApplicationOperationState { + message + phase + type + syncResult { + revision + source { + repoURL + targetRevision + path + chart + __typename + } + resources { + status + hookPhase + __typename + } + __typename + } + __typename +} + +query ApplicationsStatusesQuery( + $runtime: String! + $name: String! + $namespace: String +) { + application(runtime: $runtime, name: $name, namespace: $namespace) { + metadata { + runtime + name + runtime + namespace + created + uid + labels { + key + value + __typename + } + cluster + __typename + } + healthStatus + syncStatus + syncPolicy + isHelmApp + repoURL + revision + updatedAt + size + desiredManifest + appsRelations { + referencedBy { + kind + __typename + } + __typename + } + specSource { + repoURL + targetRevision + path + chart + __typename + } + destination { + name + server + namespace + __typename + } + status { + minHistoryId + __typename + } + source { + gitManifest + path + revision + gitSource { + metadata { + name + __typename + } + self { + repoURL + revision + path + __typename + } + permissions { + read + write + user { + id + __typename + } + __typename + } + __typename + } + __typename + } + errors { + __typename + object { + metadata { + kind + name + namespace + runtime + group + version + __typename + } + __typename + } + level + title + message + lastSeen + ... on SyncError { + code + context { + repoURL + revision + path + fileUrl + commitAuthor + commitUrl + commitMessage + commitDate + __typename + } + __typename + } + } + operationState { + ...ApplicationShortOperationStateFragment + __typename + } + sync { + status + revision + comparedTo { + source { + repoURL + targetRevision + path + chart + __typename + } + __typename + } + __typename + } + __typename + } +} diff --git a/incubating/argocd-app-status/requirements.txt b/incubating/argocd-app-status/requirements.txt new file mode 100644 index 000000000..0a3c3e93c --- /dev/null +++ b/incubating/argocd-app-status/requirements.txt @@ -0,0 +1,6 @@ +gql==3.4.0 +graphql-core==3.2.3 +requests==2.28.2 +requests-toolbelt==0.10.1 +urllib3==1.26.15 +multidict==6.0.4 diff --git a/incubating/argocd-app-status/step.yaml b/incubating/argocd-app-status/step.yaml new file mode 100644 index 000000000..0def776af --- /dev/null +++ b/incubating/argocd-app-status/step.yaml @@ -0,0 +1,76 @@ +kind: step-type +metadata: + name: argocd-app-status + version: 1.0.1 + isPublic: true + description: Get Argo CD App status and return SYNC_STATUS and HEALTH_STATUS + sources: + - 'https://github.com/codefresh-io/steps/tree/master/incubating/argocd-app-status' + stage: incubating + maintainers: + - name: Laurent Rochette + - email: laurent.rochette@codefresh.io + categories: + - GitOps + official: true + tags: [] + icon: + type: svg + url: https://cdn.jsdelivr.net/gh/codefresh-io/steps/graduated/argocd-sync/argo.svg + background: "#f4f4f4" + examples: + - description: Get Argo CD app status + workflow: + argocd_app_status: + title: Get Argo CD app status + type: argocd-app-status + arguments: + RUNTIME: my-runtime + APPLICATION: my-app + +spec: + arguments: |- + { + "definitions": {}, + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": true, + "patterns": [], + "required": [ + "RUNTIME", + "APPLICATION" + ], + "properties": { + "RUNTIME": { + "type": "string", + "description": "The name of the GitOps Runtime managing the Argo CD Application" + }, + "APPLICATION": { + "type": "string", + "description": "The name of the Argo CD Application to be checked" + }, + "IMAGE_NAME": { + "type": "string", + "default": "quay.io/codefreshplugins/argocd-app-status", + "description": "OPTIONAL - To overwrite the image name to use" + }, + "IMAGE_TAG": { + "type": "string", + "default": "1.0.1", + "description": "OPTIONAL - To overwrite the tag to use" + } + } + } + stepsTemplate: |- + argocd_app_status: + image: '[[.Arguments.IMAGE_NAME]]:[[.Arguments.IMAGE_TAG]]' + environment: + [[ range $key, $val := .Arguments ]] + - '[[ $key ]]=[[ $val ]]' + [[- end ]] + commands: + - cd /app + - python3 argocd_app_status.py + delimiters: + left: '[[' + right: ']]'