# Bridgeman Accessible's Azure types (BA-az-types)
[![PyPI - Version](https://img.shields.io/pypi/v/ba_az_types.svg)](https://pypi.org/project/ba_az_types)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ba_az_types.svg)](https://pypi.org/project/ba_az_types)

Bridgeman Accessible (BA)'s internal representation of Azure (az) resource types.

-----

**Table of Contents**

- [Installation](#installation)
- [License](#license)

## Installation

```console
pip install ba_az_types
```

## License

`ba-az-types` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.


## Azure Resource Definition
In the proceeding sections details of each section of the Azure Resource definition will be explained and explored.

### Resource Groups (RGs) Section
The resource groups section does as you might expect in terms of defining resource groups. These are simplistic definitions consisting mostly of just a name.

```json
{
    "resourceGroups": [
        {
            "name": "{Resource Group Name}"
        }
    ]
}
```

### Storage Section
The storage section can be found in one of two places at the top level along with the other resource types or within the [Categorized Resources section](#categorized-resources-section).

The storage section defines an array of objects that each define a storage account and can have optional frurther definition
```json
{
    ...
    "storage": [
        {
            "name": "{account name}",
            "webApps": [
                "{webapp id}"
                ...
            ],
            "resourceGroup?": "{resource group}",
            "containers?": [
                {
                    "name": "{container name}",
                    "varName?": "{variable name}" | {
                        "prefixCategory": true | false,
                        "replacements": {
                            "{search text: text to be replaced}": "{replace text: text to replace with}"
                        },
                        "suffix?": "{suffix text}"
                    }
                }
            ],
            "tables": [
                {
                    "name": "{table name}",
                    "varName?": "{variable name}" | {
                        "prefixCategory": true | false,
                        "replacements": {
                            "{search text: text to be replaced}": "{replace text: text to replace with}"
                        },
                        "suffix?": "{suffix text}"
                    },
                    "data?": [
                        {
                            "{column name}": "{column value}"
                        }
                    ]
                }
            ]
        }
    ],
    ...
}
```

#### Storage Accounts
When storage accounts are set up the associated app(s) get the following three variables:
- Storage account's name
- Storage account's key
- Storage account's connection string

##### Storage Account Name
This is more or less transposed directly from the definition provided 

The resulting environment variable will take one of two forms depending if it's categorized or not:
- `{Storage Account Name}_NAME` for uncategorized storage accounts
- `{Category Name}_STORAGE_ACCOUNT_NAME` for categorized storage accounts

#### Storage Account Key
This is the key to access the storage account (it can be thought of as the storage account password). This is generated by Azure or the development environment infrastructure depending on the environment being deployed to.

The resulting environment variable will take one of two forms depending if it's categorized or not:
- `{Storage Account Name}_KEY` for uncategorized storage accounts
- `{Category Name}_STORAGE_ACCOUNT_KEY` for categorized storage accounts

#### Storage Account Connection String
This is an amalgamation of the name and key (as seen above) along with some other information into a single string/variable representation that can be used with SDKs etc... for easier access than managing the name and key separately.

The resulting environment variable will take one of two forms depending if it's categorized or not:
- `{Storage Account Name}_CONNECTION_STRING` for uncategorized storage accounts
- `{Category Name}_STORAGE_ACCOUNT_CONNECTION_STRING` for categorized storage accounts

### Categorized Resources Section
Where Azure has [RGs](#resource-groups-section) for how it groups resources together to make it easy to perform group actione. Bridgeman Accessible's infrastructure has a similar but slightly different mechanism for grouping resources called *Categorized Resources*. 

To that point, Categorized Resources are predominantly meant to provide a mechanism to prefix environment variable(s) that are created so that it's easier for the end app developer to intuitively understand the relationship between the variables and the resources their attached to.

Consider the following:
```json
{
    ...
    "storage": [
        {
            "name": "{Storage Account Name 1}",
            ...
            "containers": [
                {
                    "name": "uploadedVideos"
                    ...
                }
            ]
        },
        {
            "name": "{Storage Account Name 2}",
            ...
            "containers": [
                {
                    "name": "uploadedVideos"
                }
            ]
        }
    ],
    ...
}
```

Notice that the containers in both accounts is named exactly the same. This can happen because storage containers, tables, etc... within a storage account don't have to be globally unique (this is a good thing overall but introduces some complications initially) but can cause some confusion. To that end, to make these unique you could do some kind of prefix/suffix scheme with the account name which would guarantee uniqueness (because of the uniqueness requirement of storage account names across Azure). However, this uniqueness requirement ends up being a bit of a double edged sword in that you end up using slightly more convoluted naming schemes to meet this uniqueness requirements and the end result of this strategy (if your not extremely careful/vigilant) ends up with some really awkward variable names that are hard to remember. 

Consequently, it was conceived that if we introduce our own grouping mechanism that helps/allows for better control over the resulting environment variable name while being transparent to Azure (that is not effecting the names of anything within Azure) this seemed to address this issue without having to compromise beyond having an extra layer within the file (which also helps keep it organized and allows associated resources of different types)

Taking the above example again with categorized resources

```json
{
    ...
    "categorizedResources": {
        "videoEditing": {
            "storage": [
                {
                    "name": "{Storage Account Name}",
                    ...
                    "containers": [
                        {
                            "name": "uploadedVideos",
                            ...
                        }
                    ]
                }
            ]
        },
        "videoHosting": {
            "storage": [
                {
                    "name": "{Storage Account Name}",
                    ...
                    "containers": [
                        {
                            "name": "uploadedVideos"
                        }
                    ]
                }
            ]
        }
    },
    ...
}
```

With this approach you would end up with environment variables similar to `VIDEO_EDITING_UPLOADED_VIDEOS_CONTAINER_NAME` and `VIDEO_HOSTING_UPLOADED_VIDEOS_CONTAINER_NAME` while arguably not particularly short variable names they are unique while also being clear and descriptive about what their connected to.

Moreover, this also allows you to link resources of different types (as briefly mentioned above). Consider the following where your creating some kind of YouTube upload app:
```json
{
    ...
    "storage": [
        {
            "name": "{Storage Account Name}",
            ...
            "containers": [
                {
                    "name": "uploadedVideos",
                    ...
                }
            ]
        }
    ],
    "vaults": [
        {
            "name": "userTokens",
            ...
        }
    ],
    ...
}
```

The argument here being if you had this you'd probably end up with environment variables similar to `UPLOADED_VIDEOS_CONTAINER_NAME` and `USER_TOKENS_KEY_VAULT_NAME` which is valid but assumes the end app developer knows/understand the relationship between these two resources.

With the introduction of Categorized Resources this would become:
```json
{
    ...
    "categorizedResources": {
        "videoUploading": {
            "storage": [
                {
                    "name": "{Storage Account Name}",
                    ...
                    "containers": [
                        {
                            "name": "uploadedVideos",
                            ...
                        }
                    ]
                },
            ],
            "vaults": [
                {
                    "name": "userTokens",
                    ...
                }
            ]
        }
    }
}
```

Which would result with `VIDEO_UPLOADING_UPLOADED_VIDEOS_CONTAINER_NAME` and `VIDEO_UPLOADING_USER_TOKENS_KEY_VAULT_NAME` while arguably not the shortest name these do make it a lot more clear that these resources are related to one another and likely are intended to be used in conjunction with one another.

Furthermore, this can also be helpful when used in conjunction with regular expressions to easily pick out the relevant resources.

It's worth noting that there was discussion if using RGs instead of a custom categorization mechanism might be better. However, it was thought that while the RGs may provide this structure, we didn't want to force on people (particularly for an external platform) and felt that having our own categorization mechanism transparent of Azure provided more flexibility and allows developers and organizations to choose how to organize within Azure (including maintaining existing practices/standards for organizations or teams that may have them).
