This commit is contained in:
Pieter de Bruin 2021-12-23 12:30:23 +01:00
Родитель 3d1a26b0d2
Коммит 39713764e8
12 изменённых файлов: 459 добавлений и 0 удалений

9
.vscode/settings.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,9 @@
{
"azureFunctions.projectSubpath": "function",
"markdownlint.config": {
"MD028": false,
"MD025": {
"front_matter_title": ""
}
}
}

52
docs/blobindex.md Normal file
Просмотреть файл

@ -0,0 +1,52 @@
# Blobindexreact - Index and tags <!-- omit in toc -->
## Contents <!-- omit in toc -->
- [Blob index and tags](#blob-index-and-tags)
- [Category and product tags](#category-and-product-tags)
- [Security](#security)
## Blob index and tags
In Azure Storage you can store blobs, files, queue messages and table entities. This sample focuses on blobs or Binary Large OBjects, where they are jpg images and json structured data objects. In Azure Storage blobs have system properties, like name, size and created on date. They can also have user-defined meta data, which are name-value pairs to store additional values. Lastly blobs can have tags, which are also user-defined with the additional benefit that they are indexed. So although you can store the same information with meta data and tags, working with tags is more efficient since you can just search for a tag instead of going over every object and compare meta data to satisfy your search condition.
With that in mind we wanted to demonstrate what you could potentially do with blob tags and index in an application development solution. So we came up with a scenario of a web shop, or any other catalog, where the most important data is the images of items, and the extend them with tags for simple structure and additional information.
In this sample you will see that the tags of category and product are used to find the blobs. Other tags like description, price and color are simply for display purposes. They could be useful in future releases of tags and index when you may be able to search for parts of a text, get price ranges, and get tag keys and their values for filtering.
![Category tags](./tags_category.png "Category tags")
![Product tags](./tags_product.png "Product tags")
## Category and product tags
In the sample we are assuming that image blobs will all have a category value. Categories have an empty product value and product do have a value in their product tag. So search query for categories looks like:
```javascript
var partialquery = "product = '' AND category > ''";
```
and the search query for products looks like:
```javascript
var partialquery = "product > '' AND category = '" + categoryname + "'";
```
These partial queries are both used in the generic findBlobs function and extended with a @container to narrow the search to just the catalog container.
```javascript
var query = "@container = '" + catalogContainerName + "' AND " + partialquery;
let iter = blobServiceClient.findBlobsByTags(query);
```
The result is a list of blob items. Since tags are not included in the result, for each of these items call gettags to get their tags and add them to the blob object.
## Security
For completeness you should be aware that so far the user interaction with Azure Storage happens using a SAS token that has read access to the product catalog container. Since Azure Storage security is a topic on its own, take a look at the [rbac page](./rbac.md).
## More info
https://docs.microsoft.com/azure/storage/blobs/storage-blob-index-how-to
https://docs.microsoft.com/azure/storage/blobs/storage-manage-find-blobs

64
docs/deploy.md Normal file
Просмотреть файл

@ -0,0 +1,64 @@
# BlobIndexReact - Deploy <!-- omit in toc -->
## Contents <!-- omit in toc -->
- [BlobIndexReact Prerequisites](#blobindexreact-prerequisites)
- [Deploy BlobIndexReact](#deploy-blobindexreact)
## BlobIndexReact Prerequisites
BlobIndexReact requires the following Azure services and role assignments to be deployed:
- Access to an Azure subscription
- Global Admin in Azure Active Directory
- App Registration with API permissions and admin consent
- Contributor (or equivalent) [RBAC](https://docs.microsoft.com/azure/role-based-access-control/overview) assignments at a subscription scope to create the following Azure services:
- [Azure Storage](https://azure.microsoft.com/services/storage/)
- [Azure Active Directory](https://azure.microsoft.com/services/active-directory/)
- [Azure Event Grid](https://azure.microsoft.com/services/event-grid/)
- [Azure Functions](https://azure.microsoft.com/services/functions/)
BlobIndexReact depends on a script to deploy its components and data. To deploy these, the following is required:
- [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest)
- Node & NPM (Default in codespaces) https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04
- Func https://docs.microsoft.com/azure/azure-functions/functions-run-local
Note: The deploy script uses `az ad` commands, to configure Azure Active Directory, which is not supported in Azure Cloud Shell. https://github.com/Azure/azure-cli/issues/12137#issuecomment-596567479
The sample was built in GitHub CodeSpaces, which has az cli and node configured out-of-the-box.
## Deploy BlobIndexReact
For a complete set of instruction to deploy the sample, see deploy.sh in the scripts folder.
**Please note** that the script currently requires a workaround, because az cli doesn't support tf permissions to generate a sas. https://github.com/Azure/azure-cli/issues/20368 The following instructions help create the read sas token in the Azure portal and then build and deploy the React web app.
In the Azure Portal, find the new storage account, navigate to shared access signature and create a new one using these settings:
Allowed services: Blob
Allowed resource types: Service, Container, Object
Allowed permissions: Read, List
Blob versioning permissions: None
Allowed blob index permissions: Read/Write, Filter
End: Choose a date, for instance 2 months ahead
Leave the remaining settings to their defaults.
Click Generate SAS and connection string.
Copy the SAS token value (starting with ?sv=) and paste it to replace the #insertmanually# value.
Note that this script assumes present working directory is the scripts folder.
``` Bash
echo "Temporary workaround. Copy the below instructions to a text editor:"
echo "Create a SAS token as described in deploy.md"
echo "Set READSASTOKEN in ../web/src/authConfig.js"
echo "RG=$RG"
echo "STORAGEACCOUNT=$STORAGEACCOUNT"
echo 'SACONNSTRING="$(az storage account show-connection-string --name $STORAGEACCOUNT -g $RG -o tsv)"'
echo "npm run build --if-present --prefix ../web"
echo 'az storage blob upload-batch --account-name $STORAGEACCOUNT --auth-mode key -d '"'"'$web'"'"' -s ../web/build/. --connection-string $SACONNSTRING --overwrite true'
echo "Deployment done. Web app is available at $STORAGEWEBURL"
```
## Remove
The deploy script of BlobIndexReact creates all Azure services in one resource group. Additionally it creates an app registration in Azure Active Directory. You can remove both in the Azure portal.

24
docs/eventhandler.md Normal file
Просмотреть файл

@ -0,0 +1,24 @@
# Blobindexreact - Event handler <!-- omit in toc -->
## Contents <!-- omit in toc -->
- [Event Grid system topic](#event-grid-system-topic)
- [Azure Function](#azure-function)
- [Security](#security)
## Event Grid system topic
Azure Event Grid provides native integration with various event sources to listen to, including Azure Blob Storage, and with various event handlers, including Azure Functions. In this sample we are using this combination to handle the event of a new user signing in the web application to make sure a user-specific storage container exists. It is secured using role-based access control for storage, which works like regular Azure identity and access management where a role is assigned to an identity. In the future this could be a relevant scenario for storage tasks.
In this scenario the web application doesn't know about the user until they sign-in. Once they sign in, they need to get a storage container with permissions to write their orders to and to read them from. This flow is started by the web application creating a temporary blob with name of the user guid. This blob creation is noticed by Event Grid, which then triggers the Function to handle the logic. To be specific the function and the topic only are interested in blob created events in the temp container; other events and containers are not relevant to the function.
![Event topic](./eventhandler_subscription.png "Event topic")
## Azure Function
Azure Functions is also known as serverless compute: a light-weight option to run custom logic. The function is started when it is triggered by Event Grid, which is defined in the binding and configured by the event grid subscription. The function receives the Event Grid event and can then do its logic. In this sample the topic and subject contain all the information the function need to create the container, assign the Storage Blob Data Contributor to the new user and delete the temporary blob that started the flow.
![Function log](./eventhandler_log.png "Function log")
## Security
For completeness you should be aware that the function interaction with Azure Storage happens using a system managed identity that has access to the control plane and data plane of the storage account. Since Azure Storage security is a topic on its own, take a look at the [rbac page](./rbac.md).
## More info
https://docs.microsoft.com/azure/event-grid/event-schema-blob-storage

26
docs/monitor.md Normal file
Просмотреть файл

@ -0,0 +1,26 @@
# Blobindexreact - Monitor <!-- omit in toc -->
Monitoring in Azure can be done within the individual services or in a central location using a combination of Azure Monitor, Log Analytics and Application Insights. In this sample monitoring is a bit different since the essence happens in the React single-page app in the browser of your users. Testing the app using multiple identities and browsers is probably the most useful. Next to that this section describes how to verify the flow of events in Azure.
## Contents <!-- omit in toc -->
- [F12 Developer tools](#f12-developer-tools)
- [Signing in](#signing-in)
## F12 Developer tools
The majority of code in this sample is in the React single-page app. Browsers provide default functionality for developer through F12, including a console view to see errors and log messages and a network view to understand what is being communicated.
When the React application starts it asks storage for categories; blobs with category tag filled and empty product tag. For more details, see [blobindex description](./blobindex.md). When this fails, check in the dev tools console whether the request succeeded. If it didn't, check the url and read sas token by retrieving one image with that token. If it did, then check the storage account, container, images, and tags.
## Signing in
The actual sign-in is relatively straightforward since this sample reuses the react AAD sample. When signing-in doesn't work, check the authConfig.js configuration, specifically the clientid and authority, and their existence in Azure Active Directory. Also note when running the sample locally using npm start, the browser automatically opens to http://127.0.0.1:3000, which is not a valid return url in aad, so use http://localhost:3000 instead.
After the sign-in, the integration flow starts: First the app checks whether the user-specific container exists. If the container and permissions exist, the flow ends here. If the container or the permissions don't exist, the request fails visibly in the dev tools console, which is expected. The app then tries to create a user guid blob in the temp container using the createtempblobsastoken. If this fails, check the storage account, container and sas token.
Next the creation of the blob triggers an Event Grid event and this is passed on to the Azure Function, which can be monitored in the metrics of the Event Grid System Topic.
Lastly the actual event handling is done by the HandleEventsFunc Function in the Function App. The function can be monitored in the monitor tab and shows the three operations: creating the container, setting role assignment and deleting the temp blob. The function app should run as system managed identity with (owner and storage blob data contributor) permissions to perform these operations. Note that the invocation logs may take up to five minutes before they show in the portal. When debugging use the logs tab to view live log stream.
https://docs.microsoft.com/azure/role-based-access-control/troubleshooting#role-assignment-changes-are-not-being-detected

52
docs/rbac.md Normal file
Просмотреть файл

@ -0,0 +1,52 @@
# Blobindexreact - Role-based access control <!-- omit in toc -->
## Contents <!-- omit in toc -->
- [Azure Storage authentication and authorization](#azure-storage-authentication-and-authorization)
- [Access tokens](#access-tokens)
- [SAS tokens](#sas-tokens)
- [RBAC](#rbac)
- [System assigned managed identity](#system-assigned-managed-identity)
## Azure Storage authentication and authorization
There are a number of ways to get access to an Azure Storage account. This sample uses sas tokens, role-based access control for signed-in user in the web application and a system managed identity for the function. For completeness we should also mention that there are many ways to secure and open up storage accounts.
## Access keys
Access keys are similar to a root password for your storage account. They are probably a bit too powerful for a simple web application.
## SAS tokens
Shared access signatures also provide anonymous access, however they can do so in a more specific way by providing details on allowed scope, services, permissions and time.
In this sample there are two SAS tokens. The first SAS token is a read sas to allow anonymous users to browse the catalog. The second is a create sas to write a temporary blob for new users.
The read SAS is used for browsing the images in the product catalog container. Normally when using listblobs operations you could just use a container level sas token with read and list permissions. Since the browse function in this sample uses blob index and tags and the findblobsbytag operation exists at the service level, you need an account level SAS token with r(ead), l(ist), t(ag) and f(ilter) permissions for the blob service and resource types of service, container and object. For the expiry chose a period that is manageable, which is a tradeoff between how often you want to refresh the token versus for how long can your live with a lost token.
The create SAS is used to create a temporary blob in a temp container to trigger creation of a user-specific container with permissions, if that doesn't exist yet for the user. For more information on this flow, see the [event handler description](./eventhandler.md). This create SAS can be configured at the temp container level and needs create permissions.
## RBAC
Known users will often interact with storage through the identity of a serverside api. In this sample there is a single-page application that connects directly to storage. Role-based access control can be used to authorize those known users in storage. The setup here is that each user will have their own storage container with the name of the user guid. That container also has an RBAC rule that allows only the user to read and write in that container, plus users with permissions at a higher level including subscription, resource group and storage account.
Before using RBAC with storage, the user has to sign in with Azure Active Directory. AAD integration requires an AAD application registration and authority configured in authConfig.js. This app registration needs to have redirect URIs configured to the locations where the app is running, like localhost and the storage static website url. Also the app registration needs to have API Permissions to use Azure Storage user impersonation.
Consent message:
This app would like to:
Access Azure Storage As the Signed-in User
View your basic profile
Maintain access to data you have given it access to
Consent on behalf of your organization
After signing in, the react Microsoft Authentication Library is aware of the signed in user. Next this credential has to be used in the API calls to storage. In this sample that is a InteractiveBrowserCredential.
![Storage RBAC](./storage_rbac.png "Storage RBAC")
## ABAC
At the moment you can have [a maximum of 2000 Azure RBAC role assignmetns in a subscription](https://docs.microsoft.com/azure/storage/common/storage-auth-abac). In this solution there is one role assignment per user. When you need more, take a look at attribute based access control. For instance, all users could be assigned to a group that is Storage Blob Data Contributor, and then additional ABAC conditions could be used to allow access based on a blob's userid tag or container name.
https://docs.microsoft.com/azure/storage/common/storage-auth-abac-examples
https://docs.microsoft.com/azure/storage/common/storage-auth-abac-cli
## System assigned managed identity
The Azure Function creates storage containers, sets role assignments and deletes temporary blobs, for which it needs an identity. The easiest way give an Azure service instance an identity is by using the system assigned managed identity, which means that the management of the identity and secrets is done by Azure. You only need to assign roles, in this case the owner and storage blob data owner, both on the storage account.
## More info
https://docs.microsoft.com/azure/storage/common/authorize-data-access

14
docs/resources.md Normal file
Просмотреть файл

@ -0,0 +1,14 @@
# BlobIndexReact - Resources <!-- omit in toc -->
## Contents <!-- omit in toc -->
- [Useful links](#useful-links)
## Useful links
[Azure Storage javascript SDK](https://docs.microsoft.com/javascript/api/@azure/storage-blob/blobserviceclient)
[AAD MSAL React sample](https://docs.microsoft.com/azure/active-directory/develop/tutorial-v2-react)
[AAD permissions and consent](https://docs.microsoft.com/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes)
[Joe Morgan's React tutorial](https://www.digitalocean.com/community/tutorial_series/how-to-code-in-react-js)

138
scripts/deploy.sh Normal file
Просмотреть файл

@ -0,0 +1,138 @@
#!/bin/bash
# Set these variables to match your environment
REGION="westeurope"
SUBSCRIPTIONNAME="prodold"
# When rerunning you can set SUFFIX to your previous value
SUFFIX=$RANDOM
# Optionally change
PREFIX="blobindexreact"
RG=$PREFIX"rg"$SUFFIX
export STORAGEACCOUNT=$PREFIX"sa$SUFFIX"
export IMAGESCONTAINER="productcatalog"
TEMPCONTAINER="temp"
ADAPPNAME=$PREFIX"web"$SUFFIX
EVENTTOPIC=$PREFIX"event"$SUFFIX
EVENTSUB=$PREFIX"eventsub"
FUNCTIONAPP=$PREFIX"function"$SUFFIX
FUNCTIONNAME="HandleEventsFunc"
echo "Logging in"
#az login
az account set -s $SUBSCRIPTIONNAME
echo "Creating resource group"
az group create -n $RG -l $REGION
### Storage account ###
echo "Creating storage account"
STORAGEID="$(az storage account create --name $STORAGEACCOUNT --access-tier Hot --kind StorageV2 --sku Standard_LRS --https-only true -g $RG -l $REGION --query id -o tsv)"
export SACONNSTRING="$(az storage account show-connection-string --name $STORAGEACCOUNT -g $RG -o tsv)"
STORAGEURL="https://$STORAGEACCOUNT.blob.core.windows.net"
STORAGEWEBURL="https://$STORAGEACCOUNT.z6.web.core.windows.net"
# Deploying services that take time to become available (instead of sleep)
echo "Creating app registration"
ADAPPID="$(az ad app create --display-name $ADAPPNAME --required-resource-accesses @manifest.json --native-app false --oauth2-allow-implicit-flow false --reply-urls $STORAGEWEBURL "http://localhost:3000/" --available-to-other-tenants true --query appId -o tsv)"
echo "Creating function app"
az functionapp create -n $FUNCTIONAPP -g $RG -s $STORAGEACCOUNT -c $REGION --assign-identity [system] --functions-version 4 --runtime node --os-type Linux --runtime-version 14
az storage container create -n $IMAGESCONTAINER --connection-string $SACONNSTRING
source ./sampledata.sh
echo "Enabling static website"
az storage blob service-properties update --account-name $STORAGEACCOUNT --static-website --index-document index.html
echo "Enabling CORS"
az storage cors add --methods GET HEAD OPTIONS POST PUT --origins '*' --allowed-headers '*' --exposed-headers '*' --max-age 86400 --services b --connection-string $SACONNSTRING
echo "Creating temp container"
az storage container create -n $TEMPCONTAINER --connection-string $SACONNSTRING
# Authorize the signed-in user
USERID="$(az ad signed-in-user show --query objectId -o tsv)"
az role assignment create --assignee $USERID --role "ba92f5b4-2d11-453d-a403-e96b0029c9fe" --scope $STORAGEID
# SAS tokens
echo "Creating read sas"
EXPIRY="$(date -u -d "2 months" '+%Y-%m-%dT%H:%M:%SZ')" # '+%Y-%m-%dT%H:%M:%SZ'
# While tf permissions are not yet supported in az cli, create it manually using the portal or powershell https://github.com/Azure/azure-cli/issues/20368
# READSASTOKEN="$(az storage account generate-sas --account-name $STORAGEACCOUNT --permissions rltf --services b --resource-types sco --expiry $EXPIRY --https-only --connection-string $SACONNSTRING -o tsv)"
# Rest doesn't support tf permissions yet
# SUBSCRIPTIONID=$(az account show --query id -o tsv)
# RESTURI='https://management.azure.com/subscriptions/'$SUBSCRIPTIONID'/resourceGroups/'$RG'/providers/Microsoft.Storage/storageAccounts/'$STORAGEACCOUNT'/ListAccountSas?api-version=2021-04-01'
# READSASTOKEN="$(az rest --method POST --uri $RESTURI --headers 'Content-Type=application/json' --body '{"signedVersion":"2020-08-04","signedServices":"b","signedResourceTypes":"sco","signedPermission":"rltf","signedExpiry":"'$EXPIRY'","keyToSign":"key1"}')"
# READSASTOKEN="#insertmanually#"
echo "Creating create sas"
CREATETEMPBLOBSASTOKEN=?"$(az storage container generate-sas -n $TEMPCONTAINER --permissions w --expiry $EXPIRY --https-only --connection-string $SACONNSTRING -o tsv)"
### AAD App registration ###
echo "Creating AAD app registration. (Az ad commands do not work in Azure Cloud Shell)"
ADOBJECTID=$(az ad app show --id $ADAPPID --query objectId --output tsv)
# Workaround to set the type to Spa
az rest --method PATCH --uri 'https://graph.microsoft.com/v1.0/applications/'$ADOBJECTID --headers 'Content-Type=application/json' --body '{"spa":{"redirectUris":["'$STORAGEWEBURL'", "http://localhost:3000/"]}}'
AUTHORITY="https://login.microsoftonline.com/$(az account show --query homeTenantId -o tsv)"
# az ad app permission admin-consent --id $ADAPPID
echo "Updating env vars in web app"
sed -i "s|#accountendpoint#|$STORAGEURL|g" ../web/src/authConfig.js
# First escape ampersand which is a special character in sed
READSASTOKEN2=$(echo $READSASTOKEN | sed -e 's/&/\\\&/g')
# Then replace the placeholder with the actual value
#sed -i "s|#readsastoken#|$READSASTOKEN2|" ../web/src/authConfig.js
CREATETEMPBLOBSASTOKEN2=$(echo $CREATETEMPBLOBSASTOKEN | sed -e 's/&/\\\&/g')
sed -i "s|#createtempblobsastoken#|$CREATETEMPBLOBSASTOKEN2|" ../web/src/authConfig.js
sed -i "s|#clientid#|${ADAPPID}|" ../web/src/authConfig.js
sed -i "s|#authority#|${AUTHORITY}|" ../web/src/authConfig.js
echo "Builing web app" # including the updated authConfig.js
npm install --if-present --prefix ../web
npm run build --if-present --prefix ../web
echo "Deploying web app"
az storage blob upload-batch --account-name $STORAGEACCOUNT --auth-mode key -d '$web' -s ../web/build/. --connection-string $SACONNSTRING --overwrite true
### Azure Function ###
echo "Creating function app"
pushd ../function
echo "Deploying function app"
npm install --if-present
func azure functionapp publish $FUNCTIONAPP
popd
FUNCTIONPRINCIPALID="$(az functionapp show -g $RG -n $PREFIX"function"$SUFFIX --query identity.principalId --output tsv)"
az role assignment create --assignee $FUNCTIONPRINCIPALID --role "ba92f5b4-2d11-453d-a403-e96b0029c9fe" --scope $STORAGEID
az role assignment create --assignee $FUNCTIONPRINCIPALID --role "8e3af657-a8ff-443c-a75c-2fe8c4bcb635" --scope $STORAGEID
FUNCTIONID="$(az functionapp show --name $FUNCTIONAPP --resource-group $RG --query id --output tsv)"/functions/$FUNCTIONNAME
### Event Grid ###
echo "Creating eventgrid system-topic"
az provider register --namespace Microsoft.EventGrid
az eventgrid system-topic create --resource-group $RG --name $EVENTTOPIC --location $REGION --source $STORAGEID --topic-type microsoft.storage.storageaccounts
echo "Creating eventgrid system-topic event-subscription"
az eventgrid system-topic event-subscription create --name $EVENTSUB -g $RG --system-topic-name $EVENTTOPIC --endpoint $FUNCTIONID --endpoint-type azurefunction --included-event-types "Microsoft.Storage.BlobCreated" --subject-begins-with "/blobServices/default/containers/temp" --event-delivery-schema eventgridschema
### Workaround for read sas ###
echo "Temporary workaround. Copy the below instructions to a text editor:"
echo "Create a SAS token as described in deploy.md"
echo "Set READSASTOKEN in ../web/src/authConfig.js"
echo "RG=$RG"
echo "STORAGEACCOUNT=$STORAGEACCOUNT"
echo 'SACONNSTRING="$(az storage account show-connection-string --name $STORAGEACCOUNT -g $RG -o tsv)"'
echo "npm run build --if-present --prefix ../web"
echo 'az storage blob upload-batch --account-name $STORAGEACCOUNT --auth-mode key -d '"'"'$web'"'"' -s ../web/build/. --connection-string $SACONNSTRING --overwrite true'
echo "Deployment done. Web app is available at $STORAGEWEBURL"

13
scripts/manifest.json Normal file
Просмотреть файл

@ -0,0 +1,13 @@
[
{
"additionalProperties": null,
"resourceAccess": [
{
"additionalProperties": null,
"id": "03e0da56-190b-40ad-a80c-ea378c433f7f",
"type": "Scope"
}
],
"resourceAppId": "e406a681-f3d4-42a8-90b6-c2b029497af1"
}
]

21
scripts/prerequisites.sh Normal file
Просмотреть файл

@ -0,0 +1,21 @@
# Install AZ CLI
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Install NPM 14
sudo apt-get update
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
source ~/.bashrc
nvm install v14.17.6
sudo apt install nodejs (14.17.6)
sudo apt install npm
npm install -g npm
# Install Func core tools
curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg
sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-$(lsb_release -cs)-prod $(lsb_release -cs) main" > /etc/apt/sources.list.d/dotnetdev.list'
sudo apt-get update
sudo apt-get install azure-functions-core-tools-4

8
scripts/reset.sh Normal file
Просмотреть файл

@ -0,0 +1,8 @@
#!/bin/bash
pushd ../web/src
rm authConfig.js
cp 'authConfig placeholders.js' authConfig.js
popd

38
scripts/sampledata.sh Normal file
Просмотреть файл

@ -0,0 +1,38 @@
echo "Uploading images"
az storage blob upload-batch --account-name $STORAGEACCOUNT --auth-mode key -d $IMAGESCONTAINER -s ../blobs/. --connection-string $SACONNSTRING
az config set extension.use_dynamic_install=yes_without_prompt
az storage blob tag set --tags category=Casual product="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-adam-dubec-1595476 - cat.jpg"
az storage blob tag set --tags category=Casual product="Great bike" price="1.99" color="Red" description="Lorum ipsum" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name pexels-adam-dubec-1595476.jpg
az storage blob tag set --tags category="Casual" product="Country bike" price="9.99" color="white" description="This is a great bike that you really should try for yourself" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-adam-dubec-1595483.jpg"
az storage blob tag set --tags category="Kids" product="" price="" color="" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-afta-putta-gunawan-680108 - cat.jpg"
az storage blob tag set --tags category="Kids" product="Toddler bike" price="8.99" color="pink" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-afta-putta-gunawan-680108.jpg"
az storage blob tag set --tags category="Pre-owned" product="" price="" color="" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-alain-frechette-1431117 - cat.jpg"
az storage blob tag set --tags category="Pre-owned" product="Spare bike" price="4.99" color="pink" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-alain-frechette-1431117.jpg"
az storage blob tag set --tags category="Sports" product="" price=".99" color="" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-burst-545004 - cat.jpg"
az storage blob tag set --tags category="Sports" product="Road race bike" price="19.99" color="black" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-burst-545004.jpg"
az storage blob tag set --tags category="Casual" product="Urban bike" price="9.99" color="green" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-clem-onojeghuo-175741.jpg"
az storage blob tag set --tags category="Sports" product="BMX bike" price="5.99" color="" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-cottonbro-5464921.jpg"
az storage blob tag set --tags category="Hybrid" product="" price="" color="" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-david-mcbee-255934 - cat.jpg"
az storage blob tag set --tags category="Hybrid" product="Commuter bike" price="14.99" color="white" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-david-mcbee-255934.jpg"
az storage blob tag set --tags category="Casual" product="City bike" price="10.99" color="white" description="Ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-dominika-roseclay-4318197.jpg"
az storage blob tag set --tags category="Pre-owned" product="Lost and found bike" price="3.99" color="" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-ekrulila-2668723.jpg"
az storage blob tag set --tags category="Casual" product="Retro bike" price="7.99" color="" description="Lorum" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-emanuele-intagliata-6630622.jpg"
az storage blob tag set --tags category="Hybrid" product="Work out bike" price="15.99" color="black" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-eva-elijas-5777054.jpg"
az storage blob tag set --tags category="Casual" product="Family bike" price="18.99" color="blue" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-gaspar-csaki-957157.jpg"
az storage blob tag set --tags category="Casual" product="Fruity bike" price="6.99" color="white" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-iryna-stasiukova-212185.jpg"
az storage blob tag set --tags category="Casual" product="Suburban bike" price="4.99" color="green" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-javon-swaby-3370153.jpg"
az storage blob tag set --tags category="Casual" product="Chopper bike" price="4.99" color="yellow" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-jess-loiterton-4602966.jpg"
az storage blob tag set --tags category="Casual" product="Looking sharp bike" price="13.99" color="pink" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-jodie-louise-805303.jpg"
az storage blob tag set --tags category="Casual" product="Flowery bike" price="11.99" color="lime" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-kostiantyn-stupak-190335.jpg"
az storage blob tag set --tags category="Hybrid" product="7 speed cruiser" price="12.99" color="white" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-maria-orlova-4906464.jpg"
az storage blob tag set --tags category="Casual" product="Advertising bike" price="4.99" color="orange" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-matteus-silva-5976796.jpg"
az storage blob tag set --tags category="Casual" product="Leathery bike" price="21.99" color="white" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-melike-benli-9930483.jpg"
az storage blob tag set --tags category="Pre-owned" product="Pumpkin bike" price="3.99" color="orange" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-monstera-5634616.jpg"
az storage blob tag set --tags category="Hybrid" product="Work out bike" price="12.99" color="black" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-nathan-engel-186100.jpg"
az storage blob tag set --tags category="Sports" product="All terrain bike" price="19.99" color="white" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-nikita-lyamkin-1553406.jpg"
az storage blob tag set --tags category="Casual" product="Rugged bike" price="8.99" color="black" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-nils-johansson-7775429.jpg"
az storage blob tag set --tags category="Hybrid" product="Fresh air bike" price="13.99" color="black" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-philipp-m-100582.jpg"
az storage blob tag set --tags category="Casual" product="Sunset bike" price="7.99" color="white" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-pixabay-210117.jpg"
az storage blob tag set --tags category="Casual" product="Cherry blossom bike" price="6.99" color="pink" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-taryn-elliott-4198566.jpg"
az storage blob tag set --tags category="Casual" product="Haut couture bike" price="23.99" color="aqua" description="" --connection-string $SACONNSTRING --container-name $IMAGESCONTAINER --name "pexels-timea-kadar-2130611.jpg"