create storage account outside of arm template

There are concurrent issues on Azure deployment script count.
If too many deployments in progress in subscription level,
 the old scripts may not able to deleted on time.
Deploy storage account outside of template to workaround it.
This commit is contained in:
Chi Song 2020-11-09 18:39:00 +08:00
Родитель fb16d77f89
Коммит 6d39968054
5 изменённых файлов: 85 добавлений и 5 удалений

Просмотреть файл

@ -8,6 +8,12 @@
"description": "resource group name"
}
},
"storageName": {
"type": "string",
"metadata": {
"description": "storage name for boot diagnosis"
}
},
"location": {
"type": "string",
"metadata": {
@ -58,7 +64,6 @@
}
},
"variables": {
"storageName": "[concat('lisas', substring(parameters('location'),0,min(11, length(parameters('location')))), substring(subscription().id,sub(length(subscription().id),8),8))]",
"sharedRGName": "lisa_shared_resource",
"storageDeploymentName": "[concat('storage-deploy-', substring(parameters('resourceGroupName'),sub(length(parameters('resourceGroupName')),22),22))]"
},
@ -85,7 +90,7 @@
"value": "[parameters('location')]"
},
"storageName": {
"value": "[variables('storageName')]"
"value": "[parameters('storageName')]"
}
},
"mode": "Incremental",
@ -161,7 +166,7 @@
"value": "[parameters('availabilitySetProperties')]"
},
"storageName": {
"value": "[variables('storageName')]"
"value": "[parameters('storageName')]"
},
"sharedRGName": {
"value": "[variables('sharedRGName')]"

Просмотреть файл

@ -3,6 +3,7 @@ from typing import TYPE_CHECKING, Any
from azure.mgmt.compute import ComputeManagementClient # type: ignore
from azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements # type: ignore
from azure.mgmt.storage import StorageManagementClient # type: ignore
from lisa.environment import Environment
from lisa.node import Node
@ -40,6 +41,21 @@ def get_compute_client(platform: Any) -> ComputeManagementClient:
)
def get_storage_client(platform: Any) -> ComputeManagementClient:
azure_platform: AzurePlatform = platform
return StorageManagementClient(
credential=azure_platform.credential,
subscription_id=azure_platform.subscription_id,
)
def get_storage_account_name(platform: Any, location: str) -> str:
azure_platform: AzurePlatform = platform
subscription_id_postfix = azure_platform.subscription_id[-8:]
# name should be shorter than 24 charactor
return f"lisas{location[0:11]}{subscription_id_postfix}"
def get_marketplace_ordering_client(platform: Any) -> MarketplaceOrderingAgreements:
azure_platform: AzurePlatform = platform
return MarketplaceOrderingAgreements(

Просмотреть файл

@ -28,6 +28,7 @@ from azure.mgmt.resource.resources.models import ( # type: ignore
DeploymentMode,
DeploymentProperties,
)
from azure.mgmt.storage.models import Sku, StorageAccountCreateParameters # type:ignore
from dataclasses_json import LetterCase, dataclass_json # type: ignore
from marshmallow import fields, validate
from retry import retry # type: ignore
@ -56,11 +57,14 @@ from .common import (
get_environment_context,
get_marketplace_ordering_client,
get_node_context,
get_storage_account_name,
get_storage_client,
wait_operation,
)
# used by azure
AZURE_RG_NAME_KEY = "resource_group_name"
AZURE_SHARED_RG_NAME = "lisa_shared_resource"
VM_SIZE_FALLBACK_PATTERNS = [
# exclude Standard_DS1_v2, because one core is too slow,
@ -196,6 +200,7 @@ class AzureNodeSchema:
class AzureArmParameter:
resource_group_name: str = ""
resource_group_location: str = ""
storage_name: str = ""
location: str = ""
admin_username: str = ""
admin_password: str = ""
@ -778,6 +783,9 @@ class AzurePlatform(Platform):
log.info(f"vm setting: {azure_node_runbook}")
arm_parameters.nodes = nodes_parameters
arm_parameters.storage_name = get_storage_account_name(
self, arm_parameters.location
)
# load template
template = self._load_template()
@ -796,7 +804,7 @@ class AzurePlatform(Platform):
"deployment_name": f"lisa_deploy_"
f"{environment_context.resource_group_name[-50:]}",
"parameters": Deployment(
location=RESOURCE_GROUP_LOCATION, properties=deployment_properties
location=arm_parameters.location, properties=deployment_properties
),
}
@ -830,6 +838,10 @@ class AzurePlatform(Platform):
def _deploy(self, deployment_parameters: Dict[str, Any], log: Logger) -> None:
log.info("deployment is in progress...")
self._check_or_create_storage_account(
location=deployment_parameters["parameters"].location, log=log
)
deployment_operation: Any = None
deployments = self._rm_client.deployments
try:
@ -1058,3 +1070,32 @@ class AzurePlatform(Platform):
publisher=image_info.plan.publisher,
)
return plan
def _check_or_create_storage_account(self, location: str, log: Logger) -> None:
# check and deploy storage account.
# storage account can be deployed inside of arm template, but if the concurrent
# is too big, Azure may not able to delete deployment script on time. so there
# will be error like below
# Creating the deployment 'name' would exceed the quota of '800'.
storage_client = get_storage_client(self)
storage_account_exists = True
account_name = get_storage_account_name(platform=self, location=location)
try:
storage_client.storage_accounts.get_properties(
account_name=account_name,
resource_group_name=AZURE_SHARED_RG_NAME,
)
log.debug(f"found storage account: {account_name}")
except Exception:
storage_account_exists = False
if not storage_account_exists:
log.debug(f"creating storage account: {account_name}")
parameters = StorageAccountCreateParameters(
sku=Sku(name="Standard_LRS"), kind="StorageV2", location=location
)
operation = storage_client.storage_accounts.begin_create(
resource_group_name=AZURE_SHARED_RG_NAME,
account_name=account_name,
parameters=parameters,
)
wait_operation(operation)

