From 7bad9e36fbf71507b8b3b7032d156f97ab29db6d Mon Sep 17 00:00:00 2001 From: sgollapudi77 <85578033+sgollapudi77@users.noreply.github.com> Date: Mon, 23 Oct 2023 11:59:25 +0530 Subject: [PATCH 1/7] Update requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index a3c7c6ad6..8208e9f6e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ Flask==2.0.2 gunicorn +werkzeug==2.2.2 From 880dd8dbf64a83d55ad036a215230599712eda1b Mon Sep 17 00:00:00 2001 From: sgollapudi77 <85578033+sgollapudi77@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:11:32 +0530 Subject: [PATCH 2/7] Update requirements.txt Update Flask framework version for succcessful deploy. --- requirements.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 8208e9f6e..d908130a3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,2 @@ -Flask==2.0.2 +Flask==3.0.0 gunicorn -werkzeug==2.2.2 From 8685726a082a4540f9e0c2f5c55871b31c07c85b Mon Sep 17 00:00:00 2001 From: Mangesh Sangapu Date: Mon, 11 Dec 2023 14:45:53 -0600 Subject: [PATCH 3/7] Update requirements.txt --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a3c7c6ad6..c785af01f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ -Flask==2.0.2 +Flask==2.2.2 gunicorn +Werkzeug==2.2.2 From 00765b19ae6df1424962cd5792dcbdc229179e6f Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Thu, 30 Jan 2025 21:58:27 +0000 Subject: [PATCH 4/7] Add basic dev container --- .devcontainer/devcontainer.json | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..f115d9024 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,36 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "msdocs-python-flask-webapp-quickstart", + "image": "mcr.microsoft.com/devcontainers/python:3.12-bullseye", + "features": { + "ghcr.io/devcontainers/features/azure-cli:latest": {}, + "ghcr.io/azure/azure-dev/azd:latest": {} + }, + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + // Set *default* container specific settings.json values on container create. + "settings": { + "python.defaultInterpreterPath": "/usr/local/bin/python" + }, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python" + ] + } + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [5000], + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "", + + // Use 'postStartCommand' to run commands after the container is started (more frequently than create). + "postStartCommand": "pip install --user -r requirements.txt", + + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode" +} \ No newline at end of file From cd7156ab6a10fa2e02849c17acaba4287f5c3e24 Mon Sep 17 00:00:00 2001 From: Bob Tabor Date: Wed, 26 Feb 2025 15:10:07 -0600 Subject: [PATCH 5/7] Bump Flask version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b5065c236..d8b131866 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -Flask==3.0.0 +Flask==3.1.0 gunicorn \ No newline at end of file From 751c46cdb77f46ce69dff0f5fd378241147f9819 Mon Sep 17 00:00:00 2001 From: Cephas Lin Date: Mon, 31 Mar 2025 10:09:14 +0000 Subject: [PATCH 6/7] add azd files --- azure.yaml | 15 ++ infra/abbreviations.json | 136 +++++++++++++++++++ infra/core/host/appservice-appsettings.bicep | 17 +++ infra/core/host/appservice.bicep | 123 +++++++++++++++++ infra/core/host/appserviceplan.bicep | 22 +++ infra/main.bicep | 91 +++++++++++++ infra/main.parameters.json | 12 ++ 7 files changed, 416 insertions(+) create mode 100644 azure.yaml create mode 100644 infra/abbreviations.json create mode 100644 infra/core/host/appservice-appsettings.bicep create mode 100644 infra/core/host/appservice.bicep create mode 100644 infra/core/host/appserviceplan.bicep create mode 100644 infra/main.bicep create mode 100644 infra/main.parameters.json diff --git a/azure.yaml b/azure.yaml new file mode 100644 index 000000000..d02d432b1 --- /dev/null +++ b/azure.yaml @@ -0,0 +1,15 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json + +# This is an example starter azure.yaml file containing several example services in comments below. +# Make changes as needed to describe your application setup. +# To learn more about the azure.yaml file, visit https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/azd-schema + +# Name of the application. +name: msdocs-python-flask-webapp-quickstart +metadata: + template: msdocs-python-flask-webapp-quickstart@0.0.1-beta +services: + web: + project: . + language: python + host: appservice \ No newline at end of file diff --git a/infra/abbreviations.json b/infra/abbreviations.json new file mode 100644 index 000000000..289a08aa0 --- /dev/null +++ b/infra/abbreviations.json @@ -0,0 +1,136 @@ +{ + "analysisServicesServers": "as", + "apiManagementService": "apim-", + "appConfigurationConfigurationStores": "appcs-", + "appManagedEnvironments": "cae-", + "appContainerApps": "ca-", + "authorizationPolicyDefinitions": "policy-", + "automationAutomationAccounts": "aa-", + "blueprintBlueprints": "bp-", + "blueprintBlueprintsArtifacts": "bpa-", + "cacheRedis": "redis-", + "cdnProfiles": "cdnp-", + "cdnProfilesEndpoints": "cdne-", + "cognitiveServicesAccounts": "cog-", + "cognitiveServicesFormRecognizer": "cog-fr-", + "cognitiveServicesTextAnalytics": "cog-ta-", + "computeAvailabilitySets": "avail-", + "computeCloudServices": "cld-", + "computeDiskEncryptionSets": "des", + "computeDisks": "disk", + "computeDisksOs": "osdisk", + "computeGalleries": "gal", + "computeSnapshots": "snap-", + "computeVirtualMachines": "vm", + "computeVirtualMachineScaleSets": "vmss-", + "containerInstanceContainerGroups": "ci", + "containerRegistryRegistries": "cr", + "containerServiceManagedClusters": "aks-", + "databricksWorkspaces": "dbw-", + "dataFactoryFactories": "adf-", + "dataLakeAnalyticsAccounts": "dla", + "dataLakeStoreAccounts": "dls", + "dataMigrationServices": "dms-", + "dBforMySQLServers": "mysql-", + "dBforPostgreSQLServers": "psql-", + "devicesIotHubs": "iot-", + "devicesProvisioningServices": "provs-", + "devicesProvisioningServicesCertificates": "pcert-", + "documentDBDatabaseAccounts": "cosmos-", + "eventGridDomains": "evgd-", + "eventGridDomainsTopics": "evgt-", + "eventGridEventSubscriptions": "evgs-", + "eventHubNamespaces": "evhns-", + "eventHubNamespacesEventHubs": "evh-", + "hdInsightClustersHadoop": "hadoop-", + "hdInsightClustersHbase": "hbase-", + "hdInsightClustersKafka": "kafka-", + "hdInsightClustersMl": "mls-", + "hdInsightClustersSpark": "spark-", + "hdInsightClustersStorm": "storm-", + "hybridComputeMachines": "arcs-", + "insightsActionGroups": "ag-", + "insightsComponents": "appi-", + "keyVaultVaults": "kv-", + "kubernetesConnectedClusters": "arck", + "kustoClusters": "dec", + "kustoClustersDatabases": "dedb", + "loadTesting": "lt-", + "logicIntegrationAccounts": "ia-", + "logicWorkflows": "logic-", + "machineLearningServicesWorkspaces": "mlw-", + "managedIdentityUserAssignedIdentities": "id-", + "managementManagementGroups": "mg-", + "migrateAssessmentProjects": "migr-", + "networkApplicationGateways": "agw-", + "networkApplicationSecurityGroups": "asg-", + "networkAzureFirewalls": "afw-", + "networkBastionHosts": "bas-", + "networkConnections": "con-", + "networkDnsZones": "dnsz-", + "networkExpressRouteCircuits": "erc-", + "networkFirewallPolicies": "afwp-", + "networkFirewallPoliciesWebApplication": "waf", + "networkFirewallPoliciesRuleGroups": "wafrg", + "networkFrontDoors": "fd-", + "networkFrontdoorWebApplicationFirewallPolicies": "fdfp-", + "networkLoadBalancersExternal": "lbe-", + "networkLoadBalancersInternal": "lbi-", + "networkLoadBalancersInboundNatRules": "rule-", + "networkLocalNetworkGateways": "lgw-", + "networkNatGateways": "ng-", + "networkNetworkInterfaces": "nic-", + "networkNetworkSecurityGroups": "nsg-", + "networkNetworkSecurityGroupsSecurityRules": "nsgsr-", + "networkNetworkWatchers": "nw-", + "networkPrivateDnsZones": "pdnsz-", + "networkPrivateLinkServices": "pl-", + "networkPublicIPAddresses": "pip-", + "networkPublicIPPrefixes": "ippre-", + "networkRouteFilters": "rf-", + "networkRouteTables": "rt-", + "networkRouteTablesRoutes": "udr-", + "networkTrafficManagerProfiles": "traf-", + "networkVirtualNetworkGateways": "vgw-", + "networkVirtualNetworks": "vnet-", + "networkVirtualNetworksSubnets": "snet-", + "networkVirtualNetworksVirtualNetworkPeerings": "peer-", + "networkVirtualWans": "vwan-", + "networkVpnGateways": "vpng-", + "networkVpnGatewaysVpnConnections": "vcn-", + "networkVpnGatewaysVpnSites": "vst-", + "notificationHubsNamespaces": "ntfns-", + "notificationHubsNamespacesNotificationHubs": "ntf-", + "operationalInsightsWorkspaces": "log-", + "portalDashboards": "dash-", + "powerBIDedicatedCapacities": "pbi-", + "purviewAccounts": "pview-", + "recoveryServicesVaults": "rsv-", + "resourcesResourceGroups": "rg-", + "searchSearchServices": "srch-", + "serviceBusNamespaces": "sb-", + "serviceBusNamespacesQueues": "sbq-", + "serviceBusNamespacesTopics": "sbt-", + "serviceEndPointPolicies": "se-", + "serviceFabricClusters": "sf-", + "signalRServiceSignalR": "sigr", + "sqlManagedInstances": "sqlmi-", + "sqlServers": "sql-", + "sqlServersDataWarehouse": "sqldw-", + "sqlServersDatabases": "sqldb-", + "sqlServersDatabasesStretch": "sqlstrdb-", + "storageStorageAccounts": "st", + "storageStorageAccountsVm": "stvm", + "storSimpleManagers": "ssimp", + "streamAnalyticsCluster": "asa-", + "synapseWorkspaces": "syn", + "synapseWorkspacesAnalyticsWorkspaces": "synw", + "synapseWorkspacesSqlPoolsDedicated": "syndp", + "synapseWorkspacesSqlPoolsSpark": "synsp", + "timeSeriesInsightsEnvironments": "tsi-", + "webServerFarms": "plan-", + "webSitesAppService": "app-", + "webSitesAppServiceEnvironment": "ase-", + "webSitesFunctions": "func-", + "webStaticSites": "stapp-" +} \ No newline at end of file diff --git a/infra/core/host/appservice-appsettings.bicep b/infra/core/host/appservice-appsettings.bicep new file mode 100644 index 000000000..f4b22f816 --- /dev/null +++ b/infra/core/host/appservice-appsettings.bicep @@ -0,0 +1,17 @@ +metadata description = 'Updates app settings for an Azure App Service.' +@description('The name of the app service resource within the current resource group scope') +param name string + +@description('The app settings to be applied to the app service') +@secure() +param appSettings object + +resource appService 'Microsoft.Web/sites@2022-03-01' existing = { + name: name +} + +resource settings 'Microsoft.Web/sites/config@2022-03-01' = { + name: 'appsettings' + parent: appService + properties: appSettings +} diff --git a/infra/core/host/appservice.bicep b/infra/core/host/appservice.bicep new file mode 100644 index 000000000..bef4d2ba4 --- /dev/null +++ b/infra/core/host/appservice.bicep @@ -0,0 +1,123 @@ +metadata description = 'Creates an Azure App Service in an existing Azure App Service plan.' +param name string +param location string = resourceGroup().location +param tags object = {} + +// Reference Properties +param applicationInsightsName string = '' +param appServicePlanId string +param keyVaultName string = '' +param managedIdentity bool = !empty(keyVaultName) + +// Runtime Properties +@allowed([ + 'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom' +]) +param runtimeName string +param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}' +param runtimeVersion string + +// Microsoft.Web/sites Properties +param kind string = 'app,linux' + +// Microsoft.Web/sites/config +param allowedOrigins array = [] +param alwaysOn bool = true +param appCommandLine string = '' +@secure() +param appSettings object = {} +param clientAffinityEnabled bool = false +param enableOryxBuild bool = contains(kind, 'linux') +param functionAppScaleLimit int = -1 +param linuxFxVersion string = runtimeNameAndVersion +param minimumElasticInstanceCount int = -1 +param numberOfWorkers int = -1 +param scmDoBuildDuringDeployment bool = false +param use32BitWorkerProcess bool = false +param ftpsState string = 'FtpsOnly' +param healthCheckPath string = '' + +resource appService 'Microsoft.Web/sites@2022-03-01' = { + name: name + location: location + tags: tags + kind: kind + properties: { + serverFarmId: appServicePlanId + siteConfig: { + linuxFxVersion: linuxFxVersion + alwaysOn: alwaysOn + ftpsState: ftpsState + minTlsVersion: '1.2' + appCommandLine: appCommandLine + numberOfWorkers: numberOfWorkers != -1 ? numberOfWorkers : null + minimumElasticInstanceCount: minimumElasticInstanceCount != -1 ? minimumElasticInstanceCount : null + use32BitWorkerProcess: use32BitWorkerProcess + functionAppScaleLimit: functionAppScaleLimit != -1 ? functionAppScaleLimit : null + healthCheckPath: healthCheckPath + cors: { + allowedOrigins: union([ 'https://portal.azure.com/', 'https://ms.portal.azure.com/' ], allowedOrigins) + } + } + clientAffinityEnabled: clientAffinityEnabled + httpsOnly: true + } + + identity: { type: managedIdentity ? 'SystemAssigned' : 'None' } + + resource basicPublishingCredentialsPoliciesFtp 'basicPublishingCredentialsPolicies' = { + name: 'ftp' + properties: { + allow: false + } + } + + resource basicPublishingCredentialsPoliciesScm 'basicPublishingCredentialsPolicies' = { + name: 'scm' + properties: { + allow: false + } + } +} + +// Updates to the single Microsoft.sites/web/config resources that need to be performed sequentially +// sites/web/config 'appsettings' +module configAppSettings 'appservice-appsettings.bicep' = { + name: '${name}-appSettings' + params: { + name: appService.name + appSettings: union(appSettings, + { + SCM_DO_BUILD_DURING_DEPLOYMENT: string(scmDoBuildDuringDeployment) + ENABLE_ORYX_BUILD: string(enableOryxBuild) + }, + runtimeName == 'python' && appCommandLine == '' ? { PYTHON_ENABLE_GUNICORN_MULTIWORKERS: 'true'} : {}, + !empty(applicationInsightsName) ? { APPLICATIONINSIGHTS_CONNECTION_STRING: applicationInsights.properties.ConnectionString } : {}, + !empty(keyVaultName) ? { AZURE_KEY_VAULT_ENDPOINT: keyVault.properties.vaultUri } : {}) + } +} + +// sites/web/config 'logs' +resource configLogs 'Microsoft.Web/sites/config@2022-03-01' = { + name: 'logs' + parent: appService + properties: { + applicationLogs: { fileSystem: { level: 'Verbose' } } + detailedErrorMessages: { enabled: true } + failedRequestsTracing: { enabled: true } + httpLogs: { fileSystem: { enabled: true, retentionInDays: 1, retentionInMb: 35 } } + } + dependsOn: [configAppSettings] +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = if (!(empty(keyVaultName))) { + name: keyVaultName +} + +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (!empty(applicationInsightsName)) { + name: applicationInsightsName +} + +output identityPrincipalId string = managedIdentity ? appService.identity.principalId : '' +output name string = appService.name +output uri string = 'https://${appservice.properties.defaulthostname}/' diff --git a/infra/core/host/appserviceplan.bicep b/infra/core/host/appserviceplan.bicep new file mode 100644 index 000000000..2e37e041f --- /dev/null +++ b/infra/core/host/appserviceplan.bicep @@ -0,0 +1,22 @@ +metadata description = 'Creates an Azure App Service plan.' +param name string +param location string = resourceGroup().location +param tags object = {} + +param kind string = '' +param reserved bool = true +param sku object + +resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { + name: name + location: location + tags: tags + sku: sku + kind: kind + properties: { + reserved: reserved + } +} + +output id string = appServicePlan.id +output name string = appServicePlan.name diff --git a/infra/main.bicep b/infra/main.bicep new file mode 100644 index 000000000..d45d3cc70 --- /dev/null +++ b/infra/main.bicep @@ -0,0 +1,91 @@ +targetScope = 'subscription' + +// The main bicep module to provision Azure resources. +// For a more complete walkthrough to understand how this file works with azd, +// see https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/make-azd-compatible?pivots=azd-create + +@minLength(1) +@maxLength(64) +@description('Name of the the environment which is used to generate a short unique hash used in all resources.') +param environmentName string + +@minLength(1) +@description('Primary location for all resources') +param location string + +// Optional parameters to override the default azd resource naming conventions. +// Add the following to main.parameters.json to provide values: +// "resourceGroupName": { +// "value": "myGroupName" +// } +param resourceGroupName string = '' +param appServiceName string = '' +param appServicePlanName string = '' + +var abbrs = loadJsonContent('./abbreviations.json') + +// tags that should be applied to all resources. +var tags = { + // Tag all resources with the environment name. + 'azd-env-name': environmentName +} + +// Generate a unique token to be used in naming resources. +// Remove linter suppression after using. +#disable-next-line no-unused-vars +var resourceToken = toLower(uniqueString(subscription().id, environmentName, location)) + +// Name of the service defined in azure.yaml +// A tag named azd-service-name with this value should be applied to the service host resource, such as: +// Microsoft.Web/sites for appservice, function +// Example usage: +// tags: union(tags, { 'azd-service-name': apiServiceName }) + +// Organize resources in a resource group +resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: !empty(resourceGroupName) ? resourceGroupName : '${abbrs.resourcesResourceGroups}${environmentName}' + location: location + tags: tags +} + +// Add resources to be provisioned below. + +// The application App +module web './core/host/appservice.bicep' = { + name: 'web' + scope: rg + params: { + name: !empty(appServiceName) ? appServiceName : '${abbrs.webSitesAppService}web-${resourceToken}' + location: location + appServicePlanId: appServicePlan.outputs.id + runtimeName: 'python' + runtimeVersion: '3.13' + tags: union(tags, { 'azd-service-name': 'web' }) + } +} + +// Create an App Service Plan to group applications under the same payment plan and SKU +module appServicePlan './core/host/appserviceplan.bicep' = { + name: 'appserviceplan' + scope: rg + params: { + name: !empty(appServicePlanName) ? appServicePlanName : '${abbrs.webServerFarms}${resourceToken}' + location: location + tags: tags + sku: { + name: 'B1' + } + } +} + +// Add outputs from the deployment here, if needed. +// +// This allows the outputs to be referenced by other bicep deployments in the deployment pipeline, +// or by the local machine as a way to reference created resources in Azure for local development. +// Secrets should not be added here. +// +// Outputs are automatically saved in the local azd environment .env file. +// To see these outputs, run `azd env get-values`, or `azd env get-values --output json` for json output. +output AZURE_LOCATION string = location +output AZURE_TENANT_ID string = tenant().tenantId + diff --git a/infra/main.parameters.json b/infra/main.parameters.json new file mode 100644 index 000000000..f1600cfbc --- /dev/null +++ b/infra/main.parameters.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "environmentName": { + "value": "${AZURE_ENV_NAME}" + }, + "location": { + "value": "${AZURE_LOCATION}" + } + } +} From 590498fd22365a0ed67580a9d2d81b2df9b2eae0 Mon Sep 17 00:00:00 2001 From: Cephas Lin Date: Wed, 2 Apr 2025 10:57:04 +0000 Subject: [PATCH 7/7] add SCM build --- infra/main.bicep | 1 + 1 file changed, 1 insertion(+) diff --git a/infra/main.bicep b/infra/main.bicep index d45d3cc70..391f0103f 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -60,6 +60,7 @@ module web './core/host/appservice.bicep' = { appServicePlanId: appServicePlan.outputs.id runtimeName: 'python' runtimeVersion: '3.13' + scmDoBuildDuringDeployment: true tags: union(tags, { 'azd-service-name': 'web' }) } }