16
16
import uuid
17
17
import zipfile
18
18
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
20
21
21
22
from azure .common .client_factory import get_client_from_cli_profile
22
23
from azure .common .credentials import get_cli_profile
62
63
63
64
from data_migration import migrate
64
65
from registration import (
66
+ OnefuzzAppRole ,
65
67
add_application_password ,
66
68
assign_scaleset_role ,
67
69
authorize_application ,
68
70
get_application ,
69
- OnefuzzAppRole ,
70
71
register_application ,
71
72
update_pool_registration ,
72
73
)
94
95
logger = logging .getLogger ("deploy" )
95
96
96
97
97
- def gen_guid ():
98
+ def gen_guid () -> str :
98
99
return str (uuid .uuid4 ())
99
100
100
101
101
102
class Client :
102
103
def __init__ (
103
104
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 ],
118
120
export_appinsights : bool ,
119
121
log_service_principal : bool ,
120
122
upgrade : bool ,
@@ -130,11 +132,11 @@ def __init__(
130
132
self .third_party = third_party
131
133
self .create_registration = create_registration
132
134
self .upgrade = upgrade
133
- self .results = {
135
+ self .results : Dict = {
134
136
"client_id" : client_id ,
135
137
"client_secret" : client_secret ,
136
138
}
137
- self .cli_config = {
139
+ self .cli_config : Dict [ str , Union [ str , UUID ]] = {
138
140
"client_id" : ONEFUZZ_CLI_APP ,
139
141
"authority" : ONEFUZZ_CLI_AUTHORITY ,
140
142
}
@@ -161,22 +163,22 @@ def __init__(
161
163
with open (workbook_data ) as f :
162
164
self .workbook_data = json .load (f )
163
165
164
- def get_subscription_id (self ):
166
+ def get_subscription_id (self ) -> str :
165
167
profile = get_cli_profile ()
166
- return profile .get_subscription_id ()
168
+ return cast ( str , profile .get_subscription_id () )
167
169
168
- def get_location_display_name (self ):
170
+ def get_location_display_name (self ) -> str :
169
171
location_client = get_client_from_cli_profile (SubscriptionClient )
170
172
locations = location_client .subscriptions .list_locations (
171
173
self .get_subscription_id ()
172
174
)
173
175
for location in locations :
174
176
if location .name == self .location :
175
- return location .display_name
177
+ return cast ( str , location .display_name )
176
178
177
179
raise Exception ("unknown location: %s" , self .location )
178
180
179
- def check_region (self ):
181
+ def check_region (self ) -> None :
180
182
# At the moment, this only checks are the specified providers available
181
183
# in the selected region
182
184
@@ -223,7 +225,7 @@ def check_region(self):
223
225
print ("\n " .join (["* " + x for x in unsupported ]))
224
226
sys .exit (1 )
225
227
226
- def create_password (self , object_id ) :
228
+ def create_password (self , object_id : UUID ) -> Tuple [ str , str ] :
227
229
# Work-around the race condition where the app is created but passwords cannot
228
230
# be created yet.
229
231
count = 0
@@ -238,7 +240,7 @@ def create_password(self, object_id):
238
240
if count > timeout_seconds / wait :
239
241
raise Exception ("creating password failed, trying again" )
240
242
241
- def setup_rbac (self ):
243
+ def setup_rbac (self ) -> None :
242
244
"""
243
245
Setup the client application for the OneFuzz instance.
244
246
@@ -281,6 +283,8 @@ def setup_rbac(self):
281
283
),
282
284
]
283
285
286
+ app : Optional [Application ] = None
287
+
284
288
if not existing :
285
289
logger .info ("creating Application registration" )
286
290
url = "https://%s.azurewebsites.net" % self .application_name
@@ -311,7 +315,7 @@ def setup_rbac(self):
311
315
)
312
316
client .service_principals .create (service_principal_params )
313
317
else :
314
- app : Application = existing [0 ]
318
+ app = existing [0 ]
315
319
existing_role_values = [app_role .value for app_role in app .app_roles ]
316
320
has_missing_roles = any (
317
321
[role .value not in existing_role_values for role in app_roles ]
@@ -365,7 +369,7 @@ def setup_rbac(self):
365
369
else :
366
370
logger .debug ("client_id: %s client_secret: %s" , app .app_id , password )
367
371
368
- def deploy_template (self ):
372
+ def deploy_template (self ) -> None :
369
373
logger .info ("deploying arm template: %s" , self .arm_template )
370
374
371
375
with open (self .arm_template , "r" ) as template_handle :
@@ -403,7 +407,7 @@ def deploy_template(self):
403
407
sys .exit (1 )
404
408
self .results ["deploy" ] = result .properties .outputs
405
409
406
- def assign_scaleset_identity_role (self ):
410
+ def assign_scaleset_identity_role (self ) -> None :
407
411
if self .upgrade :
408
412
logger .info ("Upgrading: skipping assignment of the managed identity role" )
409
413
return
@@ -413,14 +417,14 @@ def assign_scaleset_identity_role(self):
413
417
self .results ["deploy" ]["scaleset-identity" ]["value" ],
414
418
)
415
419
416
- def apply_migrations (self ):
420
+ def apply_migrations (self ) -> None :
417
421
self .results ["deploy" ]["func-storage" ]["value" ]
418
422
name = self .results ["deploy" ]["func-name" ]["value" ]
419
423
key = self .results ["deploy" ]["func-key" ]["value" ]
420
424
table_service = TableService (account_name = name , account_key = key )
421
425
migrate (table_service , self .migrations )
422
426
423
- def create_queues (self ):
427
+ def create_queues (self ) -> None :
424
428
logger .info ("creating eventgrid destination queue" )
425
429
426
430
name = self .results ["deploy" ]["func-name" ]["value" ]
@@ -443,7 +447,7 @@ def create_queues(self):
443
447
except ResourceExistsError :
444
448
pass
445
449
446
- def create_eventgrid (self ):
450
+ def create_eventgrid (self ) -> None :
447
451
logger .info ("creating eventgrid subscription" )
448
452
src_resource_id = self .results ["deploy" ]["fuzz-storage" ]["value" ]
449
453
dst_resource_id = self .results ["deploy" ]["func-storage" ]["value" ]
@@ -474,7 +478,7 @@ def create_eventgrid(self):
474
478
% json .dumps (result .as_dict (), indent = 4 , sort_keys = True ),
475
479
)
476
480
477
- def add_instance_id (self ):
481
+ def add_instance_id (self ) -> None :
478
482
logger .info ("setting instance_id log export" )
479
483
480
484
container_name = "base-config"
@@ -497,7 +501,7 @@ def add_instance_id(self):
497
501
498
502
logger .info ("instance_id: %s" , instance_id )
499
503
500
- def add_log_export (self ):
504
+ def add_log_export (self ) -> None :
501
505
if not self .export_appinsights :
502
506
logger .info ("not exporting appinsights" )
503
507
return
@@ -561,7 +565,7 @@ def add_log_export(self):
561
565
self .resource_group , self .application_name , req
562
566
)
563
567
564
- def upload_tools (self ):
568
+ def upload_tools (self ) -> None :
565
569
logger .info ("uploading tools from %s" , self .tools )
566
570
account_name = self .results ["deploy" ]["func-name" ]["value" ]
567
571
key = self .results ["deploy" ]["func-key" ]["value" ]
@@ -587,7 +591,7 @@ def upload_tools(self):
587
591
[self .azcopy , "sync" , self .tools , url , "--delete-destination" , "true" ]
588
592
)
589
593
590
- def upload_instance_setup (self ):
594
+ def upload_instance_setup (self ) -> None :
591
595
logger .info ("uploading instance-specific-setup from %s" , self .instance_specific )
592
596
account_name = self .results ["deploy" ]["func-name" ]["value" ]
593
597
key = self .results ["deploy" ]["func-key" ]["value" ]
@@ -622,7 +626,7 @@ def upload_instance_setup(self):
622
626
]
623
627
)
624
628
625
- def upload_third_party (self ):
629
+ def upload_third_party (self ) -> None :
626
630
logger .info ("uploading third-party tools from %s" , self .third_party )
627
631
account_name = self .results ["deploy" ]["fuzz-name" ]["value" ]
628
632
key = self .results ["deploy" ]["fuzz-key" ]["value" ]
@@ -654,18 +658,21 @@ def upload_third_party(self):
654
658
[self .azcopy , "sync" , path , url , "--delete-destination" , "true" ]
655
659
)
656
660
657
- def deploy_app (self ):
661
+ def deploy_app (self ) -> None :
658
662
logger .info ("deploying function app %s" , self .app_zip )
659
663
with tempfile .TemporaryDirectory () as tmpdirname :
660
664
with zipfile .ZipFile (self .app_zip , "r" ) as zip_ref :
665
+ func = shutil .which ("func" )
666
+ assert func is not None
667
+
661
668
zip_ref .extractall (tmpdirname )
662
669
error : Optional [subprocess .CalledProcessError ] = None
663
670
max_tries = 5
664
671
for i in range (max_tries ):
665
672
try :
666
673
subprocess .check_output (
667
674
[
668
- shutil . which ( " func" ) ,
675
+ func ,
669
676
"azure" ,
670
677
"functionapp" ,
671
678
"publish" ,
@@ -688,12 +695,12 @@ def deploy_app(self):
688
695
if error is not None :
689
696
raise error
690
697
691
- def update_registration (self ):
698
+ def update_registration (self ) -> None :
692
699
if not self .create_registration :
693
700
return
694
701
update_pool_registration (self .application_name )
695
702
696
- def done (self ):
703
+ def done (self ) -> None :
697
704
logger .info (TELEMETRY_NOTICE )
698
705
client_secret_arg = (
699
706
("--client_secret %s" % self .cli_config ["client_secret" ])
@@ -710,19 +717,19 @@ def done(self):
710
717
)
711
718
712
719
713
- def arg_dir (arg ) :
720
+ def arg_dir (arg : str ) -> str :
714
721
if not os .path .isdir (arg ):
715
722
raise argparse .ArgumentTypeError ("not a directory: %s" % arg )
716
723
return arg
717
724
718
725
719
- def arg_file (arg ) :
726
+ def arg_file (arg : str ) -> str :
720
727
if not os .path .isfile (arg ):
721
728
raise argparse .ArgumentTypeError ("not a file: %s" % arg )
722
729
return arg
723
730
724
731
725
- def main ():
732
+ def main () -> None :
726
733
states = [
727
734
("check_region" , Client .check_region ),
728
735
("rbac" , Client .setup_rbac ),
@@ -826,23 +833,23 @@ def main():
826
833
sys .exit (1 )
827
834
828
835
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 ,
846
853
)
847
854
if args .verbose :
848
855
level = logging .DEBUG
0 commit comments