Почему мое развертывание функций Azure не работает через GitLab CI/CD, несмотря на работу с расширением Azure Function CPython

Программы на Python
Ответить
Anonymous
 Почему мое развертывание функций Azure не работает через GitLab CI/CD, несмотря на работу с расширением Azure Function C

Сообщение Anonymous »

Я создал несколько функций Azure с помощью Python (3.9), и у меня возникли проблемы с настройкой CI/CD в репозитории GitLab, где находится код. Этот репозиторий находится на виртуальной машине Azure, не уверен, что это актуально. Функции подключаются к базе данных Azure PostgreSQL, как вы увидите далее в коде.
.gitlab-ci.yml запускает 3 задания: 2 первых создают и развертывают React. app в статические веб-приложения Azure. Третий успешно работает в конвейерах GitLab, но после этого я не вижу никаких функций на странице обзора приложения-функции Azure. Я также не вижу журналов ошибок в задании.
При использовании расширения VSCode основных инструментов функций Azure для развертывания непосредственно в приложении-функции Azure развертывание проходит успешно, и функции отображаются на странице обзора, и они работают правильно, подключаются к базе данных и все такое. Я также могу запускать и тестировать функции локально.
Вот различные фрагменты кода. Некоторая информация будет опущена в целях конфиденциальности, например URL-адреса
.gitlab-ci.yml:
stages:
- build-react
- deploy-react
- deploy-functions

# Build the React app
build-react:
stage: build-react
image: registry.gitlab.com/static-web-apps/azure-static-web-apps-deploy
script:
- cd app-frontend
- npm install
- VITE_FUNCTIONS_BASE_URL=azurewebsites-url npx vite build
artifacts:
paths:
- app-frontend/dist
only:
- main

# Deploy the React app to Azure Static Web Apps
deploy-react:
stage: deploy-react
image: registry.gitlab.com/static-web-apps/azure-static-web-apps-deploy
script:
- cd app-frontend
- npm install -g @azure/static-web-apps-cli
- swa deploy --env production --deployment-token token --output-location ./dist
only:
- main

deploy-functions:
stage: deploy-functions
image: mcr.microsoft.com/azure-functions/python:3.0 # Azure Functions image
script:
- set -e
- cd azure_functions # Navigate to the folder containing your Azure Function app
- zip -r ../my-functions.zip . # Create a zip file of only the contents of the azure_functions folder
- cd .. # Navigate back to the root directory
- echo "Zipped successfully"
- apt-get update && apt-get install -y ca-certificates curl apt-transport-https lsb-release gnupg
- curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
- echo "Deploying to Azure..."
- az login --service-principal -u $AZURE_CLIENT_ID -p $AZURE_CLIENT_SECRET --tenant $AZURE_TENANT_ID
- az functionapp deployment source config-zip --resource-group $AZURE_RESOURCE_GROUP --name $AZURE_FUNCTIONAPP_NAME --src ./my-functions.zip
only:
- main


requirements.txt:
azure-functions
psycopg2-binary

function_app.py:
import json
import azure.functions as func
import logging
from datetime import datetime
import psycopg2
import os

# Database connection details
DB_HOST = os.getenv("DB_HOST")
DB_NAME = os.getenv("DB_NAME")
DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")
DB_PORT = os.getenv("DB_PORT")

app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)

@app.route(route="desks", methods=["GET"], auth_level=func.AuthLevel.ANONYMOUS)
def getDesks(req: func.HttpRequest) -> func.HttpResponse:
# Connect to database and fetch reservations for the given date
try:
connection = psycopg2.connect(
host=DB_HOST,
port=DB_PORT,
database=DB_NAME,
user=DB_USER,
password=DB_PASSWORD,
)

cursor = connection.cursor()

# Query to get all desks
query = """
SELECT d.id
FROM desks d;
"""

cursor.execute(query)
desks = cursor.fetchall()

# Prepare the response data
if desks:
response_data = [{"id": desk[0]} for desk in desks]
return func.HttpResponse(
body=json.dumps(response_data),
status_code=200,
mimetype="application/json",
)
else:
return func.HttpResponse("No desks found", status_code=200)

