From 4343387adc8e0a5b262ef53a1231cb641e129459 Mon Sep 17 00:00:00 2001 From: Adil Hafeez Date: Tue, 3 Dec 2024 19:22:31 -0800 Subject: [PATCH 1/5] Add demo for acm --- arch/arch_config_schema.yaml | 7 + crates/common/src/configuration.rs | 23 +- crates/common/src/lib.rs | 1 + crates/common/src/path.rs | 82 ++ crates/prompt_gateway/src/stream_context.rs | 32 +- demos/acm_k8s/README.md | 2 + demos/acm_k8s/acm_api.yaml | 117 ++ demos/acm_k8s/acm_service/.dockerignore | 72 + demos/acm_k8s/acm_service/.gitignore | 66 + .../acm_service/.openapi-generator-ignore | 23 + .../acm_service/.openapi-generator/FILES | 26 + .../acm_service/.openapi-generator/VERSION | 1 + demos/acm_k8s/acm_service/.travis.yml | 14 + demos/acm_k8s/acm_service/Dockerfile | 16 + demos/acm_k8s/acm_service/README.md | 49 + demos/acm_k8s/acm_service/git_push.sh | 57 + .../acm_service/openapi_server/__init__.py | 0 .../acm_service/openapi_server/__main__.py | 23 + .../openapi_server/controllers/__init__.py | 0 .../openapi_server/controllers/controller.py | 84 ++ .../controllers/default_controller.py | 88 ++ .../controllers/security_controller.py | 1 + .../acm_service/openapi_server/encoder.py | 19 + .../openapi_server/models/__init__.py | 8 + .../openapi_server/models/base_model.py | 70 + .../openapi_server/models/managed_cluster.py | 186 +++ .../models/managed_cluster_client_config.py | 81 ++ .../openapi_server/models/metadata.py | 81 ++ .../acm_service/openapi_server/models/spec.py | 98 ++ .../openapi_server/openapi/openapi.yaml | 162 +++ .../openapi_server/test/__init__.py | 15 + .../test/test_default_controller.py | 89 ++ .../openapi_server/typing_utils.py | 30 + .../acm_service/openapi_server/util.py | 149 ++ demos/acm_k8s/acm_service/requirements.txt | 13 + demos/acm_k8s/acm_service/setup.py | 34 + .../acm_k8s/acm_service/test-requirements.txt | 4 + demos/acm_k8s/acm_service/tox.ini | 11 + demos/acm_k8s/arch_config.yaml | 67 + demos/acm_k8s/docker-compose.yaml | 31 + demos/acm_k8s/generate_acm_service_stub.sh | 6 + demos/acm_k8s/petstore.yml | 1206 +++++++++++++++++ demos/acm_k8s/run_demo.sh | 47 + model_server/app/main.py | 6 + 44 files changed, 3194 insertions(+), 3 deletions(-) create mode 100644 crates/common/src/path.rs create mode 100644 demos/acm_k8s/README.md create mode 100644 demos/acm_k8s/acm_api.yaml create mode 100644 demos/acm_k8s/acm_service/.dockerignore create mode 100644 demos/acm_k8s/acm_service/.gitignore create mode 100644 demos/acm_k8s/acm_service/.openapi-generator-ignore create mode 100644 demos/acm_k8s/acm_service/.openapi-generator/FILES create mode 100644 demos/acm_k8s/acm_service/.openapi-generator/VERSION create mode 100644 demos/acm_k8s/acm_service/.travis.yml create mode 100644 demos/acm_k8s/acm_service/Dockerfile create mode 100644 demos/acm_k8s/acm_service/README.md create mode 100644 demos/acm_k8s/acm_service/git_push.sh create mode 100644 demos/acm_k8s/acm_service/openapi_server/__init__.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/__main__.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/controllers/__init__.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/controllers/controller.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/controllers/default_controller.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/controllers/security_controller.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/encoder.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/models/__init__.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/models/base_model.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/models/managed_cluster.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/models/managed_cluster_client_config.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/models/metadata.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/models/spec.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml create mode 100644 demos/acm_k8s/acm_service/openapi_server/test/__init__.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/test/test_default_controller.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/typing_utils.py create mode 100644 demos/acm_k8s/acm_service/openapi_server/util.py create mode 100644 demos/acm_k8s/acm_service/requirements.txt create mode 100644 demos/acm_k8s/acm_service/setup.py create mode 100644 demos/acm_k8s/acm_service/test-requirements.txt create mode 100644 demos/acm_k8s/acm_service/tox.ini create mode 100644 demos/acm_k8s/arch_config.yaml create mode 100644 demos/acm_k8s/docker-compose.yaml create mode 100644 demos/acm_k8s/generate_acm_service_stub.sh create mode 100644 demos/acm_k8s/petstore.yml create mode 100644 demos/acm_k8s/run_demo.sh diff --git a/arch/arch_config_schema.yaml b/arch/arch_config_schema.yaml index a11e9562..0f7e55ac 100644 --- a/arch/arch_config_schema.yaml +++ b/arch/arch_config_schema.yaml @@ -92,6 +92,8 @@ properties: type: array items: type: string + in_path: + type: boolean additionalProperties: false required: - name @@ -108,6 +110,11 @@ properties: required: - name - path + http_method: + type: string + enum: + - GET + - POST system_prompt: type: string additionalProperties: false diff --git a/crates/common/src/configuration.rs b/crates/common/src/configuration.rs index 543849c9..7486e3d9 100644 --- a/crates/common/src/configuration.rs +++ b/crates/common/src/configuration.rs @@ -179,8 +179,6 @@ impl Display for LlmProvider { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Endpoint { pub endpoint: Option, - // pub connect_timeout: Option, - // pub timeout: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -193,6 +191,7 @@ pub struct Parameter { #[serde(rename = "enum")] pub enum_values: Option>, pub default: Option, + pub in_path: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -201,11 +200,31 @@ pub struct EndpointDetails { pub path: Option, } +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Default)] +pub enum HttpMethod { + #[serde(rename = "GET")] + Get, + #[default] + #[serde(rename = "POST")] + Post, +} + +impl Display for HttpMethod { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + HttpMethod::Get => write!(f, "GET"), + HttpMethod::Post => write!(f, "POST"), + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PromptTarget { pub name: String, pub default: Option, pub description: String, + #[serde(rename = "http_method")] + pub method: Option, pub endpoint: Option, pub parameters: Option>, pub system_prompt: Option, diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index a41badf9..aa34f2fd 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -11,3 +11,4 @@ pub mod routing; pub mod stats; pub mod tokenizer; pub mod tracing; +pub mod path; diff --git a/crates/common/src/path.rs b/crates/common/src/path.rs new file mode 100644 index 00000000..2b289c9d --- /dev/null +++ b/crates/common/src/path.rs @@ -0,0 +1,82 @@ +use std::collections::HashMap; + +pub fn replace_params_in_path(path: &str, params: &HashMap) -> Result { + let mut result = String::new(); + let mut in_param = false; + let mut current_param = String::new(); + + for c in path.chars() { + if c == '{' { + in_param = true; + } else if c == '}' { + in_param = false; + let param_name = current_param.clone(); + if let Some(value) = params.get(¶m_name) { + result.push_str(value); + } else { + return Err(format!("Missing value for parameter `{}`", param_name)); + } + current_param.clear(); + } else { + if in_param { + current_param.push(c); + } else { + result.push(c); + } + } + } + + Ok(result) +} + +#[cfg(test)] +mod test { + #[test] + fn test_replace_path() { + let path = "/cluster.open-cluster-management.io/v1/managedclusters/{cluster_name}"; + let params = vec![("cluster_name".to_string(), "test1".to_string())] + .into_iter() + .collect(); + assert_eq!( + super::replace_params_in_path(path, ¶ms), + Ok("/cluster.open-cluster-management.io/v1/managedclusters/test1".to_string()) + ); + + let path = "/cluster.open-cluster-management.io/v1/managedclusters"; + let params = vec![].into_iter().collect(); + assert_eq!( + super::replace_params_in_path(path, ¶ms), + Ok("/cluster.open-cluster-management.io/v1/managedclusters".to_string()) + ); + + let path = "/foo/{bar}/baz"; + let params = vec![("bar".to_string(), "qux".to_string())] + .into_iter() + .collect(); + assert_eq!( + super::replace_params_in_path(path, ¶ms), + Ok("/foo/qux/baz".to_string()) + ); + + let path = "/foo/{bar}/baz/{qux}"; + let params = vec![ + ("bar".to_string(), "qux".to_string()), + ("qux".to_string(), "quux".to_string()), + ] + .into_iter() + .collect(); + assert_eq!( + super::replace_params_in_path(path, ¶ms), + Ok("/foo/qux/baz/quux".to_string()) + ); + + let path = "/foo/{bar}/baz/{qux}"; + let params = vec![("bar".to_string(), "qux".to_string())] + .into_iter() + .collect(); + assert_eq!( + super::replace_params_in_path(path, ¶ms), + Err("Missing value for parameter `qux`".to_string()) + ); + } +} diff --git a/crates/prompt_gateway/src/stream_context.rs b/crates/prompt_gateway/src/stream_context.rs index 6df5a4d1..1a4b6cba 100644 --- a/crates/prompt_gateway/src/stream_context.rs +++ b/crates/prompt_gateway/src/stream_context.rs @@ -29,6 +29,7 @@ use derivative::Derivative; use http::StatusCode; use log::{debug, info, trace, warn}; use proxy_wasm::traits::*; +use serde_yaml::Value; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; @@ -892,9 +893,38 @@ impl StreamContext { let endpoint = prompt_target.endpoint.unwrap(); let path: String = endpoint.path.unwrap_or(String::from("/")); + // only add params that are of string and number type + let url_params = tool_params + .iter() + .filter(|(_, value)| value.is_number() || value.is_string() || value.is_bool()) + .map(|(key, value)| match value { + Value::Number(n) => (key.clone(), n.to_string()), + Value::String(s) => (key.clone(), s.clone()), + Value::Bool(b) => (key.clone(), b.to_string()), + Value::Null => todo!(), + Value::Sequence(_) => todo!(), + Value::Mapping(_) => todo!(), + Value::Tagged(_) => todo!(), + }) + .collect::>(); + + let path = match common::path::replace_params_in_path(&path, &url_params) { + Ok(path) => path, + Err(e) => { + return self.send_server_error( + ServerError::BadRequest { + why: format!("error replacing params in path: {}", e), + }, + Some(StatusCode::BAD_REQUEST), + ); + } + }; + + let http_method = prompt_target.method.unwrap_or_default().to_string(); + info!("http_method: {}", http_method); let mut headers = vec![ (ARCH_UPSTREAM_HOST_HEADER, endpoint.name.as_str()), - (":method", "POST"), + (":method", &http_method), (":path", &path), (":authority", endpoint.name.as_str()), ("content-type", "application/json"), diff --git a/demos/acm_k8s/README.md b/demos/acm_k8s/README.md new file mode 100644 index 00000000..91fff783 --- /dev/null +++ b/demos/acm_k8s/README.md @@ -0,0 +1,2 @@ +# Function calling +This demo shows arch gateway interacting with ACM rest APIs. diff --git a/demos/acm_k8s/acm_api.yaml b/demos/acm_k8s/acm_api.yaml new file mode 100644 index 00000000..4b4ec9fd --- /dev/null +++ b/demos/acm_k8s/acm_api.yaml @@ -0,0 +1,117 @@ +openapi: 3.0.0 +info: + version: 2.12.0 + title: ACM API for cluster management + description: This is the API for managing clusters using ACM - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags + contact: + name: Katanemo Labs Inc. + email: support@katanemo.com + url: https://katanemo.com +paths: + /cluster.open-cluster-management.io/v1/managedclusters: + get: + summary: Query your clusters for more details. + operationId: listManagedClusters + responses: + "200": + description: List of managed clusters + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ManagedCluster" + post: + summary: Create a cluster + operationId: createCluster + requestBody: + description: Details about the service, including the text-representation of the service APIs. + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ManagedCluster" + responses: + "200": + description: cluster created successfully + content: + application/json: + schema: + $ref: "#/components/schemas/ManagedCluster" + + /cluster.open-cluster-management.io/v1/managedclusters/{cluster_name}: + get: + summary: Query a single cluster for more details + operationId: getCluster + parameters: + - name: cluster_name + in: path + description: The name of the cluster to retrieve + required: true + schema: + type: string + responses: + "200": + description: Cluster details + content: + application/json: + schema: + $ref: "#/components/schemas/ManagedCluster" + delete: + summary: Delete a single cluster + responses: + "200": + description: Cluster details + content: + application/json: + schema: + $ref: "#/components/schemas/ManagedCluster" + +components: + schemas: + ManagedCluster: + title: managed cluster details + type: object + properties: + apiVersion: + type: string + enum: + - cluster.open-cluster-management.io/v1 + kind: + type: string + enum: + - ManagedCluster + metadata: + $ref: "#/components/schemas/Metadata" + spec: + $ref: "#/components/schemas/Spec" + status: + type: string + Metadata: + title: metadata details + type: object + properties: + name: + type: string + labels: + type: object + additionalProperties: + type: string + Spec: + title: spec details + type: object + properties: + hubAcceptsClient: + type: boolean + managedClusterClientConfigs: + type: array + items: + $ref: "#/components/schemas/ManagedClusterClientConfig" + ManagedClusterClientConfig: + title: managed cluster client config details + type: object + properties: + url: + type: string + caBundle: + type: string diff --git a/demos/acm_k8s/acm_service/.dockerignore b/demos/acm_k8s/acm_service/.dockerignore new file mode 100644 index 00000000..f9619601 --- /dev/null +++ b/demos/acm_k8s/acm_service/.dockerignore @@ -0,0 +1,72 @@ +.travis.yaml +.openapi-generator-ignore +README.md +tox.ini +git_push.sh +test-requirements.txt +setup.py + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ +venv/ +.python-version + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +#Ipython Notebook +.ipynb_checkpoints diff --git a/demos/acm_k8s/acm_service/.gitignore b/demos/acm_k8s/acm_service/.gitignore new file mode 100644 index 00000000..43995bd4 --- /dev/null +++ b/demos/acm_k8s/acm_service/.gitignore @@ -0,0 +1,66 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ +venv/ +.venv/ +.python-version +.pytest_cache + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +#Ipython Notebook +.ipynb_checkpoints diff --git a/demos/acm_k8s/acm_service/.openapi-generator-ignore b/demos/acm_k8s/acm_service/.openapi-generator-ignore new file mode 100644 index 00000000..7484ee59 --- /dev/null +++ b/demos/acm_k8s/acm_service/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/demos/acm_k8s/acm_service/.openapi-generator/FILES b/demos/acm_k8s/acm_service/.openapi-generator/FILES new file mode 100644 index 00000000..5387d276 --- /dev/null +++ b/demos/acm_k8s/acm_service/.openapi-generator/FILES @@ -0,0 +1,26 @@ +.dockerignore +.gitignore +.travis.yml +Dockerfile +README.md +git_push.sh +openapi_server/__init__.py +openapi_server/__main__.py +openapi_server/controllers/__init__.py +openapi_server/controllers/default_controller.py +openapi_server/controllers/security_controller.py +openapi_server/encoder.py +openapi_server/models/__init__.py +openapi_server/models/base_model.py +openapi_server/models/managed_cluster.py +openapi_server/models/managed_cluster_client_config.py +openapi_server/models/metadata.py +openapi_server/models/spec.py +openapi_server/openapi/openapi.yaml +openapi_server/test/__init__.py +openapi_server/typing_utils.py +openapi_server/util.py +requirements.txt +setup.py +test-requirements.txt +tox.ini diff --git a/demos/acm_k8s/acm_service/.openapi-generator/VERSION b/demos/acm_k8s/acm_service/.openapi-generator/VERSION new file mode 100644 index 00000000..88411912 --- /dev/null +++ b/demos/acm_k8s/acm_service/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.11.0-SNAPSHOT diff --git a/demos/acm_k8s/acm_service/.travis.yml b/demos/acm_k8s/acm_service/.travis.yml new file mode 100644 index 00000000..ad71ee5c --- /dev/null +++ b/demos/acm_k8s/acm_service/.travis.yml @@ -0,0 +1,14 @@ +# ref: https://docs.travis-ci.com/user/languages/python +language: python +python: + - "3.2" + - "3.3" + - "3.4" + - "3.5" + - "3.6" + - "3.7" + - "3.8" +# command to install dependencies +install: "pip install -r requirements.txt" +# command to run tests +script: nosetests diff --git a/demos/acm_k8s/acm_service/Dockerfile b/demos/acm_k8s/acm_service/Dockerfile new file mode 100644 index 00000000..ac9e33ab --- /dev/null +++ b/demos/acm_k8s/acm_service/Dockerfile @@ -0,0 +1,16 @@ +FROM python:3-alpine + +RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app + +COPY requirements.txt /usr/src/app/ + +RUN pip3 install --no-cache-dir -r requirements.txt + +COPY . /usr/src/app + +EXPOSE 8080 + +ENTRYPOINT ["python3"] + +CMD ["-m", "openapi_server"] diff --git a/demos/acm_k8s/acm_service/README.md b/demos/acm_k8s/acm_service/README.md new file mode 100644 index 00000000..9525e3e1 --- /dev/null +++ b/demos/acm_k8s/acm_service/README.md @@ -0,0 +1,49 @@ +# OpenAPI generated server + +## Overview +This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the +[OpenAPI-Spec](https://openapis.org) from a remote server, you can easily generate a server stub. This +is an example of building a OpenAPI-enabled Flask server. + +This example uses the [Connexion](https://github.com/zalando/connexion) library on top of Flask. + +## Requirements +Python 3.5.2+ + +## Usage +To run the server, please execute the following from the root directory: + +``` +pip3 install -r requirements.txt +python3 -m openapi_server +``` + +and open your browser to here: + +``` +http://localhost:8080/ui/ +``` + +Your OpenAPI definition lives here: + +``` +http://localhost:8080/openapi.json +``` + +To launch the integration tests, use tox: +``` +sudo pip install tox +tox +``` + +## Running with Docker + +To run the server on a Docker container, please execute the following from the root directory: + +```bash +# building the image +docker build -t openapi_server . + +# starting up a container +docker run -p 8080:8080 openapi_server +``` diff --git a/demos/acm_k8s/acm_service/git_push.sh b/demos/acm_k8s/acm_service/git_push.sh new file mode 100644 index 00000000..f53a75d4 --- /dev/null +++ b/demos/acm_k8s/acm_service/git_push.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 +git_host=$4 + +if [ "$git_host" = "" ]; then + git_host="github.com" + echo "[INFO] No command line input provided. Set \$git_host to $git_host" +fi + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=$(git remote) +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' diff --git a/demos/acm_k8s/acm_service/openapi_server/__init__.py b/demos/acm_k8s/acm_service/openapi_server/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/demos/acm_k8s/acm_service/openapi_server/__main__.py b/demos/acm_k8s/acm_service/openapi_server/__main__.py new file mode 100644 index 00000000..417a9020 --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/__main__.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +import connexion + +from openapi_server import encoder + + +def main(): + app = connexion.App(__name__, specification_dir="./openapi/") + app.app.json_encoder = encoder.JSONEncoder + app.add_api( + "openapi.yaml", + arguments={ + "title": "ACM API for cluster management - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags" + }, + pythonic_params=True, + ) + + app.run(port=8080) + + +if __name__ == "__main__": + main() diff --git a/demos/acm_k8s/acm_service/openapi_server/controllers/__init__.py b/demos/acm_k8s/acm_service/openapi_server/controllers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/demos/acm_k8s/acm_service/openapi_server/controllers/controller.py b/demos/acm_k8s/acm_service/openapi_server/controllers/controller.py new file mode 100644 index 00000000..5b334a5d --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/controllers/controller.py @@ -0,0 +1,84 @@ +import connexion +from typing import Dict +from typing import Tuple +from typing import Union + +from openapi_server.models.managed_cluster import ManagedCluster # noqa: E501 +from openapi_server.models.metadata import Metadata # noqa: E501 +from openapi_server.models.spec import Spec # noqa: E501 +from openapi_server import util + +managed_cluster = { + "test1": ManagedCluster( + "cluster.open-cluster-management.io/v1", + "ManagedCluster", + Metadata("test1"), + Spec(True, None), + "test1 cluster in service", + ), +} + + +def cluster_open_cluster_management_io_v1_managedclusters_cluster_name_delete(): # noqa: E501 + """Delete a single cluster + + # noqa: E501 + + + :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] + """ + return "do some magic!" + + +def create_cluster( + api_version=None, kind=None, metadata=None, spec=None, status=None +): # noqa: E501 + """Create a cluster + + # noqa: E501 + + :param api_version: + :type api_version: str + :param kind: + :type kind: str + :param metadata: + :type metadata: dict | bytes + :param spec: + :type spec: dict | bytes + :param status: + :type status: str + + :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] + """ + if connexion.request.is_json: + metadata = Metadata.from_dict(connexion.request.get_json()) # noqa: E501 + if connexion.request.is_json: + spec = Spec.from_dict(connexion.request.get_json()) # noqa: E501 + return "do some magic!" + + +def get_cluster(cluster_name): # noqa: E501 + """Query a single cluster for more details + + # noqa: E501 + + :param cluster_name: The name of the cluster to retrieve + :type cluster_name: str + + :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] + """ + if cluster_name in managed_cluster: + return managed_cluster[cluster_name] + else: + return "Cluster not found", 404 + + +def list_managed_clusters(): # noqa: E501 + """Query your clusters for more details. + + # noqa: E501 + + + :rtype: Union[List[ManagedCluster], Tuple[List[ManagedCluster], int], Tuple[List[ManagedCluster], int, Dict[str, str]] + """ + return list(managed_cluster.values()) diff --git a/demos/acm_k8s/acm_service/openapi_server/controllers/default_controller.py b/demos/acm_k8s/acm_service/openapi_server/controllers/default_controller.py new file mode 100644 index 00000000..7984540a --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/controllers/default_controller.py @@ -0,0 +1,88 @@ +import connexion +from typing import Dict +from typing import Tuple +from typing import Union + +from openapi_server.models.managed_cluster import ManagedCluster # noqa: E501 +from openapi_server.models.metadata import Metadata # noqa: E501 +from openapi_server.models.spec import Spec # noqa: E501 +from openapi_server import util + +managed_cluster = { + "test1": ManagedCluster( + "cluster.open-cluster-management.io/v1", + "ManagedCluster", + Metadata("test1"), + Spec(True, None), + "test1 cluster in service", + ), +} + + +def cluster_open_cluster_management_io_v1_managedclusters_cluster_name_delete(): # noqa: E501 + """Delete a single cluster + + # noqa: E501 + + + :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] + """ + return "do some magic!" + + +def create_cluster( + api_version=None, kind=None, metadata=None, spec=None, status=None +): # noqa: E501 + """Create a cluster + + # noqa: E501 + + :param api_version: + :type api_version: str + :param kind: + :type kind: str + :param metadata: + :type metadata: dict | bytes + :param spec: + :type spec: dict | bytes + :param status: + :type status: str + + :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] + """ + if connexion.request.is_json: + request_json = connexion.request.get_json() + if "metadata" in request_json: + metadata = Metadata.from_dict(request_json["metadata"]) # noqa: E501 + if "spec" in request_json: + spec = Spec.from_dict(request_json["spec"]) # noqa: E501 + cluster = ManagedCluster(api_version, kind, metadata, spec, status) + managed_cluster[metadata.name] = cluster + return "cluster created", 200 + + +def get_cluster(cluster_name): # noqa: E501 + """Query a single cluster for more details + + # noqa: E501 + + :param cluster_name: The name of the cluster to retrieve + :type cluster_name: str + + :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] + """ + if cluster_name in managed_cluster: + return managed_cluster[cluster_name] + else: + return "Cluster not found", 404 + + +def list_managed_clusters(): # noqa: E501 + """Query your clusters for more details. + + # noqa: E501 + + + :rtype: Union[List[ManagedCluster], Tuple[List[ManagedCluster], int], Tuple[List[ManagedCluster], int, Dict[str, str]] + """ + return list(managed_cluster.values()) diff --git a/demos/acm_k8s/acm_service/openapi_server/controllers/security_controller.py b/demos/acm_k8s/acm_service/openapi_server/controllers/security_controller.py new file mode 100644 index 00000000..7d686cba --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/controllers/security_controller.py @@ -0,0 +1 @@ +from typing import List diff --git a/demos/acm_k8s/acm_service/openapi_server/encoder.py b/demos/acm_k8s/acm_service/openapi_server/encoder.py new file mode 100644 index 00000000..60f4fa67 --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/encoder.py @@ -0,0 +1,19 @@ +from connexion.apps.flask_app import FlaskJSONEncoder + +from openapi_server.models.base_model import Model + + +class JSONEncoder(FlaskJSONEncoder): + include_nulls = False + + def default(self, o): + if isinstance(o, Model): + dikt = {} + for attr in o.openapi_types: + value = getattr(o, attr) + if value is None and not self.include_nulls: + continue + attr = o.attribute_map[attr] + dikt[attr] = value + return dikt + return FlaskJSONEncoder.default(self, o) diff --git a/demos/acm_k8s/acm_service/openapi_server/models/__init__.py b/demos/acm_k8s/acm_service/openapi_server/models/__init__.py new file mode 100644 index 00000000..a4294dbb --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/models/__init__.py @@ -0,0 +1,8 @@ +# flake8: noqa +# import models into model package +from openapi_server.models.managed_cluster import ManagedCluster +from openapi_server.models.managed_cluster_client_config import ( + ManagedClusterClientConfig, +) +from openapi_server.models.metadata import Metadata +from openapi_server.models.spec import Spec diff --git a/demos/acm_k8s/acm_service/openapi_server/models/base_model.py b/demos/acm_k8s/acm_service/openapi_server/models/base_model.py new file mode 100644 index 00000000..c6144bed --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/models/base_model.py @@ -0,0 +1,70 @@ +import pprint + +import typing + +from openapi_server import util + +T = typing.TypeVar("T") + + +class Model: + # openapiTypes: The key is attribute name and the + # value is attribute type. + openapi_types: typing.Dict[str, type] = {} + + # attributeMap: The key is attribute name and the + # value is json key in definition. + attribute_map: typing.Dict[str, str] = {} + + @classmethod + def from_dict(cls: typing.Type[T], dikt) -> T: + """Returns the dict as a model""" + return util.deserialize_model(dikt, cls) + + def to_dict(self): + """Returns the model properties as a dict + + :rtype: dict + """ + result = {} + + for attr in self.openapi_types: + value = getattr(self, attr) + if isinstance(value, list): + result[attr] = list( + map(lambda x: x.to_dict() if hasattr(x, "to_dict") else x, value) + ) + elif hasattr(value, "to_dict"): + result[attr] = value.to_dict() + elif isinstance(value, dict): + result[attr] = dict( + map( + lambda item: (item[0], item[1].to_dict()) + if hasattr(item[1], "to_dict") + else item, + value.items(), + ) + ) + else: + result[attr] = value + + return result + + def to_str(self): + """Returns the string representation of the model + + :rtype: str + """ + return pprint.pformat(self.to_dict()) + + def __repr__(self): + """For `print` and `pprint`""" + return self.to_str() + + def __eq__(self, other): + """Returns true if both objects are equal""" + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Returns true if both objects are not equal""" + return not self == other diff --git a/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster.py b/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster.py new file mode 100644 index 00000000..be68653d --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster.py @@ -0,0 +1,186 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from openapi_server.models.base_model import Model +from openapi_server.models.metadata import Metadata +from openapi_server.models.spec import Spec +from openapi_server import util + +from openapi_server.models.metadata import Metadata # noqa: E501 +from openapi_server.models.spec import Spec # noqa: E501 + + +class ManagedCluster(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__( + self, api_version=None, kind=None, metadata=None, spec=None, status=None + ): # noqa: E501 + """ManagedCluster - a model defined in OpenAPI + + :param api_version: The api_version of this ManagedCluster. # noqa: E501 + :type api_version: str + :param kind: The kind of this ManagedCluster. # noqa: E501 + :type kind: str + :param metadata: The metadata of this ManagedCluster. # noqa: E501 + :type metadata: Metadata + :param spec: The spec of this ManagedCluster. # noqa: E501 + :type spec: Spec + :param status: The status of this ManagedCluster. # noqa: E501 + :type status: str + """ + self.openapi_types = { + "api_version": str, + "kind": str, + "metadata": Metadata, + "spec": Spec, + "status": str, + } + + self.attribute_map = { + "api_version": "apiVersion", + "kind": "kind", + "metadata": "metadata", + "spec": "spec", + "status": "status", + } + + self._api_version = api_version + self._kind = kind + self._metadata = metadata + self._spec = spec + self._status = status + + @classmethod + def from_dict(cls, dikt) -> "ManagedCluster": + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ManagedCluster of this ManagedCluster. # noqa: E501 + :rtype: ManagedCluster + """ + return util.deserialize_model(dikt, cls) + + @property + def api_version(self) -> str: + """Gets the api_version of this ManagedCluster. + + + :return: The api_version of this ManagedCluster. + :rtype: str + """ + return self._api_version + + @api_version.setter + def api_version(self, api_version: str): + """Sets the api_version of this ManagedCluster. + + + :param api_version: The api_version of this ManagedCluster. + :type api_version: str + """ + allowed_values = ["cluster.open-cluster-management.io/v1"] # noqa: E501 + if api_version not in allowed_values: + raise ValueError( + "Invalid value for `api_version` ({0}), must be one of {1}".format( + api_version, allowed_values + ) + ) + + self._api_version = api_version + + @property + def kind(self) -> str: + """Gets the kind of this ManagedCluster. + + + :return: The kind of this ManagedCluster. + :rtype: str + """ + return self._kind + + @kind.setter + def kind(self, kind: str): + """Sets the kind of this ManagedCluster. + + + :param kind: The kind of this ManagedCluster. + :type kind: str + """ + allowed_values = ["ManagedCluster"] # noqa: E501 + if kind not in allowed_values: + raise ValueError( + "Invalid value for `kind` ({0}), must be one of {1}".format( + kind, allowed_values + ) + ) + + self._kind = kind + + @property + def metadata(self) -> Metadata: + """Gets the metadata of this ManagedCluster. + + + :return: The metadata of this ManagedCluster. + :rtype: Metadata + """ + return self._metadata + + @metadata.setter + def metadata(self, metadata: Metadata): + """Sets the metadata of this ManagedCluster. + + + :param metadata: The metadata of this ManagedCluster. + :type metadata: Metadata + """ + + self._metadata = metadata + + @property + def spec(self) -> Spec: + """Gets the spec of this ManagedCluster. + + + :return: The spec of this ManagedCluster. + :rtype: Spec + """ + return self._spec + + @spec.setter + def spec(self, spec: Spec): + """Sets the spec of this ManagedCluster. + + + :param spec: The spec of this ManagedCluster. + :type spec: Spec + """ + + self._spec = spec + + @property + def status(self) -> str: + """Gets the status of this ManagedCluster. + + + :return: The status of this ManagedCluster. + :rtype: str + """ + return self._status + + @status.setter + def status(self, status: str): + """Sets the status of this ManagedCluster. + + + :param status: The status of this ManagedCluster. + :type status: str + """ + + self._status = status diff --git a/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster_client_config.py b/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster_client_config.py new file mode 100644 index 00000000..bf362e05 --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster_client_config.py @@ -0,0 +1,81 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from openapi_server.models.base_model import Model +from openapi_server import util + + +class ManagedClusterClientConfig(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, url=None, ca_bundle=None): # noqa: E501 + """ManagedClusterClientConfig - a model defined in OpenAPI + + :param url: The url of this ManagedClusterClientConfig. # noqa: E501 + :type url: str + :param ca_bundle: The ca_bundle of this ManagedClusterClientConfig. # noqa: E501 + :type ca_bundle: str + """ + self.openapi_types = {"url": str, "ca_bundle": str} + + self.attribute_map = {"url": "url", "ca_bundle": "caBundle"} + + self._url = url + self._ca_bundle = ca_bundle + + @classmethod + def from_dict(cls, dikt) -> "ManagedClusterClientConfig": + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ManagedClusterClientConfig of this ManagedClusterClientConfig. # noqa: E501 + :rtype: ManagedClusterClientConfig + """ + return util.deserialize_model(dikt, cls) + + @property + def url(self) -> str: + """Gets the url of this ManagedClusterClientConfig. + + + :return: The url of this ManagedClusterClientConfig. + :rtype: str + """ + return self._url + + @url.setter + def url(self, url: str): + """Sets the url of this ManagedClusterClientConfig. + + + :param url: The url of this ManagedClusterClientConfig. + :type url: str + """ + + self._url = url + + @property + def ca_bundle(self) -> str: + """Gets the ca_bundle of this ManagedClusterClientConfig. + + + :return: The ca_bundle of this ManagedClusterClientConfig. + :rtype: str + """ + return self._ca_bundle + + @ca_bundle.setter + def ca_bundle(self, ca_bundle: str): + """Sets the ca_bundle of this ManagedClusterClientConfig. + + + :param ca_bundle: The ca_bundle of this ManagedClusterClientConfig. + :type ca_bundle: str + """ + + self._ca_bundle = ca_bundle diff --git a/demos/acm_k8s/acm_service/openapi_server/models/metadata.py b/demos/acm_k8s/acm_service/openapi_server/models/metadata.py new file mode 100644 index 00000000..a2833d6f --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/models/metadata.py @@ -0,0 +1,81 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from openapi_server.models.base_model import Model +from openapi_server import util + + +class Metadata(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, name=None, labels=None): # noqa: E501 + """Metadata - a model defined in OpenAPI + + :param name: The name of this Metadata. # noqa: E501 + :type name: str + :param labels: The labels of this Metadata. # noqa: E501 + :type labels: Dict[str, str] + """ + self.openapi_types = {"name": str, "labels": Dict[str, str]} + + self.attribute_map = {"name": "name", "labels": "labels"} + + self._name = name + self._labels = labels + + @classmethod + def from_dict(cls, dikt) -> "Metadata": + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The Metadata of this Metadata. # noqa: E501 + :rtype: Metadata + """ + return util.deserialize_model(dikt, cls) + + @property + def name(self) -> str: + """Gets the name of this Metadata. + + + :return: The name of this Metadata. + :rtype: str + """ + return self._name + + @name.setter + def name(self, name: str): + """Sets the name of this Metadata. + + + :param name: The name of this Metadata. + :type name: str + """ + + self._name = name + + @property + def labels(self) -> Dict[str, str]: + """Gets the labels of this Metadata. + + + :return: The labels of this Metadata. + :rtype: Dict[str, str] + """ + return self._labels + + @labels.setter + def labels(self, labels: Dict[str, str]): + """Sets the labels of this Metadata. + + + :param labels: The labels of this Metadata. + :type labels: Dict[str, str] + """ + + self._labels = labels diff --git a/demos/acm_k8s/acm_service/openapi_server/models/spec.py b/demos/acm_k8s/acm_service/openapi_server/models/spec.py new file mode 100644 index 00000000..b319c461 --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/models/spec.py @@ -0,0 +1,98 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from openapi_server.models.base_model import Model +from openapi_server.models.managed_cluster_client_config import ( + ManagedClusterClientConfig, +) +from openapi_server import util + +from openapi_server.models.managed_cluster_client_config import ( + ManagedClusterClientConfig, +) # noqa: E501 + + +class Spec(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__( + self, hub_accepts_client=None, managed_cluster_client_configs=None + ): # noqa: E501 + """Spec - a model defined in OpenAPI + + :param hub_accepts_client: The hub_accepts_client of this Spec. # noqa: E501 + :type hub_accepts_client: bool + :param managed_cluster_client_configs: The managed_cluster_client_configs of this Spec. # noqa: E501 + :type managed_cluster_client_configs: List[ManagedClusterClientConfig] + """ + self.openapi_types = { + "hub_accepts_client": bool, + "managed_cluster_client_configs": List[ManagedClusterClientConfig], + } + + self.attribute_map = { + "hub_accepts_client": "hubAcceptsClient", + "managed_cluster_client_configs": "managedClusterClientConfigs", + } + + self._hub_accepts_client = hub_accepts_client + self._managed_cluster_client_configs = managed_cluster_client_configs + + @classmethod + def from_dict(cls, dikt) -> "Spec": + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The Spec of this Spec. # noqa: E501 + :rtype: Spec + """ + return util.deserialize_model(dikt, cls) + + @property + def hub_accepts_client(self) -> bool: + """Gets the hub_accepts_client of this Spec. + + + :return: The hub_accepts_client of this Spec. + :rtype: bool + """ + return self._hub_accepts_client + + @hub_accepts_client.setter + def hub_accepts_client(self, hub_accepts_client: bool): + """Sets the hub_accepts_client of this Spec. + + + :param hub_accepts_client: The hub_accepts_client of this Spec. + :type hub_accepts_client: bool + """ + + self._hub_accepts_client = hub_accepts_client + + @property + def managed_cluster_client_configs(self) -> List[ManagedClusterClientConfig]: + """Gets the managed_cluster_client_configs of this Spec. + + + :return: The managed_cluster_client_configs of this Spec. + :rtype: List[ManagedClusterClientConfig] + """ + return self._managed_cluster_client_configs + + @managed_cluster_client_configs.setter + def managed_cluster_client_configs( + self, managed_cluster_client_configs: List[ManagedClusterClientConfig] + ): + """Sets the managed_cluster_client_configs of this Spec. + + + :param managed_cluster_client_configs: The managed_cluster_client_configs of this Spec. + :type managed_cluster_client_configs: List[ManagedClusterClientConfig] + """ + + self._managed_cluster_client_configs = managed_cluster_client_configs diff --git a/demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml b/demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml new file mode 100644 index 00000000..61202a34 --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml @@ -0,0 +1,162 @@ +openapi: 3.0.0 +info: + contact: + email: support@katanemo.com + name: Katanemo Labs Inc. + url: https://katanemo.com + title: ACM API for cluster management - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags + version: 2.12.0 +servers: +- url: / +paths: + /cluster.open-cluster-management.io/v1/managedclusters: + get: + operationId: list_managed_clusters + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ManagedCluster' + type: array + description: List of managed clusters + summary: Query your clusters for more details. + x-openapi-router-controller: openapi_server.controllers.default_controller + post: + operationId: create_cluster + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ManagedCluster' + description: "Details about the service, including the text-representation\ + \ of the service APIs." + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ManagedCluster' + description: cluster created successfully + summary: Create a cluster + x-openapi-router-controller: openapi_server.controllers.default_controller + /cluster.open-cluster-management.io/v1/managedclusters/{cluster_name}: + delete: + operationId: cluster_open_cluster_management_io_v1_managedclusters_cluster_name_delete + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ManagedCluster' + description: Cluster details + summary: Delete a single cluster + x-openapi-router-controller: openapi_server.controllers.default_controller + get: + operationId: get_cluster + parameters: + - description: The name of the cluster to retrieve + explode: false + in: path + name: cluster_name + required: true + schema: + type: string + style: simple + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ManagedCluster' + description: Cluster details + summary: Query a single cluster for more details + x-openapi-router-controller: openapi_server.controllers.default_controller +components: + schemas: + ManagedCluster: + example: + metadata: + name: name + labels: + key: labels + apiVersion: cluster.open-cluster-management.io/v1 + kind: ManagedCluster + spec: + hubAcceptsClient: true + managedClusterClientConfigs: + - caBundle: caBundle + url: url + - caBundle: caBundle + url: url + status: status + properties: + apiVersion: + enum: + - cluster.open-cluster-management.io/v1 + title: apiVersion + type: string + kind: + enum: + - ManagedCluster + title: kind + type: string + metadata: + $ref: '#/components/schemas/Metadata' + spec: + $ref: '#/components/schemas/Spec' + status: + title: status + type: string + title: managed cluster details + type: object + Metadata: + example: + name: name + labels: + key: labels + properties: + name: + title: name + type: string + labels: + additionalProperties: + type: string + title: labels + type: object + title: metadata details + type: object + Spec: + example: + hubAcceptsClient: true + managedClusterClientConfigs: + - caBundle: caBundle + url: url + - caBundle: caBundle + url: url + properties: + hubAcceptsClient: + title: hubAcceptsClient + type: boolean + managedClusterClientConfigs: + items: + $ref: '#/components/schemas/ManagedClusterClientConfig' + title: managedClusterClientConfigs + type: array + title: spec details + type: object + ManagedClusterClientConfig: + example: + caBundle: caBundle + url: url + properties: + url: + title: url + type: string + caBundle: + title: caBundle + type: string + title: managed cluster client config details + type: object diff --git a/demos/acm_k8s/acm_service/openapi_server/test/__init__.py b/demos/acm_k8s/acm_service/openapi_server/test/__init__.py new file mode 100644 index 00000000..aefd85c2 --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/test/__init__.py @@ -0,0 +1,15 @@ +import logging + +import connexion +from flask_testing import TestCase + +from openapi_server.encoder import JSONEncoder + + +class BaseTestCase(TestCase): + def create_app(self): + logging.getLogger("connexion.operation").setLevel("ERROR") + app = connexion.App(__name__, specification_dir="../openapi/") + app.app.json_encoder = JSONEncoder + app.add_api("openapi.yaml", pythonic_params=True) + return app.app diff --git a/demos/acm_k8s/acm_service/openapi_server/test/test_default_controller.py b/demos/acm_k8s/acm_service/openapi_server/test/test_default_controller.py new file mode 100644 index 00000000..2a669114 --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/test/test_default_controller.py @@ -0,0 +1,89 @@ +import unittest + +from flask import json + +from openapi_server.models.managed_cluster import ManagedCluster # noqa: E501 +from openapi_server.models.metadata import Metadata # noqa: E501 +from openapi_server.models.spec import Spec # noqa: E501 +from openapi_server.test import BaseTestCase + + +class TestDefaultController(BaseTestCase): + """DefaultController integration test stubs""" + + def test_cluster_open_cluster_management_io_v1_managedclusters_cluster_name_delete( + self, + ): + """Test case for cluster_open_cluster_management_io_v1_managedclusters_cluster_name_delete + + Delete a single cluster + """ + headers = { + "Accept": "application/json", + } + response = self.client.open( + "/cluster.open-cluster-management.io/v1/managedclusters/{cluster_name}", + method="DELETE", + headers=headers, + ) + self.assert200(response, "Response body is : " + response.data.decode("utf-8")) + + @unittest.skip("multipart/form-data not supported by Connexion") + def test_create_cluster(self): + """Test case for create_cluster + + Create a cluster + """ + headers = { + "Accept": "application/json", + "Content-Type": "multipart/form-data", + } + data = dict( + api_version="api_version_example", + kind="kind_example", + metadata=openapi_server.Metadata(), + spec=openapi_server.Spec(), + status="status_example", + ) + response = self.client.open( + "/cluster.open-cluster-management.io/v1/managedclusters", + method="POST", + headers=headers, + data=data, + content_type="multipart/form-data", + ) + self.assert200(response, "Response body is : " + response.data.decode("utf-8")) + + def test_get_cluster(self): + """Test case for get_cluster + + Query a single cluster for more details + """ + headers = { + "Accept": "application/json", + } + response = self.client.open( + "/cluster.open-cluster-management.io/v1/managedclusters/{cluster_name}", + method="GET", + headers=headers, + ) + self.assert200(response, "Response body is : " + response.data.decode("utf-8")) + + def test_list_managed_clusters(self): + """Test case for list_managed_clusters + + Query your clusters for more details. + """ + headers = { + "Accept": "application/json", + } + response = self.client.open( + "/cluster.open-cluster-management.io/v1/managedclusters", + method="GET", + headers=headers, + ) + self.assert200(response, "Response body is : " + response.data.decode("utf-8")) + + +if __name__ == "__main__": + unittest.main() diff --git a/demos/acm_k8s/acm_service/openapi_server/typing_utils.py b/demos/acm_k8s/acm_service/openapi_server/typing_utils.py new file mode 100644 index 00000000..c905b1db --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/typing_utils.py @@ -0,0 +1,30 @@ +import sys + +if sys.version_info < (3, 7): + import typing + + def is_generic(klass): + """Determine whether klass is a generic class""" + return type(klass) == typing.GenericMeta + + def is_dict(klass): + """Determine whether klass is a Dict""" + return klass.__extra__ == dict + + def is_list(klass): + """Determine whether klass is a List""" + return klass.__extra__ == list + +else: + + def is_generic(klass): + """Determine whether klass is a generic class""" + return hasattr(klass, "__origin__") + + def is_dict(klass): + """Determine whether klass is a Dict""" + return klass.__origin__ == dict + + def is_list(klass): + """Determine whether klass is a List""" + return klass.__origin__ == list diff --git a/demos/acm_k8s/acm_service/openapi_server/util.py b/demos/acm_k8s/acm_service/openapi_server/util.py new file mode 100644 index 00000000..182c4085 --- /dev/null +++ b/demos/acm_k8s/acm_service/openapi_server/util.py @@ -0,0 +1,149 @@ +import datetime + +import typing +from openapi_server import typing_utils + + +def _deserialize(data, klass): + """Deserializes dict, list, str into an object. + + :param data: dict, list or str. + :param klass: class literal, or string of class name. + + :return: object. + """ + if data is None: + return None + + if klass in (int, float, str, bool, bytearray): + return _deserialize_primitive(data, klass) + elif klass == object: + return _deserialize_object(data) + elif klass == datetime.date: + return deserialize_date(data) + elif klass == datetime.datetime: + return deserialize_datetime(data) + elif typing_utils.is_generic(klass): + if typing_utils.is_list(klass): + return _deserialize_list(data, klass.__args__[0]) + if typing_utils.is_dict(klass): + return _deserialize_dict(data, klass.__args__[1]) + else: + return deserialize_model(data, klass) + + +def _deserialize_primitive(data, klass): + """Deserializes to primitive type. + + :param data: data to deserialize. + :param klass: class literal. + + :return: int, long, float, str, bool. + :rtype: int | long | float | str | bool + """ + try: + value = klass(data) + except UnicodeEncodeError: + value = data + except TypeError: + value = data + return value + + +def _deserialize_object(value): + """Return an original value. + + :return: object. + """ + return value + + +def deserialize_date(string): + """Deserializes string to date. + + :param string: str. + :type string: str + :return: date. + :rtype: date + """ + if string is None: + return None + + try: + from dateutil.parser import parse + + return parse(string).date() + except ImportError: + return string + + +def deserialize_datetime(string): + """Deserializes string to datetime. + + The string should be in iso8601 datetime format. + + :param string: str. + :type string: str + :return: datetime. + :rtype: datetime + """ + if string is None: + return None + + try: + from dateutil.parser import parse + + return parse(string) + except ImportError: + return string + + +def deserialize_model(data, klass): + """Deserializes list or dict to model. + + :param data: dict, list. + :type data: dict | list + :param klass: class literal. + :return: model object. + """ + instance = klass() + + if not instance.openapi_types: + return data + + for attr, attr_type in instance.openapi_types.items(): + if ( + data is not None + and instance.attribute_map[attr] in data + and isinstance(data, (list, dict)) + ): + value = data[instance.attribute_map[attr]] + setattr(instance, attr, _deserialize(value, attr_type)) + + return instance + + +def _deserialize_list(data, boxed_type): + """Deserializes a list and its elements. + + :param data: list to deserialize. + :type data: list + :param boxed_type: class literal. + + :return: deserialized list. + :rtype: list + """ + return [_deserialize(sub_data, boxed_type) for sub_data in data] + + +def _deserialize_dict(data, boxed_type): + """Deserializes a dict and its elements. + + :param data: dict to deserialize. + :type data: dict + :param boxed_type: class literal. + + :return: deserialized dict. + :rtype: dict + """ + return {k: _deserialize(v, boxed_type) for k, v in data.items()} diff --git a/demos/acm_k8s/acm_service/requirements.txt b/demos/acm_k8s/acm_service/requirements.txt new file mode 100644 index 00000000..2cb06891 --- /dev/null +++ b/demos/acm_k8s/acm_service/requirements.txt @@ -0,0 +1,13 @@ +connexion[swagger-ui] >= 2.6.0; python_version>="3.6" +# 2.3 is the last version that supports python 3.4-3.5 +connexion[swagger-ui] <= 2.3.0; python_version=="3.5" or python_version=="3.4" +# prevent breaking dependencies from advent of connexion>=3.0 +connexion[swagger-ui] <= 2.14.2; python_version>"3.4" +# connexion requires werkzeug but connexion < 2.4.0 does not install werkzeug +# we must peg werkzeug versions below to fix connexion +# https://github.com/zalando/connexion/pull/1044 +werkzeug == 0.16.1; python_version=="3.5" or python_version=="3.4" +swagger-ui-bundle >= 0.0.2 +python_dateutil >= 2.6.0 +setuptools >= 21.0.0 +Flask == 2.1.1 diff --git a/demos/acm_k8s/acm_service/setup.py b/demos/acm_k8s/acm_service/setup.py new file mode 100644 index 00000000..6eb19f15 --- /dev/null +++ b/demos/acm_k8s/acm_service/setup.py @@ -0,0 +1,34 @@ +import sys +from setuptools import setup, find_packages + +NAME = "openapi_server" +VERSION = "1.0.0" + +# To install the library, run the following +# +# python setup.py install +# +# prerequisite: setuptools +# http://pypi.python.org/pypi/setuptools + +REQUIRES = ["connexion>=2.0.2", "swagger-ui-bundle>=0.0.2", "python_dateutil>=2.6.0"] + +setup( + name=NAME, + version=VERSION, + description="ACM API for cluster management - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags", + author_email="support@katanemo.com", + url="", + keywords=[ + "OpenAPI", + "ACM API for cluster management - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags", + ], + install_requires=REQUIRES, + packages=find_packages(), + package_data={"": ["openapi/openapi.yaml"]}, + include_package_data=True, + entry_points={"console_scripts": ["openapi_server=openapi_server.__main__:main"]}, + long_description="""\ + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + """, +) diff --git a/demos/acm_k8s/acm_service/test-requirements.txt b/demos/acm_k8s/acm_service/test-requirements.txt new file mode 100644 index 00000000..58f51d6a --- /dev/null +++ b/demos/acm_k8s/acm_service/test-requirements.txt @@ -0,0 +1,4 @@ +pytest~=7.1.0 +pytest-cov>=2.8.1 +pytest-randomly>=1.2.3 +Flask-Testing==0.8.1 diff --git a/demos/acm_k8s/acm_service/tox.ini b/demos/acm_k8s/acm_service/tox.ini new file mode 100644 index 00000000..7663dfb6 --- /dev/null +++ b/demos/acm_k8s/acm_service/tox.ini @@ -0,0 +1,11 @@ +[tox] +envlist = py3 +skipsdist=True + +[testenv] +deps=-r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt + {toxinidir} + +commands= + pytest --cov=openapi_server diff --git a/demos/acm_k8s/arch_config.yaml b/demos/acm_k8s/arch_config.yaml new file mode 100644 index 00000000..c7d315f8 --- /dev/null +++ b/demos/acm_k8s/arch_config.yaml @@ -0,0 +1,67 @@ +version: "0.1-beta" + +listener: + address: 0.0.0.0 + port: 10000 + message_format: huggingface + connect_timeout: 0.005s + +overrides: + # confidence threshold for prompt target intent matching + prompt_target_intent_matching_threshold: 0.6 + +endpoints: + acm_service: + endpoint: host.docker.internal:18083 + connect_timeout: 0.005s + +llm_providers: + - name: gpt-4o-mini + access_key: $OPENAI_API_KEY + provider: openai + model: gpt-4o-mini + default: true + + - name: gpt-3.5-turbo-0125 + access_key: $OPENAI_API_KEY + provider: openai + model: gpt-3.5-turbo-0125 + + - name: gpt-4o + access_key: $OPENAI_API_KEY + provider: openai + model: gpt-4o + +system_prompt: | + You are a helpful assistant. + +prompt_guards: + input_guards: + jailbreak: + on_exception: + message: Looks like you're curious about my abilities, but I can only provide assistance for weather forecasting. + +prompt_targets: + - name: listManagedClusters + description: Query your clusters for more details. + http_method: GET + endpoint: + name: acm_service + path: /cluster.open-cluster-management.io/v1/managedclusters + + - name: getCluster + description: Query a single cluster for more details + http_method: GET + endpoint: + name: acm_service + path: /cluster.open-cluster-management.io/v1/managedclusters/{cluster_name} + parameters: + - name: cluster_name + in_path: true + description: The name of the cluster to retrieve + required: true + type: str + +tracing: + random_sampling: 100 + trace_arch_internal: true diff --git a/demos/acm_k8s/docker-compose.yaml b/demos/acm_k8s/docker-compose.yaml new file mode 100644 index 00000000..21884159 --- /dev/null +++ b/demos/acm_k8s/docker-compose.yaml @@ -0,0 +1,31 @@ +services: + acm_service: + build: + context: acm_service/ + environment: + - OLTP_HOST=http://jaeger:4317 + extra_hosts: + - "host.docker.internal:host-gateway" + ports: + - "18083:8080" + + chatbot_ui: + build: + context: ../shared/chatbot_ui + ports: + - "18080:8080" + environment: + # this is only because we are running the sample app in the same docker container environemtn as archgw + - CHAT_COMPLETION_ENDPOINT=http://host.docker.internal:10000/v1 + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - ./arch_config.yaml:/app/arch_config.yaml + + jaeger: + build: + context: ../shared/jaeger + ports: + - "16686:16686" + - "4317:4317" + - "4318:4318" diff --git a/demos/acm_k8s/generate_acm_service_stub.sh b/demos/acm_k8s/generate_acm_service_stub.sh new file mode 100644 index 00000000..a3ead749 --- /dev/null +++ b/demos/acm_k8s/generate_acm_service_stub.sh @@ -0,0 +1,6 @@ +docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:latest generate \ + --skip-validate-spec \ + -i /local/acm_api.yaml \ + -g python-flask \ + -o /local/acm_server \ + # --additional-properties=defaultController=your.package.YourController \ diff --git a/demos/acm_k8s/petstore.yml b/demos/acm_k8s/petstore.yml new file mode 100644 index 00000000..853db5e2 --- /dev/null +++ b/demos/acm_k8s/petstore.yml @@ -0,0 +1,1206 @@ +openapi: 3.0.0 +servers: + - url: 'http://petstore.swagger.io/v2' +info: + description: >- + This is a sample server Petstore server. For this sample, you can use the api key + `special-key` to test the authorization filters. + version: 1.0.0 + title: OpenAPI Petstore + license: + name: Apache-2.0 + url: 'https://www.apache.org/licenses/LICENSE-2.0.html' +tags: + - name: pet + description: Everything about your Pets + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user +paths: + /pet: + post: + tags: + - pet + summary: Add a new pet to the store + description: '' + operationId: addPet + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '405': + description: Invalid input + security: + - http_auth: [] + requestBody: + $ref: '#/components/requestBodies/Pet' + put: + tags: + - pet + summary: Update an existing pet + description: '' + operationId: updatePet + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + '405': + description: Validation exception + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + $ref: '#/components/requestBodies/Pet' + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + style: form + explode: true # change to true for testing purpose + deprecated: true + schema: + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + responses: + '200': + description: successful operation + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'read:pets' + /pet/findByTags: + get: + tags: + - pet + summary: Finds Pets by tags + description: >- + Multiple tags can be provided with comma separated strings. Use tag1, + tag2, tag3 for testing. + operationId: findPetsByTags + parameters: + - name: tags + in: query + description: Tags to filter by + required: true + style: form + explode: false + schema: + type: array + items: + type: string + responses: + '200': + description: successful operation + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid tag value + # comment out for testing purpose + #security: + # - petstore_auth: + # - 'read:pets' + deprecated: true + '/pet/{petId}': + get: + tags: + - pet + summary: Find pet by ID + description: Returns a single pet + operationId: getPetById + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + security: + - BearerToken: [] + post: + tags: + - pet + summary: Updates a pet in the store with form data + description: '' + operationId: updatePetWithForm + parameters: + - name: petId + in: path + description: ID of pet that needs to be updated + required: true + schema: + type: integer + format: int64 + responses: + '405': + description: Invalid input + #security: + # - petstore_auth: + # - 'write:pets' + # - 'read:pets' + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + name: + description: Updated name of the pet + type: string + status: + description: Updated status of the pet + type: string + delete: + tags: + - pet + summary: Deletes a pet + description: '' + operationId: deletePet + parameters: + - name: api_key + in: header + required: false + schema: + type: string + - name: petId + in: path + description: Pet id to delete + required: true + schema: + type: integer + format: int64 + responses: + '400': + description: Invalid pet value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + '/pet_header_test': + get: + tags: + - pet + summary: Header test + description: Header test + operationId: test_header + x-streaming: true + parameters: + - name: header_test_int + in: header + description: header test int + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + security: + - api_key: [] + '/pet/{petId}?streaming': + get: + tags: + - pet + summary: Find pet by ID (streaming) + description: Returns a single pet + operationId: getPetByIdStreaming + x-streaming: true + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + security: + - api_key: [] + '/pet/{petId}/uploadImage': + post: + tags: + - pet + summary: uploads an image + description: '' + operationId: uploadFile + parameters: + - name: petId + in: path + description: ID of pet to update + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + additionalMetadata: + description: Additional data to pass to server + type: string + file: + description: file to upload + type: string + format: binary + /store/inventory: + get: + tags: + - store + summary: Returns pet inventories by status + description: Returns a map of status codes to quantities + operationId: getInventory + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: object + additionalProperties: + type: integer + format: int32 + security: + - api_key: [] + /store/order: + post: + tags: + - store + summary: Place an order for a pet + description: '' + operationId: placeOrder + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Order' + application/json: + schema: + $ref: '#/components/schemas/Order' + '400': + description: Invalid Order + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + description: order placed for purchasing the pet + required: true + '/store/order/{orderId}': + get: + tags: + - store + summary: Find purchase order by ID + description: >- + For valid response try integer IDs with value <= 5 or > 10. Other values + will generate exceptions + operationId: getOrderById + parameters: + - name: orderId + in: path + description: ID of pet that needs to be fetched + required: true + schema: + type: integer + format: int64 + minimum: 1 + maximum: 5 + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Order' + application/json: + schema: + $ref: '#/components/schemas/Order' + '400': + description: Invalid ID supplied + '404': + description: Order not found + delete: + tags: + - store + summary: Delete purchase order by ID + description: >- + For valid response try integer IDs with value < 1000. Anything above + 1000 or nonintegers will generate API errors + operationId: deleteOrder + parameters: + - name: orderId + in: path + description: ID of the order that needs to be deleted + required: true + schema: + type: string + responses: + '400': + description: Invalid ID supplied + '404': + description: Order not found + /user: + post: + tags: + - user + summary: Create user + description: This can only be done by the logged in user. + operationId: createUser + responses: + default: + description: successful operation + security: + - api_key: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/User' + description: Created user object + required: true + /user/createWithArray: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithArrayInput + responses: + default: + description: successful operation + security: + - api_key: [] + requestBody: + $ref: '#/components/requestBodies/UserArray' + /user/createWithList: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithListInput + responses: + default: + description: successful operation + security: + - api_key: [] + requestBody: + $ref: '#/components/requestBodies/UserArray' + /user/login: + get: + tags: + - user + summary: Logs user into the system + description: '' + operationId: loginUser + parameters: + - name: username + in: query + description: The user name for login + required: true + schema: + type: string + pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$' + - name: password + in: query + description: The password for login in clear text + required: true + schema: + type: string + responses: + '200': + description: successful operation + headers: + Set-Cookie: + description: >- + Cookie authentication key for use with the `api_key` + apiKey authentication. + schema: + type: string + example: AUTH_KEY=abcde12345; Path=/; HttpOnly + X-Rate-Limit: + description: calls per hour allowed by the user + schema: + type: integer + format: int32 + X-Expires-After: + description: date in UTC when token expires + schema: + type: string + format: date-time + content: + application/xml: + schema: + type: string + application/json: + schema: + type: string + '400': + description: Invalid username/password supplied + /user/logout: + get: + tags: + - user + summary: Logs out current logged in user session + description: '' + operationId: logoutUser + responses: + default: + description: successful operation + security: + - api_key: [] + '/user/{username}': + get: + tags: + - user + summary: Get user by user name + description: '' + operationId: getUserByName + parameters: + - name: username + in: path + description: The name that needs to be fetched. Use user1 for testing. + required: true + schema: + type: string + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/User' + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Invalid username supplied + '404': + description: User not found + put: + tags: + - user + summary: Updated user + description: This can only be done by the logged in user. + operationId: updateUser + parameters: + - name: username + in: path + description: name that need to be deleted + required: true + schema: + type: string + responses: + '400': + description: Invalid user supplied + '404': + description: User not found + security: + - api_key: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/User' + description: Updated user object + required: true + delete: + tags: + - user + summary: Delete user + description: This can only be done by the logged in user. + operationId: deleteUser + parameters: + - name: username + in: path + description: The name that needs to be deleted + required: true + schema: + type: string + responses: + '400': + description: Invalid username supplied + '404': + description: User not found + security: + - api_key: [] + /fake/path_array/{path_array}/testing: + get: + tags: + - fake + summary: test array parameter in path + description: '' + operationId: fake_path_array + parameters: + - name: path_array + in: path + description: dummy path parameter + required: true + schema: + type: array + items: + type: string + responses: + '200': + description: successful operation + /fake/regular_expression: + get: + tags: + - fake + summary: test regular expression to ensure no exception + description: '' + operationId: fake_regular-expression + parameters: + - name: reg_exp_test + in: header + description: dummy required parameter + required: true + schema: + type: string + pattern: /^[A-Za-z0-9_]{1,15}$/ + responses: + '200': + description: successful operation + /fake/data_file: + get: + tags: + - fake + summary: test data_file to ensure it's escaped correctly + description: '' + operationId: fake_data_file + parameters: + - name: dummy + in: header + description: dummy required parameter + required: true + schema: + type: string + - name: data_file + in: header + description: header data file + required: false + schema: + type: string + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/User' + application/json: + schema: + $ref: '#/components/schemas/User' + /fake/set_query_parameter: + get: + tags: + - fake + summary: test set query parameter + description: '' + operationId: fake_set_query + parameters: + - name: set_dummy + in: query + description: set query + required: true + schema: + type: array + uniqueItems: true + items: + type: string + - name: array_dummy + in: query + description: array query + required: true + schema: + type: array + uniqueItems: false + items: + type: string + responses: + '200': + description: successful operation + /fake/test_optional_body_parameter: + post: + tags: + - fake + summary: Add a new pet to the store (optional body) + description: '' + operationId: addPetOptional + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '405': + description: Invalid input + security: + - http_auth: [] + requestBody: + $ref: '#/components/requestBodies/OptionalPet' +externalDocs: + description: Find out more about Swagger + url: 'http://swagger.io' +components: + requestBodies: + UserArray: + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + description: List of user object + required: true + Pet: + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + multipart/related: # message with binary body part + schema: + type: object + properties: # Request parts + jsonData: + $ref: '#/components/schemas/Pet' + binaryDataN2Information: + type: string + format: binary + encoding: + jsonData: + contentType: application/json + binaryDataN2Information: + contentType: application/vnd.3gpp.ngap + headers: + Content-Id: + schema: + type: string + description: Pet object that needs to be added to the store + required: true + OptionalPet: + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + multipart/related: # message with binary body part + schema: + type: object + properties: # Request parts + jsonData: + $ref: '#/components/schemas/Pet' + binaryDataN2Information: + type: string + format: binary + encoding: + jsonData: + contentType: application/json + binaryDataN2Information: + contentType: application/vnd.3gpp.ngap + headers: + Content-Id: + schema: + type: string + description: Pet object that needs to be added to the store + required: false + securitySchemes: + http_auth: + type : http + scheme : basic + BearerToken: + type : http + scheme : bearer + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog' + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header + schemas: + Order: + title: Pet Order + description: An order for a pets from the pet store + type: object + properties: + id: + type: integer + format: int64 + petId: + type: integer + format: int64 + quantity: + type: integer + format: int32 + shipDate: + type: string + format: date-time + status: + type: string + description: Order Status + enum: + - placed + - approved + - delivered + complete: + type: boolean + default: false + xml: + name: Order + Category: + title: Pet category + description: A category for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$' + xml: + name: Category + User: + title: a User + description: A User who is purchasing from the pet store + type: object + properties: + id: + type: integer + format: int64 + username: + type: string + firstName: + type: string + lastName: + type: string + email: + type: string + password: + type: string + phone: + type: string + userStatus: + type: integer + format: int32 + description: User Status + xml: + name: User + Tag: + title: Pet Tag + description: A tag for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Tag + Pet: + title: a Pet + description: A pet for sale in the pet store + type: object + required: + - name + - photoUrls + properties: + id: + type: integer + format: int64 + category: + $ref: '#/components/schemas/Category' + name: + type: string + example: doggie + photoUrls: + type: array + xml: + name: photoUrl + wrapped: true + items: + type: string + tags: + type: array + xml: + name: tag + wrapped: true + items: + $ref: '#/components/schemas/Tag' + status: + type: string + description: pet status in the store + deprecated: true + enum: + - available + - pending + - sold + xml: + name: Pet + PetMap: + title: a PetMap + description: A mock map of a pet and some properties + type: object + properties: + pet: + type: object + additionalProperties: + type: string + ApiResponse: + title: An uploaded response + description: Describes the result of uploading an image resource + type: object + properties: + code: + type: integer + format: int32 + type: + type: string + message: + type: string + Special: + title: An uploaded response + description: Describes the result of uploading an image resource + type: object + properties: + set_test: + uniqueItems: true + type: array + items: + type: string + self: + type: integer + format: int32 + private: + type: string + super: + type: string + "123_number": + type: string + "array[test]": + type: string + "": + type: string + Dog: + allOf: + - $ref: '#/components/schemas/Animal' + - type: object + properties: + breed: + type: string + Cat: + allOf: + - $ref: '#/components/schemas/Animal' + - $ref: '#/components/schemas/Address' + - type: object + properties: + declawed: + type: boolean + Address: + type: object + additionalProperties: + type: integer + Animal: + type: object + discriminator: + propertyName: className + required: + - className + properties: + className: + type: string + color: + type: string + default: red + allof_tag_api_response: + allOf: + - $ref: '#/components/schemas/Tag' + - $ref: '#/components/schemas/ApiResponse' + AnyOfPig: + anyOf: + - $ref: '#/components/schemas/BasquePig' + - $ref: '#/components/schemas/DanishPig' + Pig: + oneOf: + - $ref: '#/components/schemas/BasquePig' + - $ref: '#/components/schemas/DanishPig' + discriminator: + propertyName: className + BasquePig: + type: object + properties: + className: + type: string + color: + type: string + required: + - className + - color + DanishPig: + type: object + properties: + className: + type: string + size: + type: integer + required: + - className + - size + NestedOneOf: + type: object + properties: + size: + type: integer + nested_pig: + $ref: '#/components/schemas/Pig' + OneOfPrimitiveTypeTest: + oneOf: + - type: "integer" + - type: "string" + AnyOfPrimitiveTypeTest: + oneOf: + - type: "integer" + - type: "string" + mammal: + oneOf: + - $ref: '#/components/schemas/whale' + - $ref: '#/components/schemas/zebra' + discriminator: + propertyName: className + mapping: + whale: '#/components/schemas/whale' + zebra: '#/components/schemas/zebra' + whale: + type: object + properties: + hasBaleen: + type: boolean + hasTeeth: + type: boolean + className: + type: string + required: + - className + zebra: + type: object + properties: + type: + type: string + enum: + - plains + - mountain + - grevys + className: + type: string + required: + - className + Date: + description: to test the model name `Date` + type: object + properties: + className: + type: string + percent_description: + description: using % in the description + type: string + url_property: + type: string + format: uri + required: + - className + - url_property + dummy_model: + description: to test the model name mapping + type: object + properties: + property: + type: string + format_test: + type: object + required: + - number + - byte + - date + - password + properties: + integer: + type: integer + maximum: 100 + minimum: 10 + int32: + type: integer + format: int32 + maximum: 200 + minimum: 20 + int64: + type: integer + format: int64 + number: + maximum: 543.2 + minimum: 32.1 + type: number + float: + type: number + format: float + maximum: 987.6 + minimum: 54.3 + double: + type: number + format: double + maximum: 123.4 + minimum: 67.8 + string: + type: string + pattern: '/[a-z]/i' + byte: + type: string + format: byte + binary: + type: string + format: binary + date: + type: string + format: date + default: 2019-07-19 + dateTime: + type: string + format: date-time + default: 2015-10-28T14:38:02Z + uuid: + type: string + format: uuid + example: 72f98069-206d-4f12-9f12-3d1e525a8e84 + password: + type: string + format: password + maxLength: 64 + minLength: 10 + pattern_with_digits: + description: A string that is a 10 digit number. Can have leading zeros. + type: string + pattern: '^\d{10}$' + pattern_with_digits_and_delimiter: + description: A string starting with 'image_' (case insensitive) and one to three digits following i.e. Image_01. + type: string + pattern: '/^image_\d{1,3}$/i' diff --git a/demos/acm_k8s/run_demo.sh b/demos/acm_k8s/run_demo.sh new file mode 100644 index 00000000..e6c678e8 --- /dev/null +++ b/demos/acm_k8s/run_demo.sh @@ -0,0 +1,47 @@ +#!/bin/bash +set -e + +# Function to start the demo +start_demo() { + # Step 1: Check if .env file exists + if [ -f ".env" ]; then + echo ".env file already exists. Skipping creation." + else + # Step 2: Create `.env` file and set OpenAI key + if [ -z "$OPENAI_API_KEY" ]; then + echo "Error: OPENAI_API_KEY environment variable is not set for the demo." + exit 1 + fi + + echo "Creating .env file..." + echo "OPENAI_API_KEY=$OPENAI_API_KEY" > .env + echo ".env file created with OPENAI_API_KEY." + fi + + # Step 3: Start Arch + echo "Starting Arch with arch_config.yaml..." + archgw up arch_config.yaml + + # Step 4: Start Network Agent + echo "Starting Network Agent using Docker Compose..." + docker compose up -d # Run in detached mode +} + +# Function to stop the demo +stop_demo() { + # Step 1: Stop Docker Compose services + echo "Stopping Network Agent using Docker Compose..." + docker compose down + + # Step 2: Stop Arch + echo "Stopping Arch..." + archgw down +} + +# Main script logic +if [ "$1" == "down" ]; then + stop_demo +else + # Default action is to bring the demo up + start_demo +fi diff --git a/model_server/app/main.py b/model_server/app/main.py index 43be1f74..4f9337bd 100644 --- a/model_server/app/main.py +++ b/model_server/app/main.py @@ -220,6 +220,12 @@ async def hallucination(req: HallucinationRequest, res: Response): if "messages" in req.parameters: req.parameters.pop("messages") + if not req.parameters or len(req.parameters) == 0: + return { + "params_scores": {}, + "model": req.model, + } + candidate_labels = {f"{k} is {v}": k for k, v in req.parameters.items()} predictions = classifier( From af028070046c6c78f564f6add872437cd8105f10 Mon Sep 17 00:00:00 2001 From: Adil Hafeez Date: Tue, 3 Dec 2024 19:35:37 -0800 Subject: [PATCH 2/5] remove debug statement --- crates/prompt_gateway/src/stream_context.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/prompt_gateway/src/stream_context.rs b/crates/prompt_gateway/src/stream_context.rs index 1a4b6cba..ebcb0636 100644 --- a/crates/prompt_gateway/src/stream_context.rs +++ b/crates/prompt_gateway/src/stream_context.rs @@ -921,7 +921,6 @@ impl StreamContext { }; let http_method = prompt_target.method.unwrap_or_default().to_string(); - info!("http_method: {}", http_method); let mut headers = vec![ (ARCH_UPSTREAM_HOST_HEADER, endpoint.name.as_str()), (":method", &http_method), From 5e182b6c09645f91d5d5f85dc247901c0952f41f Mon Sep 17 00:00:00 2001 From: Adil Hafeez Date: Thu, 5 Dec 2024 10:11:55 -0800 Subject: [PATCH 3/5] pending --- arch/tools/cli/config_generator.py | 4 +- crates/prompt_gateway/src/stream_context.rs | 111 ++++++++++++++---- demos/acm_k8s/acm_api.yaml | 1 - .../acm_service/openapi_server/__main__.py | 4 +- .../openapi_server/openapi/openapi.yaml | 3 +- demos/acm_k8s/acm_service/setup.py | 9 +- demos/acm_k8s/arch_config.yaml | 32 ++++- demos/acm_k8s/generate_acm_service_stub.sh | 3 +- 8 files changed, 125 insertions(+), 42 deletions(-) diff --git a/arch/tools/cli/config_generator.py b/arch/tools/cli/config_generator.py index 293ffc8a..c32dae16 100644 --- a/arch/tools/cli/config_generator.py +++ b/arch/tools/cli/config_generator.py @@ -49,7 +49,9 @@ def validate_and_render_schema(): if "prompt_targets" in config_yaml: for prompt_target in config_yaml["prompt_targets"]: - name = prompt_target.get("endpoint", {}).get("name", "") + name = prompt_target.get("endpoint", {}).get("name", None) + if not name: + continue if name not in inferred_clusters: inferred_clusters[name] = { "name": name, diff --git a/crates/prompt_gateway/src/stream_context.rs b/crates/prompt_gateway/src/stream_context.rs index ebcb0636..501e25a9 100644 --- a/crates/prompt_gateway/src/stream_context.rs +++ b/crates/prompt_gateway/src/stream_context.rs @@ -494,6 +494,53 @@ impl StreamContext { .find(|pt| pt.default.unwrap_or(false)) { debug!("default prompt target found, forwarding request to default prompt target"); + if default_prompt_target.endpoint.is_none() { + info!("default prompt target endpoint not found"); + + let system_prompt = self.get_system_prompt(Some(default_prompt_target.clone())); + + let messages = vec![ + Message { + content: system_prompt, + role: SYSTEM_ROLE.to_string(), + model: Some(ARCH_FC_MODEL_NAME.to_string()), + tool_calls: None, + tool_call_id: None, + }, + Message { + content: self.user_prompt.as_ref().unwrap().content.clone(), + role: ASSISTANT_ROLE.to_string(), + model: Some(ARCH_FC_MODEL_NAME.to_string()), + tool_calls: None, + tool_call_id: None, + }, + ]; + + let chat_completions_request: ChatCompletionsRequest = ChatCompletionsRequest { + model: callout_context.request_body.model, + messages, + tools: None, + stream: callout_context.request_body.stream, + stream_options: callout_context.request_body.stream_options, + metadata: None, + }; + + let llm_request_str = match serde_json::to_string(&chat_completions_request) { + Ok(json_string) => json_string, + Err(e) => { + return self.send_server_error(ServerError::Serialization(e), None); + } + }; + + self.set_http_request_body( + 0, + self.request_body_size, + &llm_request_str.into_bytes(), + ); + + self.resume_http_request(); + return; + } let endpoint = default_prompt_target.endpoint.clone().unwrap(); let upstream_path: String = endpoint.path.unwrap_or(String::from("/")); @@ -547,7 +594,7 @@ impl StreamContext { // if no default prompt target is found and similarity score is low send response to upstream llm // removing tool calls and tool response - let messages = self.filter_out_arch_messages(&callout_context); + let messages = self.construct_llm_messages(&callout_context); let chat_completions_request: ChatCompletionsRequest = ChatCompletionsRequest { model: callout_context.request_body.model, @@ -988,7 +1035,7 @@ impl StreamContext { self.tool_call_response.as_ref().unwrap() ); - let mut messages = self.filter_out_arch_messages(&callout_context); + let mut messages = self.construct_llm_messages(&callout_context); let user_message = match messages.pop() { Some(user_message) => user_message, @@ -1045,25 +1092,43 @@ impl StreamContext { self.resume_http_request(); } - fn filter_out_arch_messages(&mut self, callout_context: &StreamCallContext) -> Vec { - let mut messages: Vec = Vec::new(); - // add system prompt + fn get_system_prompt(&self, prompt_target: Option) -> Option { + match prompt_target { + None => self.system_prompt.as_ref().clone(), + Some(prompt_target) => prompt_target.system_prompt, + } + } + fn filter_out_arch_messages(&self, messages: &Vec) -> Vec { + messages + .into_iter() + .filter(|m| { + if m.role == TOOL_ROLE + || m.content.is_none() + || (m.tool_calls.is_some() && !m.tool_calls.as_ref().unwrap().is_empty()) + { + true + } else { + false + } + }) + .cloned() + .collect() + } + + fn construct_llm_messages(&mut self, callout_context: &StreamCallContext) -> Vec { + let mut messages: Vec = Vec::new(); + + // add system prompt let system_prompt = match callout_context.prompt_target_name.as_ref() { None => self.system_prompt.as_ref().clone(), Some(prompt_target_name) => { - let prompt_system_prompt = self - .prompt_targets - .get(prompt_target_name) - .unwrap() - .clone() - .system_prompt; - match prompt_system_prompt { - None => self.system_prompt.as_ref().clone(), - Some(system_prompt) => Some(system_prompt), - } + self.get_system_prompt(self.prompt_targets.get(prompt_target_name).cloned()) } }; + + info!("messages 1: {:?}", callout_context.request_body.messages); + if system_prompt.is_some() { let system_prompt_message = Message { role: SYSTEM_ROLE.to_string(), @@ -1075,18 +1140,12 @@ impl StreamContext { messages.push(system_prompt_message); } - // don't send tools message and api response to chat gpt - for m in callout_context.request_body.messages.iter() { - // don't send api response and tool calls to upstream LLMs - if m.role == TOOL_ROLE - || m.content.is_none() - || (m.tool_calls.is_some() && !m.tool_calls.as_ref().unwrap().is_empty()) - { - continue; - } - messages.push(m.clone()); - } + info!("messages 2: {:?}", messages); + messages.append( + &mut self.filter_out_arch_messages(callout_context.request_body.messages.as_ref()), + ); + info!("messages 3: {:?}", messages); messages } diff --git a/demos/acm_k8s/acm_api.yaml b/demos/acm_k8s/acm_api.yaml index 4b4ec9fd..e7638523 100644 --- a/demos/acm_k8s/acm_api.yaml +++ b/demos/acm_k8s/acm_api.yaml @@ -66,7 +66,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ManagedCluster" - components: schemas: ManagedCluster: diff --git a/demos/acm_k8s/acm_service/openapi_server/__main__.py b/demos/acm_k8s/acm_service/openapi_server/__main__.py index 417a9020..31ada589 100644 --- a/demos/acm_k8s/acm_service/openapi_server/__main__.py +++ b/demos/acm_k8s/acm_service/openapi_server/__main__.py @@ -10,9 +10,7 @@ def main(): app.app.json_encoder = encoder.JSONEncoder app.add_api( "openapi.yaml", - arguments={ - "title": "ACM API for cluster management - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags" - }, + arguments={"title": "ACM API for cluster management"}, pythonic_params=True, ) diff --git a/demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml b/demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml index 61202a34..46503e9c 100644 --- a/demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml +++ b/demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml @@ -4,7 +4,8 @@ info: email: support@katanemo.com name: Katanemo Labs Inc. url: https://katanemo.com - title: ACM API for cluster management - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags + description: This is the API for managing clusters using ACM - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags + title: ACM API for cluster management version: 2.12.0 servers: - url: / diff --git a/demos/acm_k8s/acm_service/setup.py b/demos/acm_k8s/acm_service/setup.py index 6eb19f15..36741ffd 100644 --- a/demos/acm_k8s/acm_service/setup.py +++ b/demos/acm_k8s/acm_service/setup.py @@ -16,19 +16,16 @@ REQUIRES = ["connexion>=2.0.2", "swagger-ui-bundle>=0.0.2", "python_dateutil>=2. setup( name=NAME, version=VERSION, - description="ACM API for cluster management - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags", + description="ACM API for cluster management", author_email="support@katanemo.com", url="", - keywords=[ - "OpenAPI", - "ACM API for cluster management - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags", - ], + keywords=["OpenAPI", "ACM API for cluster management"], install_requires=REQUIRES, packages=find_packages(), package_data={"": ["openapi/openapi.yaml"]}, include_package_data=True, entry_points={"console_scripts": ["openapi_server=openapi_server.__main__:main"]}, long_description="""\ - No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + This is the API for managing clusters using ACM - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags """, ) diff --git a/demos/acm_k8s/arch_config.yaml b/demos/acm_k8s/arch_config.yaml index c7d315f8..cdfd6bee 100644 --- a/demos/acm_k8s/arch_config.yaml +++ b/demos/acm_k8s/arch_config.yaml @@ -42,14 +42,14 @@ prompt_guards: message: Looks like you're curious about my abilities, but I can only provide assistance for weather forecasting. prompt_targets: - - name: listManagedClusters + - name: listAllClusterDetails description: Query your clusters for more details. http_method: GET endpoint: name: acm_service path: /cluster.open-cluster-management.io/v1/managedclusters - - name: getCluster + - name: getClusterDetails description: Query a single cluster for more details http_method: GET endpoint: @@ -62,6 +62,34 @@ prompt_targets: required: true type: str + - name: default_target + default: true + description: This is the default target for all unmatched prompts. + system_prompt: | + You are a helpful assistant that can help answer ACM queries. Following is a list of available commands user can ask. Based on question asked, tell me which command you want to execute. + + - name: listAllClusterDetails + description: Query your clusters for more details. + http_method: GET + endpoint: + name: acm_service + path: /cluster.open-cluster-management.io/v1/managedclusters + + - name: getClusterDetails + description: Query a single cluster for more details + http_method: GET + endpoint: + name: acm_service + path: /cluster.open-cluster-management.io/v1/managedclusters/{cluster_name} + parameters: + - name: cluster_name + in_path: true + description: The name of the cluster to retrieve + required: true + type: str + + auto_llm_dispatch_on_response: true + tracing: random_sampling: 100 trace_arch_internal: true diff --git a/demos/acm_k8s/generate_acm_service_stub.sh b/demos/acm_k8s/generate_acm_service_stub.sh index a3ead749..2dedf44c 100644 --- a/demos/acm_k8s/generate_acm_service_stub.sh +++ b/demos/acm_k8s/generate_acm_service_stub.sh @@ -2,5 +2,4 @@ docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:latest gen --skip-validate-spec \ -i /local/acm_api.yaml \ -g python-flask \ - -o /local/acm_server \ - # --additional-properties=defaultController=your.package.YourController \ + -o /local/acm_service \ From 63d7d9126717cd2876aba3545407bf2cd0627510 Mon Sep 17 00:00:00 2001 From: Adil Hafeez Date: Thu, 5 Dec 2024 14:53:05 -0800 Subject: [PATCH 4/5] remove demo code change --- demos/acm_k8s/README.md | 2 - demos/acm_k8s/acm_api.yaml | 116 -- demos/acm_k8s/acm_service/.dockerignore | 72 - demos/acm_k8s/acm_service/.gitignore | 66 - .../acm_service/.openapi-generator-ignore | 23 - .../acm_service/.openapi-generator/FILES | 26 - .../acm_service/.openapi-generator/VERSION | 1 - demos/acm_k8s/acm_service/.travis.yml | 14 - demos/acm_k8s/acm_service/Dockerfile | 16 - demos/acm_k8s/acm_service/README.md | 49 - demos/acm_k8s/acm_service/git_push.sh | 57 - .../acm_service/openapi_server/__init__.py | 0 .../acm_service/openapi_server/__main__.py | 21 - .../openapi_server/controllers/__init__.py | 0 .../openapi_server/controllers/controller.py | 84 -- .../controllers/default_controller.py | 88 -- .../controllers/security_controller.py | 1 - .../acm_service/openapi_server/encoder.py | 19 - .../openapi_server/models/__init__.py | 8 - .../openapi_server/models/base_model.py | 70 - .../openapi_server/models/managed_cluster.py | 186 --- .../models/managed_cluster_client_config.py | 81 -- .../openapi_server/models/metadata.py | 81 -- .../acm_service/openapi_server/models/spec.py | 98 -- .../openapi_server/openapi/openapi.yaml | 163 --- .../openapi_server/test/__init__.py | 15 - .../test/test_default_controller.py | 89 -- .../openapi_server/typing_utils.py | 30 - .../acm_service/openapi_server/util.py | 149 -- demos/acm_k8s/acm_service/requirements.txt | 13 - demos/acm_k8s/acm_service/setup.py | 31 - .../acm_k8s/acm_service/test-requirements.txt | 4 - demos/acm_k8s/acm_service/tox.ini | 11 - demos/acm_k8s/arch_config.yaml | 95 -- demos/acm_k8s/docker-compose.yaml | 31 - demos/acm_k8s/generate_acm_service_stub.sh | 5 - demos/acm_k8s/petstore.yml | 1206 ----------------- demos/acm_k8s/run_demo.sh | 47 - 38 files changed, 3068 deletions(-) delete mode 100644 demos/acm_k8s/README.md delete mode 100644 demos/acm_k8s/acm_api.yaml delete mode 100644 demos/acm_k8s/acm_service/.dockerignore delete mode 100644 demos/acm_k8s/acm_service/.gitignore delete mode 100644 demos/acm_k8s/acm_service/.openapi-generator-ignore delete mode 100644 demos/acm_k8s/acm_service/.openapi-generator/FILES delete mode 100644 demos/acm_k8s/acm_service/.openapi-generator/VERSION delete mode 100644 demos/acm_k8s/acm_service/.travis.yml delete mode 100644 demos/acm_k8s/acm_service/Dockerfile delete mode 100644 demos/acm_k8s/acm_service/README.md delete mode 100644 demos/acm_k8s/acm_service/git_push.sh delete mode 100644 demos/acm_k8s/acm_service/openapi_server/__init__.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/__main__.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/controllers/__init__.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/controllers/controller.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/controllers/default_controller.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/controllers/security_controller.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/encoder.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/models/__init__.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/models/base_model.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/models/managed_cluster.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/models/managed_cluster_client_config.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/models/metadata.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/models/spec.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml delete mode 100644 demos/acm_k8s/acm_service/openapi_server/test/__init__.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/test/test_default_controller.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/typing_utils.py delete mode 100644 demos/acm_k8s/acm_service/openapi_server/util.py delete mode 100644 demos/acm_k8s/acm_service/requirements.txt delete mode 100644 demos/acm_k8s/acm_service/setup.py delete mode 100644 demos/acm_k8s/acm_service/test-requirements.txt delete mode 100644 demos/acm_k8s/acm_service/tox.ini delete mode 100644 demos/acm_k8s/arch_config.yaml delete mode 100644 demos/acm_k8s/docker-compose.yaml delete mode 100644 demos/acm_k8s/generate_acm_service_stub.sh delete mode 100644 demos/acm_k8s/petstore.yml delete mode 100644 demos/acm_k8s/run_demo.sh diff --git a/demos/acm_k8s/README.md b/demos/acm_k8s/README.md deleted file mode 100644 index 91fff783..00000000 --- a/demos/acm_k8s/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Function calling -This demo shows arch gateway interacting with ACM rest APIs. diff --git a/demos/acm_k8s/acm_api.yaml b/demos/acm_k8s/acm_api.yaml deleted file mode 100644 index e7638523..00000000 --- a/demos/acm_k8s/acm_api.yaml +++ /dev/null @@ -1,116 +0,0 @@ -openapi: 3.0.0 -info: - version: 2.12.0 - title: ACM API for cluster management - description: This is the API for managing clusters using ACM - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags - contact: - name: Katanemo Labs Inc. - email: support@katanemo.com - url: https://katanemo.com -paths: - /cluster.open-cluster-management.io/v1/managedclusters: - get: - summary: Query your clusters for more details. - operationId: listManagedClusters - responses: - "200": - description: List of managed clusters - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/ManagedCluster" - post: - summary: Create a cluster - operationId: createCluster - requestBody: - description: Details about the service, including the text-representation of the service APIs. - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/ManagedCluster" - responses: - "200": - description: cluster created successfully - content: - application/json: - schema: - $ref: "#/components/schemas/ManagedCluster" - - /cluster.open-cluster-management.io/v1/managedclusters/{cluster_name}: - get: - summary: Query a single cluster for more details - operationId: getCluster - parameters: - - name: cluster_name - in: path - description: The name of the cluster to retrieve - required: true - schema: - type: string - responses: - "200": - description: Cluster details - content: - application/json: - schema: - $ref: "#/components/schemas/ManagedCluster" - delete: - summary: Delete a single cluster - responses: - "200": - description: Cluster details - content: - application/json: - schema: - $ref: "#/components/schemas/ManagedCluster" -components: - schemas: - ManagedCluster: - title: managed cluster details - type: object - properties: - apiVersion: - type: string - enum: - - cluster.open-cluster-management.io/v1 - kind: - type: string - enum: - - ManagedCluster - metadata: - $ref: "#/components/schemas/Metadata" - spec: - $ref: "#/components/schemas/Spec" - status: - type: string - Metadata: - title: metadata details - type: object - properties: - name: - type: string - labels: - type: object - additionalProperties: - type: string - Spec: - title: spec details - type: object - properties: - hubAcceptsClient: - type: boolean - managedClusterClientConfigs: - type: array - items: - $ref: "#/components/schemas/ManagedClusterClientConfig" - ManagedClusterClientConfig: - title: managed cluster client config details - type: object - properties: - url: - type: string - caBundle: - type: string diff --git a/demos/acm_k8s/acm_service/.dockerignore b/demos/acm_k8s/acm_service/.dockerignore deleted file mode 100644 index f9619601..00000000 --- a/demos/acm_k8s/acm_service/.dockerignore +++ /dev/null @@ -1,72 +0,0 @@ -.travis.yaml -.openapi-generator-ignore -README.md -tox.ini -git_push.sh -test-requirements.txt -setup.py - -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover -.hypothesis/ -venv/ -.python-version - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -#Ipython Notebook -.ipynb_checkpoints diff --git a/demos/acm_k8s/acm_service/.gitignore b/demos/acm_k8s/acm_service/.gitignore deleted file mode 100644 index 43995bd4..00000000 --- a/demos/acm_k8s/acm_service/.gitignore +++ /dev/null @@ -1,66 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover -.hypothesis/ -venv/ -.venv/ -.python-version -.pytest_cache - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -#Ipython Notebook -.ipynb_checkpoints diff --git a/demos/acm_k8s/acm_service/.openapi-generator-ignore b/demos/acm_k8s/acm_service/.openapi-generator-ignore deleted file mode 100644 index 7484ee59..00000000 --- a/demos/acm_k8s/acm_service/.openapi-generator-ignore +++ /dev/null @@ -1,23 +0,0 @@ -# OpenAPI Generator Ignore -# Generated by openapi-generator https://github.com/openapitools/openapi-generator - -# Use this file to prevent files from being overwritten by the generator. -# The patterns follow closely to .gitignore or .dockerignore. - -# As an example, the C# client generator defines ApiClient.cs. -# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: -#ApiClient.cs - -# You can match any string of characters against a directory, file or extension with a single asterisk (*): -#foo/*/qux -# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux - -# You can recursively match patterns against a directory, file or extension with a double asterisk (**): -#foo/**/qux -# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux - -# You can also negate patterns with an exclamation (!). -# For example, you can ignore all files in a docs folder with the file extension .md: -#docs/*.md -# Then explicitly reverse the ignore rule for a single file: -#!docs/README.md diff --git a/demos/acm_k8s/acm_service/.openapi-generator/FILES b/demos/acm_k8s/acm_service/.openapi-generator/FILES deleted file mode 100644 index 5387d276..00000000 --- a/demos/acm_k8s/acm_service/.openapi-generator/FILES +++ /dev/null @@ -1,26 +0,0 @@ -.dockerignore -.gitignore -.travis.yml -Dockerfile -README.md -git_push.sh -openapi_server/__init__.py -openapi_server/__main__.py -openapi_server/controllers/__init__.py -openapi_server/controllers/default_controller.py -openapi_server/controllers/security_controller.py -openapi_server/encoder.py -openapi_server/models/__init__.py -openapi_server/models/base_model.py -openapi_server/models/managed_cluster.py -openapi_server/models/managed_cluster_client_config.py -openapi_server/models/metadata.py -openapi_server/models/spec.py -openapi_server/openapi/openapi.yaml -openapi_server/test/__init__.py -openapi_server/typing_utils.py -openapi_server/util.py -requirements.txt -setup.py -test-requirements.txt -tox.ini diff --git a/demos/acm_k8s/acm_service/.openapi-generator/VERSION b/demos/acm_k8s/acm_service/.openapi-generator/VERSION deleted file mode 100644 index 88411912..00000000 --- a/demos/acm_k8s/acm_service/.openapi-generator/VERSION +++ /dev/null @@ -1 +0,0 @@ -7.11.0-SNAPSHOT diff --git a/demos/acm_k8s/acm_service/.travis.yml b/demos/acm_k8s/acm_service/.travis.yml deleted file mode 100644 index ad71ee5c..00000000 --- a/demos/acm_k8s/acm_service/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -# ref: https://docs.travis-ci.com/user/languages/python -language: python -python: - - "3.2" - - "3.3" - - "3.4" - - "3.5" - - "3.6" - - "3.7" - - "3.8" -# command to install dependencies -install: "pip install -r requirements.txt" -# command to run tests -script: nosetests diff --git a/demos/acm_k8s/acm_service/Dockerfile b/demos/acm_k8s/acm_service/Dockerfile deleted file mode 100644 index ac9e33ab..00000000 --- a/demos/acm_k8s/acm_service/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM python:3-alpine - -RUN mkdir -p /usr/src/app -WORKDIR /usr/src/app - -COPY requirements.txt /usr/src/app/ - -RUN pip3 install --no-cache-dir -r requirements.txt - -COPY . /usr/src/app - -EXPOSE 8080 - -ENTRYPOINT ["python3"] - -CMD ["-m", "openapi_server"] diff --git a/demos/acm_k8s/acm_service/README.md b/demos/acm_k8s/acm_service/README.md deleted file mode 100644 index 9525e3e1..00000000 --- a/demos/acm_k8s/acm_service/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# OpenAPI generated server - -## Overview -This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the -[OpenAPI-Spec](https://openapis.org) from a remote server, you can easily generate a server stub. This -is an example of building a OpenAPI-enabled Flask server. - -This example uses the [Connexion](https://github.com/zalando/connexion) library on top of Flask. - -## Requirements -Python 3.5.2+ - -## Usage -To run the server, please execute the following from the root directory: - -``` -pip3 install -r requirements.txt -python3 -m openapi_server -``` - -and open your browser to here: - -``` -http://localhost:8080/ui/ -``` - -Your OpenAPI definition lives here: - -``` -http://localhost:8080/openapi.json -``` - -To launch the integration tests, use tox: -``` -sudo pip install tox -tox -``` - -## Running with Docker - -To run the server on a Docker container, please execute the following from the root directory: - -```bash -# building the image -docker build -t openapi_server . - -# starting up a container -docker run -p 8080:8080 openapi_server -``` diff --git a/demos/acm_k8s/acm_service/git_push.sh b/demos/acm_k8s/acm_service/git_push.sh deleted file mode 100644 index f53a75d4..00000000 --- a/demos/acm_k8s/acm_service/git_push.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh -# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ -# -# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com" - -git_user_id=$1 -git_repo_id=$2 -release_note=$3 -git_host=$4 - -if [ "$git_host" = "" ]; then - git_host="github.com" - echo "[INFO] No command line input provided. Set \$git_host to $git_host" -fi - -if [ "$git_user_id" = "" ]; then - git_user_id="GIT_USER_ID" - echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" -fi - -if [ "$git_repo_id" = "" ]; then - git_repo_id="GIT_REPO_ID" - echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" -fi - -if [ "$release_note" = "" ]; then - release_note="Minor update" - echo "[INFO] No command line input provided. Set \$release_note to $release_note" -fi - -# Initialize the local directory as a Git repository -git init - -# Adds the files in the local repository and stages them for commit. -git add . - -# Commits the tracked changes and prepares them to be pushed to a remote repository. -git commit -m "$release_note" - -# Sets the new remote -git_remote=$(git remote) -if [ "$git_remote" = "" ]; then # git remote not defined - - if [ "$GIT_TOKEN" = "" ]; then - echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." - git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git - else - git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git - fi - -fi - -git pull origin master - -# Pushes (Forces) the changes in the local repository up to the remote repository -echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git" -git push origin master 2>&1 | grep -v 'To https' diff --git a/demos/acm_k8s/acm_service/openapi_server/__init__.py b/demos/acm_k8s/acm_service/openapi_server/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/demos/acm_k8s/acm_service/openapi_server/__main__.py b/demos/acm_k8s/acm_service/openapi_server/__main__.py deleted file mode 100644 index 31ada589..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/__main__.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 - -import connexion - -from openapi_server import encoder - - -def main(): - app = connexion.App(__name__, specification_dir="./openapi/") - app.app.json_encoder = encoder.JSONEncoder - app.add_api( - "openapi.yaml", - arguments={"title": "ACM API for cluster management"}, - pythonic_params=True, - ) - - app.run(port=8080) - - -if __name__ == "__main__": - main() diff --git a/demos/acm_k8s/acm_service/openapi_server/controllers/__init__.py b/demos/acm_k8s/acm_service/openapi_server/controllers/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/demos/acm_k8s/acm_service/openapi_server/controllers/controller.py b/demos/acm_k8s/acm_service/openapi_server/controllers/controller.py deleted file mode 100644 index 5b334a5d..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/controllers/controller.py +++ /dev/null @@ -1,84 +0,0 @@ -import connexion -from typing import Dict -from typing import Tuple -from typing import Union - -from openapi_server.models.managed_cluster import ManagedCluster # noqa: E501 -from openapi_server.models.metadata import Metadata # noqa: E501 -from openapi_server.models.spec import Spec # noqa: E501 -from openapi_server import util - -managed_cluster = { - "test1": ManagedCluster( - "cluster.open-cluster-management.io/v1", - "ManagedCluster", - Metadata("test1"), - Spec(True, None), - "test1 cluster in service", - ), -} - - -def cluster_open_cluster_management_io_v1_managedclusters_cluster_name_delete(): # noqa: E501 - """Delete a single cluster - - # noqa: E501 - - - :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] - """ - return "do some magic!" - - -def create_cluster( - api_version=None, kind=None, metadata=None, spec=None, status=None -): # noqa: E501 - """Create a cluster - - # noqa: E501 - - :param api_version: - :type api_version: str - :param kind: - :type kind: str - :param metadata: - :type metadata: dict | bytes - :param spec: - :type spec: dict | bytes - :param status: - :type status: str - - :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] - """ - if connexion.request.is_json: - metadata = Metadata.from_dict(connexion.request.get_json()) # noqa: E501 - if connexion.request.is_json: - spec = Spec.from_dict(connexion.request.get_json()) # noqa: E501 - return "do some magic!" - - -def get_cluster(cluster_name): # noqa: E501 - """Query a single cluster for more details - - # noqa: E501 - - :param cluster_name: The name of the cluster to retrieve - :type cluster_name: str - - :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] - """ - if cluster_name in managed_cluster: - return managed_cluster[cluster_name] - else: - return "Cluster not found", 404 - - -def list_managed_clusters(): # noqa: E501 - """Query your clusters for more details. - - # noqa: E501 - - - :rtype: Union[List[ManagedCluster], Tuple[List[ManagedCluster], int], Tuple[List[ManagedCluster], int, Dict[str, str]] - """ - return list(managed_cluster.values()) diff --git a/demos/acm_k8s/acm_service/openapi_server/controllers/default_controller.py b/demos/acm_k8s/acm_service/openapi_server/controllers/default_controller.py deleted file mode 100644 index 7984540a..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/controllers/default_controller.py +++ /dev/null @@ -1,88 +0,0 @@ -import connexion -from typing import Dict -from typing import Tuple -from typing import Union - -from openapi_server.models.managed_cluster import ManagedCluster # noqa: E501 -from openapi_server.models.metadata import Metadata # noqa: E501 -from openapi_server.models.spec import Spec # noqa: E501 -from openapi_server import util - -managed_cluster = { - "test1": ManagedCluster( - "cluster.open-cluster-management.io/v1", - "ManagedCluster", - Metadata("test1"), - Spec(True, None), - "test1 cluster in service", - ), -} - - -def cluster_open_cluster_management_io_v1_managedclusters_cluster_name_delete(): # noqa: E501 - """Delete a single cluster - - # noqa: E501 - - - :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] - """ - return "do some magic!" - - -def create_cluster( - api_version=None, kind=None, metadata=None, spec=None, status=None -): # noqa: E501 - """Create a cluster - - # noqa: E501 - - :param api_version: - :type api_version: str - :param kind: - :type kind: str - :param metadata: - :type metadata: dict | bytes - :param spec: - :type spec: dict | bytes - :param status: - :type status: str - - :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] - """ - if connexion.request.is_json: - request_json = connexion.request.get_json() - if "metadata" in request_json: - metadata = Metadata.from_dict(request_json["metadata"]) # noqa: E501 - if "spec" in request_json: - spec = Spec.from_dict(request_json["spec"]) # noqa: E501 - cluster = ManagedCluster(api_version, kind, metadata, spec, status) - managed_cluster[metadata.name] = cluster - return "cluster created", 200 - - -def get_cluster(cluster_name): # noqa: E501 - """Query a single cluster for more details - - # noqa: E501 - - :param cluster_name: The name of the cluster to retrieve - :type cluster_name: str - - :rtype: Union[ManagedCluster, Tuple[ManagedCluster, int], Tuple[ManagedCluster, int, Dict[str, str]] - """ - if cluster_name in managed_cluster: - return managed_cluster[cluster_name] - else: - return "Cluster not found", 404 - - -def list_managed_clusters(): # noqa: E501 - """Query your clusters for more details. - - # noqa: E501 - - - :rtype: Union[List[ManagedCluster], Tuple[List[ManagedCluster], int], Tuple[List[ManagedCluster], int, Dict[str, str]] - """ - return list(managed_cluster.values()) diff --git a/demos/acm_k8s/acm_service/openapi_server/controllers/security_controller.py b/demos/acm_k8s/acm_service/openapi_server/controllers/security_controller.py deleted file mode 100644 index 7d686cba..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/controllers/security_controller.py +++ /dev/null @@ -1 +0,0 @@ -from typing import List diff --git a/demos/acm_k8s/acm_service/openapi_server/encoder.py b/demos/acm_k8s/acm_service/openapi_server/encoder.py deleted file mode 100644 index 60f4fa67..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/encoder.py +++ /dev/null @@ -1,19 +0,0 @@ -from connexion.apps.flask_app import FlaskJSONEncoder - -from openapi_server.models.base_model import Model - - -class JSONEncoder(FlaskJSONEncoder): - include_nulls = False - - def default(self, o): - if isinstance(o, Model): - dikt = {} - for attr in o.openapi_types: - value = getattr(o, attr) - if value is None and not self.include_nulls: - continue - attr = o.attribute_map[attr] - dikt[attr] = value - return dikt - return FlaskJSONEncoder.default(self, o) diff --git a/demos/acm_k8s/acm_service/openapi_server/models/__init__.py b/demos/acm_k8s/acm_service/openapi_server/models/__init__.py deleted file mode 100644 index a4294dbb..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/models/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# flake8: noqa -# import models into model package -from openapi_server.models.managed_cluster import ManagedCluster -from openapi_server.models.managed_cluster_client_config import ( - ManagedClusterClientConfig, -) -from openapi_server.models.metadata import Metadata -from openapi_server.models.spec import Spec diff --git a/demos/acm_k8s/acm_service/openapi_server/models/base_model.py b/demos/acm_k8s/acm_service/openapi_server/models/base_model.py deleted file mode 100644 index c6144bed..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/models/base_model.py +++ /dev/null @@ -1,70 +0,0 @@ -import pprint - -import typing - -from openapi_server import util - -T = typing.TypeVar("T") - - -class Model: - # openapiTypes: The key is attribute name and the - # value is attribute type. - openapi_types: typing.Dict[str, type] = {} - - # attributeMap: The key is attribute name and the - # value is json key in definition. - attribute_map: typing.Dict[str, str] = {} - - @classmethod - def from_dict(cls: typing.Type[T], dikt) -> T: - """Returns the dict as a model""" - return util.deserialize_model(dikt, cls) - - def to_dict(self): - """Returns the model properties as a dict - - :rtype: dict - """ - result = {} - - for attr in self.openapi_types: - value = getattr(self, attr) - if isinstance(value, list): - result[attr] = list( - map(lambda x: x.to_dict() if hasattr(x, "to_dict") else x, value) - ) - elif hasattr(value, "to_dict"): - result[attr] = value.to_dict() - elif isinstance(value, dict): - result[attr] = dict( - map( - lambda item: (item[0], item[1].to_dict()) - if hasattr(item[1], "to_dict") - else item, - value.items(), - ) - ) - else: - result[attr] = value - - return result - - def to_str(self): - """Returns the string representation of the model - - :rtype: str - """ - return pprint.pformat(self.to_dict()) - - def __repr__(self): - """For `print` and `pprint`""" - return self.to_str() - - def __eq__(self, other): - """Returns true if both objects are equal""" - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - """Returns true if both objects are not equal""" - return not self == other diff --git a/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster.py b/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster.py deleted file mode 100644 index be68653d..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster.py +++ /dev/null @@ -1,186 +0,0 @@ -from datetime import date, datetime # noqa: F401 - -from typing import List, Dict # noqa: F401 - -from openapi_server.models.base_model import Model -from openapi_server.models.metadata import Metadata -from openapi_server.models.spec import Spec -from openapi_server import util - -from openapi_server.models.metadata import Metadata # noqa: E501 -from openapi_server.models.spec import Spec # noqa: E501 - - -class ManagedCluster(Model): - """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - - Do not edit the class manually. - """ - - def __init__( - self, api_version=None, kind=None, metadata=None, spec=None, status=None - ): # noqa: E501 - """ManagedCluster - a model defined in OpenAPI - - :param api_version: The api_version of this ManagedCluster. # noqa: E501 - :type api_version: str - :param kind: The kind of this ManagedCluster. # noqa: E501 - :type kind: str - :param metadata: The metadata of this ManagedCluster. # noqa: E501 - :type metadata: Metadata - :param spec: The spec of this ManagedCluster. # noqa: E501 - :type spec: Spec - :param status: The status of this ManagedCluster. # noqa: E501 - :type status: str - """ - self.openapi_types = { - "api_version": str, - "kind": str, - "metadata": Metadata, - "spec": Spec, - "status": str, - } - - self.attribute_map = { - "api_version": "apiVersion", - "kind": "kind", - "metadata": "metadata", - "spec": "spec", - "status": "status", - } - - self._api_version = api_version - self._kind = kind - self._metadata = metadata - self._spec = spec - self._status = status - - @classmethod - def from_dict(cls, dikt) -> "ManagedCluster": - """Returns the dict as a model - - :param dikt: A dict. - :type: dict - :return: The ManagedCluster of this ManagedCluster. # noqa: E501 - :rtype: ManagedCluster - """ - return util.deserialize_model(dikt, cls) - - @property - def api_version(self) -> str: - """Gets the api_version of this ManagedCluster. - - - :return: The api_version of this ManagedCluster. - :rtype: str - """ - return self._api_version - - @api_version.setter - def api_version(self, api_version: str): - """Sets the api_version of this ManagedCluster. - - - :param api_version: The api_version of this ManagedCluster. - :type api_version: str - """ - allowed_values = ["cluster.open-cluster-management.io/v1"] # noqa: E501 - if api_version not in allowed_values: - raise ValueError( - "Invalid value for `api_version` ({0}), must be one of {1}".format( - api_version, allowed_values - ) - ) - - self._api_version = api_version - - @property - def kind(self) -> str: - """Gets the kind of this ManagedCluster. - - - :return: The kind of this ManagedCluster. - :rtype: str - """ - return self._kind - - @kind.setter - def kind(self, kind: str): - """Sets the kind of this ManagedCluster. - - - :param kind: The kind of this ManagedCluster. - :type kind: str - """ - allowed_values = ["ManagedCluster"] # noqa: E501 - if kind not in allowed_values: - raise ValueError( - "Invalid value for `kind` ({0}), must be one of {1}".format( - kind, allowed_values - ) - ) - - self._kind = kind - - @property - def metadata(self) -> Metadata: - """Gets the metadata of this ManagedCluster. - - - :return: The metadata of this ManagedCluster. - :rtype: Metadata - """ - return self._metadata - - @metadata.setter - def metadata(self, metadata: Metadata): - """Sets the metadata of this ManagedCluster. - - - :param metadata: The metadata of this ManagedCluster. - :type metadata: Metadata - """ - - self._metadata = metadata - - @property - def spec(self) -> Spec: - """Gets the spec of this ManagedCluster. - - - :return: The spec of this ManagedCluster. - :rtype: Spec - """ - return self._spec - - @spec.setter - def spec(self, spec: Spec): - """Sets the spec of this ManagedCluster. - - - :param spec: The spec of this ManagedCluster. - :type spec: Spec - """ - - self._spec = spec - - @property - def status(self) -> str: - """Gets the status of this ManagedCluster. - - - :return: The status of this ManagedCluster. - :rtype: str - """ - return self._status - - @status.setter - def status(self, status: str): - """Sets the status of this ManagedCluster. - - - :param status: The status of this ManagedCluster. - :type status: str - """ - - self._status = status diff --git a/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster_client_config.py b/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster_client_config.py deleted file mode 100644 index bf362e05..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/models/managed_cluster_client_config.py +++ /dev/null @@ -1,81 +0,0 @@ -from datetime import date, datetime # noqa: F401 - -from typing import List, Dict # noqa: F401 - -from openapi_server.models.base_model import Model -from openapi_server import util - - -class ManagedClusterClientConfig(Model): - """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - - Do not edit the class manually. - """ - - def __init__(self, url=None, ca_bundle=None): # noqa: E501 - """ManagedClusterClientConfig - a model defined in OpenAPI - - :param url: The url of this ManagedClusterClientConfig. # noqa: E501 - :type url: str - :param ca_bundle: The ca_bundle of this ManagedClusterClientConfig. # noqa: E501 - :type ca_bundle: str - """ - self.openapi_types = {"url": str, "ca_bundle": str} - - self.attribute_map = {"url": "url", "ca_bundle": "caBundle"} - - self._url = url - self._ca_bundle = ca_bundle - - @classmethod - def from_dict(cls, dikt) -> "ManagedClusterClientConfig": - """Returns the dict as a model - - :param dikt: A dict. - :type: dict - :return: The ManagedClusterClientConfig of this ManagedClusterClientConfig. # noqa: E501 - :rtype: ManagedClusterClientConfig - """ - return util.deserialize_model(dikt, cls) - - @property - def url(self) -> str: - """Gets the url of this ManagedClusterClientConfig. - - - :return: The url of this ManagedClusterClientConfig. - :rtype: str - """ - return self._url - - @url.setter - def url(self, url: str): - """Sets the url of this ManagedClusterClientConfig. - - - :param url: The url of this ManagedClusterClientConfig. - :type url: str - """ - - self._url = url - - @property - def ca_bundle(self) -> str: - """Gets the ca_bundle of this ManagedClusterClientConfig. - - - :return: The ca_bundle of this ManagedClusterClientConfig. - :rtype: str - """ - return self._ca_bundle - - @ca_bundle.setter - def ca_bundle(self, ca_bundle: str): - """Sets the ca_bundle of this ManagedClusterClientConfig. - - - :param ca_bundle: The ca_bundle of this ManagedClusterClientConfig. - :type ca_bundle: str - """ - - self._ca_bundle = ca_bundle diff --git a/demos/acm_k8s/acm_service/openapi_server/models/metadata.py b/demos/acm_k8s/acm_service/openapi_server/models/metadata.py deleted file mode 100644 index a2833d6f..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/models/metadata.py +++ /dev/null @@ -1,81 +0,0 @@ -from datetime import date, datetime # noqa: F401 - -from typing import List, Dict # noqa: F401 - -from openapi_server.models.base_model import Model -from openapi_server import util - - -class Metadata(Model): - """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - - Do not edit the class manually. - """ - - def __init__(self, name=None, labels=None): # noqa: E501 - """Metadata - a model defined in OpenAPI - - :param name: The name of this Metadata. # noqa: E501 - :type name: str - :param labels: The labels of this Metadata. # noqa: E501 - :type labels: Dict[str, str] - """ - self.openapi_types = {"name": str, "labels": Dict[str, str]} - - self.attribute_map = {"name": "name", "labels": "labels"} - - self._name = name - self._labels = labels - - @classmethod - def from_dict(cls, dikt) -> "Metadata": - """Returns the dict as a model - - :param dikt: A dict. - :type: dict - :return: The Metadata of this Metadata. # noqa: E501 - :rtype: Metadata - """ - return util.deserialize_model(dikt, cls) - - @property - def name(self) -> str: - """Gets the name of this Metadata. - - - :return: The name of this Metadata. - :rtype: str - """ - return self._name - - @name.setter - def name(self, name: str): - """Sets the name of this Metadata. - - - :param name: The name of this Metadata. - :type name: str - """ - - self._name = name - - @property - def labels(self) -> Dict[str, str]: - """Gets the labels of this Metadata. - - - :return: The labels of this Metadata. - :rtype: Dict[str, str] - """ - return self._labels - - @labels.setter - def labels(self, labels: Dict[str, str]): - """Sets the labels of this Metadata. - - - :param labels: The labels of this Metadata. - :type labels: Dict[str, str] - """ - - self._labels = labels diff --git a/demos/acm_k8s/acm_service/openapi_server/models/spec.py b/demos/acm_k8s/acm_service/openapi_server/models/spec.py deleted file mode 100644 index b319c461..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/models/spec.py +++ /dev/null @@ -1,98 +0,0 @@ -from datetime import date, datetime # noqa: F401 - -from typing import List, Dict # noqa: F401 - -from openapi_server.models.base_model import Model -from openapi_server.models.managed_cluster_client_config import ( - ManagedClusterClientConfig, -) -from openapi_server import util - -from openapi_server.models.managed_cluster_client_config import ( - ManagedClusterClientConfig, -) # noqa: E501 - - -class Spec(Model): - """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - - Do not edit the class manually. - """ - - def __init__( - self, hub_accepts_client=None, managed_cluster_client_configs=None - ): # noqa: E501 - """Spec - a model defined in OpenAPI - - :param hub_accepts_client: The hub_accepts_client of this Spec. # noqa: E501 - :type hub_accepts_client: bool - :param managed_cluster_client_configs: The managed_cluster_client_configs of this Spec. # noqa: E501 - :type managed_cluster_client_configs: List[ManagedClusterClientConfig] - """ - self.openapi_types = { - "hub_accepts_client": bool, - "managed_cluster_client_configs": List[ManagedClusterClientConfig], - } - - self.attribute_map = { - "hub_accepts_client": "hubAcceptsClient", - "managed_cluster_client_configs": "managedClusterClientConfigs", - } - - self._hub_accepts_client = hub_accepts_client - self._managed_cluster_client_configs = managed_cluster_client_configs - - @classmethod - def from_dict(cls, dikt) -> "Spec": - """Returns the dict as a model - - :param dikt: A dict. - :type: dict - :return: The Spec of this Spec. # noqa: E501 - :rtype: Spec - """ - return util.deserialize_model(dikt, cls) - - @property - def hub_accepts_client(self) -> bool: - """Gets the hub_accepts_client of this Spec. - - - :return: The hub_accepts_client of this Spec. - :rtype: bool - """ - return self._hub_accepts_client - - @hub_accepts_client.setter - def hub_accepts_client(self, hub_accepts_client: bool): - """Sets the hub_accepts_client of this Spec. - - - :param hub_accepts_client: The hub_accepts_client of this Spec. - :type hub_accepts_client: bool - """ - - self._hub_accepts_client = hub_accepts_client - - @property - def managed_cluster_client_configs(self) -> List[ManagedClusterClientConfig]: - """Gets the managed_cluster_client_configs of this Spec. - - - :return: The managed_cluster_client_configs of this Spec. - :rtype: List[ManagedClusterClientConfig] - """ - return self._managed_cluster_client_configs - - @managed_cluster_client_configs.setter - def managed_cluster_client_configs( - self, managed_cluster_client_configs: List[ManagedClusterClientConfig] - ): - """Sets the managed_cluster_client_configs of this Spec. - - - :param managed_cluster_client_configs: The managed_cluster_client_configs of this Spec. - :type managed_cluster_client_configs: List[ManagedClusterClientConfig] - """ - - self._managed_cluster_client_configs = managed_cluster_client_configs diff --git a/demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml b/demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml deleted file mode 100644 index 46503e9c..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/openapi/openapi.yaml +++ /dev/null @@ -1,163 +0,0 @@ -openapi: 3.0.0 -info: - contact: - email: support@katanemo.com - name: Katanemo Labs Inc. - url: https://katanemo.com - description: This is the API for managing clusters using ACM - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags - title: ACM API for cluster management - version: 2.12.0 -servers: -- url: / -paths: - /cluster.open-cluster-management.io/v1/managedclusters: - get: - operationId: list_managed_clusters - responses: - "200": - content: - application/json: - schema: - items: - $ref: '#/components/schemas/ManagedCluster' - type: array - description: List of managed clusters - summary: Query your clusters for more details. - x-openapi-router-controller: openapi_server.controllers.default_controller - post: - operationId: create_cluster - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ManagedCluster' - description: "Details about the service, including the text-representation\ - \ of the service APIs." - required: true - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/ManagedCluster' - description: cluster created successfully - summary: Create a cluster - x-openapi-router-controller: openapi_server.controllers.default_controller - /cluster.open-cluster-management.io/v1/managedclusters/{cluster_name}: - delete: - operationId: cluster_open_cluster_management_io_v1_managedclusters_cluster_name_delete - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/ManagedCluster' - description: Cluster details - summary: Delete a single cluster - x-openapi-router-controller: openapi_server.controllers.default_controller - get: - operationId: get_cluster - parameters: - - description: The name of the cluster to retrieve - explode: false - in: path - name: cluster_name - required: true - schema: - type: string - style: simple - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/ManagedCluster' - description: Cluster details - summary: Query a single cluster for more details - x-openapi-router-controller: openapi_server.controllers.default_controller -components: - schemas: - ManagedCluster: - example: - metadata: - name: name - labels: - key: labels - apiVersion: cluster.open-cluster-management.io/v1 - kind: ManagedCluster - spec: - hubAcceptsClient: true - managedClusterClientConfigs: - - caBundle: caBundle - url: url - - caBundle: caBundle - url: url - status: status - properties: - apiVersion: - enum: - - cluster.open-cluster-management.io/v1 - title: apiVersion - type: string - kind: - enum: - - ManagedCluster - title: kind - type: string - metadata: - $ref: '#/components/schemas/Metadata' - spec: - $ref: '#/components/schemas/Spec' - status: - title: status - type: string - title: managed cluster details - type: object - Metadata: - example: - name: name - labels: - key: labels - properties: - name: - title: name - type: string - labels: - additionalProperties: - type: string - title: labels - type: object - title: metadata details - type: object - Spec: - example: - hubAcceptsClient: true - managedClusterClientConfigs: - - caBundle: caBundle - url: url - - caBundle: caBundle - url: url - properties: - hubAcceptsClient: - title: hubAcceptsClient - type: boolean - managedClusterClientConfigs: - items: - $ref: '#/components/schemas/ManagedClusterClientConfig' - title: managedClusterClientConfigs - type: array - title: spec details - type: object - ManagedClusterClientConfig: - example: - caBundle: caBundle - url: url - properties: - url: - title: url - type: string - caBundle: - title: caBundle - type: string - title: managed cluster client config details - type: object diff --git a/demos/acm_k8s/acm_service/openapi_server/test/__init__.py b/demos/acm_k8s/acm_service/openapi_server/test/__init__.py deleted file mode 100644 index aefd85c2..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/test/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -import logging - -import connexion -from flask_testing import TestCase - -from openapi_server.encoder import JSONEncoder - - -class BaseTestCase(TestCase): - def create_app(self): - logging.getLogger("connexion.operation").setLevel("ERROR") - app = connexion.App(__name__, specification_dir="../openapi/") - app.app.json_encoder = JSONEncoder - app.add_api("openapi.yaml", pythonic_params=True) - return app.app diff --git a/demos/acm_k8s/acm_service/openapi_server/test/test_default_controller.py b/demos/acm_k8s/acm_service/openapi_server/test/test_default_controller.py deleted file mode 100644 index 2a669114..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/test/test_default_controller.py +++ /dev/null @@ -1,89 +0,0 @@ -import unittest - -from flask import json - -from openapi_server.models.managed_cluster import ManagedCluster # noqa: E501 -from openapi_server.models.metadata import Metadata # noqa: E501 -from openapi_server.models.spec import Spec # noqa: E501 -from openapi_server.test import BaseTestCase - - -class TestDefaultController(BaseTestCase): - """DefaultController integration test stubs""" - - def test_cluster_open_cluster_management_io_v1_managedclusters_cluster_name_delete( - self, - ): - """Test case for cluster_open_cluster_management_io_v1_managedclusters_cluster_name_delete - - Delete a single cluster - """ - headers = { - "Accept": "application/json", - } - response = self.client.open( - "/cluster.open-cluster-management.io/v1/managedclusters/{cluster_name}", - method="DELETE", - headers=headers, - ) - self.assert200(response, "Response body is : " + response.data.decode("utf-8")) - - @unittest.skip("multipart/form-data not supported by Connexion") - def test_create_cluster(self): - """Test case for create_cluster - - Create a cluster - """ - headers = { - "Accept": "application/json", - "Content-Type": "multipart/form-data", - } - data = dict( - api_version="api_version_example", - kind="kind_example", - metadata=openapi_server.Metadata(), - spec=openapi_server.Spec(), - status="status_example", - ) - response = self.client.open( - "/cluster.open-cluster-management.io/v1/managedclusters", - method="POST", - headers=headers, - data=data, - content_type="multipart/form-data", - ) - self.assert200(response, "Response body is : " + response.data.decode("utf-8")) - - def test_get_cluster(self): - """Test case for get_cluster - - Query a single cluster for more details - """ - headers = { - "Accept": "application/json", - } - response = self.client.open( - "/cluster.open-cluster-management.io/v1/managedclusters/{cluster_name}", - method="GET", - headers=headers, - ) - self.assert200(response, "Response body is : " + response.data.decode("utf-8")) - - def test_list_managed_clusters(self): - """Test case for list_managed_clusters - - Query your clusters for more details. - """ - headers = { - "Accept": "application/json", - } - response = self.client.open( - "/cluster.open-cluster-management.io/v1/managedclusters", - method="GET", - headers=headers, - ) - self.assert200(response, "Response body is : " + response.data.decode("utf-8")) - - -if __name__ == "__main__": - unittest.main() diff --git a/demos/acm_k8s/acm_service/openapi_server/typing_utils.py b/demos/acm_k8s/acm_service/openapi_server/typing_utils.py deleted file mode 100644 index c905b1db..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/typing_utils.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys - -if sys.version_info < (3, 7): - import typing - - def is_generic(klass): - """Determine whether klass is a generic class""" - return type(klass) == typing.GenericMeta - - def is_dict(klass): - """Determine whether klass is a Dict""" - return klass.__extra__ == dict - - def is_list(klass): - """Determine whether klass is a List""" - return klass.__extra__ == list - -else: - - def is_generic(klass): - """Determine whether klass is a generic class""" - return hasattr(klass, "__origin__") - - def is_dict(klass): - """Determine whether klass is a Dict""" - return klass.__origin__ == dict - - def is_list(klass): - """Determine whether klass is a List""" - return klass.__origin__ == list diff --git a/demos/acm_k8s/acm_service/openapi_server/util.py b/demos/acm_k8s/acm_service/openapi_server/util.py deleted file mode 100644 index 182c4085..00000000 --- a/demos/acm_k8s/acm_service/openapi_server/util.py +++ /dev/null @@ -1,149 +0,0 @@ -import datetime - -import typing -from openapi_server import typing_utils - - -def _deserialize(data, klass): - """Deserializes dict, list, str into an object. - - :param data: dict, list or str. - :param klass: class literal, or string of class name. - - :return: object. - """ - if data is None: - return None - - if klass in (int, float, str, bool, bytearray): - return _deserialize_primitive(data, klass) - elif klass == object: - return _deserialize_object(data) - elif klass == datetime.date: - return deserialize_date(data) - elif klass == datetime.datetime: - return deserialize_datetime(data) - elif typing_utils.is_generic(klass): - if typing_utils.is_list(klass): - return _deserialize_list(data, klass.__args__[0]) - if typing_utils.is_dict(klass): - return _deserialize_dict(data, klass.__args__[1]) - else: - return deserialize_model(data, klass) - - -def _deserialize_primitive(data, klass): - """Deserializes to primitive type. - - :param data: data to deserialize. - :param klass: class literal. - - :return: int, long, float, str, bool. - :rtype: int | long | float | str | bool - """ - try: - value = klass(data) - except UnicodeEncodeError: - value = data - except TypeError: - value = data - return value - - -def _deserialize_object(value): - """Return an original value. - - :return: object. - """ - return value - - -def deserialize_date(string): - """Deserializes string to date. - - :param string: str. - :type string: str - :return: date. - :rtype: date - """ - if string is None: - return None - - try: - from dateutil.parser import parse - - return parse(string).date() - except ImportError: - return string - - -def deserialize_datetime(string): - """Deserializes string to datetime. - - The string should be in iso8601 datetime format. - - :param string: str. - :type string: str - :return: datetime. - :rtype: datetime - """ - if string is None: - return None - - try: - from dateutil.parser import parse - - return parse(string) - except ImportError: - return string - - -def deserialize_model(data, klass): - """Deserializes list or dict to model. - - :param data: dict, list. - :type data: dict | list - :param klass: class literal. - :return: model object. - """ - instance = klass() - - if not instance.openapi_types: - return data - - for attr, attr_type in instance.openapi_types.items(): - if ( - data is not None - and instance.attribute_map[attr] in data - and isinstance(data, (list, dict)) - ): - value = data[instance.attribute_map[attr]] - setattr(instance, attr, _deserialize(value, attr_type)) - - return instance - - -def _deserialize_list(data, boxed_type): - """Deserializes a list and its elements. - - :param data: list to deserialize. - :type data: list - :param boxed_type: class literal. - - :return: deserialized list. - :rtype: list - """ - return [_deserialize(sub_data, boxed_type) for sub_data in data] - - -def _deserialize_dict(data, boxed_type): - """Deserializes a dict and its elements. - - :param data: dict to deserialize. - :type data: dict - :param boxed_type: class literal. - - :return: deserialized dict. - :rtype: dict - """ - return {k: _deserialize(v, boxed_type) for k, v in data.items()} diff --git a/demos/acm_k8s/acm_service/requirements.txt b/demos/acm_k8s/acm_service/requirements.txt deleted file mode 100644 index 2cb06891..00000000 --- a/demos/acm_k8s/acm_service/requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -connexion[swagger-ui] >= 2.6.0; python_version>="3.6" -# 2.3 is the last version that supports python 3.4-3.5 -connexion[swagger-ui] <= 2.3.0; python_version=="3.5" or python_version=="3.4" -# prevent breaking dependencies from advent of connexion>=3.0 -connexion[swagger-ui] <= 2.14.2; python_version>"3.4" -# connexion requires werkzeug but connexion < 2.4.0 does not install werkzeug -# we must peg werkzeug versions below to fix connexion -# https://github.com/zalando/connexion/pull/1044 -werkzeug == 0.16.1; python_version=="3.5" or python_version=="3.4" -swagger-ui-bundle >= 0.0.2 -python_dateutil >= 2.6.0 -setuptools >= 21.0.0 -Flask == 2.1.1 diff --git a/demos/acm_k8s/acm_service/setup.py b/demos/acm_k8s/acm_service/setup.py deleted file mode 100644 index 36741ffd..00000000 --- a/demos/acm_k8s/acm_service/setup.py +++ /dev/null @@ -1,31 +0,0 @@ -import sys -from setuptools import setup, find_packages - -NAME = "openapi_server" -VERSION = "1.0.0" - -# To install the library, run the following -# -# python setup.py install -# -# prerequisite: setuptools -# http://pypi.python.org/pypi/setuptools - -REQUIRES = ["connexion>=2.0.2", "swagger-ui-bundle>=0.0.2", "python_dateutil>=2.6.0"] - -setup( - name=NAME, - version=VERSION, - description="ACM API for cluster management", - author_email="support@katanemo.com", - url="", - keywords=["OpenAPI", "ACM API for cluster management"], - install_requires=REQUIRES, - packages=find_packages(), - package_data={"": ["openapi/openapi.yaml"]}, - include_package_data=True, - entry_points={"console_scripts": ["openapi_server=openapi_server.__main__:main"]}, - long_description="""\ - This is the API for managing clusters using ACM - https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_management_for_kubernetes/2.12/html/apis/apis#tags - """, -) diff --git a/demos/acm_k8s/acm_service/test-requirements.txt b/demos/acm_k8s/acm_service/test-requirements.txt deleted file mode 100644 index 58f51d6a..00000000 --- a/demos/acm_k8s/acm_service/test-requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -pytest~=7.1.0 -pytest-cov>=2.8.1 -pytest-randomly>=1.2.3 -Flask-Testing==0.8.1 diff --git a/demos/acm_k8s/acm_service/tox.ini b/demos/acm_k8s/acm_service/tox.ini deleted file mode 100644 index 7663dfb6..00000000 --- a/demos/acm_k8s/acm_service/tox.ini +++ /dev/null @@ -1,11 +0,0 @@ -[tox] -envlist = py3 -skipsdist=True - -[testenv] -deps=-r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt - {toxinidir} - -commands= - pytest --cov=openapi_server diff --git a/demos/acm_k8s/arch_config.yaml b/demos/acm_k8s/arch_config.yaml deleted file mode 100644 index cdfd6bee..00000000 --- a/demos/acm_k8s/arch_config.yaml +++ /dev/null @@ -1,95 +0,0 @@ -version: "0.1-beta" - -listener: - address: 0.0.0.0 - port: 10000 - message_format: huggingface - connect_timeout: 0.005s - -overrides: - # confidence threshold for prompt target intent matching - prompt_target_intent_matching_threshold: 0.6 - -endpoints: - acm_service: - endpoint: host.docker.internal:18083 - connect_timeout: 0.005s - -llm_providers: - - name: gpt-4o-mini - access_key: $OPENAI_API_KEY - provider: openai - model: gpt-4o-mini - default: true - - - name: gpt-3.5-turbo-0125 - access_key: $OPENAI_API_KEY - provider: openai - model: gpt-3.5-turbo-0125 - - - name: gpt-4o - access_key: $OPENAI_API_KEY - provider: openai - model: gpt-4o - -system_prompt: | - You are a helpful assistant. - -prompt_guards: - input_guards: - jailbreak: - on_exception: - message: Looks like you're curious about my abilities, but I can only provide assistance for weather forecasting. - -prompt_targets: - - name: listAllClusterDetails - description: Query your clusters for more details. - http_method: GET - endpoint: - name: acm_service - path: /cluster.open-cluster-management.io/v1/managedclusters - - - name: getClusterDetails - description: Query a single cluster for more details - http_method: GET - endpoint: - name: acm_service - path: /cluster.open-cluster-management.io/v1/managedclusters/{cluster_name} - parameters: - - name: cluster_name - in_path: true - description: The name of the cluster to retrieve - required: true - type: str - - - name: default_target - default: true - description: This is the default target for all unmatched prompts. - system_prompt: | - You are a helpful assistant that can help answer ACM queries. Following is a list of available commands user can ask. Based on question asked, tell me which command you want to execute. - - - name: listAllClusterDetails - description: Query your clusters for more details. - http_method: GET - endpoint: - name: acm_service - path: /cluster.open-cluster-management.io/v1/managedclusters - - - name: getClusterDetails - description: Query a single cluster for more details - http_method: GET - endpoint: - name: acm_service - path: /cluster.open-cluster-management.io/v1/managedclusters/{cluster_name} - parameters: - - name: cluster_name - in_path: true - description: The name of the cluster to retrieve - required: true - type: str - - auto_llm_dispatch_on_response: true - -tracing: - random_sampling: 100 - trace_arch_internal: true diff --git a/demos/acm_k8s/docker-compose.yaml b/demos/acm_k8s/docker-compose.yaml deleted file mode 100644 index 21884159..00000000 --- a/demos/acm_k8s/docker-compose.yaml +++ /dev/null @@ -1,31 +0,0 @@ -services: - acm_service: - build: - context: acm_service/ - environment: - - OLTP_HOST=http://jaeger:4317 - extra_hosts: - - "host.docker.internal:host-gateway" - ports: - - "18083:8080" - - chatbot_ui: - build: - context: ../shared/chatbot_ui - ports: - - "18080:8080" - environment: - # this is only because we are running the sample app in the same docker container environemtn as archgw - - CHAT_COMPLETION_ENDPOINT=http://host.docker.internal:10000/v1 - extra_hosts: - - "host.docker.internal:host-gateway" - volumes: - - ./arch_config.yaml:/app/arch_config.yaml - - jaeger: - build: - context: ../shared/jaeger - ports: - - "16686:16686" - - "4317:4317" - - "4318:4318" diff --git a/demos/acm_k8s/generate_acm_service_stub.sh b/demos/acm_k8s/generate_acm_service_stub.sh deleted file mode 100644 index 2dedf44c..00000000 --- a/demos/acm_k8s/generate_acm_service_stub.sh +++ /dev/null @@ -1,5 +0,0 @@ -docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:latest generate \ - --skip-validate-spec \ - -i /local/acm_api.yaml \ - -g python-flask \ - -o /local/acm_service \ diff --git a/demos/acm_k8s/petstore.yml b/demos/acm_k8s/petstore.yml deleted file mode 100644 index 853db5e2..00000000 --- a/demos/acm_k8s/petstore.yml +++ /dev/null @@ -1,1206 +0,0 @@ -openapi: 3.0.0 -servers: - - url: 'http://petstore.swagger.io/v2' -info: - description: >- - This is a sample server Petstore server. For this sample, you can use the api key - `special-key` to test the authorization filters. - version: 1.0.0 - title: OpenAPI Petstore - license: - name: Apache-2.0 - url: 'https://www.apache.org/licenses/LICENSE-2.0.html' -tags: - - name: pet - description: Everything about your Pets - - name: store - description: Access to Petstore orders - - name: user - description: Operations about user -paths: - /pet: - post: - tags: - - pet - summary: Add a new pet to the store - description: '' - operationId: addPet - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/json: - schema: - $ref: '#/components/schemas/Pet' - '405': - description: Invalid input - security: - - http_auth: [] - requestBody: - $ref: '#/components/requestBodies/Pet' - put: - tags: - - pet - summary: Update an existing pet - description: '' - operationId: updatePet - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/json: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid ID supplied - '404': - description: Pet not found - '405': - description: Validation exception - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - requestBody: - $ref: '#/components/requestBodies/Pet' - /pet/findByStatus: - get: - tags: - - pet - summary: Finds Pets by status - description: Multiple status values can be provided with comma separated strings - operationId: findPetsByStatus - parameters: - - name: status - in: query - description: Status values that need to be considered for filter - required: true - style: form - explode: true # change to true for testing purpose - deprecated: true - schema: - type: array - items: - type: string - enum: - - available - - pending - - sold - default: available - responses: - '200': - description: successful operation - content: - application/xml: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid status value - security: - - petstore_auth: - - 'read:pets' - /pet/findByTags: - get: - tags: - - pet - summary: Finds Pets by tags - description: >- - Multiple tags can be provided with comma separated strings. Use tag1, - tag2, tag3 for testing. - operationId: findPetsByTags - parameters: - - name: tags - in: query - description: Tags to filter by - required: true - style: form - explode: false - schema: - type: array - items: - type: string - responses: - '200': - description: successful operation - content: - application/xml: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid tag value - # comment out for testing purpose - #security: - # - petstore_auth: - # - 'read:pets' - deprecated: true - '/pet/{petId}': - get: - tags: - - pet - summary: Find pet by ID - description: Returns a single pet - operationId: getPetById - parameters: - - name: petId - in: path - description: ID of pet to return - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/json: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid ID supplied - '404': - description: Pet not found - security: - - BearerToken: [] - post: - tags: - - pet - summary: Updates a pet in the store with form data - description: '' - operationId: updatePetWithForm - parameters: - - name: petId - in: path - description: ID of pet that needs to be updated - required: true - schema: - type: integer - format: int64 - responses: - '405': - description: Invalid input - #security: - # - petstore_auth: - # - 'write:pets' - # - 'read:pets' - requestBody: - content: - application/x-www-form-urlencoded: - schema: - type: object - properties: - name: - description: Updated name of the pet - type: string - status: - description: Updated status of the pet - type: string - delete: - tags: - - pet - summary: Deletes a pet - description: '' - operationId: deletePet - parameters: - - name: api_key - in: header - required: false - schema: - type: string - - name: petId - in: path - description: Pet id to delete - required: true - schema: - type: integer - format: int64 - responses: - '400': - description: Invalid pet value - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - '/pet_header_test': - get: - tags: - - pet - summary: Header test - description: Header test - operationId: test_header - x-streaming: true - parameters: - - name: header_test_int - in: header - description: header test int - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/json: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid ID supplied - '404': - description: Pet not found - security: - - api_key: [] - '/pet/{petId}?streaming': - get: - tags: - - pet - summary: Find pet by ID (streaming) - description: Returns a single pet - operationId: getPetByIdStreaming - x-streaming: true - parameters: - - name: petId - in: path - description: ID of pet to return - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/json: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid ID supplied - '404': - description: Pet not found - security: - - api_key: [] - '/pet/{petId}/uploadImage': - post: - tags: - - pet - summary: uploads an image - description: '' - operationId: uploadFile - parameters: - - name: petId - in: path - description: ID of pet to update - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/ApiResponse' - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - requestBody: - content: - multipart/form-data: - schema: - type: object - properties: - additionalMetadata: - description: Additional data to pass to server - type: string - file: - description: file to upload - type: string - format: binary - /store/inventory: - get: - tags: - - store - summary: Returns pet inventories by status - description: Returns a map of status codes to quantities - operationId: getInventory - responses: - '200': - description: successful operation - content: - application/json: - schema: - type: object - additionalProperties: - type: integer - format: int32 - security: - - api_key: [] - /store/order: - post: - tags: - - store - summary: Place an order for a pet - description: '' - operationId: placeOrder - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Order' - application/json: - schema: - $ref: '#/components/schemas/Order' - '400': - description: Invalid Order - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - description: order placed for purchasing the pet - required: true - '/store/order/{orderId}': - get: - tags: - - store - summary: Find purchase order by ID - description: >- - For valid response try integer IDs with value <= 5 or > 10. Other values - will generate exceptions - operationId: getOrderById - parameters: - - name: orderId - in: path - description: ID of pet that needs to be fetched - required: true - schema: - type: integer - format: int64 - minimum: 1 - maximum: 5 - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Order' - application/json: - schema: - $ref: '#/components/schemas/Order' - '400': - description: Invalid ID supplied - '404': - description: Order not found - delete: - tags: - - store - summary: Delete purchase order by ID - description: >- - For valid response try integer IDs with value < 1000. Anything above - 1000 or nonintegers will generate API errors - operationId: deleteOrder - parameters: - - name: orderId - in: path - description: ID of the order that needs to be deleted - required: true - schema: - type: string - responses: - '400': - description: Invalid ID supplied - '404': - description: Order not found - /user: - post: - tags: - - user - summary: Create user - description: This can only be done by the logged in user. - operationId: createUser - responses: - default: - description: successful operation - security: - - api_key: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/User' - description: Created user object - required: true - /user/createWithArray: - post: - tags: - - user - summary: Creates list of users with given input array - description: '' - operationId: createUsersWithArrayInput - responses: - default: - description: successful operation - security: - - api_key: [] - requestBody: - $ref: '#/components/requestBodies/UserArray' - /user/createWithList: - post: - tags: - - user - summary: Creates list of users with given input array - description: '' - operationId: createUsersWithListInput - responses: - default: - description: successful operation - security: - - api_key: [] - requestBody: - $ref: '#/components/requestBodies/UserArray' - /user/login: - get: - tags: - - user - summary: Logs user into the system - description: '' - operationId: loginUser - parameters: - - name: username - in: query - description: The user name for login - required: true - schema: - type: string - pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$' - - name: password - in: query - description: The password for login in clear text - required: true - schema: - type: string - responses: - '200': - description: successful operation - headers: - Set-Cookie: - description: >- - Cookie authentication key for use with the `api_key` - apiKey authentication. - schema: - type: string - example: AUTH_KEY=abcde12345; Path=/; HttpOnly - X-Rate-Limit: - description: calls per hour allowed by the user - schema: - type: integer - format: int32 - X-Expires-After: - description: date in UTC when token expires - schema: - type: string - format: date-time - content: - application/xml: - schema: - type: string - application/json: - schema: - type: string - '400': - description: Invalid username/password supplied - /user/logout: - get: - tags: - - user - summary: Logs out current logged in user session - description: '' - operationId: logoutUser - responses: - default: - description: successful operation - security: - - api_key: [] - '/user/{username}': - get: - tags: - - user - summary: Get user by user name - description: '' - operationId: getUserByName - parameters: - - name: username - in: path - description: The name that needs to be fetched. Use user1 for testing. - required: true - schema: - type: string - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/User' - application/json: - schema: - $ref: '#/components/schemas/User' - '400': - description: Invalid username supplied - '404': - description: User not found - put: - tags: - - user - summary: Updated user - description: This can only be done by the logged in user. - operationId: updateUser - parameters: - - name: username - in: path - description: name that need to be deleted - required: true - schema: - type: string - responses: - '400': - description: Invalid user supplied - '404': - description: User not found - security: - - api_key: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/User' - description: Updated user object - required: true - delete: - tags: - - user - summary: Delete user - description: This can only be done by the logged in user. - operationId: deleteUser - parameters: - - name: username - in: path - description: The name that needs to be deleted - required: true - schema: - type: string - responses: - '400': - description: Invalid username supplied - '404': - description: User not found - security: - - api_key: [] - /fake/path_array/{path_array}/testing: - get: - tags: - - fake - summary: test array parameter in path - description: '' - operationId: fake_path_array - parameters: - - name: path_array - in: path - description: dummy path parameter - required: true - schema: - type: array - items: - type: string - responses: - '200': - description: successful operation - /fake/regular_expression: - get: - tags: - - fake - summary: test regular expression to ensure no exception - description: '' - operationId: fake_regular-expression - parameters: - - name: reg_exp_test - in: header - description: dummy required parameter - required: true - schema: - type: string - pattern: /^[A-Za-z0-9_]{1,15}$/ - responses: - '200': - description: successful operation - /fake/data_file: - get: - tags: - - fake - summary: test data_file to ensure it's escaped correctly - description: '' - operationId: fake_data_file - parameters: - - name: dummy - in: header - description: dummy required parameter - required: true - schema: - type: string - - name: data_file - in: header - description: header data file - required: false - schema: - type: string - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/User' - application/json: - schema: - $ref: '#/components/schemas/User' - /fake/set_query_parameter: - get: - tags: - - fake - summary: test set query parameter - description: '' - operationId: fake_set_query - parameters: - - name: set_dummy - in: query - description: set query - required: true - schema: - type: array - uniqueItems: true - items: - type: string - - name: array_dummy - in: query - description: array query - required: true - schema: - type: array - uniqueItems: false - items: - type: string - responses: - '200': - description: successful operation - /fake/test_optional_body_parameter: - post: - tags: - - fake - summary: Add a new pet to the store (optional body) - description: '' - operationId: addPetOptional - responses: - '200': - description: successful operation - content: - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/json: - schema: - $ref: '#/components/schemas/Pet' - '405': - description: Invalid input - security: - - http_auth: [] - requestBody: - $ref: '#/components/requestBodies/OptionalPet' -externalDocs: - description: Find out more about Swagger - url: 'http://swagger.io' -components: - requestBodies: - UserArray: - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/User' - description: List of user object - required: true - Pet: - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - multipart/related: # message with binary body part - schema: - type: object - properties: # Request parts - jsonData: - $ref: '#/components/schemas/Pet' - binaryDataN2Information: - type: string - format: binary - encoding: - jsonData: - contentType: application/json - binaryDataN2Information: - contentType: application/vnd.3gpp.ngap - headers: - Content-Id: - schema: - type: string - description: Pet object that needs to be added to the store - required: true - OptionalPet: - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - multipart/related: # message with binary body part - schema: - type: object - properties: # Request parts - jsonData: - $ref: '#/components/schemas/Pet' - binaryDataN2Information: - type: string - format: binary - encoding: - jsonData: - contentType: application/json - binaryDataN2Information: - contentType: application/vnd.3gpp.ngap - headers: - Content-Id: - schema: - type: string - description: Pet object that needs to be added to the store - required: false - securitySchemes: - http_auth: - type : http - scheme : basic - BearerToken: - type : http - scheme : bearer - petstore_auth: - type: oauth2 - flows: - implicit: - authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog' - scopes: - 'write:pets': modify pets in your account - 'read:pets': read your pets - api_key: - type: apiKey - name: api_key - in: header - schemas: - Order: - title: Pet Order - description: An order for a pets from the pet store - type: object - properties: - id: - type: integer - format: int64 - petId: - type: integer - format: int64 - quantity: - type: integer - format: int32 - shipDate: - type: string - format: date-time - status: - type: string - description: Order Status - enum: - - placed - - approved - - delivered - complete: - type: boolean - default: false - xml: - name: Order - Category: - title: Pet category - description: A category for a pet - type: object - properties: - id: - type: integer - format: int64 - name: - type: string - pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$' - xml: - name: Category - User: - title: a User - description: A User who is purchasing from the pet store - type: object - properties: - id: - type: integer - format: int64 - username: - type: string - firstName: - type: string - lastName: - type: string - email: - type: string - password: - type: string - phone: - type: string - userStatus: - type: integer - format: int32 - description: User Status - xml: - name: User - Tag: - title: Pet Tag - description: A tag for a pet - type: object - properties: - id: - type: integer - format: int64 - name: - type: string - xml: - name: Tag - Pet: - title: a Pet - description: A pet for sale in the pet store - type: object - required: - - name - - photoUrls - properties: - id: - type: integer - format: int64 - category: - $ref: '#/components/schemas/Category' - name: - type: string - example: doggie - photoUrls: - type: array - xml: - name: photoUrl - wrapped: true - items: - type: string - tags: - type: array - xml: - name: tag - wrapped: true - items: - $ref: '#/components/schemas/Tag' - status: - type: string - description: pet status in the store - deprecated: true - enum: - - available - - pending - - sold - xml: - name: Pet - PetMap: - title: a PetMap - description: A mock map of a pet and some properties - type: object - properties: - pet: - type: object - additionalProperties: - type: string - ApiResponse: - title: An uploaded response - description: Describes the result of uploading an image resource - type: object - properties: - code: - type: integer - format: int32 - type: - type: string - message: - type: string - Special: - title: An uploaded response - description: Describes the result of uploading an image resource - type: object - properties: - set_test: - uniqueItems: true - type: array - items: - type: string - self: - type: integer - format: int32 - private: - type: string - super: - type: string - "123_number": - type: string - "array[test]": - type: string - "": - type: string - Dog: - allOf: - - $ref: '#/components/schemas/Animal' - - type: object - properties: - breed: - type: string - Cat: - allOf: - - $ref: '#/components/schemas/Animal' - - $ref: '#/components/schemas/Address' - - type: object - properties: - declawed: - type: boolean - Address: - type: object - additionalProperties: - type: integer - Animal: - type: object - discriminator: - propertyName: className - required: - - className - properties: - className: - type: string - color: - type: string - default: red - allof_tag_api_response: - allOf: - - $ref: '#/components/schemas/Tag' - - $ref: '#/components/schemas/ApiResponse' - AnyOfPig: - anyOf: - - $ref: '#/components/schemas/BasquePig' - - $ref: '#/components/schemas/DanishPig' - Pig: - oneOf: - - $ref: '#/components/schemas/BasquePig' - - $ref: '#/components/schemas/DanishPig' - discriminator: - propertyName: className - BasquePig: - type: object - properties: - className: - type: string - color: - type: string - required: - - className - - color - DanishPig: - type: object - properties: - className: - type: string - size: - type: integer - required: - - className - - size - NestedOneOf: - type: object - properties: - size: - type: integer - nested_pig: - $ref: '#/components/schemas/Pig' - OneOfPrimitiveTypeTest: - oneOf: - - type: "integer" - - type: "string" - AnyOfPrimitiveTypeTest: - oneOf: - - type: "integer" - - type: "string" - mammal: - oneOf: - - $ref: '#/components/schemas/whale' - - $ref: '#/components/schemas/zebra' - discriminator: - propertyName: className - mapping: - whale: '#/components/schemas/whale' - zebra: '#/components/schemas/zebra' - whale: - type: object - properties: - hasBaleen: - type: boolean - hasTeeth: - type: boolean - className: - type: string - required: - - className - zebra: - type: object - properties: - type: - type: string - enum: - - plains - - mountain - - grevys - className: - type: string - required: - - className - Date: - description: to test the model name `Date` - type: object - properties: - className: - type: string - percent_description: - description: using % in the description - type: string - url_property: - type: string - format: uri - required: - - className - - url_property - dummy_model: - description: to test the model name mapping - type: object - properties: - property: - type: string - format_test: - type: object - required: - - number - - byte - - date - - password - properties: - integer: - type: integer - maximum: 100 - minimum: 10 - int32: - type: integer - format: int32 - maximum: 200 - minimum: 20 - int64: - type: integer - format: int64 - number: - maximum: 543.2 - minimum: 32.1 - type: number - float: - type: number - format: float - maximum: 987.6 - minimum: 54.3 - double: - type: number - format: double - maximum: 123.4 - minimum: 67.8 - string: - type: string - pattern: '/[a-z]/i' - byte: - type: string - format: byte - binary: - type: string - format: binary - date: - type: string - format: date - default: 2019-07-19 - dateTime: - type: string - format: date-time - default: 2015-10-28T14:38:02Z - uuid: - type: string - format: uuid - example: 72f98069-206d-4f12-9f12-3d1e525a8e84 - password: - type: string - format: password - maxLength: 64 - minLength: 10 - pattern_with_digits: - description: A string that is a 10 digit number. Can have leading zeros. - type: string - pattern: '^\d{10}$' - pattern_with_digits_and_delimiter: - description: A string starting with 'image_' (case insensitive) and one to three digits following i.e. Image_01. - type: string - pattern: '/^image_\d{1,3}$/i' diff --git a/demos/acm_k8s/run_demo.sh b/demos/acm_k8s/run_demo.sh deleted file mode 100644 index e6c678e8..00000000 --- a/demos/acm_k8s/run_demo.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -set -e - -# Function to start the demo -start_demo() { - # Step 1: Check if .env file exists - if [ -f ".env" ]; then - echo ".env file already exists. Skipping creation." - else - # Step 2: Create `.env` file and set OpenAI key - if [ -z "$OPENAI_API_KEY" ]; then - echo "Error: OPENAI_API_KEY environment variable is not set for the demo." - exit 1 - fi - - echo "Creating .env file..." - echo "OPENAI_API_KEY=$OPENAI_API_KEY" > .env - echo ".env file created with OPENAI_API_KEY." - fi - - # Step 3: Start Arch - echo "Starting Arch with arch_config.yaml..." - archgw up arch_config.yaml - - # Step 4: Start Network Agent - echo "Starting Network Agent using Docker Compose..." - docker compose up -d # Run in detached mode -} - -# Function to stop the demo -stop_demo() { - # Step 1: Stop Docker Compose services - echo "Stopping Network Agent using Docker Compose..." - docker compose down - - # Step 2: Stop Arch - echo "Stopping Arch..." - archgw down -} - -# Main script logic -if [ "$1" == "down" ]; then - stop_demo -else - # Default action is to bring the demo up - start_demo -fi From aa6ce2ff7989f0b88cdd353160f6ee88025e35e1 Mon Sep 17 00:00:00 2001 From: Adil Hafeez Date: Thu, 5 Dec 2024 14:56:46 -0800 Subject: [PATCH 5/5] more changes --- crates/prompt_gateway/src/stream_context.rs | 111 +++++--------------- 1 file changed, 26 insertions(+), 85 deletions(-) diff --git a/crates/prompt_gateway/src/stream_context.rs b/crates/prompt_gateway/src/stream_context.rs index 501e25a9..e134e07c 100644 --- a/crates/prompt_gateway/src/stream_context.rs +++ b/crates/prompt_gateway/src/stream_context.rs @@ -494,53 +494,6 @@ impl StreamContext { .find(|pt| pt.default.unwrap_or(false)) { debug!("default prompt target found, forwarding request to default prompt target"); - if default_prompt_target.endpoint.is_none() { - info!("default prompt target endpoint not found"); - - let system_prompt = self.get_system_prompt(Some(default_prompt_target.clone())); - - let messages = vec![ - Message { - content: system_prompt, - role: SYSTEM_ROLE.to_string(), - model: Some(ARCH_FC_MODEL_NAME.to_string()), - tool_calls: None, - tool_call_id: None, - }, - Message { - content: self.user_prompt.as_ref().unwrap().content.clone(), - role: ASSISTANT_ROLE.to_string(), - model: Some(ARCH_FC_MODEL_NAME.to_string()), - tool_calls: None, - tool_call_id: None, - }, - ]; - - let chat_completions_request: ChatCompletionsRequest = ChatCompletionsRequest { - model: callout_context.request_body.model, - messages, - tools: None, - stream: callout_context.request_body.stream, - stream_options: callout_context.request_body.stream_options, - metadata: None, - }; - - let llm_request_str = match serde_json::to_string(&chat_completions_request) { - Ok(json_string) => json_string, - Err(e) => { - return self.send_server_error(ServerError::Serialization(e), None); - } - }; - - self.set_http_request_body( - 0, - self.request_body_size, - &llm_request_str.into_bytes(), - ); - - self.resume_http_request(); - return; - } let endpoint = default_prompt_target.endpoint.clone().unwrap(); let upstream_path: String = endpoint.path.unwrap_or(String::from("/")); @@ -594,7 +547,7 @@ impl StreamContext { // if no default prompt target is found and similarity score is low send response to upstream llm // removing tool calls and tool response - let messages = self.construct_llm_messages(&callout_context); + let messages = self.filter_out_arch_messages(&callout_context); let chat_completions_request: ChatCompletionsRequest = ChatCompletionsRequest { model: callout_context.request_body.model, @@ -940,7 +893,7 @@ impl StreamContext { let endpoint = prompt_target.endpoint.unwrap(); let path: String = endpoint.path.unwrap_or(String::from("/")); - // only add params that are of string and number type + // only add params that are of string, number and bool type let url_params = tool_params .iter() .filter(|(_, value)| value.is_number() || value.is_string() || value.is_bool()) @@ -1035,7 +988,7 @@ impl StreamContext { self.tool_call_response.as_ref().unwrap() ); - let mut messages = self.construct_llm_messages(&callout_context); + let mut messages = self.filter_out_arch_messages(&callout_context); let user_message = match messages.pop() { Some(user_message) => user_message, @@ -1092,43 +1045,25 @@ impl StreamContext { self.resume_http_request(); } - fn get_system_prompt(&self, prompt_target: Option) -> Option { - match prompt_target { - None => self.system_prompt.as_ref().clone(), - Some(prompt_target) => prompt_target.system_prompt, - } - } - - fn filter_out_arch_messages(&self, messages: &Vec) -> Vec { - messages - .into_iter() - .filter(|m| { - if m.role == TOOL_ROLE - || m.content.is_none() - || (m.tool_calls.is_some() && !m.tool_calls.as_ref().unwrap().is_empty()) - { - true - } else { - false - } - }) - .cloned() - .collect() - } - - fn construct_llm_messages(&mut self, callout_context: &StreamCallContext) -> Vec { + fn filter_out_arch_messages(&mut self, callout_context: &StreamCallContext) -> Vec { let mut messages: Vec = Vec::new(); - // add system prompt + let system_prompt = match callout_context.prompt_target_name.as_ref() { None => self.system_prompt.as_ref().clone(), Some(prompt_target_name) => { - self.get_system_prompt(self.prompt_targets.get(prompt_target_name).cloned()) + let prompt_system_prompt = self + .prompt_targets + .get(prompt_target_name) + .unwrap() + .clone() + .system_prompt; + match prompt_system_prompt { + None => self.system_prompt.as_ref().clone(), + Some(system_prompt) => Some(system_prompt), + } } }; - - info!("messages 1: {:?}", callout_context.request_body.messages); - if system_prompt.is_some() { let system_prompt_message = Message { role: SYSTEM_ROLE.to_string(), @@ -1140,12 +1075,18 @@ impl StreamContext { messages.push(system_prompt_message); } - info!("messages 2: {:?}", messages); + // don't send tools message and api response to chat gpt + for m in callout_context.request_body.messages.iter() { + // don't send api response and tool calls to upstream LLMs + if m.role == TOOL_ROLE + || m.content.is_none() + || (m.tool_calls.is_some() && !m.tool_calls.as_ref().unwrap().is_empty()) + { + continue; + } + messages.push(m.clone()); + } - messages.append( - &mut self.filter_out_arch_messages(callout_context.request_body.messages.as_ref()), - ); - info!("messages 3: {:?}", messages); messages }