diff --git a/ansible/roles_ocp_workloads/ocp4_workload_ols/defaults/main.yml b/ansible/roles_ocp_workloads/ocp4_workload_ols/defaults/main.yml index 1ffd8ed851e..59835a7be7b 100644 --- a/ansible/roles_ocp_workloads/ocp4_workload_ols/defaults/main.yml +++ b/ansible/roles_ocp_workloads/ocp4_workload_ols/defaults/main.yml @@ -37,7 +37,7 @@ ocp4_workload_ols_print_access_information: false # When not set (or set to "") use the default channel for the # OpenShift version this operator is installed on. If there is # no matching version use the `defaultChannel` -ocp4_workload_ols_channel: preview +ocp4_workload_ols_channel: alpha # Set automatic InstallPlan approval. If set to false it is # also suggested to set the starting_csv to pin a specific @@ -82,16 +82,28 @@ ocp4_workload_ai_platform: azure #openai, azure, watson, openshiftai # Token to Access GPT Model for OpenShift LightSpeed ocp4_workload_ols_api_token_secret: "{{ ocp4_workload_ols_api_token }}" #Coming from Vault +# Select if using bearer token or api key for Azure AI Services +ocp4_workload_ols_token: true #false if using api key based access + +#Mandatory values to pass during Azure AI Services Access using Bearer Token instead of api key +ocp4_workload_ols_main_client_id: "changeme" +ocp4_workload_ols_main_client_secret: "changeme" +ocp4_workload_ols_azure_tenant_id: "changeme" +ocp4_workload_ols_azure_group_id: "changeme" +ocp4_workload_ols_azure_region: "eastus" # e.g., westus, eastus +ocp4_workload_ols_child_app_display_name: "RHDP-lightspeed" + # LLM provider variables (for Azure) -ocp4_workload_ols_llm_providers_models_name: gpt-4o +ocp4_workload_ols_llm_providers_models_name: gpt-4 ocp4_workload_ols_llm_providers_provide_name: Azure ocp4_workload_ols_llm_providers_provide_type: azure_openai -ocp4_workload_ols_llm_providers_url: 'https://ols-test.openai.azure.com/' +ocp4_workload_ols_llm_providers_url: 'https://llm-gpt4-lightspeed.openai.azure.com/' +ocp4_workload_ols_llm_deploymentname: gpt-4 #this variable is required only for Azure -ocp4_workload_ols_llm_deploymentname: 4o-jun24 #this variable is required only for Azure +# Only for Watson Ai Service ocp4_workload_ols_watson_projectid: projectid #Change this with Watson Project ID, only when using Watson Model. # OLS Default Mode vars -ocp4_workload_ols_defaultmodel: gpt-4o +ocp4_workload_ols_defaultmodel: gpt-4 ocp4_workload_ols_defaultprovider: Azure ocp4_workload_ols_loglevel: DEBUG diff --git a/ansible/roles_ocp_workloads/ocp4_workload_ols/tasks/workload.yml b/ansible/roles_ocp_workloads/ocp4_workload_ols/tasks/workload.yml index b70e475fd8e..cdf6dc46be3 100644 --- a/ansible/roles_ocp_workloads/ocp4_workload_ols/tasks/workload.yml +++ b/ansible/roles_ocp_workloads/ocp4_workload_ols/tasks/workload.yml @@ -1,4 +1,3 @@ ---- # Implement your Workload deployment tasks here - name: Setting up workload for user debug: @@ -6,22 +5,185 @@ - name: OLS Operator Installation block: - - name: Install OLS Operator - when: ocp4_workload_ols_install_operator | bool - include_tasks: install_ols_operator.yml - - - name: Create secret - kubernetes.core.k8s: - definition: "{{ lookup('ansible.builtin.template', 'templates/create_secret.yml.j2') }}" - wait: true - wait_timeout: 300 - - - name: OLSConfig setup - kubernetes.core.k8s: - definition: "{{ lookup('ansible.builtin.template', 'templates/install_{{ ocp4_workload_ai_platform }}_olsconfig.j2') }}" - wait: true - wait_timeout: 300 - when: ocp4_workload_ai_platform is defined + - name: Install OLS Operator + when: ocp4_workload_ols_install_operator | bool + include_tasks: install_ols_operator.yml + + - name: Azure AI Cognitive Services + when: ocp4_workload_ols_token | bool + block: + - name: Get Token for Master App + uri: + url: "https://login.microsoftonline.com/{{ ocp4_workload_ols_azure_tenant_id }}/oauth2/v2.0/token" + method: POST + headers: + Content-Type: "application/x-www-form-urlencoded" + # yamllint disable rule:line-length + body: "grant_type=client_credentials&client_id={{ ocp4_workload_ols_main_client_id }}&client_secret={{ ocp4_workload_ols_main_client_secret }}&scope=https://graph.microsoft.com/.default" + # yamllint enable rule:line-length + return_content: true + status_code: 200 + register: master_token_response + + - name: Debug Master Token Response + debug: + var: master_token_response + + - name: Set Main Access Token + set_fact: + master_access_token: "{{ master_token_response.json.access_token }}" + + - name: Create Child App Registration + uri: + url: "https://graph.microsoft.com/v1.0/applications" + method: POST + headers: + Authorization: "Bearer {{ master_access_token }}" + Content-Type: "application/json" + body: + displayName: "{{ ocp4_workload_ols_child_app_display_name }}-{{ guid }}" + passwordCredentials: + - displayName: "ChildAppRegistrationSecret" + body_format: json + return_content: true + status_code: 201 # Expect 201 Created + register: child_app_response + + - name: Set Child App ID and Secret + set_fact: + _child_app_id: "{{ child_app_response.json.appId }}" + _child_client_secret: "{{ child_app_response.json.passwordCredentials[0].secretText }}" + + # Introduce a 30-second delay before the next tasks + - name: Pause for 30 seconds + pause: + seconds: 30 + + - name: Create Service Principal for Child App + uri: + url: "https://graph.microsoft.com/v1.0/servicePrincipals" + method: POST + headers: + Authorization: "Bearer {{ master_access_token }}" + Content-Type: "application/json" + body: + appId: "{{ _child_app_id | string }}" + body_format: json + return_content: true + status_code: 201 # Expect 201 Created + register: service_principal_response + + # Introduce a 30-second delay before the next tasks + - name: Pause for 30 seconds + pause: + seconds: 30 + + - name: Set Child Service Principal Object ID + set_fact: + _child_service_principal_object_id: "{{ service_principal_response.json.id }}" + + - name: Add Child App to Azure AD Group + uri: + url: "https://graph.microsoft.com/v1.0/groups/{{ ocp4_workload_ols_azure_group_id }}/members/$ref" + method: POST + headers: + Authorization: "Bearer {{ master_access_token }}" + Content-Type: "application/json" + body: + "@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/{{ _child_service_principal_object_id }}" + body_format: json + return_content: true + status_code: [201, 204] # Expect 201 Created or 204 No Content + + # Introduce a 30-second delay before the next tasks + - name: Pause for 30 seconds + pause: + seconds: 30 + + - name: Get Token for Child App using REST API call + uri: + url: "https://login.microsoftonline.com/{{ ocp4_workload_ols_azure_tenant_id }}/oauth2/v2.0/token" + method: POST + headers: + Content-Type: "application/x-www-form-urlencoded" + body_format: form-urlencoded + body: + grant_type: client_credentials + client_id: "{{ _child_app_id }}" + client_secret: "{{ _child_client_secret }}" + scope: https://cognitiveservices.azure.com/.default + register: child_token_response + + - name: Set Child Access Token + set_fact: + _child_access_token: "{{ child_token_response.json.access_token }}" + + # Introduce a 30-second delay before the next tasks + - name: Pause for 30 seconds + pause: + seconds: 30 + + - name: Ask AI Service Using Child App + uri: + url: "https://llm-gpt4-lightspeed.openai.azure.com/openai/deployments/gpt-4/chat/completions?api-version=2023-06-01-preview" + method: POST + headers: + Content-Type: "application/json" + Authorization: "Bearer {{ _child_access_token }}" + body: + messages: + - role: system + content: "You are a helpful assistant." + - role: user + content: "What is the largest city in India?" + max_tokens: 100 + body_format: json + register: ai_service_response + + - name: Display AI Service Response + debug: + var: ai_service_response.stdout + + # Create bearer token secret, Azure App SP Secret and + # OLSConfig setup based on token condition. + - name: Create secret (Bearer Token) + when: ocp4_workload_ols_token | bool + kubernetes.core.k8s: + definition: "{{ lookup('ansible.builtin.template', 'templates/create_secret_token.yml.j2') }}" + wait: true + wait_timeout: 300 + + - name: Create App Service Principal + when: ocp4_workload_ols_token | bool + kubernetes.core.k8s: + definition: "{{ lookup('ansible.builtin.template', 'templates/create_azure_api_token.yml.j2') }}" + wait: true + wait_timeout: 300 + + - name: OLSConfig setup (Bearer Token) + when: + ocp4_workload_ols_token | bool + and ocp4_workload_ai_platform is defined + kubernetes.core.k8s: + definition: "{{ lookup('ansible.builtin.template', 'templates/install_azure_app_sp_olsconfig.yml.j2') }}" + wait: true + wait_timeout: 300 + + - name: Create secret (API Key) + when: not ocp4_workload_ols_token | bool + kubernetes.core.k8s: + definition: "{{ lookup('ansible.builtin.template', 'templates/create_secret.yml.j2') }}" + wait: true + wait_timeout: 300 + + - name: OLSConfig setup (API Key) + when: + not ocp4_workload_ols_token | bool + and ocp4_workload_ai_platform is defined + kubernetes.core.k8s: + definition: "{{ lookup('ansible.builtin.template', 'templates/install_{{ ocp4_workload_ai_platform }}_olsconfig.yml.j2') }}" + wait: true + wait_timeout: 300 - name: Create broken pod kubernetes.core.k8s: @@ -31,4 +193,4 @@ - name: workload tasks complete debug: msg: "Workload Tasks completed successfully." - when: not silent|bool + when: not silent | bool diff --git a/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/create_azure_api_token.yml.j2 b/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/create_azure_api_token.yml.j2 new file mode 100644 index 00000000000..65243eb1aec --- /dev/null +++ b/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/create_azure_api_token.yml.j2 @@ -0,0 +1,12 @@ +kind: Secret +apiVersion: v1 +metadata: + name: azure-api-keys + namespace: openshift-lightspeed + annotations: + ols.openshift.io/watcher: cluster +stringData: + client_id: "{{ _child_app_id }}" + client_secret: "{{ _child_client_secret }}" + tenant_id: "{{ ocp4_workload_ols_azure_tenant_id }}" +type: Opaque diff --git a/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/create_secret_token.yml.j2 b/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/create_secret_token.yml.j2 new file mode 100644 index 00000000000..1ed428ac0fb --- /dev/null +++ b/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/create_secret_token.yml.j2 @@ -0,0 +1,8 @@ +apiVersion: v1 +stringData: + Bearer: "{{ _child_access_token }}" +kind: Secret +metadata: + name: credentials + namespace: openshift-lightspeed +type: Opaque diff --git a/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_azure_app_sp_olsconfig.yml.j2 b/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_azure_app_sp_olsconfig.yml.j2 new file mode 100644 index 00000000000..845c9faaf19 --- /dev/null +++ b/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_azure_app_sp_olsconfig.yml.j2 @@ -0,0 +1,27 @@ +--- +apiVersion: ols.openshift.io/v1alpha1 +kind: OLSConfig +metadata: + name: cluster +spec: + llm: + providers: + - credentialsSecretRef: + name: azure-api-keys + #Use the name of the deployment with the provider + deploymentName: "{{ ocp4_workload_ols_llm_deploymentname }}" + models: + - name: "{{ ocp4_workload_ols_llm_providers_models_name }}" + name: "{{ ocp4_workload_ols_llm_providers_provide_name }}" + type: "{{ ocp4_workload_ols_llm_providers_provide_type }}" + # Use the URL you recorded after you created the deployment + url: "{{ ocp4_workload_ols_llm_providers_url }}" + + ols: + queryFilters: + - name: ip-address + pattern: '((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}' + replaceWith: + defaultModel: "{{ ocp4_workload_ols_defaultmodel }}" + defaultProvider: "{{ ocp4_workload_ols_defaultprovider }}" + logLevel: "{{ ocp4_workload_ols_loglevel }}" diff --git a/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_azure_olsconfig.j2 b/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_azure_olsconfig.yml.j2 similarity index 99% rename from ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_azure_olsconfig.j2 rename to ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_azure_olsconfig.yml.j2 index 332957b00dd..6a1c5f686a2 100644 --- a/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_azure_olsconfig.j2 +++ b/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_azure_olsconfig.yml.j2 @@ -24,4 +24,3 @@ spec: defaultModel: "{{ ocp4_workload_ols_defaultmodel }}" defaultProvider: "{{ ocp4_workload_ols_defaultprovider }}" logLevel: "{{ ocp4_workload_ols_loglevel }}" - diff --git a/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_openai_olsconfig.j2 b/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_openai_olsconfig.yml.j2 similarity index 100% rename from ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_openai_olsconfig.j2 rename to ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_openai_olsconfig.yml.j2 diff --git a/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_rhoai_vllm.olsconfig.j2 b/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_rhoai_vllm.olsconfig.yml.j2 similarity index 100% rename from ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_rhoai_vllm.olsconfig.j2 rename to ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_rhoai_vllm.olsconfig.yml.j2 diff --git a/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_watson_olsconfig.j2 b/ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_watson_olsconfig.yml.j2 similarity index 100% rename from ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_watson_olsconfig.j2 rename to ansible/roles_ocp_workloads/ocp4_workload_ols/templates/install_watson_olsconfig.yml.j2