except Exception as e:
logging.error(f"Error fetching desks: {str(e)}")
return func.HttpResponse(
"An error occurred while processing the request.", status_code=500
)
finally:
if cursor:
cursor.close()
if connection:
connection.close()

@app.route(route="reservations", methods=["GET"], auth_level=func.AuthLevel.ANONYMOUS)
def getReservationsForDate(req: func.HttpRequest) -> func.HttpResponse:
# Get the date from the query parameter (expected format: YYYY-MM-DD)
reservation_date = req.params.get("date")
if not reservation_date:
return func.HttpResponse(
"Please provide a 'date' query parameter (YYYY-MM-DD).", status_code=400
)

try:
# Convert string date to a date object for validation
reservation_date = datetime.strptime(reservation_date, "%Y-%m-%d").date()
except ValueError:
return func.HttpResponse(
"Invalid date format. Please provide a valid date in YYYY-MM-DD format.",
status_code=400,
)

# Connect to database and fetch reservations for the given date
try:
connection = psycopg2.connect(
host=DB_HOST,
port=DB_PORT,
database=DB_NAME,
user=DB_USER,
password=DB_PASSWORD,
)

cursor = connection.cursor()

# Query to get all reservations for the provided date
query = """
SELECT r.id, r.desk_id, r.reserved_by, r.reservation_date
FROM reservations r
WHERE r.reservation_date = %s;
"""

cursor.execute(query, (reservation_date,))
reservations = cursor.fetchall()

# Prepare the response data
if reservations:
response_data = [
{
"id": res[0],
"desk_id": res[1],
"reserved_by": res[2],
"reservation_date": res[3].strftime("%Y-%m-%d"),
}
for res in reservations
]
return func.HttpResponse(
body=json.dumps(response_data),
status_code=200,
mimetype="application/json",
)
else:
return func.HttpResponse(body=json.dumps([]), status_code=200)

except Exception as e:
logging.error(f"Error fetching reservations: {str(e)}")
return func.HttpResponse(
"An error occurred while processing the request.", status_code=500
)
finally:
if cursor:
cursor.close()
if connection:
connection.close()

@app.route(
route="reservation-dates", methods=["GET"], auth_level=func.AuthLevel.ANONYMOUS
)
def getDatesWithReservationForEmail(req: func.HttpRequest) -> func.HttpResponse:
email = req.params.get("email")
if not email:
return func.HttpResponse(
"Please provide an 'email' query parameter.", status_code=400
)

todays_date = datetime.today().date()

# Connect to database and fetch dates in which the email provided has reservations
try:
connection = psycopg2.connect(
host=DB_HOST,
port=DB_PORT,
database=DB_NAME,
user=DB_USER,
password=DB_PASSWORD,
)

cursor = connection.cursor()

# Query to get all reservations for the provided date
query = """
SELECT r.reservation_date
FROM reservations r
WHERE r.reserved_by = %s AND r.reservation_date >= %s;
"""

cursor.execute(query, (email, todays_date))
reservation_dates = cursor.fetchall()

# Prepare the response data
if reservation_dates:
response_data = [res[0].strftime("%Y-%m-%d") for res in reservation_dates]
return func.HttpResponse(
body=json.dumps(response_data),
status_code=200,
mimetype="application/json",
)
else:
return func.HttpResponse(body=json.dumps([]), status_code=200)

except Exception as e:
logging.error(f"Error fetching reservation dates for email {email}: {str(e)}")
return func.HttpResponse(
"An error occurred while processing the request.", status_code=500
)
finally:
if cursor:
cursor.close()
if connection:
connection.close()

@app.route(route="reservations", methods=["POST"], auth_level=func.AuthLevel.ANONYMOUS)
def reserveDesks(req: func.HttpRequest) -> func.HttpResponse:
# Parse the JSON body
request_body = req.get_json()
if not request_body:
return func.HttpResponse("Invalid or missing JSON body.", status_code=400)

