Compare commits
8 Commits
055f51aa55
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| de9ba78089 | |||
| 3c4e10eda7 | |||
| 287dfc0b8b | |||
| 5561f10958 | |||
| 85dd574991 | |||
| 4f97dc3362 | |||
| 9100f71ab5 | |||
| 0d12f24dec |
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Sławomir Koszewski
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
84
README.md
84
README.md
@@ -1,46 +1,78 @@
|
|||||||
# Azure Image Chooser
|
# Azure Image Chooser
|
||||||
|
|
||||||
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 Node.js application that allows users to select Azure VM images from the Azure Marketplace.
|
||||||
|
|
||||||
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 has a TypeScript backend (Express) and a React frontend (Vite). At the time of writing this, Node.js 24 is used by the container image and is the recommended version for local runs.
|
||||||
|
|
||||||
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.
|
You can run it on your local machine or deploy to any platform that runs containers.
|
||||||
|
|
||||||
|
## Environment variables
|
||||||
|
|
||||||
|
Required for both local and container run:
|
||||||
|
|
||||||
|
- `AZURE_SUBSCRIPTION_ID`: Azure subscription used for Marketplace queries.
|
||||||
|
|
||||||
|
Authentication variables (only needed when identity is not provided by the environment):
|
||||||
|
|
||||||
|
- `AZURE_TENANT_ID`: Microsoft Entra tenant ID for service principal auth.
|
||||||
|
- `AZURE_CLIENT_ID`: Service principal (app registration) client ID.
|
||||||
|
- `AZURE_CLIENT_SECRET`: Service principal client secret.
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
|
||||||
|
- `PORT`: Backend listening port. Default is `3000`.
|
||||||
|
|
||||||
|
Local run notes:
|
||||||
|
|
||||||
|
- `AZURE_SUBSCRIPTION_ID` must be set.
|
||||||
|
- Use either Azure CLI login (`az login`) or the service principal variables above.
|
||||||
|
|
||||||
|
Container run notes:
|
||||||
|
|
||||||
|
- `AZURE_SUBSCRIPTION_ID` must be passed to the container.
|
||||||
|
- Pass `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, and `AZURE_CLIENT_SECRET` unless your container runtime provides identity (for example Managed Identity / Workload Identity).
|
||||||
|
|
||||||
## Running on a local machine
|
## Running on a local machine
|
||||||
|
|
||||||
Create a Python development environment file `.env`:
|
Load environment variables from the repository environment file:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
AZURE_SUBSCRIPTION_ID="subscription_id"
|
set -a; source azure.env; set +a
|
||||||
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 install dependencies, build, and run the app:
|
||||||
|
|
||||||
Execute the following commands to run the app:
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
python3 -m venv .venv
|
cd app/backend
|
||||||
source .venv/bin/activate
|
npm ci
|
||||||
python -m pip install pip --upgrade
|
|
||||||
pip install -r requirements.txt
|
cd ../frontend
|
||||||
cd app
|
npm ci
|
||||||
streamlit run image-chooser.py
|
|
||||||
|
cd backend
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
cd ../frontend
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
cd ../backend
|
||||||
|
npm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
The app will block terminal and start a web server. Follow the instructions in the terminal to access the app.
|
The app will block the terminal and start a web server on port 3000. Open http://localhost:3000 in your browser.
|
||||||
|
|
||||||
## Add Certificate Binding for Azure Deployment
|
## Running with Docker
|
||||||
|
|
||||||
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.
|
Build and run the container:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Find the certificate name
|
docker build -t azure-image-chooser-node ./app
|
||||||
CERTIFICATE_LOWERCASE_NAME=$(az containerapp env certificate list -g $RESOURCE_GROUP -n $ENVIRONMENT --query '[].name' -o tsv)
|
docker run --rm -p 3000:3000 \
|
||||||
|
-e AZURE_SUBSCRIPTION_ID="subscription_id" \
|
||||||
# Bind the certificate to the container app
|
-e AZURE_CLIENT_ID="client_id" \
|
||||||
az containerapp hostname bind --hostname $DOMAIN_NAME -g $RESOURCE_GROUP -n $CONTAINER_APP --environment $ENVIRONMENT --certificate $CERTIFICATE_LOWERCASE_NAME --validation-method CNAME
|
-e AZURE_CLIENT_SECRET="client_secret" \
|
||||||
|
-e AZURE_TENANT_ID="tenant_id" \
|
||||||
|
azure-image-chooser-node
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> NOTE: As with local runs, you can omit AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, and AZURE_TENANT_ID when the runtime environment already provides Azure credentials.
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
FROM node:24-trixie-slim AS build
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY app-new/backend/package*.json backend/
|
|
||||||
COPY app-new/frontend/package*.json frontend/
|
|
||||||
RUN cd backend && npm ci
|
|
||||||
RUN cd frontend && npm ci
|
|
||||||
|
|
||||||
COPY app-new .
|
|
||||||
|
|
||||||
RUN cd backend && npm run build
|
|
||||||
RUN cd frontend && npm run build
|
|
||||||
RUN cd backend && npm prune --omit=dev
|
|
||||||
|
|
||||||
FROM node:24-trixie-slim AS runtime
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
ENV PORT=3000
|
|
||||||
|
|
||||||
COPY --from=build /app/dist dist
|
|
||||||
COPY --from=build /app/templates templates
|
|
||||||
COPY --from=build /app/templates.json templates.json
|
|
||||||
COPY --from=build /app/backend/node_modules dist/backend/node_modules
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
COPY entrypoint.sh entrypoint.sh
|
|
||||||
COPY healthcheck.js healthcheck.js
|
|
||||||
RUN chmod +x entrypoint.sh
|
|
||||||
|
|
||||||
EXPOSE 3000
|
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 CMD ["node", "/app/healthcheck.js"]
|
|
||||||
ENTRYPOINT ["./entrypoint.sh"]
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
exec node /app/dist/backend/server.js
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"label": "Terraform VM image reference",
|
|
||||||
"language": "hcl",
|
|
||||||
"file": "azurerm_hcl.tpl"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Azure CLI",
|
|
||||||
"language": "shell",
|
|
||||||
"file": "shell.tpl"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Azure Resource Manager Template",
|
|
||||||
"language": "json",
|
|
||||||
"file": "arm_vm.jsonc"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Bicep VM image reference",
|
|
||||||
"language": "bicep",
|
|
||||||
"file": "bicep_vm.tpl"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
15
app-streamlit/Dockerfile
Normal file
15
app-streamlit/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
FROM python:3.13-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
RUN pip install --root-user-action=ignore --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY image-chooser.py .
|
||||||
|
COPY templates/ templates/
|
||||||
|
COPY templates.json .
|
||||||
|
COPY ./entrypoint.sh /
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/entrypoint.sh" ]
|
||||||
|
CMD [ "run", "image-chooser.py" ]
|
||||||
46
app-streamlit/README.md
Normal file
46
app-streamlit/README.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Azure Image Chooser
|
||||||
|
|
||||||
|
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 written in Python and requires Python interpreter. At the time of writing this, Python 3.13 is the latest.
|
||||||
|
|
||||||
|
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
|
||||||
|
python3 -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
python -m pip install pip --upgrade
|
||||||
|
pip install -r requirements.txt
|
||||||
|
cd app
|
||||||
|
streamlit run image-chooser.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The app will block terminal and start a web server. Follow the instructions in the terminal to access the app.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
# Find the certificate name
|
||||||
|
CERTIFICATE_LOWERCASE_NAME=$(az containerapp env certificate list -g $RESOURCE_GROUP -n $ENVIRONMENT --query '[].name' -o tsv)
|
||||||
|
|
||||||
|
# Bind the certificate to the container app
|
||||||
|
az containerapp hostname bind --hostname $DOMAIN_NAME -g $RESOURCE_GROUP -n $CONTAINER_APP --environment $ENVIRONMENT --certificate $CERTIFICATE_LOWERCASE_NAME --validation-method CNAME
|
||||||
|
```
|
||||||
8
app-streamlit/entrypoint.sh
Executable file
8
app-streamlit/entrypoint.sh
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ "$1" = "-s" ] || [ "$1" = "--shell" ]; then
|
||||||
|
shift
|
||||||
|
exec bash $@
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec streamlit $@
|
||||||
17
app-streamlit/templates.json
Normal file
17
app-streamlit/templates.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"label": "Terraform VM image reference",
|
||||||
|
"language": "hcl",
|
||||||
|
"file": "azurerm_hcl.tpl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Azure CLI",
|
||||||
|
"language": "shell",
|
||||||
|
"file": "shell.tpl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Azure Resource Manager Template",
|
||||||
|
"language": "json",
|
||||||
|
"file": "arm_vm.jsonc"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -1 +1 @@
|
|||||||
az create -n MyVM -g MyResourceGroup --image {{ publisher }}:{{ offer }}:{{ sku }}:{{ version }}
|
az create -n MyVM -g MyResourceGroup --image {{ publisher }}:{{ offer }}:{{ sku }}:{{ version }}
|
||||||
@@ -1,15 +1,50 @@
|
|||||||
FROM python:3.13-slim
|
# Build stage
|
||||||
|
FROM node:24-trixie-slim AS build
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY requirements.txt .
|
# Copy sources required for build
|
||||||
|
COPY backend/*.json backend/
|
||||||
|
COPY backend/src backend/src
|
||||||
|
|
||||||
RUN pip install --root-user-action=ignore --no-cache-dir -r requirements.txt
|
COPY frontend/*.json frontend/
|
||||||
|
COPY frontend/vite.config.ts frontend/vite.config.ts
|
||||||
|
COPY frontend/index.html frontend/index.html
|
||||||
|
COPY frontend/src frontend/src
|
||||||
|
COPY frontend/test frontend/test
|
||||||
|
|
||||||
COPY image-chooser.py .
|
COPY templates templates
|
||||||
COPY templates/ templates/
|
COPY templates.json templates.json
|
||||||
COPY templates.json .
|
|
||||||
COPY ./entrypoint.sh /
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/entrypoint.sh" ]
|
# Build backend and frontend
|
||||||
CMD [ "run", "image-chooser.py" ]
|
RUN cd backend && npm ci && npm run build && npm prune --omit=dev
|
||||||
|
RUN cd frontend && npm ci && npm run build
|
||||||
|
|
||||||
|
# Build the container
|
||||||
|
FROM node:24-trixie-slim AS runtime
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy built artifacts
|
||||||
|
COPY --from=build /app/dist dist
|
||||||
|
COPY --from=build /app/templates templates
|
||||||
|
COPY --from=build /app/templates.json templates.json
|
||||||
|
COPY --from=build /app/backend/node_modules dist/backend/node_modules
|
||||||
|
|
||||||
|
# Copy entrypoint and healthcheck scripts
|
||||||
|
COPY entrypoint.sh entrypoint.sh
|
||||||
|
COPY healthcheck.js healthcheck.js
|
||||||
|
|
||||||
|
# Ensure entrypoint script is executable
|
||||||
|
RUN chmod +x entrypoint.sh
|
||||||
|
|
||||||
|
# Set environment variables and expose port
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV PORT=3000
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Configure health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 CMD ["node", "/app/healthcheck.js"]
|
||||||
|
|
||||||
|
# Configure entrypoint
|
||||||
|
ENTRYPOINT ["./entrypoint.sh"]
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "azure-image-chooser-backend",
|
"name": "azure-image-chooser-backend",
|
||||||
"version": "0.1.0",
|
"version": "1.0.0",
|
||||||
|
"author": "Sławomir Koszewski",
|
||||||
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -6,7 +6,7 @@ import { z } from "zod";
|
|||||||
import { AzureImageService } from "./azure-service";
|
import { AzureImageService } from "./azure-service";
|
||||||
import { TemplateService } from "./template-service";
|
import { TemplateService } from "./template-service";
|
||||||
|
|
||||||
const findAppNewRoot = (): string => {
|
const findAppRoot = (): string => {
|
||||||
const candidates = [join(__dirname, "../../.."), join(__dirname, "../..")];
|
const candidates = [join(__dirname, "../../.."), join(__dirname, "../..")];
|
||||||
|
|
||||||
for (const candidate of candidates) {
|
for (const candidate of candidates) {
|
||||||
@@ -15,7 +15,7 @@ const findAppNewRoot = (): string => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error("Unable to resolve app-new root");
|
throw new Error("Unable to resolve app root");
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryLocation = z.object({ location: z.string().min(1) });
|
const queryLocation = z.object({ location: z.string().min(1) });
|
||||||
@@ -143,7 +143,7 @@ const makeApp = () => {
|
|||||||
res.status(500).json({ message });
|
res.status(500).json({ message });
|
||||||
});
|
});
|
||||||
|
|
||||||
const frontendRoot = join(findAppNewRoot(), "dist/frontend");
|
const frontendRoot = join(findAppRoot(), "dist/frontend");
|
||||||
if (existsSync(frontendRoot)) {
|
if (existsSync(frontendRoot)) {
|
||||||
app.use(express.static(frontendRoot));
|
app.use(express.static(frontendRoot));
|
||||||
app.get(/^(?!\/api).*/, (_req, res) => {
|
app.get(/^(?!\/api).*/, (_req, res) => {
|
||||||
@@ -3,7 +3,7 @@ import { join } from "node:path";
|
|||||||
import nunjucks from "nunjucks";
|
import nunjucks from "nunjucks";
|
||||||
import type { ImageSelection, UsageTemplate } from "./types";
|
import type { ImageSelection, UsageTemplate } from "./types";
|
||||||
|
|
||||||
const findAppNewRoot = (): string => {
|
const findAppRoot = (): string => {
|
||||||
const candidates = [join(__dirname, "../../.."), join(__dirname, "../..")];
|
const candidates = [join(__dirname, "../../.."), join(__dirname, "../..")];
|
||||||
|
|
||||||
for (const candidate of candidates) {
|
for (const candidate of candidates) {
|
||||||
@@ -12,19 +12,19 @@ const findAppNewRoot = (): string => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error("Unable to resolve app-new template root");
|
throw new Error("Unable to resolve app template root");
|
||||||
};
|
};
|
||||||
|
|
||||||
export class TemplateService {
|
export class TemplateService {
|
||||||
private readonly appNewRoot = findAppNewRoot();
|
private readonly appRoot = findAppRoot();
|
||||||
|
|
||||||
private readonly env = nunjucks.configure(join(this.appNewRoot, "templates"), {
|
private readonly env = nunjucks.configure(join(this.appRoot, "templates"), {
|
||||||
autoescape: false,
|
autoescape: false,
|
||||||
noCache: true
|
noCache: true
|
||||||
});
|
});
|
||||||
|
|
||||||
private readonly templates: UsageTemplate[] = JSON.parse(
|
private readonly templates: UsageTemplate[] = JSON.parse(
|
||||||
readFileSync(join(this.appNewRoot, "templates.json"), "utf8")
|
readFileSync(join(this.appRoot, "templates.json"), "utf8")
|
||||||
) as UsageTemplate[];
|
) as UsageTemplate[];
|
||||||
|
|
||||||
public getTemplates(): UsageTemplate[] {
|
public getTemplates(): UsageTemplate[] {
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/usr/bin/env sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
if [ "$1" = "-s" ] || [ "$1" = "--shell" ]; then
|
exec node /app/dist/backend/server.js
|
||||||
shift
|
|
||||||
exec bash $@
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec streamlit $@
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "azure-image-chooser-frontend",
|
"name": "azure-image-chooser-frontend",
|
||||||
"version": "0.1.0",
|
"version": "1.0.0",
|
||||||
|
"author": "Sławomir Koszewski",
|
||||||
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -1,17 +1,22 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"label": "Terraform VM image reference",
|
"label": "Terraform VM image reference",
|
||||||
"language": "hcl",
|
"language": "hcl",
|
||||||
"file": "azurerm_hcl.tpl"
|
"file": "azurerm_hcl.tpl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Azure CLI",
|
"label": "Azure CLI",
|
||||||
"language": "shell",
|
"language": "shell",
|
||||||
"file": "shell.tpl"
|
"file": "shell.tpl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Azure Resource Manager Template",
|
"label": "Azure Resource Manager Template",
|
||||||
"language": "json",
|
"language": "json",
|
||||||
"file": "arm_vm.jsonc"
|
"file": "arm_vm.jsonc"
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"label": "Bicep VM image reference",
|
||||||
|
"language": "bicep",
|
||||||
|
"file": "bicep_vm.tpl"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
az create -n MyVM -g MyResourceGroup --image {{ publisher }}:{{ offer }}:{{ sku }}:{{ version }}
|
az create -n MyVM -g MyResourceGroup --image {{ publisher }}:{{ offer }}:{{ sku }}:{{ version }}
|
||||||
|
|||||||
Reference in New Issue
Block a user