From 640d66a5175d21426965cee29c0b65b3bf810873 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 19 Nov 2024 01:50:16 +0700 Subject: [PATCH 1/3] docs: add proxy docs --- docs/docs/configurations/index.mdx | 1 + docs/docs/configurations/proxy.mdx | 207 ++++++++++++++++++++++++++++ docs/sidebars.ts | 5 + engine/services/download_service.cc | 5 + engine/utils/config_yaml_utils.h | 2 +- engine/utils/curl_utils.h | 12 +- 6 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 docs/docs/configurations/proxy.mdx diff --git a/docs/docs/configurations/index.mdx b/docs/docs/configurations/index.mdx index 38e7d8e92..fe3ab2f0e 100644 --- a/docs/docs/configurations/index.mdx +++ b/docs/docs/configurations/index.mdx @@ -8,5 +8,6 @@ title: Cortex configurations Welcome to the Cortex configurations documentation. Here you will find detailed guides and references for configuring various aspects of Cortex, including: - **CORS**: Learn how to set up Cross-Origin Resource Sharing. +- **Proxy**: Configure the proxy for Cortex. Use the sidebar to navigate through the different configuration topics. diff --git a/docs/docs/configurations/proxy.mdx b/docs/docs/configurations/proxy.mdx new file mode 100644 index 000000000..ccd3aa9dc --- /dev/null +++ b/docs/docs/configurations/proxy.mdx @@ -0,0 +1,207 @@ +--- +title: Proxy +description: Setting up Proxy +slug: "proxy" +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +:::warning +🚧 Cortex.cpp is currently under development. Our documentation outlines the intended behavior of Cortex, which may not yet be fully implemented in the codebase. +::: + +# Proxy Configuration Guide + +This document describes how to configure proxy settings for Cortex to be able to work behind your proxy. + +## Command Line Interface (CLI) + +### Basic Usage + +```bash +cortex config [OPTIONS] [COMMAND] +``` + +### Commands + +- `status`: Display all current configurations + +```bash +cortex config status +``` + +Example Output: + +```bash ++-----------------------+------------------------+ +| Config name | Value | ++-----------------------+------------------------+ +| no_proxy | localhost,127.0.0.1 | ++-----------------------+------------------------+ +| proxy_password | | ++-----------------------+------------------------+ +| proxy_url | http://localhost:8080 | ++-----------------------+------------------------+ +| proxy_username | | ++-----------------------+------------------------+ +| verify_host_ssl | true | ++-----------------------+------------------------+ +| verify_peer_ssl | false | ++-----------------------+------------------------+ +| verify_proxy_host_ssl | true | ++-----------------------+------------------------+ +| verify_proxy_ssl | true | ++-----------------------+------------------------+ +``` + +### Options + +| Option | Description | Example | +| ----------------------------------- | --------------------------- | ------------------------------------------------- | +| `-h, --help` | Print help message and exit | +| `--proxy_url ` | Set the proxy URL | `cortex config --proxy_url http://localhost:8080` | +| `--proxy_username ` | Set the username for proxy | `cortex config --proxy_username my_username` | +| `--proxy_password ` | Set the password for proxy | `cortex config --proxy_password my_password` | +| `--no_proxy ` | Set the no_proxy list | `cortex config --no_proxy localhost,127.0.0.1` | +| `--verify_proxy_ssl [on/off]` | Verify proxy SSL | `cortex config --verify_proxy_ssl on` | +| `--verify_proxy_host_ssl [on/off]` | Verify proxy host SSL | `cortex config --verify_proxy_host_ssl on` | +| `--verify_peer_ssl [on/off]` | Verify peer SSL | `cortex config --verify_peer_ssl off` | +| `--verify_host_ssl [on/off]` | Verify host SSL | `cortex config --verify_host_ssl on` | + +## Proxy API Configuration + +### Endpoints + +#### Get Current Configuration + +```http +GET /v1/configs +``` + +Retrieves the current configuration settings. + +##### Response + +```json +{ + "allowed_origins": [ + "http://localhost:39281", + "http://127.0.0.1:39281", + "http://0.0.0.0:39281" + ], + "cors": true, + "no_proxy": "localhost,127.0.0.1", + "proxy_password": "", + "proxy_url": "http://localhost:8080", + "proxy_username": "", + "verify_host_ssl": true, + "verify_peer_ssl": false, + "verify_proxy_host_ssl": true, + "verify_proxy_ssl": true +} +``` + +#### Update Configuration + +```http +PATCH /v1/configs +``` + +Updates proxy configuration settings. + +##### Request Headers + +``` +Content-Type: application/json +``` + +##### Request Body + +```json +{ + "no_proxy": "localhost", + "proxy_url": "http://localhost:8080", + "proxy_username": "my_username", + "proxy_password": "my_password", + "verify_host_ssl": false, + "verify_peer_ssl": false, + "verify_proxy_host_ssl": false, + "verify_proxy_ssl": false +} +``` + +##### Parameters + +| Field | Type | Description | +| ----------------------- | ------- | -------------------------------------------------------------------------------------- | +| `no_proxy` | string | List of origins which request do not need to go through a proxy. Comma separated value | +| `proxy_url` | string | Proxy URL | +| `proxy_username` | string | Username for proxy authentication | +| `proxy_password` | string | Password for proxy authentication | +| `verify_host_ssl` | boolean | Verify host SSL | +| `verify_peer_ssl` | boolean | Verify peer SSL | +| `verify_proxy_host_ssl` | boolean | Verify proxy host SSL | +| `verify_proxy_ssl` | boolean | Verify proxy SSL | + +##### Response + +```json +{ + "config": { + "allowed_origins": [ + "http://localhost:39281", + "http://127.0.0.1:39281", + "http://0.0.0.0:39281" + ], + "cors": true, + "no_proxy": "localhost", + "proxy_password": "my_password", + "proxy_url": "http://localhost:8080", + "proxy_username": "my_username", + "verify_host_ssl": false, + "verify_peer_ssl": false, + "verify_proxy_host_ssl": false, + "verify_proxy_ssl": false + }, + "message": "Configuration updated successfully" +} +``` + +## Testing proxy configuration + +You can test your proxy configuration using [mitmproxy](https://docs.mitmproxy.org/stable). This guide is written on macOS, but you can use it on any other platform. + +### Install mitmproxy + +```bash +brew install mitmproxy +``` + +### Start mitmproxy + +```bash +mitmproxy --set stream_large_bodies=1m +``` + +mitmproxy will start on port `8080`. After mitmproxy started, you can adding options by pressing `O`. mitmproxy will display an option screen. You can check their document to learn more about mitmproxy. But let's take a simple option for now by setting the `proxyauth` for our local proxy. Inside the option screen, search for `proxyauth` and hit enter. Then, type `username:password` and hit enter again. You will see your newly added option is red-colored. + +### Configuring Cortex to use that proxy + +Let's using CLI to configure Cortex to use that proxy. + +```bash +cortex config --proxy_url http://localhost:8080 --proxy_username username --proxy_password password +``` + +### Testing the proxy + +Now, let's test the proxy. If you are setting the username and password correctly (same with `proxyauth` in mitmproxy), you will see the request in mitmproxy. For example, command `cortex pull tinyllama` should be successfully and returns a list of selectable models. Also, you will see your request in mitmproxy CLI screen. + +Let's try to use a wrong authentication for your proxy. + +```bash +cortex config --proxy_password wrong_pw +``` + +Now, let's test the proxy again. You will see the request is failed and returns an error. diff --git a/docs/sidebars.ts b/docs/sidebars.ts index 126673f1a..188d99317 100644 --- a/docs/sidebars.ts +++ b/docs/sidebars.ts @@ -95,6 +95,11 @@ const sidebars: SidebarsConfig = { id: "configurations/cors", label: "CORS", }, + { + type: "doc", + id: "configurations/proxy", + label: "Proxy", + }, ], }, { diff --git a/engine/services/download_service.cc b/engine/services/download_service.cc index c58935fe3..09c4d1a75 100644 --- a/engine/services/download_service.cc +++ b/engine/services/download_service.cc @@ -10,6 +10,7 @@ #include "utils/format_utils.h" #include "utils/logging_utils.h" #include "utils/result.hpp" +#include "utils/string_utils.h" namespace { size_t WriteCallback(char* ptr, size_t size, size_t nmemb, void* userdata) { @@ -75,6 +76,10 @@ void SetUpProxy(CURL* handle, std::shared_ptr config_service) { CTL_INF("Verify host ssl: " << verify_host_ssl); curl_easy_setopt(handle, CURLOPT_PROXY, proxy_url.c_str()); + if (string_utils::StartsWith(proxy_url, "https")) { + curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTPS); + } + curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, verify_ssl ? 1L : 0L); curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, verify_host_ssl ? 2L : 0L); diff --git a/engine/utils/config_yaml_utils.h b/engine/utils/config_yaml_utils.h index 3dc6bc61f..6b1660467 100644 --- a/engine/utils/config_yaml_utils.h +++ b/engine/utils/config_yaml_utils.h @@ -57,7 +57,7 @@ constexpr const auto kDefaultLatestLlamacppRelease = ""; constexpr const auto kDefaultCorsEnabled = true; const std::vector kDefaultEnabledOrigins{ "http://localhost:39281", "http://127.0.0.1:39281", "http://0.0.0.0:39281"}; -constexpr const auto kDefaultNoProxy = "localhost,127.0.0.1"; +constexpr const auto kDefaultNoProxy = "example.com,::1,localhost,127.0.0.1"; inline cpp::result DumpYamlConfig(const CortexConfig& config, const std::string& path) { diff --git a/engine/utils/curl_utils.h b/engine/utils/curl_utils.h index 34fa634b5..7bfbec44c 100644 --- a/engine/utils/curl_utils.h +++ b/engine/utils/curl_utils.h @@ -10,6 +10,7 @@ #include "utils/file_manager_utils.h" #include "utils/logging_utils.h" #include "utils/result.hpp" +#include "utils/string_utils.h" #include "utils/url_parser.h" enum class RequestType { GET, PATCH, POST, DEL }; @@ -24,7 +25,7 @@ size_t WriteCallback(void* contents, size_t size, size_t nmemb, return totalSize; } -void SetUpProxy(CURL* handle) { +void SetUpProxy(CURL* handle, const std::string& url) { auto config = file_manager_utils::GetCortexConfig(); if (!config.proxyUrl.empty()) { auto proxy_url = config.proxyUrl; @@ -39,13 +40,18 @@ void SetUpProxy(CURL* handle) { auto no_proxy = config.noProxy; CTL_INF("=== Proxy configuration ==="); + CTL_INF("Request url: " << url); CTL_INF("Proxy url: " << proxy_url); CTL_INF("Verify proxy ssl: " << verify_proxy_ssl); CTL_INF("Verify proxy host ssl: " << verify_proxy_host_ssl); CTL_INF("Verify ssl: " << verify_ssl); CTL_INF("Verify host ssl: " << verify_host_ssl); + CTL_INF("No proxy: " << no_proxy); curl_easy_setopt(handle, CURLOPT_PROXY, proxy_url.c_str()); + if (string_utils::StartsWith(proxy_url, "https")) { + curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTPS); + } curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, verify_ssl ? 1L : 0L); curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, verify_host_ssl ? 2L : 0L); @@ -88,7 +94,7 @@ inline cpp::result SimpleGet(const std::string& url, std::string readBuffer; - SetUpProxy(curl); + SetUpProxy(curl, url); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); @@ -139,7 +145,7 @@ inline cpp::result SimpleRequest( } std::string readBuffer; - SetUpProxy(curl); + SetUpProxy(curl, url); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_headers); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); if (request_type == RequestType::PATCH) { From 9ff93c5e05117993f89829fffcfcb62cf378c2a4 Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:47:33 +0700 Subject: [PATCH 2/3] feat: install script for linux (#1677) * feat: install script for linux * feat: linux bash install script support both .deb and binary * docs: update installation instruction for linux * fix: update updater to support install by bash script * chore: hardcode url for stable and beta * fix: update download url * chore: add warning for cortex update linux docs --------- Co-authored-by: Hien To Co-authored-by: vansangpfiev --- README.md | 36 +++- docs/docs/installation/linux.mdx | 59 +++--- engine/cli/commands/cortex_upd_cmd.cc | 199 ++++++++++-------- engine/cli/commands/cortex_upd_cmd.h | 9 +- engine/templates/linux/install.sh | 2 +- engine/test/components/test_cortex_upd_cmd.cc | 34 --- 6 files changed, 181 insertions(+), 158 deletions(-) diff --git a/README.md b/README.md index 2c944815a..8ab39aba8 100644 --- a/README.md +++ b/README.md @@ -56,14 +56,18 @@ Cortex also has a [Network Installer](#network-installer) which downloads the ne

