Skip to content

Commit f1e683e

Browse files
committed
add python gen ai release test
1 parent 63cc68e commit f1e683e

File tree

23 files changed

+529
-325
lines changed

23 files changed

+529
-325
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
## SPDX-License-Identifier: Apache-2.0
3+
4+
name: Python EC2 LangChain Service Deployment
5+
on:
6+
push:
7+
branches:
8+
- origin/gen-ai-sample-app
9+
10+
permissions:
11+
id-token: write
12+
contents: read
13+
14+
env:
15+
E2E_TEST_AWS_REGION: 'us-west-2'
16+
# E2E_TEST_ACCOUNT_ID: ${{ secrets.APPLICATION_SIGNALS_E2E_TEST_ACCOUNT_ID }}
17+
# E2E_TEST_ROLE_NAME: ${{ secrets.APPLICATION_SIGNALS_E2E_TEST_ROLE_NAME }}
18+
E2E_TEST_ACCOUNT_ID: 571600841604
19+
E2E_TEST_ROLE_NAME: github
20+
METRIC_NAMESPACE: genesis
21+
LOG_GROUP_NAME: test/genesis
22+
TEST_RESOURCES_FOLDER: ${GITHUB_WORKSPACE}
23+
SAMPLE_APP_ZIP: s3://sigv4perfresults/langchain-service.zip
24+
25+
jobs:
26+
python-ec2-adot-genai:
27+
runs-on: ubuntu-latest
28+
timeout-minutes: 30
29+
steps:
30+
- uses: actions/checkout@v4
31+
32+
# - name: Set Get ADOT Wheel command environment variable
33+
# run: |
34+
# if [ "${{ github.event.repository.name }}" = "aws-otel-python-instrumentation" ]; then
35+
# # Reusing the adot-main-build-staging-jar bucket to store the python wheel file
36+
# echo GET_ADOT_WHEEL_COMMAND="aws s3 cp s3://adot-main-build-staging-jar/${{ env.ADOT_WHEEL_NAME }} ./${{ env.ADOT_WHEEL_NAME }} && sudo python${{ env.PYTHON_VERSION }} -m pip install ${{ env.ADOT_WHEEL_NAME }}" >> $GITHUB_ENV
37+
# elif [ "${{ env.OTEL_SOURCE }}" == "pypi" ]; then
38+
# echo GET_ADOT_WHEEL_COMMAND="sudo python${{ env.PYTHON_VERSION }} -m pip install ${{ env.ADOT_WHEEL_NAME }}" >> $GITHUB_ENV
39+
# else
40+
# latest_release_version=$(curl -sL https://github.com/aws-observability/aws-otel-python-instrumentation/releases/latest | grep -oP '/releases/tag/v\K[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)
41+
# echo "The latest version is $latest_release_version"
42+
# echo GET_ADOT_WHEEL_COMMAND="wget -O ${{ env.ADOT_WHEEL_NAME }} https://github.com/aws-observability/aws-otel-python-instrumentation/releases/latest/download/aws_opentelemetry_distro-$latest_release_version-py3-none-any.whl \
43+
# && sudo python${{ env.PYTHON_VERSION }} -m pip install ${{ env.ADOT_WHEEL_NAME }}" >> $GITHUB_ENV
44+
# fi
45+
46+
- name: Initiate Gradlew Daemon
47+
uses: ./.github/workflows/actions/execute_and_retry
48+
continue-on-error: true
49+
with:
50+
command: "./gradlew :validator:build"
51+
cleanup: "./gradlew clean"
52+
max_retry: 3
53+
sleep_time: 60
54+
55+
- name: Generate testing id
56+
run: echo TESTING_ID="${{ github.run_id }}-${{ github.run_number }}-${RANDOM}" >> $GITHUB_ENV
57+
58+
- name: Generate XRay and W3C trace ID
59+
run: |
60+
ID_1="$(printf '%08x' $(date +%s))"
61+
ID_2="$(openssl rand -hex 12)"
62+
W3C_TRACE_ID="${ID_1}${ID_2}"
63+
XRAY_TRACE_ID="1-${ID_1}-${ID_2}"
64+
echo "XRAY_TRACE_ID=${XRAY_TRACE_ID}" >> $GITHUB_ENV
65+
echo "W3C_TRACE_ID=${W3C_TRACE_ID}" >> $GITHUB_ENV
66+
echo "Generated XRay Trace ID: ${XRAY_TRACE_ID}"
67+
echo "Generated W3C Trace ID: ${W3C_TRACE_ID}"
68+
69+
- name: Configure AWS Credentials
70+
uses: aws-actions/configure-aws-credentials@v4
71+
with:
72+
role-to-assume: arn:aws:iam::${{ env.E2E_TEST_ACCOUNT_ID }}:role/${{ env.E2E_TEST_ROLE_NAME }}
73+
aws-region: ${{ env.E2E_TEST_AWS_REGION }}
74+
75+
- name: Set up terraform
76+
uses: ./.github/workflows/actions/execute_and_retry
77+
with:
78+
command: "wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg"
79+
post-command: 'echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
80+
&& sudo apt update && sudo apt install terraform'
81+
82+
- name: Initiate Terraform
83+
uses: ./.github/workflows/actions/execute_and_retry
84+
with:
85+
command: "cd ${{ env.TEST_RESOURCES_FOLDER }}/terraform/python/ec2/adot-genai && terraform init && terraform validate"
86+
cleanup: "rm -rf .terraform && rm -rf .terraform.lock.hcl"
87+
max_retry: 6
88+
89+
- name: Deploy service via terraform
90+
working-directory: terraform/python/ec2/adot-genai
91+
run: |
92+
terraform apply -auto-approve \
93+
-var="aws_region=${{ env.E2E_TEST_AWS_REGION }}" \
94+
-var="test_id=${{ env.TESTING_ID }}" \
95+
-var="service_zip_url=${{ env.SAMPLE_APP_ZIP }}"
96+
97+
- name: Get deployment info
98+
working-directory: terraform/python/ec2/adot-genai
99+
run: |
100+
echo "INSTANCE_IP=$(terraform output langchain_service_public_ip)" >> $GITHUB_ENV
101+
echo "INSTANCE_ID=$(terraform output langchain_service_instance_id)" >> $GITHUB_ENV
102+
103+
- name: Wait for Gen AI Chatbot service to be ready
104+
run: |
105+
echo "Waiting for service to be ready at http://${{ env.INSTANCE_IP }}:8000"
106+
for i in {1..60}; do
107+
if curl -f -s "http://${{ env.INSTANCE_IP }}:8000/health" > /dev/null 2>&1; then
108+
echo "Service is ready!"
109+
break
110+
fi
111+
echo "Attempt $i: Service not ready yet, waiting 10 seconds..."
112+
sleep 10
113+
done
114+
115+
# Final check
116+
if ! curl -f -s "http://${{ env.INSTANCE_IP }}:8000/health" > /dev/null 2>&1; then
117+
echo "Service failed to become ready after 10 minutes"
118+
exit 1
119+
fi
120+
121+
- name: Generate traffic
122+
run: |
123+
cd sample-apps/traffic-generator/genai
124+
chmod +x generate_traffic.sh
125+
export SERVER_URL="http://${{ env.INSTANCE_IP }}:8000"
126+
export NUM_REQUESTS="5"
127+
export DELAY_SECONDS="5"
128+
export TIMEOUT="30"
129+
export TRACE_ID="Root=${XRAY_TRACE_ID};Parent=$(openssl rand -hex 8);Sampled=1"
130+
./generate_traffic.sh
131+
132+
- name: Validate generated logs
133+
run: ./gradlew validator:run --args='-c python/ec2/adot-genai/log-validation.yml
134+
--testing-id ${{ env.TESTING_ID }}
135+
--endpoint http://${{ env.INSTANCE_IP }}:8000
136+
--region ${{ env.E2E_TEST_AWS_REGION }}
137+
--metric-namespace ${{ env.METRIC_NAMESPACE }}
138+
--log-group ${{ env.LOG_GROUP_NAME }}
139+
--service-name langchain-traceloop-app
140+
--instance-id ${{ env.INSTANCE_ID }}
141+
--trace-id ${{ env.W3C_TRACE_ID }}'
142+
143+
- name: Validate generated traces
144+
if: (success() || failure()) && !cancelled()
145+
run: ./gradlew validator:run --args='-c python/ec2/adot-genai/trace-validation.yml
146+
--testing-id ${{ env.TESTING_ID }}
147+
--endpoint http://${{ env.INSTANCE_IP }}:8000
148+
--region ${{ env.E2E_TEST_AWS_REGION }}
149+
--metric-namespace ${{ env.METRIC_NAMESPACE }}
150+
--service-name langchain-traceloop-app
151+
--instance-id ${{ env.INSTANCE_ID }}
152+
--trace-id ${{ env.XRAY_TRACE_ID }}'
153+
154+
- name: Wait for metrics to be published
155+
if: (success() || failure()) && !cancelled()
156+
run: |
157+
echo "Waiting 60 seconds to ensure EMF metrics are published to CloudWatch"
158+
sleep 60
159+
160+
- name: Validate generated metrics
161+
if: (success() || failure()) && !cancelled()
162+
run: ./gradlew validator:run --args='-c python/ec2/adot-genai/metric-validation.yml
163+
--testing-id ${{ env.TESTING_ID }}
164+
--endpoint http://${{ env.INSTANCE_IP }}:8000
165+
--region ${{ env.E2E_TEST_AWS_REGION }}
166+
--metric-namespace ${{ env.METRIC_NAMESPACE }}
167+
--log-group ${{ env.LOG_GROUP_NAME }}
168+
--service-name langchain-traceloop-app
169+
--instance-id ${{ env.INSTANCE_ID }}'
170+
171+
- name: Cleanup
172+
if: always()
173+
continue-on-error: true
174+
working-directory: terraform/python/ec2/adot-genai
175+
run: |
176+
terraform destroy -auto-approve \
177+
-var="aws_region=${{ env.E2E_TEST_AWS_REGION }}" \
178+
-var="test_id=${{ env.TESTING_ID }}" \
179+
-var="service_zip_url=${{ env.SAMPLE_APP_ZIP }}"