19
poetry.lock сгенерированный
Просмотреть файл

@ -154,6 +154,19 @@ azure-common = ">=1.1,<2.0"
azure-mgmt-core = ">=1.2.0,<2.0.0"
msrest = ">=0.5.0"
[[package]]
name = "azure-mgmt-storage"
version = "16.0.0"
description = "Microsoft Azure Storage Management Client Library for Python"
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
azure-common = ">=1.1,<2.0"
azure-mgmt-core = ">=1.2.0,<2.0.0"
msrest = ">=0.5.0"
[[package]]
name = "bcrypt"
version = "3.2.0"
@ -964,7 +977,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[metadata]
lock-version = "1.1"
python-versions = "^3.8"
content-hash = "22e17ec78556ebdada79c492c967e90c6f4b3cec0489a4655f6a33d7066fbba8"
content-hash = "a44f707696fdb38afd23be8723eccd02e6aa375323aafaf2a995b586901a2ac8"
[metadata.files]
adal = [
@ -1018,6 +1031,10 @@ azure-mgmt-resource = [
{file = "azure-mgmt-resource-15.0.0.zip", hash = "sha256:80ecb69aa21152b924edf481e4b26c641f11aa264120bc322a14284811df9c14"},
{file = "azure_mgmt_resource-15.0.0-py2.py3-none-any.whl", hash = "sha256:15bb46ef4b197426ce7ce8080a490c997111f3f3efe9f728cf8dc420982d54a2"},
]
azure-mgmt-storage = [
{file = "azure-mgmt-storage-16.0.0.zip", hash = "sha256:2f9d714d9722b1ef4bac6563676612e6e795c4e90f6f3cd323616fdadb0a99e5"},
{file = "azure_mgmt_storage-16.0.0-py2.py3-none-any.whl", hash = "sha256:a819e421d50c0b58416b551d3e9e9a9cf6029714cf977ffaaee86a37572e7113"},
]
bcrypt = [
{file = "bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6"},
{file = "bcrypt-3.2.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7"},

Просмотреть файл

@ -20,6 +20,7 @@ azure-mgmt-resource = {version = "^15.0.0-beta.1", allow-prereleases = true}
azure-mgmt-compute = {version = "^17.0.0-beta.1", allow-prereleases = true}
azure-mgmt-marketplaceordering = {version = "^0.2.1", allow-prereleases = true}
azure-mgmt-network = {version = "^16.0.0-beta.1", allow-prereleases = true}
azure-mgmt-storage = {version = "^16.0.0", allow-prereleases = true}
asserts = "^0.11.0"
[tool.poetry.dev-dependencies]