- Linux: - cortex.deb (Coming soon: Linux installation script) + Linux debian based distros: + cortex-linux-local-installer.deb

- For Linux: Download the installer and run the following command in terminal: ```bash - sudo apt install ./cortex-local-installer.deb + # Linux debian based distros + curl -s https://raw.githubusercontent.com/janhq/cortex/main/engine/templates/linux/install.sh | sudo bash -s -- --deb_local + + # Other Linux distros + curl -s https://raw.githubusercontent.com/janhq/cortex/main/engine/templates/linux/install.sh | sudo bash -s ``` - The binary will be installed in the `/usr/bin/` directory. @@ -149,6 +153,28 @@ Select a model (1-9): ``` ## Advanced Installation + +### Network Installer (Stable) + +Cortex.cpp is available with a Network Installer, which is a smaller installer but requires internet connection during installation to download the necessary dependencies. + +

+ + Windows: + cortex-windows-network-installer.exe +

+ +

+ + MacOS (Universal): + cortex-mac-network-installer.pkg +

+ +

+ + Linux debian based distros: + cortex-linux-network-installer.deb +

### Beta & Nightly Versions (Local Installer) @@ -163,7 +189,7 @@ Cortex releases Beta and Nightly versions for advanced users to try new features Version Windows MacOS - Linux + Linux debian based distros Beta (Preview) @@ -218,7 +244,7 @@ Cortex.cpp is available with a Network Installer, which is a smaller installer b Version Type Windows MacOS - Linux + Linux debian based distros Stable (Recommended) diff --git a/docs/docs/installation/linux.mdx b/docs/docs/installation/linux.mdx index 23e538a52..a14450f47 100644 --- a/docs/docs/installation/linux.mdx +++ b/docs/docs/installation/linux.mdx @@ -20,43 +20,35 @@ This instruction is for stable releases. For beta and nightly releases, please r ### Prerequisites - OpenMPI +- curl +- jq +- tar ### Install Cortex.cpp -1. Download the Linux installer: - - From release: https://github.com/janhq/cortex.cpp/releases - - From quick download links: - - Local installer `.deb`: - - Stable: https://app.cortexcpp.com/download/latest/linux-amd64-local - - Beta: https://app.cortexcpp.com/download/beta/linux-amd64-local - - Nightly: https://app.cortexcpp.com/download/nightly/linux-amd64-local - - Network installer `.deb`: - - Stable: https://app.cortexcpp.com/download/latest/linux-amd64-network - - Beta: https://app.cortexcpp.com/download/beta/linux-amd64-network - - Nightly: https://app.cortexcpp.com/download/nightly/linux-amd64-network - - Binary: - - Stable: https://app.cortexcpp.com/download/latest/linux-amd64-binary - - Beta: https://app.cortexcpp.com/download/beta/linux-amd64-binary - - Nightly: https://app.cortexcpp.com/download/nightly/linux-amd64-binary - -2. Install Cortex.cpp using the following command: - ```bash - # Installer - sudo apt install ./cortex--linux-amd64-network-installer.deb +1. Install cortex with one command +- Linux debian base distros + ```bash + # Network installer + curl -s https://raw.githubusercontent.com/janhq/cortex/main/engine/templates/linux/install.sh | sudo bash -s - # Binary - tar -xvf cortex--linux-amd64.tar.gz - cd cortex - sudo mv cortex /usr/bin/cortex - sudo chmod +x /usr/bin/Cortexs - sudo mv cortex-server /usr/bin/cortex-server + # Local installer + curl -s https://raw.githubusercontent.com/janhq/cortex/main/engine/templates/linux/install.sh | sudo bash -s -- --deb_local + ``` - ## For binary, you need to install engine manually after extracting the binary - cortex engines install llama-cpp - ``` +- Other linux distros + ```bash + curl -s https://raw.githubusercontent.com/janhq/cortex/main/engine/templates/linux/install.sh | sudo bash -s + ``` + +- Parameters + - `--channel ` cortex channel will be installed `stable`, `beta` or `nightly`. Default vaule is `stable` + - `--version ` version cortex want to install Ex `--version 1.0.2`. Default the script will get latest version of corresponding channel + - `--is_update` the current command run is for update + - `--deb_local` Using local installer for linux debian base distros -3. Ensure that Cortex.cpp is sucessfulyy installed: +2. Ensure that Cortex.cpp is sucessfulyy installed: ```bash # Stable cortex -v @@ -79,7 +71,7 @@ By default, Cortex.cpp is installed in the following directory: ## Uninstall Cortex.cpp ```bash # Stable version -sudo apt remove cortexcpp +sudo /usr/bin/cortex-uninstall.sh ``` ## Build from Source @@ -115,9 +107,10 @@ sudo apt remove cortexcpp ``` ## Update cortex to latest version -:::info -The script requires sudo permission. Supported for debians based systems only (Ubuntu, Debian, etc). +:::warning +🚧 The script requires sudo permissions and works only if the user follows the installation instructions above or if the cortex binary file and the cortex-server binary file are installed in /usr/bin for all Linux distributions. If your binary files are located in a different folder, please manually update the binary files. ::: + ```bash sudo cortex update ``` \ No newline at end of file diff --git a/engine/cli/commands/cortex_upd_cmd.cc b/engine/cli/commands/cortex_upd_cmd.cc index 30d1ed3e2..231594346 100644 --- a/engine/cli/commands/cortex_upd_cmd.cc +++ b/engine/cli/commands/cortex_upd_cmd.cc @@ -36,9 +36,6 @@ std::unique_ptr GetSystemInfoWithUniversal() { return system_info; } -// https://delta.jan.ai/cortex/v1.0.0-176/windows-amd64/cortex-1.0.0-176-windows-amd64-network-installer.exe -// https://delta.jan.ai/cortex/v1.0.0-176/mac-universal/cortex-1.0.0-176-mac-universal-network-installer.pkg -// https://delta.jan.ai/cortex/v1.0.0-176/linux-amd64/cortex-1.0.0-176-linux-amd64-network-installer.deb std::string GetNightlyInstallerName(const std::string& v, const std::string& os_arch) { const std::string kCortex = "cortex"; @@ -53,13 +50,14 @@ std::string GetNightlyInstallerName(const std::string& v, #endif } -// C:\Users\vansa\AppData\Local\Temp\cortex\cortex-windows-amd64-network-installer.exe std::string GetInstallCmd(const std::string& exe_path) { #if defined(__APPLE__) && defined(__MACH__) - return "sudo touch /var/tmp/cortex_installer_skip_postinstall_check && sudo installer " + return "sudo touch /var/tmp/cortex_installer_skip_postinstall_check && sudo " + "installer " "-pkg " + exe_path + - " -target / && sudo rm /var/tmp/cortex_installer_skip_postinstall_check"; + " -target / && sudo rm " + "/var/tmp/cortex_installer_skip_postinstall_check"; #elif defined(__linux__) return "echo -e \"n\\n\" | sudo SKIP_POSTINSTALL=true apt install -y " "--allow-downgrades " + @@ -70,8 +68,22 @@ std::string GetInstallCmd(const std::string& exe_path) { #endif } +std::string GetInstallCmdLinux(const std::string& script_path, + const std::string& channel, + const std::string& version) { + std::string cmd = "sudo " + script_path; + if (!channel.empty()) { + cmd += " --channel " + channel; + } + if (!version.empty()) { + cmd += " --version " + version.substr(1); + } + return cmd + " --is_update"; +} + bool InstallNewVersion(const std::filesystem::path& dst, - const std::string& exe_path) { + const std::string& exe_script_path, + const std::string& channel, const std::string& version) { std::filesystem::path temp = dst.parent_path() / "cortex_temp"; auto restore_binary = [&temp, &dst]() { if (std::filesystem::exists(temp)) { @@ -86,7 +98,14 @@ bool InstallNewVersion(const std::filesystem::path& dst, // rename binary std::rename(dst.string().c_str(), temp.string().c_str()); // install here - CommandExecutor c(GetInstallCmd(exe_path)); + std::string install_cmd; +#if defined(__linux__) + install_cmd = GetInstallCmdLinux(exe_script_path, channel, version); +#else + install_cmd = GetInstallCmd(exe_script_path); +#endif + CTL_INF("Cmd: " << install_cmd); + CommandExecutor c(install_cmd); auto output = c.execute(); if (!std::filesystem::exists(dst)) { CLI_LOG_ERROR("Something went wrong: could not execute command"); @@ -110,7 +129,6 @@ bool InstallNewVersion(const std::filesystem::path& dst, } return true; } - } // namespace std::optional CheckNewUpdate( @@ -200,76 +218,6 @@ std::optional CheckNewUpdate( return std::nullopt; } -bool ReplaceBinaryInflight(const std::filesystem::path& src, - const std::filesystem::path& dst) { - if (src == dst) { - // Already has the newest - return true; - } - - std::filesystem::path temp = dst.parent_path() / "cortex_temp"; - auto restore_binary = [&temp, &dst]() { - if (std::filesystem::exists(temp)) { - std::rename(temp.string().c_str(), dst.string().c_str()); - CLI_LOG("Restored binary file"); - } - }; - - try { - if (std::filesystem::exists(temp)) { - std::filesystem::remove(temp); - } -#if !defined(_WIN32) - // Get permissions of the executable file - struct stat dst_file_stat; - if (stat(dst.string().c_str(), &dst_file_stat) != 0) { - CLI_LOG_ERROR( - "Error getting permissions of executable file: " << dst.string()); - return false; - } - - // Get owner and group of the executable file - uid_t dst_file_owner = dst_file_stat.st_uid; - gid_t dst_file_group = dst_file_stat.st_gid; -#endif - - std::rename(dst.string().c_str(), temp.string().c_str()); - std::filesystem::copy_file( - src, dst, std::filesystem::copy_options::overwrite_existing); - -#if !defined(_WIN32) - // Set permissions of the executable file - if (chmod(dst.string().c_str(), dst_file_stat.st_mode) != 0) { - CLI_LOG_ERROR( - "Error setting permissions of executable file: " << dst.string()); - restore_binary(); - return false; - } - - // Set owner and group of the executable file - if (chown(dst.string().c_str(), dst_file_owner, dst_file_group) != 0) { - CLI_LOG_ERROR( - "Error setting owner and group of executable file: " << dst.string()); - restore_binary(); - return false; - } - - // Remove cortex_temp - if (unlink(temp.string().c_str()) != 0) { - CLI_LOG_ERROR("Error deleting self: " << strerror(errno)); - restore_binary(); - return false; - } -#endif - } catch (const std::exception& e) { - CLI_LOG_ERROR("Something went wrong: " << e.what()); - restore_binary(); - return false; - } - - return true; -} - void CortexUpdCmd::Exec(const std::string& v, bool force) { // Check for update, if current version is the latest, notify to user if (auto latest_version = commands::CheckNewUpdate(std::nullopt); @@ -314,6 +262,9 @@ void CortexUpdCmd::Exec(const std::string& v, bool force) { } bool CortexUpdCmd::GetStable(const std::string& v) { +#if defined(__linux__) + return GetLinuxInstallScript(v, "stable"); +#else std::optional downloaded_exe_path; auto system_info = GetSystemInfoWithUniversal(); CTL_INF("OS: " << system_info->os << ", Arch: " << system_info->arch); @@ -366,10 +317,14 @@ bool CortexUpdCmd::GetStable(const std::string& v) { }); assert(!!downloaded_exe_path); - return InstallNewVersion(dst, downloaded_exe_path.value()); + return InstallNewVersion(dst, downloaded_exe_path.value(), "", ""); +#endif } bool CortexUpdCmd::GetBeta(const std::string& v) { +#if defined(__linux__) + return GetLinuxInstallScript(v, "beta"); +#else std::optional downloaded_exe_path; auto system_info = GetSystemInfoWithUniversal(); CTL_INF("OS: " << system_info->os << ", Arch: " << system_info->arch); @@ -434,7 +389,8 @@ bool CortexUpdCmd::GetBeta(const std::string& v) { }); assert(!!downloaded_exe_path); - return InstallNewVersion(dst, downloaded_exe_path.value()); + return InstallNewVersion(dst, downloaded_exe_path.value(), "", ""); +#endif } std::optional CortexUpdCmd::HandleGithubRelease( @@ -500,6 +456,9 @@ std::optional CortexUpdCmd::HandleGithubRelease( } bool CortexUpdCmd::GetNightly(const std::string& v) { +#if defined(__linux__) + return GetLinuxInstallScript(v, "nightly"); +#else auto system_info = GetSystemInfoWithUniversal(); CTL_INF("OS: " << system_info->os << ", Arch: " << system_info->arch); @@ -566,6 +525,82 @@ bool CortexUpdCmd::GetNightly(const std::string& v) { } }); - return InstallNewVersion(dst, localPath.string()); + return InstallNewVersion(dst, localPath.string(), "", ""); +#endif +} + +bool CortexUpdCmd::GetLinuxInstallScript(const std::string& v, + const std::string& channel) { + std::vector path_list; + if (channel == "nightly") { + path_list = {"janhq", "cortex.cpp", "dev", "engine", + "templates", "linux", "install.sh"}; + } else { + path_list = {"janhq", "cortex.cpp", "main", "engine", + "templates", "linux", "install.sh"}; + } + auto url_obj = url_parser::Url{ + .protocol = "https", + .host = "raw.githubusercontent.com", + .pathParams = path_list, + }; + + CTL_INF("Linux installer script path: " << url_parser::FromUrl(url_obj)); + + std::filesystem::path localPath = + std::filesystem::temp_directory_path() / "cortex" / path_list.back(); + try { + if (!std::filesystem::exists(localPath.parent_path())) { + std::filesystem::create_directories(localPath.parent_path()); + } + } catch (const std::filesystem::filesystem_error& e) { + CLI_LOG_ERROR("Failed to create directories: " << e.what()); + return false; + } + auto download_task = + DownloadTask{.id = "cortex", + .type = DownloadType::Cortex, + .items = {DownloadItem{ + .id = "cortex", + .downloadUrl = url_parser::FromUrl(url_obj), + .localPath = localPath, + }}}; + + auto result = download_service_->AddDownloadTask( + download_task, [](const DownloadTask& finishedTask) { + // try to unzip the downloaded file + CTL_INF("Downloaded cortex path: " + << finishedTask.items[0].localPath.string()); + + CTL_INF("Finished!"); + }); + if (result.has_error()) { + CLI_LOG_ERROR("Failed to download: " << result.error()); + return false; + } + + auto executable_path = file_manager_utils::GetExecutableFolderContainerPath(); + auto dst = executable_path / GetCortexBinary(); + cortex::utils::ScopeExit se([]() { + auto cortex_tmp = std::filesystem::temp_directory_path() / "cortex"; + try { + auto n = std::filesystem::remove_all(cortex_tmp); + CTL_INF("Deleted " << n << " files or directories"); + } catch (const std::exception& e) { + CTL_WRN(e.what()); + } + }); + try { + std::filesystem::permissions(localPath, + std::filesystem::perms::owner_exec | + std::filesystem::perms::group_exec | + std::filesystem::perms::others_exec, + std::filesystem::perm_options::add); + } catch (const std::filesystem::filesystem_error& e) { + CTL_WRN("Error: " << e.what()); + return false; + } + + return InstallNewVersion(dst, localPath.string(), channel, v); } } // namespace commands diff --git a/engine/cli/commands/cortex_upd_cmd.h b/engine/cli/commands/cortex_upd_cmd.h index bd3fc51df..9c500a999 100644 --- a/engine/cli/commands/cortex_upd_cmd.h +++ b/engine/cli/commands/cortex_upd_cmd.h @@ -86,9 +86,6 @@ inline std::string GetReleasePath() { std::optional CheckNewUpdate( std::optional timeout); -bool ReplaceBinaryInflight(const std::filesystem::path& src, - const std::filesystem::path& dst); - // This class manages the 'cortex update' command functionality // There are three release types available: // - Stable: Only retrieves the latest version @@ -109,5 +106,11 @@ class CortexUpdCmd { std::optional HandleGithubRelease(const Json::Value& assets, const std::string& os_arch); bool GetNightly(const std::string& v); + + // For Linux, we use different approach to update + // The installation bash script will perform the following tasks (all logic for update will be put into the bash script): + // - Detect whether the user is performing a new installation or an update. + // - Detect whether a .deb package needs to be installed or if the binary file should be installed directly. + bool GetLinuxInstallScript(const std::string& v, const std::string& channel); }; } // namespace commands diff --git a/engine/templates/linux/install.sh b/engine/templates/linux/install.sh index e907150a8..e11b879c6 100644 --- a/engine/templates/linux/install.sh +++ b/engine/templates/linux/install.sh @@ -278,4 +278,4 @@ fi install_cortex $CHANNEL $VERSION $IS_DEB create_uninstall_script $IS_DEB -echo "Installation complete. Run cortex-uninstall.sh to uninstall." \ No newline at end of file +echo "Installation complete. Run cortex-uninstall.sh to uninstall." diff --git a/engine/test/components/test_cortex_upd_cmd.cc b/engine/test/components/test_cortex_upd_cmd.cc index a8815f4f4..772889fbd 100644 --- a/engine/test/components/test_cortex_upd_cmd.cc +++ b/engine/test/components/test_cortex_upd_cmd.cc @@ -34,37 +34,3 @@ class CortexUpdCmdTest : public ::testing::Test { } } }; - -TEST_F(CortexUpdCmdTest, return_true_if_self_replace) { - EXPECT_TRUE(commands::ReplaceBinaryInflight("test", "test")); -} - -TEST_F(CortexUpdCmdTest, replace_binary_successfully) { - std::filesystem::path new_binary(kNewReleaseFile); - std::filesystem::path cur_binary(kCurReleaseFile); -#if !defined(_WIN32) - struct stat cur_file_stat; - EXPECT_TRUE(stat(cur_binary.string().c_str(), &cur_file_stat) == 0); -#endif - - EXPECT_TRUE(commands::ReplaceBinaryInflight(new_binary, cur_binary)); - -#if !defined(_WIN32) - EXPECT_FALSE(std::filesystem::exists(kCortexTemp)); - - struct stat new_file_stat; - EXPECT_TRUE(stat(cur_binary.string().c_str(), &new_file_stat) == 0); - EXPECT_EQ(cur_file_stat.st_uid, new_file_stat.st_uid); - EXPECT_EQ(cur_file_stat.st_gid, new_file_stat.st_gid); - EXPECT_EQ(cur_file_stat.st_mode, new_file_stat.st_mode); -#else - EXPECT_TRUE(std::filesystem::exists(kCortexTemp)); -#endif -} - -TEST_F(CortexUpdCmdTest, should_restore_old_binary_if_has_error) { - std::filesystem::path new_binary("Non-exist"); - std::filesystem::path cur_binary(kCurReleaseFile); - EXPECT_FALSE(commands::ReplaceBinaryInflight(new_binary, cur_binary)); - EXPECT_FALSE(std::filesystem::exists(kCortexTemp)); -} \ No newline at end of file From 37fecbd75e451575078d5f79306a0867736aa172 Mon Sep 17 00:00:00 2001 From: vansangpfiev Date: Tue, 19 Nov 2024 11:50:04 +0700 Subject: [PATCH 3/3] feat: API to configure huggingface_token (#1699) * feat: API for configuring huggingface token * chore: API docs * chore: Token docs * chore: docs --------- Co-authored-by: vansangpfiev --- docs/docs/configurations/token.mdx | 120 +++++++++++++++++++++++ docs/sidebars.ts | 5 + docs/static/openapi/cortex.json | 16 ++- engine/common/api_server_configuration.h | 26 ++++- engine/services/config_service.cc | 18 ++-- 5 files changed, 174 insertions(+), 11 deletions(-) create mode 100644 docs/docs/configurations/token.mdx diff --git a/docs/docs/configurations/token.mdx b/docs/docs/configurations/token.mdx new file mode 100644 index 000000000..687879cb4 --- /dev/null +++ b/docs/docs/configurations/token.mdx @@ -0,0 +1,120 @@ +--- +title: Token +description: Setting up token +slug: "token" +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +:::warning +🚧 Cortex.cpp is currently under development. Our documentation outlines the intended behavior of Cortex, which may not yet be fully implemented in the codebase. +::: + +# Token Configuration Guide + +This document describes how to configure HuggingFace token settings for Cortex. + +## Command Line Interface (CLI) + +### Basic Usage + +```bash +cortex config [OPTIONS] [COMMAND] +``` + +### Commands + +- `status`: Display all current configurations + +```bash +cortex config status +``` + +Example Output: + +```bash ++-----------------------+------------------------+ +| Config name | Value | ++-----------------------+------------------------+ +| huggingface_token | | ++-----------------------+------------------------+ +``` + +### Options + +| Option | Description | Example | +| ----------------------------------- | --------------------------- | ------------------------------------------------- | +| `-h, --help` | Print help message and exit | +| `--huggingface_token ` | Set HuggingFace token | `cortex config --huggingface_token token` | + +## Token API Configuration + +### Endpoints + +#### Get Current Configuration + +```http +GET /v1/configs +``` + +Retrieves the current configuration settings. + +##### Response + +```json +{ + "allowed_origins": [ + "http://localhost:39281", + "http://127.0.0.1:39281", + "http://0.0.0.0:39281" + ], + "cors": true, + "huggingface_token": "" +} +``` + +#### Update Configuration + +```http +PATCH /v1/configs +``` + +Updates HuggingFace token configuration settings. + +##### Request Headers + +``` +Content-Type: application/json +``` + +##### Request Body + +```json +{ + "huggingface_token": "token" +} +``` + +##### Parameters + +| Field | Type | Description | +| ----------------------- | ------- | ------------------------------------------| +| `huggingface_token` | string | HuggingFace token to pull models | + +##### Response + +```json +{ + "config": { + "allowed_origins": [ + "http://localhost:39281", + "http://127.0.0.1:39281", + "http://0.0.0.0:39281" + ], + "cors": true, + "huggingface_token": "token" + }, + "message": "Configuration updated successfully" +} +``` \ No newline at end of file diff --git a/docs/sidebars.ts b/docs/sidebars.ts index 188d99317..8c0800345 100644 --- a/docs/sidebars.ts +++ b/docs/sidebars.ts @@ -100,6 +100,11 @@ const sidebars: SidebarsConfig = { id: "configurations/proxy", label: "Proxy", }, + { + type: "doc", + id: "configurations/token", + label: "Token", + } ], }, { diff --git a/docs/static/openapi/cortex.json b/docs/static/openapi/cortex.json index 9747a1830..1ac69d78e 100644 --- a/docs/static/openapi/cortex.json +++ b/docs/static/openapi/cortex.json @@ -1810,6 +1810,10 @@ "no_proxy": { "type": "string", "example": "localhost" + }, + "huggingface_token": { + "type": "string", + "example": "your_token" } } }, @@ -1826,7 +1830,8 @@ "verify_proxy_host_ssl": false, "verify_peer_ssl": false, "verify_host_ssl": false, - "no_proxy": "localhost" + "no_proxy": "localhost", + "huggingface_token": "your_token" } } } @@ -1896,6 +1901,11 @@ "type": "string", "description": "List of hosts that should not be proxied.", "example": "localhost" + }, + "huggingface_token": { + "type": "string", + "description": "HuggingFace token to pull models.", + "example": "your_token" } } } @@ -1958,6 +1968,10 @@ "no_proxy": { "type": "string", "example": "localhost" + }, + "huggingface_token": { + "type": "string", + "example": "your_token" } } }, diff --git a/engine/common/api_server_configuration.h b/engine/common/api_server_configuration.h index 5bfcbbdc5..03b3022a4 100644 --- a/engine/common/api_server_configuration.h +++ b/engine/common/api_server_configuration.h @@ -90,6 +90,13 @@ static const std::unordered_map .group = "Proxy", .accept_value = "[on|off]", .default_value = "on"}}, + {"huggingface_token", + ApiConfigurationMetadata{.name = "huggingface_token", + .desc = "HuggingFace token to pull models", + .group = "Token", + .accept_value = "string", + .default_value = "", + .allow_empty = true}}, }; class ApiServerConfiguration { @@ -99,7 +106,8 @@ class ApiServerConfiguration { bool verify_proxy_ssl = true, bool verify_proxy_host_ssl = true, const std::string& proxy_url = "", const std::string& proxy_username = "", const std::string& proxy_password = "", const std::string& no_proxy = "", - bool verify_peer_ssl = true, bool verify_host_ssl = true) + bool verify_peer_ssl = true, bool verify_host_ssl = true, + const std::string& hf_token = "") : cors{cors}, allowed_origins{allowed_origins}, verify_proxy_ssl{verify_proxy_ssl}, @@ -109,7 +117,8 @@ class ApiServerConfiguration { proxy_password{proxy_password}, no_proxy{no_proxy}, verify_peer_ssl{verify_peer_ssl}, - verify_host_ssl{verify_host_ssl} {} + verify_host_ssl{verify_host_ssl}, + hf_token{hf_token} {} // cors bool cors{true}; @@ -127,6 +136,9 @@ class ApiServerConfiguration { bool verify_peer_ssl{true}; bool verify_host_ssl{true}; + // token + std::string hf_token{""}; + Json::Value ToJson() const { Json::Value root; root["cors"] = cors; @@ -142,6 +154,7 @@ class ApiServerConfiguration { root["no_proxy"] = no_proxy; root["verify_peer_ssl"] = verify_peer_ssl; root["verify_host_ssl"] = verify_host_ssl; + root["huggingface_token"] = hf_token; return root; } @@ -225,6 +238,15 @@ class ApiServerConfiguration { return true; }}, + {"huggingface_token", + [this](const Json::Value& value) -> bool { + if (!value.isString()) { + return false; + } + hf_token = value.asString(); + return true; + }}, + {"cors", [this](const Json::Value& value) -> bool { if (!value.isBool()) { diff --git a/engine/services/config_service.cc b/engine/services/config_service.cc index 9c794bb38..ce5526090 100644 --- a/engine/services/config_service.cc +++ b/engine/services/config_service.cc @@ -6,10 +6,10 @@ cpp::result ConfigService::UpdateApiServerConfiguration(const Json::Value& json) { auto config = file_manager_utils::GetCortexConfig(); ApiServerConfiguration api_server_config{ - config.enableCors, config.allowedOrigins, config.verifyProxySsl, - config.verifyProxyHostSsl, config.proxyUrl, config.proxyUsername, - config.proxyPassword, config.noProxy, config.verifyPeerSsl, - config.verifyHostSsl}; + config.enableCors, config.allowedOrigins, config.verifyProxySsl, + config.verifyProxyHostSsl, config.proxyUrl, config.proxyUsername, + config.proxyPassword, config.noProxy, config.verifyPeerSsl, + config.verifyHostSsl, config.huggingFaceToken}; std::vector updated_fields; std::vector invalid_fields; @@ -35,6 +35,8 @@ ConfigService::UpdateApiServerConfiguration(const Json::Value& json) { config.verifyPeerSsl = api_server_config.verify_peer_ssl; config.verifyHostSsl = api_server_config.verify_host_ssl; + config.huggingFaceToken = api_server_config.hf_token; + auto result = file_manager_utils::UpdateCortexConfig(config); return api_server_config; } @@ -43,8 +45,8 @@ cpp::result ConfigService::GetApiServerConfiguration() { auto config = file_manager_utils::GetCortexConfig(); return ApiServerConfiguration{ - config.enableCors, config.allowedOrigins, config.verifyProxySsl, - config.verifyProxyHostSsl, config.proxyUrl, config.proxyUsername, - config.proxyPassword, config.noProxy, config.verifyPeerSsl, - config.verifyHostSsl}; + config.enableCors, config.allowedOrigins, config.verifyProxySsl, + config.verifyProxyHostSsl, config.proxyUrl, config.proxyUsername, + config.proxyPassword, config.noProxy, config.verifyPeerSsl, + config.verifyHostSsl, config.huggingFaceToken}; }