.github/workflows/python-ec2-genesis-test.yml

Lines changed: 0 additions & 129 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
langchain
22
langchain-community
3+
langchain_aws
34
opentelemetry-sdk
5+
openinference-instrumentation-langchain
46
opentelemetry-api
57
opentelemetry-semantic-conventions
68
python-dotenv
79
openlit
810
botocore
911
setuptools
1012
boto3
11-
./aws_opentelemetry_distro_genai_beta-0.1.0b8-py3-none-any.whl
13+
aws_opentelemetry_distro_genai_beta
1214
fastapi
1315
uvicorn[standard]

sample-apps/python/langchain_service/server.py renamed to sample-apps/python/genai_service/server.py

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,12 @@ async def root():
8282
return {
8383
"message": "LangChain Bedrock OpenInference API is running!",
8484
"endpoints": {
85-
"/chat": "Single message chat endpoint",
86-
"/batch": "Batch message processing endpoint",
87-
"/sample": "Run sample prompts"
85+
"/ai-chat": "Single message chat endpoint",
86+
"/hello": "Simple hello endpoint"
8887
}
8988
}
9089

91-
@app.post("/chat", response_model=ChatResponse)
90+
@app.post("/ai-chat", response_model=ChatResponse)
9291
async def chat(request: ChatRequest):
9392
"""
9493
Chat endpoint that processes a single user message through AWS Bedrock
@@ -100,40 +99,6 @@ async def chat(request: ChatRequest):
10099
except Exception as e:
101100
raise HTTPException(status_code=500, detail=str(e))
102101

103-
@app.post("/batch", response_model=BatchChatResponse)
104-
async def batch_chat(request: BatchChatRequest):
105-
"""
106-
Batch endpoint that processes multiple messages
107-
"""
108-
try:
109-
responses = []
110-
for message in request.messages:
111-
result = await chain.ainvoke({"input": message})
112-
responses.append({
113-
"message": message,
114-
"response": result["text"]
115-
})
116-
return BatchChatResponse(responses=responses)
117-
except Exception as e:
118-
raise HTTPException(status_code=500, detail=str(e))
119-
120-
@app.get("/sample", response_model=BatchChatResponse)
121-
async def run_samples():
122-
"""
123-
Run the predefined sample prompts
124-
"""
125-
try:
126-
responses = []
127-
for prompt in SAMPLE_PROMPTS:
128-
result = await chain.ainvoke({"input": prompt})
129-
responses.append({
130-
"message": prompt,
131-
"response": result["text"]
132-
})
133-
return BatchChatResponse(responses=responses)
134-
except Exception as e:
135-
raise HTTPException(status_code=500, detail=str(e))
136-
137102
@app.get("/health")
138103
async def health():
139104
"""Health check endpoint"""
@@ -145,4 +110,5 @@ async def health():
145110
print("Make sure AWS credentials are configured")
146111
print("Server will run on http://localhost:8000")
147112
print("API docs available at http://localhost:8000/docs")
113+
148114
uvicorn.run(app, host="0.0.0.0", port=8000)

0 commit comments

Comments
 (0)