diff --git a/.github/workflows/api-server.yml b/.github/workflows/api-server.yml index d1472fd5..e17904e6 100644 --- a/.github/workflows/api-server.yml +++ b/.github/workflows/api-server.yml @@ -58,7 +58,63 @@ jobs: run: | go build ./... - build-packages: + build-darwin-packages: + needs: [ fmt-build-test ] + runs-on: macos-latest + defaults: + run: + working-directory: api-server + steps: + - uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.21.6' + + - name: Build apiserver darwin packages + id: build + shell: bash + run: | + make -j dist/packages + + - name: Upload apiserver tar.gz packages + uses: actions/upload-artifact@v4 + with: + name: apiserver-darwin-packages-tar + if-no-files-found: error + path: | + ./api-server/dist/packages/*.tar.gz + + upload-s3-darwin-packages: + needs: ["build-darwin-packages"] + permissions: + id-token: write + contents: read + runs-on: ubuntu-latest + environment: registry-creds + if: ${{ github.event_name == 'push' }} + steps: + - name: download tar.gz binary artifacts + uses: actions/download-artifact@v4 + with: + name: apiserver-darwin-packages-tar + path: ./dist/packages + + - name: Display structure of downloaded files + run: ls -lah -R + working-directory: ./dist/packages + + - name: configure aws credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_ROLE }} + role-session-name: apiserver-ci-deploy + aws-region: us-east-1 + - name: copy binaries to s3 + run: | + aws s3 sync dist/packages s3://instructlab-ui/apiserver + + build-linux-packages: needs: [ fmt-build-test ] runs-on: ubuntu-latest defaults: @@ -80,13 +136,13 @@ jobs: - name: Upload apiserver tar.gz packages uses: actions/upload-artifact@v4 with: - name: apiserver-packages-tar + name: apiserver-linux-packages-tar if-no-files-found: error path: | ./api-server/dist/packages/*.tar.gz - upload-s3-packages: - needs: ["build-packages"] + upload-s3-linux-packages: + needs: ["build-linux-packages"] permissions: id-token: write contents: read @@ -97,7 +153,7 @@ jobs: - name: download tar.gz binary artifacts uses: actions/download-artifact@v4 with: - name: apiserver-packages-tar + name: apiserver-linux-packages-tar path: ./dist/packages - name: Display structure of downloaded files diff --git a/api-server/Makefile b/api-server/Makefile index d5d3180a..7caf323d 100644 --- a/api-server/Makefile +++ b/api-server/Makefile @@ -23,31 +23,33 @@ APISERVER_GCFLAGS?= APISERVER_BUILD_PROFILE?=dev APISERVER_LDFLAGS:=$(APISERVER_LDFLAGS) -X main.Version=$(APISERVER_VERSION)-$(APISERVER_RELEASE) -CGO_ENABLED?=0 +CGO_ENABLED?=1 ifeq ($(APISERVER_RACE_DETECTOR),1) CGO_ENABLED=1 APISERVER_BUILD_FLAGS+=-race endif -ifneq ($(APISERVER_BUILD_TAGS),) - APISERVER_BUILD_FLAGS+=-tags $(APISERVER_BUILD_TAGS) -endif ifeq ($(CGO_ENABLED),0) APISERVER_LDFLAGS+=-extldflags=-static endif +OS := $(shell uname -s) -# Crunchy DB operator does not work well on arm64, use an different overlay to work around it. -UNAME_M := $(shell uname -m) -ifeq ($(UNAME_M),arm64) - OVERLAY?=arm64 +ifeq ($(OS), Darwin) + TARGET_BIN = dist/apiserver-darwin-amd64 dist/apiserver-darwin-arm64 + TARGET_PACKAGES= dist/packages/apiserver-darwin-amd64.tar.gz dist/packages/apiserver-darwin-arm64.tar.gz +else ifeq ($(OS), Linux) + TARGET_BIN = dist/apiserver-linux-amd64 + #TARGET_BIN = dist/apiserver-linux-amd64 dist/apiserver-linux-arm64 + TARGET_PACKAGES=dist/packages/apiserver-linux-amd64.tar.gz + #TARGET_PACKAGES=dist/packages/apiserver-linux-amd64.tar.gz dist/packages/apiserver-linux-arm64.tar.gz else - OVERLAY?=dev + $(error Unsupported OS: $(OS)) endif ##@ Binaries .PHONY: apiserver -apiserver: dist/apiserver dist/apiserver-linux-arm64 dist/apiserver-linux-amd64 dist/apiserver-darwin-amd64 dist/apiserver-darwin-arm64 ## Build Instructlab UI API server +apiserver: dist/apiserver $(TARGET_BIN) ## Build Instructlab UI API server # Use go list to find all the go files that make up a binary. APISERVER_DEPS:= $(shell go list -deps -f '{{if (and .Module (eq .Module.Path "github.com/instructlab/ui/api-server"))}}{{$$dir := .Dir}}{{range .GoFiles}}{{$$dir}}/{{.}} {{end}}{{end}}' ./) @@ -67,23 +69,13 @@ dist/apiserver-%: $(APISERVER_DEPS) | dist $(CMD_PREFIX) CGO_ENABLED=$(CGO_ENABLED) GOOS=$(word 2,$(subst -, ,$(basename $@))) GOARCH=$(word 3,$(subst -, ,$(basename $@))) \ go build $(APISERVER_BUILD_FLAGS) -gcflags="$(APISERVER_GCFLAGS)" \ -ldflags="$(APISERVER_LDFLAGS)" -o $@ ./ -dist/packages: \ - dist/packages/apiserver-linux-amd64.tar.gz \ - dist/packages/apiserver-linux-arm64.tar.gz \ - dist/packages/apiserver-darwin-amd64.tar.gz \ - dist/packages/apiserver-darwin-arm64.tar.gz \ +dist/packages: $(TARGET_PACKAGES) dist/packages/%: apiserver $(CMD_PREFIX) mkdir -p $(basename $(basename $@)) - $(CMD_PREFIX) cp README.md $(basename $(basename $@)) - $(CMD_PREFIX) cp dist/apiserver-$(subst apiserver-,,$(basename $(basename $(@F))))$(if $(findstring windows,$@),.exe) $(basename $(basename $@))/ilab-apiserver$(if $(findstring windows,$@),.exe) - $(CMD_PREFIX) if test "$(word 2,$(subst -, ,$(shell basename $@)))" = "windows" ; then \ - printf " %-12s dist/packages/$(@F)\n" "[ZIP]" ;\ - cd dist/packages && zip -q9r $(@F) $(basename $(basename $(@F))) ;\ - else \ - printf " %-12s dist/packages/$(@F)\n" "[TAR]" ;\ - cd dist/packages && tar -czf $(@F) $(basename $(basename $(@F))) ;\ - fi + $(CMD_PREFIX) cp dist/apiserver-$(subst apiserver-,,$(basename $(basename $(@F)))) $(basename $(basename $@))/ilab-apiserver$ + $(CMD_PREFIX) printf " %-12s dist/packages/$(@F)\n" "[TAR]" ; + $(CMD_PREFIX) cd dist/packages && tar -czf $(@F) $(basename $(basename $(@F))); .PHONY: clean clean: ## clean built binaries diff --git a/api-server/main.go b/api-server/main.go index c6cb16e8..394d5644 100644 --- a/api-server/main.go +++ b/api-server/main.go @@ -214,7 +214,7 @@ func (srv *ILabServer) runServer(cmd *cobra.Command, args []string) { srv.ilabCmd = ilabPath } else { // Use ilab from virtual environment - srv.ilabCmd = filepath.Join(srv.baseDir, "venv", "bin", "ilab") + srv.ilabCmd = filepath.Join(srv.baseDir, "bin", "ilab") if _, err := os.Stat(srv.ilabCmd); os.IsNotExist(err) { srv.log.Fatalf("ilab binary not found at %s. Please ensure the virtual environment is set up correctly.", srv.ilabCmd) } diff --git a/deploy/podman/native/README.md b/deploy/podman/native/README.md index 2c2586df..a00f1ba7 100644 --- a/deploy/podman/native/README.md +++ b/deploy/podman/native/README.md @@ -3,11 +3,62 @@ Please follow the below instructions to deploy UI stack with Native mode enabled in Podman. -## Generate Secret +## Deploy using the installer (Recommended) + +Make a temporary directory and download the installer + +```shell +mkdir instructlab-ui +cd instructlab-ui + +curl -fsSL https://raw.githubusercontent.com/instructlab/ui/refs/heads/main/installers/podman/ilab-ui-native-installer.sh +``` + +Give execution permission to the install + +```shell +chmod a+x ilab-ui-native-installer.sh +``` + +Execute the installer and follow the instructions prompted on the terminal. + +If your deployment machine has InstructLab (ilab CLI) setup, either on the host or in python virtual environment, use the following command + +```shell +./ilab-ui-native-installer.sh --username --password + +e.g ./ilab-ui-native-installer.sh --username admin --password passw0rd +``` + +If your deployment machine don't have InstructLab CLI setup, please clone the taxonomy repo and fire the following command. + +```shell +./ilab-ui-native-installer.sh --username --password --taxonomy-dir + +e.g ./ilab-ui-native-installer.sh --username admin --password passw0rd --taxonomy-dir /Users/johndoe/instructlab/taxonomy +``` + +>[!NOTE] +> In the absence of InstructLab CLI, UI won't be able to support the synthetic data generation and fine tuning, but skill and knowledge contribution should work as expected. + +If you are deploying the UI stack on a remote machine, please provide the auth url in the input + +```shell +./ilab-ui-native-installer.sh --username --password --taxonomy-dir --auth-url http://:3000 +``` + +Please use `--help` to see more options supported by the installer. + +## Deploy manually + +If you would like to install the UI stack manually, it's a two step process + +- Generate the secret file with the required input +- Deploy the UI stack manifest file using podman. A secret is required to provide required input to the UI stack in a secure way. -Two options exist to generate the secret, either using `kubectl` or filling in values in the `secret.yaml` provided. +There are two options to generate the secret's file, either using `kubectl` or filling in values in the `secret.yaml` provided. ### Generate secrets using kubectl @@ -46,7 +97,7 @@ echo "password" | base64 Using the above to fill in all the required input fields. -## Deploy the secret +### Deploy the secret Now that the `secret.yaml` has been generated, use `podman kube play` to load the secret. @@ -54,9 +105,9 @@ Now that the `secret.yaml` has been generated, use `podman kube play` to load th podman kube play secret.yaml ``` -## Deploying the InstructLab UI Stack +### Deploy the InstructLab UI Stack -One last step before you launch the InstructLab UI. A file named [instructlab-ui.yaml](instructlab-ui.yaml) present in the [native](../native/) directory. Search for in the yaml file and replace it with the same value that is used while creating the secret.yaml file. Now with the secret in place and deployment yaml updated, use `podman kube play` to launch the containers. UI will look for the taxonomy repo in this directory to submit the skill and knowledge contributions. +One last step before you launch the InstructLab UI. A file named [instructlab-ui.yaml](instructlab-ui.yaml) present in the [native](../native/) directory. Search for in the yaml file and replace it with the same value that is used while creating the secret.yaml file. Now with the secret in place and deployment yaml updated, use `podman kube play` to launch the containers. UI will look for the taxonomy repo in this directory to submit the skill and knowledge contributions. ```bash podman kube play instructlab-ui.yaml diff --git a/deploy/podman/native/instructlab-ui.yaml b/deploy/podman/native/instructlab-ui.yaml index 25603ba6..2aa4daf5 100644 --- a/deploy/podman/native/instructlab-ui.yaml +++ b/deploy/podman/native/instructlab-ui.yaml @@ -127,5 +127,5 @@ spec: volumes: - name: taxonomy-repo hostPath: - path: + path: type: Directory diff --git a/deploy/podman/native/secret.yaml.example b/deploy/podman/native/secret.yaml.example index df0861f7..cdcd49b5 100644 --- a/deploy/podman/native/secret.yaml.example +++ b/deploy/podman/native/secret.yaml.example @@ -1,13 +1,13 @@ apiVersion: v1 data: - IL_ENABLE_DEV_MODE: ZmFsc2U= - IL_UI_ADMIN_PASSWORD: - IL_UI_ADMIN_USERNAME: - IL_UI_DEPLOYMENT: bmF0aXZl - NEXT_PUBLIC_EXPERIMENTAL_FEATURES: dHJ1ZQ== - NEXT_PUBLIC_TAXONOMY_ROOT_DIR: - NEXTAUTH_SECRET: - NEXTAUTH_URL: aHR0cDovL2xvY2FsaG9zdDozMDAw + IL_UI_ADMIN_PASSWORD: + IL_UI_ADMIN_USERNAME: + IL_UI_DEPLOYMENT: + IL_ENABLE_DEV_MODE: + NEXT_PUBLIC_EXPERIMENTAL_FEATURES: + NEXT_PUBLIC_TAXONOMY_ROOT_DIR: + NEXTAUTH_URL: + NEXTAUTH_SECRET: kind: Secret metadata: creationTimestamp: null diff --git a/installers/podman/ilab-ui-native-installer.sh b/installers/podman/ilab-ui-native-installer.sh new file mode 100755 index 00000000..af3e9fa8 --- /dev/null +++ b/installers/podman/ilab-ui-native-installer.sh @@ -0,0 +1,483 @@ +#!/bin/bash + +set -e + +# Colors +green="\033[32m" +red="\033[31m" +blue="\033[34m" +reset="\033[0m" + +declare UI_DEPLOYMENT="native" +declare USERNAME +declare PASSWORD +declare USER_TAXONOMY_DIR +declare AUTH_URL="http://localhost:3000" +declare AUTH_SECRET="your_super_secret_random_string" +declare DEV_MODE="false" +declare EXPERIMENTAL_FEATURES="false" +declare PYENV_DIR="" + +BINARY_INSTALL_DIR=./ +IS_ILAB_INSTALLED="true" +DISCOVERED_TAXONOMY_DIR="" +SELECTED_TAXONOMY_DIR="" +ILAB_APISERVER_LOG_FILE="ilab-apiserver.log" +DISCOVERED_PYENV_DIR="" + +# Usage function +usage() { + echo -e "${green}Usage: $0 COMMAND [OPTIONS]...${reset}\n" + echo -e "${green}Installer to install the InstructLab UI in the Native Mode on Podman.${reset}\n" + echo -e "${green}Commands:${reset}" + echo -e "${green} install${reset} Configures and install the InstructLab UI stack." + echo -e "${green} uninstall${reset} Uninstalls the InstructLab UI stack and removes temporary files.\n" + echo -e "${green}Options:${reset}" + echo -e "${green} --help${reset} Show this message and exit.\n" + exit 1 +} + +usage_install() { + echo -e "${green}Usage: $0 install [OPTIONS]...${reset}\n" + echo -e "${green}Installs the InstructLab UI stack in Native mode on Podman.${reset}" + echo -e "${green}This command installs one binary on the host and few containers on Podman.${reset}\n" + echo -e "${green}Options:${reset}" + echo -e "${green} --username TEXT${reset} (Required) Set username for authentication." + echo -e "${green} --password TEXT${reset} (Required) Set password for authentication." + echo -e "${green} --taxonomy-dir PATH${reset} (Optional) Path of the taxonomy repo directory." + echo -e " e.g /var/home/cloud-user/.local/share/instructlab/taxonomy." + echo -e "${green} --auth-url URL${reset} (Optional) Authentication URL. (default: https://localhost:3000)." + echo -e "${green} --auth-secret TEXT${reset} (Optional) Authentication secret." + echo -e "${green} --dev-mode ${reset} (Optional)Enable development mode. Deploys assistive features for Developers." + echo -e "${green} --experimental-features ${reset} (Optional)Enable experimental features available in Native mode." + echo -e "${green} --python-venv-dir ${reset} (Optional)Path to the InstructLab Python virtual environment directory." + echo -e " e.g /var/home/cloud-user/instructlab/venv \n" + exit 1 +} + +usage_uninstall() { + echo -e "${green}Usage: $0 uninstall [OPTIONS]...${reset}\n" + echo -e "${green}Uninstalls the InstructLab UI stack and removes temporary files downloaded during installation.${reset}\n" + echo -e "${green}Options:${reset}" + echo -e "${green} --help${reset} Show this message and exit.\n" + exit 1 +} + +# Check if Podman is installed +check_podman() { + if ! command -v podman &>/dev/null; then + echo -e "${red}Podman is not installed!.${reset}\n" + exit 1 + fi +} + +# Check if UI stack is already running + +check_ui_stack() { + # Check if UI containers are already running + containers=("ui-pod-ui" "doclingserve-pod-doclingserve" "pathservice-pod-pathservice") + + # Check each container + for container in "${containers[@]}"; do + if podman ps --format "{{.Names}}" | grep -q "^$container\$"; then + echo -e "${red}UI stack container '$container' is already running.${reset}\n" + echo -e "${red}Please uninstall the UI stack before reinstalling.${reset}\n" + exit 0 + fi + done +} + +# Verify user provide python environment +verify_user_pyenv() { + venv_ilab="$PYENV_DIR/bin/ilab" + if [ ! -e "$venv_ilab" ]; then + echo -e "${green}Seems like ilab is not installed in the provided virtual environment:$PYENV_DIR${reset}\n" + read -r -p "Do you want to discover the existing ilab installation on the host? (yes/no): " CONFIRM + if [[ "$CONFIRM" == "yes" || "$CONFIRM" == "y" ]]; then + discover_ilab + if [[ "$DISCOVERED_PYENV_DIR" != "" ]]; then + PYENV_DIR="$DISCOVERED_PYENV_DIR" + return + fi + fi + IS_ILAB_INSTALLED="false" + fi +} + +# Check if the ilab set up exist, the taxonomy location is configured is same as user provided +verify_user_taxonomy() { + if [[ "$IS_ILAB_INSTALLED" == "true" ]]; then + echo -e "${green}Seems like ilab is configured on the host. Discover the taxonomy path...${reset}\n" + + discover_taxonomy_path + if [[ "$DISCOVERED_TAXONOMY_DIR" != "" ]]; then + if [[ "$USER_TAXONOMY_DIR" != "$DISCOVERED_TAXONOMY_DIR" ]]; then + echo -e "${red}ilab configured taxonomy repo is detected under the directory - $DISCOVERED_TAXONOMY_DIR${reset}\n" + echo -e "${red}and it's not same as provided by the user - $USER_TAXONOMY_DIR${reset}\n" + echo -e "${blue}It's recommended to use the taxonomy repo configured for the ilab CLI.${reset}\n" + echo -e "${blue}In case you do not choose ilab configured taxonomy, data generation and fine tune features will not work.${reset}\n" + echo -e "${blue}But skill and knowledge contribution features should work as expected.${reset}\n" + echo -e "${red}Please choose the taxonomy repo you would like to use with InstructLab UI:${reset}" + echo -e "${red}1. ilab Taxonomy - $DISCOVERED_TAXONOMY_DIR${reset}" + echo -e "${red}2. Provided Taxonomy - $USER_TAXONOMY_DIR${reset}" + read -r -p "Please choose the taxonomy repo you would like to use with InstructLab UI? (1/2): " CHOICE + if [[ "$CHOICE" == "1" ]]; then + SELECTED_TAXONOMY_DIR=$DISCOVERED_TAXONOMY_DIR + else + SELECTED_TAXONOMY_DIR=$USER_TAXONOMY_DIR + fi + else + echo -e "${green}User provided taxonomy and the ilab configured taxonomy directory is same.{reset}\n" + fi + return + fi + fi + SELECTED_TAXONOMY_DIR=$USER_TAXONOMY_DIR +} + +# Discover python virtual environments on host +discover_pyenv() { + echo -e "${green}Discovering python virtual environment present on the host...${reset}\n" + results=() + while IFS= read -r line; do + results+=("$line") + done < <(find "$HOME" -type d -name "bin" -exec test -f {}/activate \; -print 2>/dev/null) + + # Check if any results were found + if [ ${#results[@]} -eq 0 ]; then + echo -e "${red}No python virtual environment found.${reset}\n" + return + fi + + # Display results as a numbered list + echo -e "${green}Following python virtual environments found on the host.${reset}\n" + echo -e "${green}Select a python virtual environment that is running InstructLab:${reset}" + echo -e "${green}0. Don't want to use InstructLab set up in python virtual environment${reset}" + for i in "${!results[@]}"; do + echo -e "${green}$((i + 1)). $(dirname "${results[i]}")${reset}" + done + + # Get user selection + read -r -p "Enter your choice (0-${#results[@]}): " choice + + # Validate input + if [[ "$choice" =~ ^[0-9]+$ ]] && ((choice >= 1 && choice <= ${#results[@]})); then + + DISCOVERED_PYENV_DIR=$(dirname "${results[choice - 1]}") + elif [[ "$choice" =~ ^[0-9]+$ ]] && ((choice == 0)); then + IS_ILAB_INSTALLED="false" + else + echo "Invalid choice. Exiting." + exit 1 + fi +} + +# Discover the taxonomy path if ilab is set up on the host +discover_taxonomy_path() { + echo -e "${green}Discovering ilab configured taxonomy on the host...${reset}\n" + taxonomy_path="" + if [[ "$IS_ILAB_INSTALLED" == "true" ]]; then + if [[ "$PYENV_DIR" == "" && "$DISCOVERED_PYENV_DIR" == "" ]]; then + taxonomy_path=$(ilab config show 2>/dev/null | grep "taxonomy_path" | head -n 1 | cut -d ':' -f 2) + else + # Always use discovered python virtual environment, + venv_ilab="$DISCOVERED_PYENV_DIR/bin/ilab" + taxonomy_path=$($venv_ilab config show 2>/dev/null | grep "taxonomy_path" | head -n 1 | cut -d ':' -f 2) + fi + else + echo -e "${red}ilab is not set up on the host. Skip taxonomy path discovery.{reset}\n" + return + fi + if [[ -n "$taxonomy_path" ]]; then + DISCOVERED_TAXONOMY_DIR="$taxonomy_path" + fi +} + +discover_ilab() { + # Check if ilab is installed natively or in the python virtual environment + echo -e "${green}Cheking if ilab (InstructLab CLI) is installed natively...${reset}\n" + if ! command -v ilab &>/dev/null; then + echo -e "${red}ilab (InstructLab) is not installed natively on the host!.${reset}\n" + + discover_pyenv + else + echo -e "${green}ilab is natively installed on the host.${reset}\n" + fi + +} + +# Parse input arguments +if [[ $# -lt 1 ]]; then + usage +fi + +COMMAND=$1 +shift + +if [[ "$COMMAND" == "install" ]]; then + while [[ $# -gt 0 ]]; do + case "$1" in + --username) + USERNAME="$2" + shift 2 + ;; + --password) + PASSWORD="$2" + shift 2 + ;; + --taxonomy-dir) + USER_TAXONOMY_DIR="$2" + shift 2 + ;; + --auth-url) + AUTH_URL="$2" + shift 2 + ;; + --auth-secret) + AUTH_SECRET="$2" + shift 2 + ;; + --dev-mode) + DEV_MODE="true" + shift 2 + ;; + --experimental-features) + EXPERIMENTAL_FEATURES="true" + shift 2 + ;; + --python-venv-dir) + PYENV_DIR="$2" + shift 2 + ;; + --help) + usage_install + ;; + *) + usage_install + ;; + esac + done + + if [[ -z "$USERNAME" || -z "$PASSWORD" ]]; then + usage_install + fi + + check_podman + check_ui_stack + + # Verify user provided python virtual environment + if [[ -n "$PYENV_DIR" ]]; then + verify_user_pyenv + else + discover_ilab + echo -e "\n${blue}NOTE: To skip the virtual environment discovery, you can use --python-venv-dir option to provide the python virtual environment path.${reset}\n" + fi + + # ilab is not set up and the user didn't provide that taxonomy info as well. Exit with warning info. + if [[ "$IS_ILAB_INSTALLED" == "false" ]]; then + if [[ "$USER_TAXONOMY_DIR" == "" ]]; then + echo -e "${red}Given that ilab is not set up on the host, taxonomy repo is not discovered.${reset}\n" + echo -e "${red}To proceed with the installation please do one of the following:${reset}" + echo -e "${red}1. Clone the taxonomy repo and provide the path to the directory using '--taxonomy-dir' option.${reset}" + echo -e "${red}2. Set up the ilab. If using virtual environment to set up the ilab, use --python-venv-dir option to virtual environment directory.${reset}" + exit 1 + fi + fi + + if [[ -n "$USER_TAXONOMY_DIR" ]]; then + verify_user_taxonomy + else + discover_taxonomy_path + if [[ "$DISCOVERED_TAXONOMY_DIR" != "" ]]; then + SELECTED_TAXONOMY_DIR="$DISCOVERED_TAXONOMY_DIR" + fi + echo -e "${blue}NOTE: To skip taxonomy path discovery, you can provide the taxonomy directory path using --taxonomy-dir option ${reset}\n" + fi + + # ilab is installed but not configured. + if [[ "$IS_ILAB_INSTALLED" == "true" ]]; then + if [[ "$DISCOVERED_TAXONOMY_DIR" == "" ]]; then + echo -e "${red}Seems like ilab is not initialized and configured on the host!.${reset}\n" + echo -e "${red}If ilab is not initialized, some of the UI features like synthetic data generation and fine tuning will not be available.${reset}\n" + read -r -p "Are you sure you want to continue with the UI installation? (yes/no): " CONFIRM + if [[ "$CONFIRM" != "yes" && "$CONFIRM" != "y" ]]; then + echo -e "${green}Installation aborted. Please initialize and configure ilab and attempt the installation again.${reset}\n" + exit 1 + fi + IS_ILAB_INSTALLED="false" + fi + fi + + echo -e "${green}Starting InstructLab UI installation...${reset}\n" + echo -e "${green}InstructLab UI will be set up with taxonomy present in $SELECTED_TAXONOMY_DIR.${reset}\n" + + # Encode credentials in base64 + UI_DEPLOYMENT_B64=$(echo -n "$UI_DEPLOYMENT" | base64) + USERNAME_B64=$(echo -n "$USERNAME" | base64) + PASSWORD_B64=$(echo -n "$PASSWORD" | base64) + taxonomyInPath=$(basename "$SELECTED_TAXONOMY_DIR") + if [[ "$taxonomyInPath" == "taxonomy" ]]; then + SELECTED_TAXONOMY_DIR_B64=$(echo -n "$(dirname "$SELECTED_TAXONOMY_DIR")" | base64) + else + SELECTED_TAXONOMY_DIR_B64=$(echo -n "$SELECTED_TAXONOMY_DIR" | base64) + fi + + AUTH_URL_B64=$(echo -n "$AUTH_URL" | base64) + AUTH_SECRET_B64=$(echo -n "$AUTH_SECRET" | base64) + DEV_MODE_B64=$(echo -n "$DEV_MODE" | base64) + EXPERIMENTAL_FEATURES_B64=$(echo -n "$EXPERIMENTAL_FEATURES" | base64) + + # Download secret.yaml file + echo -e "${green}Downloading the secret.yaml sample file...${reset}\n" + curl -o secret.yaml https://raw.githubusercontent.com/instructlab/ui/main/deploy/podman/native/secret.yaml.example + + # Detect OS and architecture + OS=$(uname -s | tr '[:upper:]' '[:lower:]') + ARCH=$(uname -m) + BINARY_URL="" + + # Replace placeholders with encoded values + echo -e "${green}Configuring the secrets for UI stack installation...${reset}\n" + if [[ "$OS" == "darwin" ]]; then + sed -i "" "s||$UI_DEPLOYMENT_B64|g" secret.yaml + sed -i "" "s||$USERNAME_B64|g" secret.yaml + sed -i "" "s||$PASSWORD_B64|g" secret.yaml + sed -i "" "s||$SELECTED_TAXONOMY_DIR_B64|g" secret.yaml + sed -i "" "s||$AUTH_URL_B64|g" secret.yaml + sed -i "" "s||$AUTH_SECRET_B64|g" secret.yaml + sed -i "" "s||$DEV_MODE_B64|g" secret.yaml + sed -i "" "s||$EXPERIMENTAL_FEATURES_B64|g" secret.yaml + else + sed -i "s||$UI_DEPLOYMENT_B64|g" secret.yaml + sed -i "s||$USERNAME_B64|g" secret.yaml + sed -i "s||$PASSWORD_B64|g" secret.yaml + sed -i "s||$SELECTED_TAXONOMY_DIR_B64|g" secret.yaml + sed -i "s||$AUTH_URL_B64|g" secret.yaml + sed -i "s||$AUTH_SECRET_B64|g" secret.yaml + sed -i "s||$DEV_MODE_B64|g" secret.yaml + sed -i "s||$EXPERIMENTAL_FEATURES_B64|g" secret.yaml + fi + + if [[ "$IS_ILAB_INSTALLED" == "true" ]]; then + echo -e "${green}Downloading the api server binary for OS: $OS and ARCH: $ARCH ${reset}\n" + if [[ "$OS" == "darwin" && "$ARCH" == "x86_64" ]]; then + BINARY_URL="https://instructlab-ui.s3.us-east-1.amazonaws.com/apiserver/apiserver-darwin-amd64.tar.gz" + elif [[ "$OS" == "darwin" && "$ARCH" == "arm64" ]]; then + BINARY_URL="https://instructlab-ui.s3.us-east-1.amazonaws.com/apiserver/apiserver-darwin-arm64.tar.gz" + elif [[ "$OS" == "linux" && "$ARCH" == "x86_64" ]]; then + BINARY_URL="https://instructlab-ui.s3.us-east-1.amazonaws.com/apiserver/apiserver-linux-amd64.tar.gz" + elif [[ "$OS" == "linux" && "$ARCH" == "aarch64" ]]; then + BINARY_URL="https://instructlab-ui.s3.us-east-1.amazonaws.com/apiserver/apiserver-linux-arm64.tar.gz" + else + echo -e "${red}Unsupported OS/Architecture: $OS/$ARCH${reset}\n" + exit 1 + fi + + # Download the api-server binary + curl -o apiserver.tar.gz "$BINARY_URL" + tar -xvzf apiserver.tar.gz -C "$BINARY_INSTALL_DIR" --strip-components 1 + chmod +x ./ilab-apiserver + + echo -e "${green}API server binary is downloaded and configured.${reset}\n" + + # Start the api-server + if [[ "$OS" == "darwin" ]]; then + echo -e "${green}Starting API server on OS: $OS running on arch $ARCH ${reset}\n" + nohup ./ilab-apiserver --base-dir "$DISCOVERED_PYENV_DIR" --taxonomy-path "$SELECTED_TAXONOMY_DIR" --osx --pipeline simple >$ILAB_APISERVER_LOG_FILE 2>&1 & + else + CUDA_FLAG="" + if [ "$(command -v nvcc)" ] && [ -n "$(nvcc --version)" ]; then + CUDA_FLAG="--cuda" + fi + # Check if /etc/os-release exists + # shellcheck source=/etc/os-release + # shellcheck disable=SC1091 + source /etc/os-release + echo "VARIANT_ID: $VARIANT_ID" + # Check if VARIANT_ID is "rhel_ai" + if [ "$VARIANT_ID" == "rhel_ai" ]; then + echo -e "${green}Starting API server on OS: RHEL AI running on arch $ARCH ${reset}\n" + nohup ./ilab-apiserver --taxonomy-path "$SELECTED_TAXONOMY_DIR" --rhelai "$CUDA_FLAG" >$ILAB_APISERVER_LOG_FILE 2>&1 & + else + echo -e "${green}Starting API server on OS: $OS running on arch $ARCH ${reset}\n" + nohup ./ilab-apiserver --base-dir "$DISCOVERED_PYENV_DIR" --taxonomy-path "$SELECTED_TAXONOMY_DIR" "$CUDA_FLAG" >$ILAB_APISERVER_LOG_FILE 2>&1 & + fi + + fi + echo -e "${green}API server service is started in background. Logs are available in $ILAB_APISERVER_LOG_FILE file.${reset}\n" + fi + + # Download instructlab-ui.yaml + echo -e "${green}Downloading the UI stack manifest file (instructlab-ui.yaml)...${reset}\n" + curl -o instructlab-ui.yaml https://raw.githubusercontent.com/instructlab/ui/main/deploy/podman/native/instructlab-ui.yaml + + # Replace placeholders in instructlab-ui.yaml + taxonomyInPath=$(basename "$SELECTED_TAXONOMY_DIR") + if [[ "$taxonomyInPath" == "taxonomy" ]]; then + if [[ "$OS" == "darwin" ]]; then + sed -i "" "s||$(dirname "$SELECTED_TAXONOMY_DIR")|g" instructlab-ui.yaml + else + sed -i "s||$(dirname "$SELECTED_TAXONOMY_DIR")|g" instructlab-ui.yaml + fi + else + if [[ "$OS" == "darwin" ]]; then + sed -i "" "s||$SELECTED_TAXONOMY_DIR|g" instructlab-ui.yaml + else + sed -i "s||$SELECTED_TAXONOMY_DIR|g" instructlab-ui.yaml + fi + fi + + echo -e "${green}UI stack manifest file (instructlab-ui.yaml) is configured with required parameters${reset}\n" + + # Run Podman commands + echo -e "${green}Deploying the secrets in Podman...${reset}\n" + podman kube play secret.yaml + + echo -e "\n${green}Deploying the UI stack containers in Podman...${reset}\n" + podman kube play instructlab-ui.yaml + + # Print running pods + echo -e "\n${green}Containers deployed for UI stack...${reset}\n" + podman ps + + echo -e "${green}InstructLab UI is successfully installed. You can access the UI at the following $AUTH_URL${reset}\n" + +elif [[ "$COMMAND" == "uninstall" ]]; then + while [[ $# -gt 0 ]]; do + case "$1" in + --help) + usage_uninstall + ;; + *) + usage + ;; + esac + done + + read -r -p "Are you sure you want to uninstall the InstructLab UI stack? (yes/no): " CONFIRM + if [[ "$CONFIRM" != "yes" && "$CONFIRM" != "y" ]]; then + echo -e "${green}Uninstallation aborted.${reset}\n" + exit 0 + fi + + check_podman + echo -e "${green}Uninstalling InstructLab UI stack...${reset}\n" + + if ! command -v podman &>/dev/null; then + echo -e "${red}Podman is not installed!. are you sure you installed InstructLab UI?${reset}\n" + else + # Run Podman commands to uninstall UI containers + echo -e "${green}Deleting the UI stack containers from Podman...${reset}\n" + podman kube down instructlab-ui.yaml + echo -e "${green}Deleting the UI stack secrets from Podman...${reset}\n" + podman kube down secret.yaml + fi + + echo -e "${green}Stopping API server (if installed)...${reset}\n" + pkill -f ilab-apiserver || true + echo -e "${green}Cleaning up all the downloaded and temporary files${reset}\n" + rm -f secret.yaml instructlab-ui.yaml apiserver.tar.gz ilab-apiserver + echo -e "${green}Uninstallation successfully completed.${reset}\n" +else + usage +fi