Compare commits

..

10 Commits

5 changed files with 94 additions and 58 deletions

View File

@@ -2,20 +2,40 @@
Azure Image Chooser is a [Streamlit](https://streamlit.io) application that allows users to select Azure VM images from the Azure Marketplace. Azure Image Chooser is a [Streamlit](https://streamlit.io) application that allows users to select Azure VM images from the Azure Marketplace.
It is in its preliminary version and is subject to development and change. It is provided here for you convenience and may not include all features or functionality of the final product. Azure Image Chooser is written in Python and requires Python interpreter. At the time of writing this, Python 3.13 is the latest.
Azure Image Chooser is written in Python and requires Python interpreter. At the time of writing this, Python 3.13 is the latest. Execute the following commands to run the app: You can run it on your local machine or deploy to any platform that runs containers. A Docker file and Terraform code to deploy to the Azure are provided.
## Running on a local machine
Create a Python development environment file `.env`:
```shell
AZURE_SUBSCRIPTION_ID="subscription_id"
AZURE_CLIENT_ID="client_id"
AZURE_CLIENT_SECRET="client_secret"
AZURE_TENANT_ID="tenant_id"
AZURE_LOCATION="westeurope"
```
> NOTE: Replace the placeholder values with your actual values. Omit `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, and `AZURE_TENANT_ID` if you are using Azure CLI authentication.
Execute the following commands to run the app:
```shell ```shell
python3 -m venv .venv python3 -m venv .venv
.venv/bin/python -m pip install pip --upgrade source .venv/bin/activate
.venv/bin/pip install streamlit azure-identity azure-mgmt-compute python -m pip install pip --upgrade
.venv/bin/streamlit run image-chooser.py pip install -r requirements.txt
cd app
streamlit run image-chooser.py
``` ```
You have to be authenticated in Azure CLI. The app will block terminal and start a web server. Follow the instructions in the terminal to access the app. The app will block terminal and start a web server. Follow the instructions in the terminal to access the app.
## Add Certificate Binding ## Add Certificate Binding for Azure Deployment
Unfortunately, as of now, the Terraform Azure Resource Manager Provider does not support binding certificates to container apps. You can still bind the certificate using the Azure CLI.
```shell ```shell
# Find the certificate name # Find the certificate name

View File

@@ -33,19 +33,15 @@ def clear_image_versions():
def on_publisher_changed(): def on_publisher_changed():
clear_offers() clear_offers()
# st.rerun()
def on_offer_changed(): def on_offer_changed():
clear_skus() clear_skus()
# st.rerun()
def on_sku_changed(): def on_sku_changed():
clear_skus() clear_skus()
# st.rerun()
def on_image_version_changed(): def on_image_version_changed():
clear_image_versions() clear_image_versions()
# st.rerun()
def version_key(v): def version_key(v):
return [int(x) for x in v.split('.')] return [int(x) for x in v.split('.')]
@@ -75,8 +71,11 @@ def get_locations():
if loc.metadata.region_type == 'Physical' if loc.metadata.region_type == 'Physical'
] ]
def usage_scenario_label(item):
return item['label']
subscription_id = getenv("AZURE_SUBSCRIPTION_ID") subscription_id = getenv("AZURE_SUBSCRIPTION_ID")
default_location = getenv("AZURE_LOCATION") default_location = getenv("AZURE_LOCATION", "westeurope")
credential = DefaultAzureCredential() credential = DefaultAzureCredential()
@@ -107,7 +106,7 @@ if is_valid('publishers'):
st.session_state.selected_publisher = publisher_col.selectbox('Select Publisher', options=st.session_state.publishers, on_change=on_publisher_changed, index=None) st.session_state.selected_publisher = publisher_col.selectbox('Select Publisher', options=st.session_state.publishers, on_change=on_publisher_changed, index=None)
else: else:
st.error("No publishers found. Please check your Azure subscription and location.") st.error("No publishers found. Please check your Azure subscription and location.")
st.stop() # st.stop()
# Offers # Offers
if 'offers' not in st.session_state and is_valid('selected_publisher'): if 'offers' not in st.session_state and is_valid('selected_publisher'):
@@ -117,9 +116,9 @@ if is_valid('offers'):
st.session_state.selected_offer = offer_col.selectbox('Select Offer', options=st.session_state.offers, on_change=on_offer_changed, index=None) st.session_state.selected_offer = offer_col.selectbox('Select Offer', options=st.session_state.offers, on_change=on_offer_changed, index=None)
elif is_valid('selected_publisher'): elif is_valid('selected_publisher'):
st.info("No offers found for the selected publisher. Please select a different publisher.") st.info("No offers found for the selected publisher. Please select a different publisher.")
st.stop() # st.stop()
else: # else:
st.stop() # st.stop()
# SKUs # SKUs
if 'skus' not in st.session_state and is_valid('selected_publisher') and is_valid('selected_offer'): if 'skus' not in st.session_state and is_valid('selected_publisher') and is_valid('selected_offer'):
@@ -129,9 +128,9 @@ if is_valid('skus'):
st.session_state.selected_sku = sku_col.selectbox('Select SKU', options=st.session_state.skus, on_change=on_sku_changed, index=None) st.session_state.selected_sku = sku_col.selectbox('Select SKU', options=st.session_state.skus, on_change=on_sku_changed, index=None)
elif is_valid('selected_offer'): elif is_valid('selected_offer'):
st.info("No SKUs found for the selected offer. Please select a different offer.") st.info("No SKUs found for the selected offer. Please select a different offer.")
st.stop() # st.stop()
else: # else:
st.stop() # st.stop()
# Image versions # Image versions
if 'image_versions' not in st.session_state and is_valid('selected_publisher') and is_valid('selected_offer') and is_valid('selected_sku'): if 'image_versions' not in st.session_state and is_valid('selected_publisher') and is_valid('selected_offer') and is_valid('selected_sku'):
@@ -148,9 +147,9 @@ if is_valid('image_versions'):
st.session_state.selected_image_version = version_col.selectbox('Select Image Version', options=st.session_state.image_versions, index=None) st.session_state.selected_image_version = version_col.selectbox('Select Image Version', options=st.session_state.image_versions, index=None)
elif is_valid('selected_sku'): elif is_valid('selected_sku'):
st.info("No image versions found for the selected SKU. Please select a different SKU.") st.info("No image versions found for the selected SKU. Please select a different SKU.")
st.stop() # st.stop()
else: # else:
st.stop() # st.stop()
if is_valid('selected_image_version'): if is_valid('selected_image_version'):
st.subheader("Usage example") st.subheader("Usage example")
@@ -158,9 +157,6 @@ if is_valid('selected_image_version'):
with open("templates.json") as f: with open("templates.json") as f:
templates = json.load(f) templates = json.load(f)
def usage_scenario_label(item):
return item['label']
layout = st.columns(4) layout = st.columns(4)
selected_file = layout[0].selectbox('Select usage scenario:', options=templates, format_func=usage_scenario_label) selected_file = layout[0].selectbox('Select usage scenario:', options=templates, format_func=usage_scenario_label)
@@ -175,3 +171,9 @@ if is_valid('selected_image_version'):
) )
st.code(rendered, language=selected_file['language']) st.code(rendered, language=selected_file['language'])
if is_valid('selected_publisher') and is_valid('selected_offer') and is_valid('skus'):
sku_list = '[\n' + ',\n'.join(f'\t"{sku}"' for sku in st.session_state['skus']) +'\n]'
st.subheader('Available SKUs')
st.markdown('The below HCL code is suitable to be used as SKU validation set.')
st.code(sku_list)

View File

@@ -1,17 +1,14 @@
#!/bin/bash #!//usr/bin/env bash
IMAGE_NAME="azure-image-chooser" IMAGE_NAME="azure-image-chooser"
#IMAGE="docker.io/skoszewski/$IMAGE_NAME" IMAGE="docker.io/skoszewski/$IMAGE_NAME:latest"
IMAGE="skdomlab.azurecr.io/$IMAGE_NAME" # IMAGE="skdomlab.azurecr.io/$IMAGE_NAME"
if [ "$(basename $(command -v docker))" = "docker" ]; then if command -v docker > /dev/null; then
CMD="docker" docker buildx build -t $IMAGE app
elif [ "$(basename $(command -v podman))" = "podman" ]; then elif command -v container > /dev/null; then
CMD="podman" container build -t $IMAGE app
else else
echo "No suitable container tool found" echo "No suitable container tool found"
exit 1 exit 1
fi fi
$CMD build -t $IMAGE app
$CMD push $IMAGE

View File

@@ -1,24 +1,37 @@
#!/bin/bash #!/usr/bin/env bash
if [ -z "$AZURE_CLIENT_ID" ] || [ -z "$AZURE_TENANT_ID" ] || [ -z "$AZURE_CLIENT_SECRET" ] || [ -z "$AZURE_SUBSCRIPTION_ID" ]; then SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "One or more environment variables are not set."
exit 1 if [ -f "$SCRIPT_DIR/azure.env" ]; then
source "$SCRIPT_DIR/azure.env"
fi fi
if [ "$(basename $(command -v docker))" = "docker" ]; then REQUIRED_VARS=("AZURE_CLIENT_ID" "AZURE_TENANT_ID" "AZURE_CLIENT_SECRET" "AZURE_SUBSCRIPTION_ID")
for VAR in "${REQUIRED_VARS[@]}"; do
if [ -z "${!VAR}" ]; then
echo "Environment variable $VAR is not set."
exit 1
fi
done
IMAGE_NAME="azure-image-chooser"
IMAGE="docker.io/skoszewski/$IMAGE_NAME:latest"
RUN_ARGS=(
"--env" "AZURE_CLIENT_ID=$AZURE_CLIENT_ID"
"--env" "AZURE_TENANT_ID=$AZURE_TENANT_ID"
"--env" "AZURE_CLIENT_SECRET=$AZURE_CLIENT_SECRET"
"--env" "AZURE_SUBSCRIPTION_ID=$AZURE_SUBSCRIPTION_ID"
"-p" "8501:8501"
)
if command -v docker > /dev/null; then
CMD="docker" CMD="docker"
elif [ "$(basename $(command -v podman))" = "podman" ]; then elif command -v container > /dev/null; then
CMD="podman" CMD="container"
else else
echo "No suitable container tool found" echo "No suitable container tool found"
exit 1 exit 1
fi fi
$CMD run --rm \ $CMD run --rm -it "${RUN_ARGS[@]}" $IMAGE
-it \
-e AZURE_CLIENT_ID="$AZURE_CLIENT_ID" \
-e AZURE_TENANT_ID="$AZURE_TENANT_ID" \
-e AZURE_CLIENT_SECRET="$AZURE_CLIENT_SECRET" \
-e AZURE_SUBSCRIPTION_ID="$AZURE_SUBSCRIPTION_ID" \
-p 8501:8501 \
azure-image-chooser

View File

@@ -52,7 +52,6 @@ resource "azurerm_key_vault" "kv" {
resource_group_name = azurerm_resource_group.rg.name resource_group_name = azurerm_resource_group.rg.name
sku_name = "standard" sku_name = "standard"
tenant_id = data.azurerm_client_config.current.tenant_id tenant_id = data.azurerm_client_config.current.tenant_id
enable_rbac_authorization = true
} }
resource "azurerm_role_assignment" "app_assignment" { resource "azurerm_role_assignment" "app_assignment" {
@@ -120,6 +119,11 @@ resource "azurerm_container_app" "app" {
name = "AZURE_SUBSCRIPTION_ID" name = "AZURE_SUBSCRIPTION_ID"
value = var.subscription_id value = var.subscription_id
} }
env {
name = "AZURE_LOCATION"
value = azurerm_resource_group.rg.location
}
} }
} }