# Extract `userEmail`
employee_email = request_body.get("employee")
# Extract `reservations`
reservations = request_body.get("reservations", [])

# Validate presence of required fields
if not employee_email or not reservations:
return func.HttpResponse(
"Missing 'employee' or 'reservations' in the JSON body.",
status_code=400,
)

# Database connection
try:
connection = psycopg2.connect(
host=DB_HOST,
port=DB_PORT,
database=DB_NAME,
user=DB_USER,
password=DB_PASSWORD,
)

cursor = connection.cursor()
except Exception as e:
logging.error(f"Error connecting to the database: {str(e)}")
return func.HttpResponse("Database connection failed.", status_code=500)

# Connect to database and fetch reservations for the given date
try:
for reservation in reservations:
desk_id = reservation.get("desk_id")
reservation_date = reservation.get("reservation_date")

if not desk_id or not reservation_date:
return func.HttpResponse(
"Each reservation must include 'deskId' and 'reservationDate'.",
status_code=400,
)

checkIfSameReservationAlreadyExistsQuery = """
SELECT r.id, r.desk_id, r.reserved_by, r.reservation_date
FROM reservations r
WHERE r.reservation_date = %s AND r.desk_id = %s;
"""
cursor.execute(
checkIfSameReservationAlreadyExistsQuery, (reservation_date, desk_id)
)
reservations = cursor.fetchall()
if reservations and len(reservations) > 0:
response_data = [
{
"id": res[0],
"desk_id": res[1],
"reserved_by": res[2],
"reservation_date": res[3].strftime("%Y-%m-%d"),
}
for res in reservations
]
return func.HttpResponse(
body=json.dumps(response_data),
status_code=409,
mimetype="application/json",
)

# Insert reservation into the database
insert_query = """
INSERT INTO reservations (desk_id, reserved_by, reservation_date)
VALUES (%s, %s, %s)
"""
cursor.execute(insert_query, (desk_id, employee_email, reservation_date))

# Commit the transaction
connection.commit()

except Exception as e:
logging.error(f"Error fetching reservations: {str(e)}")
return func.HttpResponse(
"An error occurred while processing the request.", status_code=500
)
finally:
if cursor:
cursor.close()
if connection:
connection.close()

# Return success response
return func.HttpResponse(
f"Successfully created {len(reservations)} reservations for {employee_email}.",
status_code=201,
)

@app.route(
route="reservations", methods=["DELETE"], auth_level=func.AuthLevel.ANONYMOUS
)
def cancelReservations(req: func.HttpRequest) -> func.HttpResponse:
# Get reservation_ids from query parameter
reservation_ids_str = req.params.get("reservation_ids")
if not reservation_ids_str:
return func.HttpResponse(
"Please provide reservation_ids as a query parameter.", status_code=400
)

try:
# Split the reservation_ids and convert them into a list of integers
reservation_ids = list(map(int, reservation_ids_str.split(",")))

# Connect to database and delete the reservations
connection = psycopg2.connect(
host=DB_HOST,
port=DB_PORT,
database=DB_NAME,
user=DB_USER,
password=DB_PASSWORD,
)

cursor = connection.cursor()

placeholders = ", ".join("%s" for _ in reservation_ids)
# Query to delete the reservations by IDs
query = f"""
DELETE FROM reservations
WHERE id IN ({placeholders});
"""
cursor.execute(query, reservation_ids)
connection.commit()

# Check how many rows were deleted
deleted_rows = cursor.rowcount

if deleted_rows > 0:
return func.HttpResponse(
f"Successfully deleted {deleted_rows} reservation(s).", status_code=200
)
else:
return func.HttpResponse(
"No reservations found with the provided IDs.", status_code=404
)

except Exception as e:
logging.error(f"Error deleting reservations: {str(e)}")
return func.HttpResponse(
"An error occurred while processing the request.", status_code=500
)

finally:
if cursor:
cursor.close()
if connection:
connection.close()



Подробнее здесь: https://stackoverflow.com/questions/792 ... ite-workin
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»