Skip to content
This repository was archived by the owner on Nov 1, 2023. It is now read-only.

Commit 3ddb756

Browse files
authored
Add linting to deployment tools (#332)
1 parent 9e2a61f commit 3ddb756

File tree

5 files changed

+118
-76
lines changed

5 files changed

+118
-76
lines changed

.github/workflows/ci.yml

+12
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,18 @@ jobs:
270270
with:
271271
name: build-artifacts
272272
path: artifacts
273+
- uses: actions/setup-python@v2
274+
with:
275+
python-version: 3.7
276+
- name: Lint
277+
shell: bash
278+
run: |
279+
set -ex
280+
cd src/deployment
281+
pip install mypy isort black
282+
mypy .
283+
isort --profile black . --check
284+
black . --check
273285
- name: Package Onefuzz
274286
run: |
275287
set -ex

src/deployment/data_migration.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
# Licensed under the MIT License.
55

66
import argparse
7-
from uuid import UUID
87
import json
98
from typing import Callable, Dict, List
9+
from uuid import UUID
1010

11+
from azure.common.client_factory import get_client_from_cli_profile
1112
from azure.cosmosdb.table.tablebatch import TableBatch
1213
from azure.cosmosdb.table.tableservice import TableService
1314
from azure.mgmt.storage import StorageManagementClient
14-
from azure.common.client_factory import get_client_from_cli_profile
1515

1616

1717
def migrate_task_os(table_service: TableService) -> None:
@@ -84,7 +84,7 @@ def migrate(table_service: TableService, migration_names: List[str]) -> None:
8484
print("migration '%s' applied" % name)
8585

8686

87-
def main():
87+
def main() -> None:
8888
formatter = argparse.ArgumentDefaultsHelpFormatter
8989
parser = argparse.ArgumentParser(formatter_class=formatter)
9090
parser.add_argument("resource_group")

src/deployment/deploy.py

+68-61
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
import uuid
1717
import zipfile
1818
from datetime import datetime, timedelta
19-
from typing import Optional
19+
from typing import Dict, List, Optional, Tuple, Union, cast
20+
from uuid import UUID
2021

2122
from azure.common.client_factory import get_client_from_cli_profile
2223
from azure.common.credentials import get_cli_profile
@@ -62,11 +63,11 @@
6263

6364
from data_migration import migrate
6465
from registration import (
66+
OnefuzzAppRole,
6567
add_application_password,
6668
assign_scaleset_role,
6769
authorize_application,
6870
get_application,
69-
OnefuzzAppRole,
7071
register_application,
7172
update_pool_registration,
7273
)
@@ -94,27 +95,28 @@
9495
logger = logging.getLogger("deploy")
9596

9697

97-
def gen_guid():
98+
def gen_guid() -> str:
9899
return str(uuid.uuid4())
99100

100101

101102
class Client:
102103
def __init__(
103104
self,
104-
resource_group,
105-
location,
106-
application_name,
107-
owner,
108-
client_id,
109-
client_secret,
110-
app_zip,
111-
tools,
112-
instance_specific,
113-
third_party,
114-
arm_template,
115-
workbook_data,
116-
create_registration,
117-
migrations,
105+
*,
106+
resource_group: str,
107+
location: str,
108+
application_name: str,
109+
owner: str,
110+
client_id: Optional[str],
111+
client_secret: Optional[str],
112+
app_zip: str,
113+
tools: str,
114+
instance_specific: str,
115+
third_party: str,
116+
arm_template: str,
117+
workbook_data: str,
118+
create_registration: bool,
119+
migrations: List[str],
118120
export_appinsights: bool,
119121
log_service_principal: bool,
120122
upgrade: bool,
@@ -130,11 +132,11 @@ def __init__(
130132
self.third_party = third_party
131133
self.create_registration = create_registration
132134
self.upgrade = upgrade
133-
self.results = {
135+
self.results: Dict = {
134136
"client_id": client_id,
135137
"client_secret": client_secret,
136138
}
137-
self.cli_config = {
139+
self.cli_config: Dict[str, Union[str, UUID]] = {
138140
"client_id": ONEFUZZ_CLI_APP,
139141
"authority": ONEFUZZ_CLI_AUTHORITY,
140142
}
@@ -161,22 +163,22 @@ def __init__(
161163
with open(workbook_data) as f:
162164
self.workbook_data = json.load(f)
163165

164-
def get_subscription_id(self):
166+
def get_subscription_id(self) -> str:
165167
profile = get_cli_profile()
166-
return profile.get_subscription_id()
168+
return cast(str, profile.get_subscription_id())
167169

168-
def get_location_display_name(self):
170+
def get_location_display_name(self) -> str:
169171
location_client = get_client_from_cli_profile(SubscriptionClient)
170172
locations = location_client.subscriptions.list_locations(
171173
self.get_subscription_id()
172174
)
173175
for location in locations:
174176
if location.name == self.location:
175-
return location.display_name
177+
return cast(str, location.display_name)
176178

177179
raise Exception("unknown location: %s", self.location)
178180

179-
def check_region(self):
181+
def check_region(self) -> None:
180182
# At the moment, this only checks are the specified providers available
181183
# in the selected region
182184

@@ -223,7 +225,7 @@ def check_region(self):
223225
print("\n".join(["* " + x for x in unsupported]))
224226
sys.exit(1)
225227

226-
def create_password(self, object_id):
228+
def create_password(self, object_id: UUID) -> Tuple[str, str]:
227229
# Work-around the race condition where the app is created but passwords cannot
228230
# be created yet.
229231
count = 0
@@ -238,7 +240,7 @@ def create_password(self, object_id):
238240
if count > timeout_seconds / wait:
239241
raise Exception("creating password failed, trying again")
240242

241-
def setup_rbac(self):
243+
def setup_rbac(self) -> None:
242244
"""
243245
Setup the client application for the OneFuzz instance.
244246
@@ -281,6 +283,8 @@ def setup_rbac(self):
281283
),
282284
]
283285

286+
app: Optional[Application] = None
287+
284288
if not existing:
285289
logger.info("creating Application registration")
286290
url = "https://%s.azurewebsites.net" % self.application_name
@@ -311,7 +315,7 @@ def setup_rbac(self):
311315
)
312316
client.service_principals.create(service_principal_params)
313317
else:
314-
app: Application = existing[0]
318+
app = existing[0]
315319
existing_role_values = [app_role.value for app_role in app.app_roles]
316320
has_missing_roles = any(
317321
[role.value not in existing_role_values for role in app_roles]
@@ -365,7 +369,7 @@ def setup_rbac(self):
365369
else:
366370
logger.debug("client_id: %s client_secret: %s", app.app_id, password)
367371

368-
def deploy_template(self):
372+
def deploy_template(self) -> None:
369373
logger.info("deploying arm template: %s", self.arm_template)
370374

371375
with open(self.arm_template, "r") as template_handle:
@@ -403,7 +407,7 @@ def deploy_template(self):
403407
sys.exit(1)
404408
self.results["deploy"] = result.properties.outputs
405409

406-
def assign_scaleset_identity_role(self):
410+
def assign_scaleset_identity_role(self) -> None:
407411
if self.upgrade:
408412
logger.info("Upgrading: skipping assignment of the managed identity role")
409413
return
@@ -413,14 +417,14 @@ def assign_scaleset_identity_role(self):
413417
self.results["deploy"]["scaleset-identity"]["value"],
414418
)
415419

416-
def apply_migrations(self):
420+
def apply_migrations(self) -> None:
417421
self.results["deploy"]["func-storage"]["value"]
418422
name = self.results["deploy"]["func-name"]["value"]
419423
key = self.results["deploy"]["func-key"]["value"]
420424
table_service = TableService(account_name=name, account_key=key)
421425
migrate(table_service, self.migrations)
422426

423-
def create_queues(self):
427+
def create_queues(self) -> None:
424428
logger.info("creating eventgrid destination queue")
425429

426430
name = self.results["deploy"]["func-name"]["value"]
@@ -443,7 +447,7 @@ def create_queues(self):
443447
except ResourceExistsError:
444448
pass
445449

446-
def create_eventgrid(self):
450+
def create_eventgrid(self) -> None:
447451
logger.info("creating eventgrid subscription")
448452
src_resource_id = self.results["deploy"]["fuzz-storage"]["value"]
449453
dst_resource_id = self.results["deploy"]["func-storage"]["value"]
@@ -474,7 +478,7 @@ def create_eventgrid(self):
474478
% json.dumps(result.as_dict(), indent=4, sort_keys=True),
475479
)
476480

477-
def add_instance_id(self):
481+
def add_instance_id(self) -> None:
478482
logger.info("setting instance_id log export")
479483

480484
container_name = "base-config"
@@ -497,7 +501,7 @@ def add_instance_id(self):
497501

498502
logger.info("instance_id: %s", instance_id)
499503

500-
def add_log_export(self):
504+
def add_log_export(self) -> None:
501505
if not self.export_appinsights:
502506
logger.info("not exporting appinsights")
503507
return
@@ -561,7 +565,7 @@ def add_log_export(self):
561565
self.resource_group, self.application_name, req
562566
)
563567

564-
def upload_tools(self):
568+
def upload_tools(self) -> None:
565569
logger.info("uploading tools from %s", self.tools)
566570
account_name = self.results["deploy"]["func-name"]["value"]
567571
key = self.results["deploy"]["func-key"]["value"]
@@ -587,7 +591,7 @@ def upload_tools(self):
587591
[self.azcopy, "sync", self.tools, url, "--delete-destination", "true"]
588592
)
589593

590-
def upload_instance_setup(self):
594+
def upload_instance_setup(self) -> None:
591595
logger.info("uploading instance-specific-setup from %s", self.instance_specific)
592596
account_name = self.results["deploy"]["func-name"]["value"]
593597
key = self.results["deploy"]["func-key"]["value"]
@@ -622,7 +626,7 @@ def upload_instance_setup(self):
622626
]
623627
)
624628

625-
def upload_third_party(self):
629+
def upload_third_party(self) -> None:
626630
logger.info("uploading third-party tools from %s", self.third_party)
627631
account_name = self.results["deploy"]["fuzz-name"]["value"]
628632
key = self.results["deploy"]["fuzz-key"]["value"]
@@ -654,18 +658,21 @@ def upload_third_party(self):
654658
[self.azcopy, "sync", path, url, "--delete-destination", "true"]
655659
)
656660

657-
def deploy_app(self):
661+
def deploy_app(self) -> None:
658662
logger.info("deploying function app %s", self.app_zip)
659663
with tempfile.TemporaryDirectory() as tmpdirname:
660664
with zipfile.ZipFile(self.app_zip, "r") as zip_ref:
665+
func = shutil.which("func")
666+
assert func is not None
667+
661668
zip_ref.extractall(tmpdirname)
662669
error: Optional[subprocess.CalledProcessError] = None
663670
max_tries = 5
664671
for i in range(max_tries):
665672
try:
666673
subprocess.check_output(
667674
[
668-
shutil.which("func"),
675+
func,
669676
"azure",
670677
"functionapp",
671678
"publish",
@@ -688,12 +695,12 @@ def deploy_app(self):
688695
if error is not None:
689696
raise error
690697

691-
def update_registration(self):
698+
def update_registration(self) -> None:
692699
if not self.create_registration:
693700
return
694701
update_pool_registration(self.application_name)
695702

696-
def done(self):
703+
def done(self) -> None:
697704
logger.info(TELEMETRY_NOTICE)
698705
client_secret_arg = (
699706
("--client_secret %s" % self.cli_config["client_secret"])
@@ -710,19 +717,19 @@ def done(self):
710717
)
711718

712719

713-
def arg_dir(arg):
720+
def arg_dir(arg: str) -> str:
714721
if not os.path.isdir(arg):
715722
raise argparse.ArgumentTypeError("not a directory: %s" % arg)
716723
return arg
717724

718725

719-
def arg_file(arg):
726+
def arg_file(arg: str) -> str:
720727
if not os.path.isfile(arg):
721728
raise argparse.ArgumentTypeError("not a file: %s" % arg)
722729
return arg
723730

724731

725-
def main():
732+
def main() -> None:
726733
states = [
727734
("check_region", Client.check_region),
728735
("rbac", Client.setup_rbac),
@@ -826,23 +833,23 @@ def main():
826833
sys.exit(1)
827834

828835
client = Client(
829-
args.resource_group,
830-
args.location,
831-
args.application_name,
832-
args.owner,
833-
args.client_id,
834-
args.client_secret,
835-
args.app_zip,
836-
args.tools,
837-
args.instance_specific,
838-
args.third_party,
839-
args.arm_template,
840-
args.workbook_data,
841-
args.create_pool_registration,
842-
args.apply_migrations,
843-
args.export_appinsights,
844-
args.log_service_principal,
845-
args.upgrade,
836+
resource_group=args.resource_group,
837+
location=args.location,
838+
application_name=args.application_name,
839+
owner=args.owner,
840+
client_id=args.client_id,
841+
client_secret=args.client_secret,
842+
app_zip=args.app_zip,
843+
tools=args.tools,
844+
instance_specific=args.instance_specific,
845+
third_party=args.third_party,
846+
arm_template=args.arm_template,
847+
workbook_data=args.workbook_data,
848+
create_registration=args.create_pool_registration,
849+
migrations=args.apply_migrations,
850+
export_appinsights=args.export_appinsights,
851+
log_service_principal=args.log_service_principal,
852+
upgrade=args.upgrade,
846853
)
847854
if args.verbose:
848855
level = logging.DEBUG

0 commit comments

Comments
 (0)