port arm template to bicep (#1724)

* port template to bicep

* Update src/deployment/azuredeploy.bicep

Co-authored-by: Teo Voinea <58236992+tevoinea@users.noreply.github.com>

* port template to bicep

* adding type annotation

* apply changes from #1679

Co-authored-by: stas <statis@microsoft.com>
Co-authored-by: Teo Voinea <58236992+tevoinea@users.noreply.github.com>
This commit is contained in:
Stas
2022-03-31 08:18:44 -07:00
committed by GitHub
parent a2e87c6158
commit dc354cffe3
5 changed files with 790 additions and 48 deletions

View File

@ -101,6 +101,31 @@ def gen_guid() -> str:
return str(uuid.uuid4())
def bicep_to_arm(bicep_template: str) -> str:
from azure.cli.core import get_default_cli
az_cli = get_default_cli()
az_cli.invoke(["bicep", "install"])
az_cli.invoke(
[
"bicep",
"build",
"--file",
bicep_template,
"--outfile",
"azuredeploy-bicep.json",
]
)
from importlib import reload
# az_cli hijacks logging, so need to reset it
logging.shutdown()
reload(logging)
global logger
logger = logging.getLogger("deploy")
return "azuredeploy-bicep.json"
class Client:
def __init__(
self,
@ -116,7 +141,7 @@ class Client:
tools: str,
instance_specific: str,
third_party: str,
arm_template: str,
arm_or_bicep_template: str,
workbook_data: str,
create_registration: bool,
migrations: List[str],
@ -129,7 +154,6 @@ class Client:
):
self.subscription_id = subscription_id
self.resource_group = resource_group
self.arm_template = arm_template
self.location = location
self.application_name = application_name
self.owner = owner
@ -158,6 +182,13 @@ class Client:
self.admins = admins
self.allowed_aad_tenants = allowed_aad_tenants
if arm_or_bicep_template:
file_name, file_extension = os.path.splitext(arm_or_bicep_template)
if file_extension == ".bicep":
self.arm_template = bicep_to_arm(arm_or_bicep_template)
else:
self.arm_template = arm_or_bicep_template
machine = platform.machine()
system = platform.system()
@ -211,37 +242,42 @@ class Client:
client = ResourceManagementClient(
credential, subscription_id=self.get_subscription_id()
)
providers = {x.namespace: x for x in client.providers.list()}
providers = {x.namespace.lower(): x for x in client.providers.list()}
unsupported = []
# we cannot validate site/config resources since they require resource group
# to exist. check_region only validates subscription level resources.
resource_group_level_resources = ["sites/config"]
for resource in arm["resources"]:
namespace, name = resource["type"].split("/", 1)
namespace, name = resource["type"].lower().split("/", 1)
# resource types are in the form of a/b/c....
# only the top two are listed as resource types within providers
name = "/".join(name.split("/")[:2])
if namespace not in providers:
unsupported.append("Unsupported provider: %s" % namespace)
continue
provider = providers[namespace]
resource_types = {x.resource_type: x for x in provider.resource_types}
if name not in resource_types:
unsupported.append(
"Unsupported resource type: %s/%s" % (namespace, name)
)
continue
resource_types = {
x.resource_type.lower(): x for x in provider.resource_types
}
if name not in resource_group_level_resources:
if name not in resource_types:
unsupported.append(
"Unsupported resource type: %s/%s" % (namespace, name)
)
continue
resource_type = resource_types[name]
if (
location not in resource_type.locations
and len(resource_type.locations) > 0
):
unsupported.append(
"%s/%s is unsupported in %s" % (namespace, name, self.location)
)
resource_type = resource_types[name]
if (
location not in resource_type.locations
and len(resource_type.locations) > 0
):
unsupported.append(
"%s/%s is unsupported in %s" % (namespace, name, self.location)
)
if unsupported:
print("The following resources required by onefuzz are not supported:")
@ -605,7 +641,7 @@ class Client:
logger.info("assigning the user managed identity role")
assign_instance_app_role(
self.application_name,
self.results["deploy"]["scaleset-identity"]["value"],
self.results["deploy"]["scaleset_identity"]["value"],
self.get_subscription_id(),
OnefuzzAppRole.ManagedNode,
)
@ -646,15 +682,15 @@ class Client:
def apply_migrations(self) -> None:
logger.info("applying database migrations")
name = self.results["deploy"]["func-name"]["value"]
key = self.results["deploy"]["func-key"]["value"]
name = self.results["deploy"]["func_name"]["value"]
key = self.results["deploy"]["func_key"]["value"]
table_service = TableService(account_name=name, account_key=key)
migrate(table_service, self.migrations)
def set_instance_config(self) -> None:
logger.info("setting instance config")
name = self.results["deploy"]["func-name"]["value"]
key = self.results["deploy"]["func-key"]["value"]
name = self.results["deploy"]["func_name"]["value"]
key = self.results["deploy"]["func_key"]["value"]
tenant = UUID(self.results["deploy"]["tenant_id"]["value"])
table_service = TableService(account_name=name, account_key=key)
@ -747,8 +783,8 @@ class Client:
container_name = "base-config"
blob_name = "instance_id"
account_name = self.results["deploy"]["func-name"]["value"]
key = self.results["deploy"]["func-key"]["value"]
account_name = self.results["deploy"]["func_name"]["value"]
key = self.results["deploy"]["func_key"]["value"]
account_url = "https://%s.blob.core.windows.net" % account_name
client = BlobServiceClient(account_url, credential=key)
if container_name not in [x["name"] for x in client.list_containers()]:
@ -773,8 +809,8 @@ class Client:
container_name = "app-insights"
logger.info("adding appinsight log export")
account_name = self.results["deploy"]["func-name"]["value"]
key = self.results["deploy"]["func-key"]["value"]
account_name = self.results["deploy"]["func_name"]["value"]
key = self.results["deploy"]["func_key"]["value"]
account_url = "https://%s.blob.core.windows.net" % account_name
client = BlobServiceClient(account_url, credential=key)
if container_name not in [x["name"] for x in client.list_containers()]:
@ -833,8 +869,8 @@ class Client:
def upload_tools(self) -> None:
logger.info("uploading tools from %s", self.tools)
account_name = self.results["deploy"]["func-name"]["value"]
key = self.results["deploy"]["func-key"]["value"]
account_name = self.results["deploy"]["func_name"]["value"]
key = self.results["deploy"]["func_key"]["value"]
account_url = "https://%s.blob.core.windows.net" % account_name
client = BlobServiceClient(account_url, credential=key)
if "tools" not in [x["name"] for x in client.list_containers()]:
@ -870,8 +906,8 @@ class Client:
def upload_instance_setup(self) -> None:
logger.info("uploading instance-specific-setup from %s", self.instance_specific)
account_name = self.results["deploy"]["func-name"]["value"]
key = self.results["deploy"]["func-key"]["value"]
account_name = self.results["deploy"]["func_name"]["value"]
key = self.results["deploy"]["func_key"]["value"]
account_url = "https://%s.blob.core.windows.net" % account_name
client = BlobServiceClient(account_url, credential=key)
if "instance-specific-setup" not in [
@ -916,8 +952,8 @@ class Client:
def upload_third_party(self) -> None:
logger.info("uploading third-party tools from %s", self.third_party)
account_name = self.results["deploy"]["fuzz-name"]["value"]
key = self.results["deploy"]["fuzz-key"]["value"]
account_name = self.results["deploy"]["fuzz_name"]["value"]
key = self.results["deploy"]["fuzz_key"]["value"]
account_url = "https://%s.blob.core.windows.net" % account_name
client = BlobServiceClient(account_url, credential=key)
@ -1067,9 +1103,9 @@ def main() -> None:
parser.add_argument("owner")
parser.add_argument("nsg_config")
parser.add_argument(
"--arm-template",
"--arm-or-bicep-template",
type=arg_file,
default="azuredeploy.json",
default="azuredeploy.bicep",
help="(default: %(default)s)",
)
parser.add_argument(
@ -1180,7 +1216,7 @@ def main() -> None:
tools=args.tools,
instance_specific=args.instance_specific,
third_party=args.third_party,
arm_template=args.arm_template,
arm_or_bicep_template=args.arm_or_bicep_template,
workbook_data=args.workbook_data,
create_registration=args.create_pool_registration,
migrations=args.apply_migrations,