1# -------------------------------------------------------------------------------------------- 2# Copyright (c) Microsoft Corporation. All rights reserved. 3# Licensed under the MIT License. See License.txt in the project root for license information. 4# -------------------------------------------------------------------------------------------- 5 6# pylint: disable=too-many-lines 7 8import argparse 9import base64 10import socket 11import os 12 13from knack.util import CLIError 14from knack.log import get_logger 15 16from azure.cli.core.commands.validators import \ 17 (validate_tags, get_default_location_from_resource_group) 18from azure.cli.core.commands.template_create import get_folded_parameter_validator 19from azure.cli.core.commands.client_factory import get_subscription_id, get_mgmt_service_client 20from azure.cli.core.commands.validators import validate_parameter_set 21from azure.cli.core.profiles import ResourceType 22from azure.cli.core.azclierror import RequiredArgumentMissingError 23 24logger = get_logger(__name__) 25 26 27def _resolve_api_version(rcf, resource_provider_namespace, parent_resource_path, resource_type): 28 """ 29 This is copied from src/azure-cli/azure/cli/command_modules/resource/custom.py in Azure/azure-cli 30 """ 31 from azure.cli.core.parser import IncorrectUsageError 32 33 provider = rcf.providers.get(resource_provider_namespace) 34 35 # If available, we will use parent resource's api-version 36 resource_type_str = (parent_resource_path.split('/')[0] if parent_resource_path else resource_type) 37 38 rt = [t for t in provider.resource_types if t.resource_type.lower() == resource_type_str.lower()] 39 if not rt: 40 raise IncorrectUsageError('Resource type {} not found.'.format(resource_type_str)) 41 if len(rt) == 1 and rt[0].api_versions: 42 npv = [v for v in rt[0].api_versions if 'preview' not in v.lower()] 43 return npv[0] if npv else rt[0].api_versions[0] 44 raise IncorrectUsageError( 45 'API version is required and could not be resolved for resource {}'.format(resource_type)) 46 47 48def get_asg_validator(loader, dest): 49 from msrestazure.tools import is_valid_resource_id, resource_id 50 51 ApplicationSecurityGroup = loader.get_models('ApplicationSecurityGroup') 52 53 def _validate_asg_name_or_id(cmd, namespace): 54 subscription_id = get_subscription_id(cmd.cli_ctx) 55 resource_group = namespace.resource_group_name 56 names_or_ids = getattr(namespace, dest) 57 ids = [] 58 59 if names_or_ids == [""] or not names_or_ids: 60 return 61 62 for val in names_or_ids: 63 if not is_valid_resource_id(val): 64 val = resource_id( 65 subscription=subscription_id, 66 resource_group=resource_group, 67 namespace='Microsoft.Network', type='applicationSecurityGroups', 68 name=val 69 ) 70 ids.append(ApplicationSecurityGroup(id=val)) 71 setattr(namespace, dest, ids) 72 73 return _validate_asg_name_or_id 74 75 76def get_subscription_list_validator(dest, model_class): 77 def _validate_subscription_list(cmd, namespace): 78 val = getattr(namespace, dest, None) 79 if not val: 80 return 81 model = cmd.get_models(model_class) 82 setattr(namespace, dest, model(subscriptions=val)) 83 84 return _validate_subscription_list 85 86 87def get_vnet_validator(dest): 88 from msrestazure.tools import is_valid_resource_id, resource_id 89 90 def _validate_vnet_name_or_id(cmd, namespace): 91 SubResource = cmd.get_models('SubResource') 92 subscription_id = get_subscription_id(cmd.cli_ctx) 93 94 resource_group = namespace.resource_group_name 95 names_or_ids = getattr(namespace, dest) 96 ids = [] 97 98 if names_or_ids == [''] or not names_or_ids: 99 return 100 101 for val in names_or_ids: 102 if not is_valid_resource_id(val): 103 val = resource_id( 104 subscription=subscription_id, 105 resource_group=resource_group, 106 namespace='Microsoft.Network', type='virtualNetworks', 107 name=val 108 ) 109 ids.append(SubResource(id=val)) 110 setattr(namespace, dest, ids) 111 112 return _validate_vnet_name_or_id 113 114 115def _validate_vpn_gateway_generation(namespace): 116 if namespace.gateway_type != 'Vpn' and namespace.vpn_gateway_generation: 117 raise CLIError('vpn_gateway_generation should not be provided if gateway_type is not Vpn.') 118 119 120def validate_vpn_connection_name_or_id(cmd, namespace): 121 if namespace.vpn_connection_ids: 122 from msrestazure.tools import is_valid_resource_id, resource_id 123 for index, vpn_connection_id in enumerate(namespace.vpn_connection_ids): 124 if not is_valid_resource_id(vpn_connection_id): 125 namespace.vpn_connection_ids[index] = resource_id( 126 subscription=get_subscription_id(cmd.cli_ctx), 127 resource_group=namespace.resource_group_name, 128 namespace='Microsoft.Network', 129 type='connections', 130 name=vpn_connection_id 131 ) 132 133 134def validate_ddos_name_or_id(cmd, namespace): 135 if namespace.ddos_protection_plan: 136 from msrestazure.tools import is_valid_resource_id, resource_id 137 if not is_valid_resource_id(namespace.ddos_protection_plan): 138 namespace.ddos_protection_plan = resource_id( 139 subscription=get_subscription_id(cmd.cli_ctx), 140 resource_group=namespace.resource_group_name, 141 namespace='Microsoft.Network', type='ddosProtectionPlans', 142 name=namespace.ddos_protection_plan 143 ) 144 145 146# pylint: disable=inconsistent-return-statements 147def dns_zone_name_type(value): 148 if value: 149 return value[:-1] if value[-1] == '.' else value 150 151 152def _generate_ag_subproperty_id(cli_ctx, namespace, child_type, child_name, subscription=None): 153 from msrestazure.tools import resource_id 154 return resource_id( 155 subscription=subscription or get_subscription_id(cli_ctx), 156 resource_group=namespace.resource_group_name, 157 namespace='Microsoft.Network', 158 type='applicationGateways', 159 name=namespace.application_gateway_name, 160 child_type_1=child_type, 161 child_name_1=child_name) 162 163 164def _generate_lb_subproperty_id(cli_ctx, namespace, child_type, child_name, subscription=None): 165 from msrestazure.tools import resource_id 166 return resource_id( 167 subscription=subscription or get_subscription_id(cli_ctx), 168 resource_group=namespace.resource_group_name, 169 namespace='Microsoft.Network', 170 type='loadBalancers', 171 name=namespace.load_balancer_name, 172 child_type_1=child_type, 173 child_name_1=child_name) 174 175 176def _generate_lb_id_list_from_names_or_ids(cli_ctx, namespace, prop, child_type): 177 from msrestazure.tools import is_valid_resource_id 178 raw = getattr(namespace, prop) 179 if not raw: 180 return 181 raw = raw if isinstance(raw, list) else [raw] 182 result = [] 183 for item in raw: 184 if is_valid_resource_id(item): 185 result.append({'id': item}) 186 else: 187 if not namespace.load_balancer_name: 188 raise CLIError('Unable to process {}. Please supply a well-formed ID or ' 189 '--lb-name.'.format(item)) 190 result.append({'id': _generate_lb_subproperty_id( 191 cli_ctx, namespace, child_type, item)}) 192 setattr(namespace, prop, result) 193 194 195def validate_address_pool_id_list(cmd, namespace): 196 _generate_lb_id_list_from_names_or_ids( 197 cmd.cli_ctx, namespace, 'load_balancer_backend_address_pool_ids', 'backendAddressPools') 198 199 200def validate_address_pool_name_or_id(cmd, namespace): 201 from msrestazure.tools import is_valid_resource_id, parse_resource_id 202 address_pool = namespace.backend_address_pool 203 lb_name = namespace.load_balancer_name 204 gateway_name = namespace.application_gateway_name 205 206 usage_error = CLIError('usage error: --address-pool ID | --lb-name NAME --address-pool NAME ' 207 '| --gateway-name NAME --address-pool NAME') 208 209 if is_valid_resource_id(address_pool): 210 if lb_name or gateway_name: 211 raise usage_error 212 parts = parse_resource_id(address_pool) 213 if parts['type'] == 'loadBalancers': 214 namespace.load_balancer_name = parts['name'] 215 elif parts['type'] == 'applicationGateways': 216 namespace.application_gateway_name = parts['name'] 217 else: 218 raise usage_error 219 else: 220 if bool(lb_name) == bool(gateway_name): 221 raise usage_error 222 223 if lb_name: 224 namespace.backend_address_pool = _generate_lb_subproperty_id( 225 cmd.cli_ctx, namespace, 'backendAddressPools', address_pool) 226 elif gateway_name: 227 namespace.backend_address_pool = _generate_ag_subproperty_id( 228 cmd.cli_ctx, namespace, 'backendAddressPools', address_pool) 229 230 231def validate_address_prefixes(namespace): 232 if namespace.subnet_type != 'new': 233 validate_parameter_set(namespace, 234 required=[], 235 forbidden=['subnet_address_prefix', 'vnet_address_prefix'], 236 description='existing subnet') 237 238 239def read_base_64_file(filename): 240 with open(filename, 'rb') as f: 241 contents = f.read() 242 base64_data = base64.b64encode(contents) 243 try: 244 return base64_data.decode('utf-8') 245 except UnicodeDecodeError: 246 return str(base64_data) 247 248 249def validate_cert(namespace): 250 if namespace.cert_data: 251 namespace.cert_data = read_base_64_file(namespace.cert_data) 252 253 254def validate_trusted_client_cert(namespace): 255 if namespace.client_cert_data is None or namespace.client_cert_name is None: 256 raise RequiredArgumentMissingError('To use this cmd, you must specify both name and data') 257 namespace.client_cert_data = read_base_64_file(namespace.client_cert_data) 258 259 260def validate_ssl_cert(namespace): 261 params = [namespace.cert_data, namespace.cert_password] 262 if all(not x for x in params) and not namespace.key_vault_secret_id: 263 # no cert supplied -- use HTTP 264 if not namespace.frontend_port: 265 namespace.frontend_port = 80 266 else: 267 if namespace.key_vault_secret_id: 268 return 269 # cert supplied -- use HTTPS 270 if not namespace.cert_data: 271 raise CLIError( 272 None, 'To use SSL certificate, you must specify both the filename') 273 274 # extract the certificate data from the provided file 275 namespace.cert_data = read_base_64_file(namespace.cert_data) 276 277 try: 278 # change default to frontend port 443 for https 279 if not namespace.frontend_port: 280 namespace.frontend_port = 443 281 except AttributeError: 282 # app-gateway ssl-cert create does not have these fields and that is okay 283 pass 284 285 286def validate_delegations(cmd, namespace): 287 if namespace.delegations: 288 Delegation = cmd.get_models('Delegation') 289 delegations = [] 290 for i, item in enumerate(namespace.delegations): 291 if '/' not in item and len(item.split('.')) == 3: 292 # convert names to serviceNames 293 _, service, resource_type = item.split('.') 294 item = 'Microsoft.{}/{}'.format(service, resource_type) 295 delegations.append(Delegation(name=str(i), service_name=item)) 296 namespace.delegations = delegations 297 298 299def validate_dns_record_type(namespace): 300 tokens = namespace.command.split(' ') 301 types = ['a', 'aaaa', 'caa', 'cname', 'mx', 'ns', 'ptr', 'soa', 'srv', 'txt'] 302 for token in tokens: 303 if token in types: 304 if hasattr(namespace, 'record_type'): 305 namespace.record_type = token 306 else: 307 namespace.record_set_type = token 308 return 309 310 311def validate_user_assigned_identity(cmd, namespace): 312 from msrestazure.tools import is_valid_resource_id, resource_id 313 314 if namespace.user_assigned_identity and not is_valid_resource_id(namespace.user_assigned_identity): 315 namespace.user_assigned_identity = resource_id( 316 subscription=get_subscription_id(cmd.cli_ctx), 317 resource_group=namespace.resource_group_name, 318 namespace='Microsoft.ManagedIdentity', 319 type='userAssignedIdentities', 320 name=namespace.user_assigned_identity 321 ) 322 323 324def validate_express_route_peering(cmd, namespace): 325 from msrestazure.tools import is_valid_resource_id, resource_id 326 circuit = namespace.circuit_name 327 peering = namespace.peering 328 329 if not circuit and not peering: 330 return 331 332 usage_error = CLIError('usage error: --peering ID | --peering NAME --circuit-name CIRCUIT') 333 if not is_valid_resource_id(peering): 334 namespace.peering = resource_id( 335 subscription=get_subscription_id(cmd.cli_ctx), 336 resource_group=namespace.resource_group_name, 337 namespace='Microsoft.Network', 338 type='expressRouteCircuits', 339 name=circuit, 340 child_type_1='peerings', 341 child_name_1=peering 342 ) 343 elif circuit: 344 raise usage_error 345 346 347def validate_express_route_port(cmd, namespace): 348 from msrestazure.tools import is_valid_resource_id, resource_id 349 if namespace.express_route_port and not is_valid_resource_id(namespace.express_route_port): 350 namespace.express_route_port = resource_id( 351 subscription=get_subscription_id(cmd.cli_ctx), 352 resource_group=namespace.resource_group_name, 353 namespace='Microsoft.Network', 354 type='expressRoutePorts', 355 name=namespace.express_route_port 356 ) 357 358 359def validate_virtul_network_gateway(cmd, namespace): 360 from msrestazure.tools import is_valid_resource_id, resource_id 361 if namespace.hosted_gateway and not is_valid_resource_id(namespace.hosted_gateway): 362 namespace.hosted_gateway = resource_id( 363 subscription=get_subscription_id(cmd.cli_ctx), 364 resource_group=namespace.resource_group_name, 365 namespace='Microsoft.Network', 366 type='virtualNetworkGateways', 367 name=namespace.hosted_gateway 368 ) 369 370 371def validate_virtual_hub(cmd, namespace): 372 from msrestazure.tools import is_valid_resource_id, resource_id 373 if namespace.virtual_hub and not is_valid_resource_id(namespace.virtual_hub): 374 namespace.virtual_hub = resource_id( 375 subscription=get_subscription_id(cmd.cli_ctx), 376 resource_group=namespace.resource_group_name, 377 namespace='Microsoft.Network', 378 type='virtualHubs', 379 name=namespace.virtual_hub 380 ) 381 382 383def validate_waf_policy(cmd, namespace): 384 from msrestazure.tools import is_valid_resource_id, resource_id 385 if namespace.firewall_policy and not is_valid_resource_id(namespace.firewall_policy): 386 namespace.firewall_policy = resource_id( 387 subscription=get_subscription_id(cmd.cli_ctx), 388 resource_group=namespace.resource_group_name, 389 namespace='Microsoft.Network', 390 type='ApplicationGatewayWebApplicationFirewallPolicies', 391 name=namespace.firewall_policy 392 ) 393 394 395def bandwidth_validator_factory(mbps=True): 396 def validator(namespace): 397 return validate_circuit_bandwidth(namespace, mbps=mbps) 398 399 return validator 400 401 402def validate_circuit_bandwidth(namespace, mbps=True): 403 # use gbps if mbps is False 404 unit = 'mbps' if mbps else 'gbps' 405 bandwidth = None 406 bandwidth = getattr(namespace, 'bandwidth_in_{}'.format(unit), None) 407 if bandwidth is None: 408 return 409 410 if len(bandwidth) == 1: 411 bandwidth_comps = bandwidth[0].split(' ') 412 else: 413 bandwidth_comps = bandwidth 414 415 usage_error = CLIError('usage error: --bandwidth INT {Mbps,Gbps}') 416 if len(bandwidth_comps) == 1: 417 logger.warning('interpretting --bandwidth as %s. Consider being explicit: Mbps, Gbps', unit) 418 setattr(namespace, 'bandwidth_in_{}'.format(unit), float(bandwidth_comps[0])) 419 return 420 if len(bandwidth_comps) > 2: 421 raise usage_error 422 423 if float(bandwidth_comps[0]) and bandwidth_comps[1].lower() in ['mbps', 'gbps']: 424 input_unit = bandwidth_comps[1].lower() 425 if input_unit == unit: 426 converted_bandwidth = float(bandwidth_comps[0]) 427 elif input_unit == 'gbps': 428 converted_bandwidth = float(bandwidth_comps[0]) * 1000 429 else: 430 converted_bandwidth = float(bandwidth_comps[0]) / 1000 431 setattr(namespace, 'bandwidth_in_{}'.format(unit), converted_bandwidth) 432 else: 433 raise usage_error 434 435 436def validate_er_peer_circuit(cmd, namespace): 437 from msrestazure.tools import resource_id, is_valid_resource_id 438 439 if not is_valid_resource_id(namespace.peer_circuit): 440 peer_id = resource_id( 441 subscription=get_subscription_id(cmd.cli_ctx), 442 resource_group=namespace.resource_group_name, 443 namespace='Microsoft.Network', 444 type='expressRouteCircuits', 445 name=namespace.peer_circuit, 446 child_type_1='peerings', 447 child_name_1=namespace.peering_name) 448 else: 449 peer_id = namespace.peer_circuit 450 451 # if the circuit ID is provided, we need to append /peerings/{peering_name} 452 if namespace.peering_name not in peer_id: 453 peer_id = '{}/peerings/{}'.format(peer_id, namespace.peering_name) 454 455 namespace.peer_circuit = peer_id 456 457 458def validate_inbound_nat_rule_id_list(cmd, namespace): 459 _generate_lb_id_list_from_names_or_ids( 460 cmd.cli_ctx, namespace, 'load_balancer_inbound_nat_rule_ids', 'inboundNatRules') 461 462 463def validate_inbound_nat_rule_name_or_id(cmd, namespace): 464 from msrestazure.tools import is_valid_resource_id 465 rule_name = namespace.inbound_nat_rule 466 lb_name = namespace.load_balancer_name 467 468 if is_valid_resource_id(rule_name): 469 if lb_name: 470 raise CLIError('Please omit --lb-name when specifying an inbound NAT rule ID.') 471 else: 472 if not lb_name: 473 raise CLIError('Please specify --lb-name when specifying an inbound NAT rule name.') 474 namespace.inbound_nat_rule = _generate_lb_subproperty_id( 475 cmd.cli_ctx, namespace, 'inboundNatRules', rule_name) 476 477 478def validate_ip_tags(cmd, namespace): 479 ''' Extracts multiple space-separated tags in TYPE=VALUE format ''' 480 IpTag = cmd.get_models('IpTag') 481 if namespace.ip_tags and IpTag: 482 ip_tags = [] 483 for item in namespace.ip_tags: 484 tag_type, tag_value = item.split('=', 1) 485 ip_tags.append(IpTag(ip_tag_type=tag_type, tag=tag_value)) 486 namespace.ip_tags = ip_tags 487 488 489def validate_frontend_ip_configs(cmd, namespace): 490 from msrestazure.tools import is_valid_resource_id 491 if namespace.frontend_ip_configurations: 492 config_ids = [] 493 for item in namespace.frontend_ip_configurations: 494 if not is_valid_resource_id(item): 495 config_ids.append(_generate_lb_subproperty_id( 496 cmd.cli_ctx, namespace, 'frontendIpConfigurations', item)) 497 else: 498 config_ids.append(item) 499 namespace.frontend_ip_configurations = config_ids 500 501 502def validate_local_gateway(cmd, namespace): 503 from msrestazure.tools import is_valid_resource_id, resource_id 504 if namespace.gateway_default_site and not is_valid_resource_id(namespace.gateway_default_site): 505 namespace.gateway_default_site = resource_id( 506 subscription=get_subscription_id(cmd.cli_ctx), 507 resource_group=namespace.resource_group_name, 508 name=namespace.gateway_default_site, 509 namespace='Microsoft.Network', 510 type='localNetworkGateways') 511 512 513def validate_match_variables(cmd, namespace): 514 if not namespace.match_variables: 515 return 516 517 MatchVariable = cmd.get_models('MatchVariable') 518 variables = [] 519 for match in namespace.match_variables: 520 try: 521 name, selector = match.split('.', 1) 522 except ValueError: 523 name = match 524 selector = None 525 variables.append(MatchVariable(variable_name=name, selector=selector)) 526 namespace.match_variables = variables 527 528 529def validate_metadata(namespace): 530 if namespace.metadata: 531 namespace.metadata = dict(x.split('=', 1) for x in namespace.metadata) 532 533 534def validate_peering_type(namespace): 535 if namespace.peering_type and namespace.peering_type == 'MicrosoftPeering': 536 537 if not namespace.advertised_public_prefixes: 538 raise CLIError( 539 'missing required MicrosoftPeering parameter --advertised-public-prefixes') 540 541 542def validate_public_ip_prefix(cmd, namespace): 543 from msrestazure.tools import is_valid_resource_id, resource_id 544 if namespace.public_ip_prefix and not is_valid_resource_id(namespace.public_ip_prefix): 545 namespace.public_ip_prefix = resource_id( 546 subscription=get_subscription_id(cmd.cli_ctx), 547 resource_group=namespace.resource_group_name, 548 name=namespace.public_ip_prefix, 549 namespace='Microsoft.Network', 550 type='publicIPPrefixes') 551 552 553def validate_nat_gateway(cmd, namespace): 554 from msrestazure.tools import is_valid_resource_id, resource_id 555 if namespace.nat_gateway and not is_valid_resource_id(namespace.nat_gateway): 556 namespace.nat_gateway = resource_id( 557 subscription=get_subscription_id(cmd.cli_ctx), 558 resource_group=namespace.resource_group_name, 559 name=namespace.nat_gateway, 560 namespace='Microsoft.Network', 561 type='natGateways') 562 563 564def validate_private_ip_address(namespace): 565 if namespace.private_ip_address and hasattr(namespace, 'private_ip_address_allocation'): 566 namespace.private_ip_address_allocation = 'static' 567 568 569def validate_route_filter(cmd, namespace): 570 from msrestazure.tools import is_valid_resource_id, resource_id 571 if namespace.route_filter: 572 if not is_valid_resource_id(namespace.route_filter): 573 namespace.route_filter = resource_id( 574 subscription=get_subscription_id(cmd.cli_ctx), 575 resource_group=namespace.resource_group_name, 576 namespace='Microsoft.Network', 577 type='routeFilters', 578 name=namespace.route_filter) 579 580 581def get_public_ip_validator(has_type_field=False, allow_none=False, allow_new=False, 582 default_none=False): 583 """ Retrieves a validator for public IP address. Accepting all defaults will perform a check 584 for an existing name or ID with no ARM-required -type parameter. """ 585 from msrestazure.tools import is_valid_resource_id, resource_id 586 587 def simple_validator(cmd, namespace): 588 if namespace.public_ip_address: 589 is_list = isinstance(namespace.public_ip_address, list) 590 591 def _validate_name_or_id(public_ip): 592 # determine if public_ip_address is name or ID 593 is_id = is_valid_resource_id(public_ip) 594 return public_ip if is_id else resource_id( 595 subscription=get_subscription_id(cmd.cli_ctx), 596 resource_group=namespace.resource_group_name, 597 namespace='Microsoft.Network', 598 type='publicIPAddresses', 599 name=public_ip) 600 601 if is_list: 602 for i, public_ip in enumerate(namespace.public_ip_address): 603 namespace.public_ip_address[i] = _validate_name_or_id(public_ip) 604 else: 605 namespace.public_ip_address = _validate_name_or_id(namespace.public_ip_address) 606 607 def complex_validator_with_type(cmd, namespace): 608 get_folded_parameter_validator( 609 'public_ip_address', 'Microsoft.Network/publicIPAddresses', '--public-ip-address', 610 allow_none=allow_none, allow_new=allow_new, default_none=default_none)(cmd, namespace) 611 612 return complex_validator_with_type if has_type_field else simple_validator 613 614 615def get_subnet_validator(has_type_field=False, allow_none=False, allow_new=False, 616 default_none=False): 617 from msrestazure.tools import is_valid_resource_id, resource_id 618 619 def simple_validator(cmd, namespace): 620 if namespace.virtual_network_name is None and namespace.subnet is None: 621 return 622 if namespace.subnet == '': 623 return 624 usage_error = ValueError('incorrect usage: ( --subnet ID | --subnet NAME --vnet-name NAME)') 625 # error if vnet-name is provided without subnet 626 if namespace.virtual_network_name and not namespace.subnet: 627 raise usage_error 628 629 # determine if subnet is name or ID 630 is_id = is_valid_resource_id(namespace.subnet) 631 632 # error if vnet-name is provided along with a subnet ID 633 if is_id and namespace.virtual_network_name: 634 raise usage_error 635 if not is_id and not namespace.virtual_network_name: 636 raise usage_error 637 638 if not is_id: 639 namespace.subnet = resource_id( 640 subscription=get_subscription_id(cmd.cli_ctx), 641 resource_group=namespace.resource_group_name, 642 namespace='Microsoft.Network', 643 type='virtualNetworks', 644 name=namespace.virtual_network_name, 645 child_type_1='subnets', 646 child_name_1=namespace.subnet) 647 648 def complex_validator_with_type(cmd, namespace): 649 650 get_folded_parameter_validator( 651 'subnet', 'subnets', '--subnet', 652 'virtual_network_name', 'Microsoft.Network/virtualNetworks', '--vnet-name', 653 allow_none=allow_none, allow_new=allow_new, default_none=default_none)(cmd, namespace) 654 655 return complex_validator_with_type if has_type_field else simple_validator 656 657 658def get_nsg_validator(has_type_field=False, allow_none=False, allow_new=False, default_none=False): 659 from msrestazure.tools import is_valid_resource_id, resource_id 660 661 def simple_validator(cmd, namespace): 662 if namespace.network_security_group: 663 # determine if network_security_group is name or ID 664 is_id = is_valid_resource_id(namespace.network_security_group) 665 if not is_id: 666 namespace.network_security_group = resource_id( 667 subscription=get_subscription_id(cmd.cli_ctx), 668 resource_group=namespace.resource_group_name, 669 namespace='Microsoft.Network', 670 type='networkSecurityGroups', 671 name=namespace.network_security_group) 672 673 def complex_validator_with_type(cmd, namespace): 674 get_folded_parameter_validator( 675 'network_security_group', 'Microsoft.Network/networkSecurityGroups', '--nsg', 676 allow_none=allow_none, allow_new=allow_new, default_none=default_none)(cmd, namespace) 677 678 return complex_validator_with_type if has_type_field else simple_validator 679 680 681def validate_service_endpoint_policy(cmd, namespace): 682 from msrestazure.tools import is_valid_resource_id, resource_id 683 if namespace.service_endpoint_policy: 684 policy_ids = [] 685 for policy in namespace.service_endpoint_policy: 686 if not is_valid_resource_id(policy): 687 policy = resource_id( 688 subscription=get_subscription_id(cmd.cli_ctx), 689 resource_group=namespace.resource_group_name, 690 name=policy, 691 namespace='Microsoft.Network', 692 type='serviceEndpointPolicies') 693 policy_ids.append(policy) 694 namespace.service_endpoint_policy = policy_ids 695 696 697def get_servers_validator(camel_case=False): 698 def validate_servers(namespace): 699 servers = [] 700 for item in namespace.servers if namespace.servers else []: 701 try: 702 socket.inet_aton(item) # pylint:disable=no-member 703 servers.append({'ipAddress' if camel_case else 'ip_address': item}) 704 except socket.error: # pylint:disable=no-member 705 servers.append({'fqdn': item}) 706 namespace.servers = servers if servers else None 707 708 return validate_servers 709 710 711def validate_subresource_list(cmd, namespace): 712 if namespace.target_resources: 713 SubResource = cmd.get_models('SubResource') 714 subresources = [] 715 for item in namespace.target_resources: 716 subresources.append(SubResource(id=item)) 717 namespace.target_resources = subresources 718 719 720def validate_target_listener(cmd, namespace): 721 from msrestazure.tools import is_valid_resource_id, resource_id 722 if namespace.target_listener and not is_valid_resource_id(namespace.target_listener): 723 namespace.target_listener = resource_id( 724 subscription=get_subscription_id(cmd.cli_ctx), 725 resource_group=namespace.resource_group_name, 726 name=namespace.application_gateway_name, 727 namespace='Microsoft.Network', 728 type='applicationGateways', 729 child_type_1='httpListeners', 730 child_name_1=namespace.target_listener) 731 732 733def validate_private_dns_zone(cmd, namespace): 734 from msrestazure.tools import is_valid_resource_id, resource_id 735 if namespace.private_dns_zone and not is_valid_resource_id(namespace.private_dns_zone): 736 namespace.private_dns_zone = resource_id( 737 subscription=get_subscription_id(cmd.cli_ctx), 738 resource_group=namespace.resource_group_name, 739 name=namespace.private_dns_zone, 740 namespace='Microsoft.Network', 741 type='privateDnsZones') 742 743 744def get_virtual_network_validator(has_type_field=False, allow_none=False, allow_new=False, 745 default_none=False): 746 from msrestazure.tools import is_valid_resource_id, resource_id 747 748 def simple_validator(cmd, namespace): 749 if namespace.virtual_network: 750 # determine if vnet is name or ID 751 is_id = is_valid_resource_id(namespace.virtual_network) 752 if not is_id: 753 namespace.virtual_network = resource_id( 754 subscription=get_subscription_id(cmd.cli_ctx), 755 resource_group=namespace.resource_group_name, 756 namespace='Microsoft.Network', 757 type='virtualNetworks', 758 name=namespace.virtual_network) 759 760 def complex_validator_with_type(cmd, namespace): 761 get_folded_parameter_validator( 762 'virtual_network', 'Microsoft.Network/virtualNetworks', '--vnet', 763 allow_none=allow_none, allow_new=allow_new, default_none=default_none)(cmd, namespace) 764 765 return complex_validator_with_type if has_type_field else simple_validator 766 767 768# COMMAND NAMESPACE VALIDATORS 769 770def process_ag_listener_create_namespace(cmd, namespace): # pylint: disable=unused-argument 771 from msrestazure.tools import is_valid_resource_id, resource_id 772 if namespace.frontend_ip and not is_valid_resource_id(namespace.frontend_ip): 773 namespace.frontend_ip = _generate_ag_subproperty_id( 774 cmd.cli_ctx, namespace, 'frontendIpConfigurations', namespace.frontend_ip) 775 776 if namespace.frontend_port and not is_valid_resource_id(namespace.frontend_port): 777 namespace.frontend_port = _generate_ag_subproperty_id( 778 cmd.cli_ctx, namespace, 'frontendPorts', namespace.frontend_port) 779 780 if namespace.ssl_cert and not is_valid_resource_id(namespace.ssl_cert): 781 namespace.ssl_cert = _generate_ag_subproperty_id( 782 cmd.cli_ctx, namespace, 'sslCertificates', namespace.ssl_cert) 783 784 if namespace.firewall_policy and not is_valid_resource_id(namespace.firewall_policy): 785 namespace.firewall_policy = resource_id( 786 subscription=get_subscription_id(cmd.cli_ctx), 787 resource_group=namespace.resource_group_name, 788 namespace='Microsoft.Network', 789 type='ApplicationGatewayWebApplicationFirewallPolicies', 790 name=namespace.firewall_policy 791 ) 792 793 794def process_ag_http_settings_create_namespace(cmd, namespace): # pylint: disable=unused-argument 795 from msrestazure.tools import is_valid_resource_id 796 if namespace.probe and not is_valid_resource_id(namespace.probe): 797 namespace.probe = _generate_ag_subproperty_id( 798 cmd.cli_ctx, namespace, 'probes', namespace.probe) 799 if namespace.auth_certs: 800 def _validate_name_or_id(val): 801 return val if is_valid_resource_id(val) else _generate_ag_subproperty_id( 802 cmd.cli_ctx, namespace, 'authenticationCertificates', val) 803 804 namespace.auth_certs = [_validate_name_or_id(x) for x in namespace.auth_certs] 805 if namespace.root_certs: 806 def _validate_name_or_id(val): 807 return val if is_valid_resource_id(val) else _generate_ag_subproperty_id( 808 cmd.cli_ctx, namespace, 'trustedRootCertificates', val) 809 810 namespace.root_certs = [_validate_name_or_id(x) for x in namespace.root_certs] 811 812 813def process_ag_rule_create_namespace(cmd, namespace): # pylint: disable=unused-argument 814 from msrestazure.tools import is_valid_resource_id 815 if namespace.address_pool and not is_valid_resource_id(namespace.address_pool): 816 namespace.address_pool = _generate_ag_subproperty_id( 817 cmd.cli_ctx, namespace, 'backendAddressPools', namespace.address_pool) 818 819 if namespace.http_listener and not is_valid_resource_id(namespace.http_listener): 820 namespace.http_listener = _generate_ag_subproperty_id( 821 cmd.cli_ctx, namespace, 'httpListeners', namespace.http_listener) 822 823 if namespace.http_settings and not is_valid_resource_id(namespace.http_settings): 824 namespace.http_settings = _generate_ag_subproperty_id( 825 cmd.cli_ctx, namespace, 'backendHttpSettingsCollection', namespace.http_settings) 826 827 if namespace.url_path_map and not is_valid_resource_id(namespace.url_path_map): 828 namespace.url_path_map = _generate_ag_subproperty_id( 829 cmd.cli_ctx, namespace, 'urlPathMaps', namespace.url_path_map) 830 831 if namespace.redirect_config and not is_valid_resource_id(namespace.redirect_config): 832 namespace.redirect_config = _generate_ag_subproperty_id( 833 cmd.cli_ctx, namespace, 'redirectConfigurations', namespace.redirect_config) 834 835 if namespace.rewrite_rule_set and not is_valid_resource_id(namespace.rewrite_rule_set): 836 namespace.rewrite_rule_set = _generate_ag_subproperty_id( 837 cmd.cli_ctx, namespace, 'rewriteRuleSets', namespace.rewrite_rule_set) 838 839 840def process_ag_ssl_policy_set_namespace(namespace): 841 if namespace.disabled_ssl_protocols and getattr(namespace, 'clear', None): 842 raise ValueError('incorrect usage: --disabled-ssl-protocols PROTOCOL [...] | --clear') 843 844 845def process_ag_url_path_map_create_namespace(cmd, namespace): # pylint: disable=unused-argument 846 from msrestazure.tools import is_valid_resource_id 847 if namespace.default_address_pool and not is_valid_resource_id(namespace.default_address_pool): 848 namespace.default_address_pool = _generate_ag_subproperty_id( 849 cmd.cli_ctx, namespace, 'backendAddressPools', namespace.default_address_pool) 850 851 if namespace.default_http_settings and not is_valid_resource_id( 852 namespace.default_http_settings): 853 namespace.default_http_settings = _generate_ag_subproperty_id( 854 cmd.cli_ctx, namespace, 'backendHttpSettingsCollection', namespace.default_http_settings) 855 856 if namespace.default_redirect_config and not is_valid_resource_id( 857 namespace.default_redirect_config): 858 namespace.default_redirect_config = _generate_ag_subproperty_id( 859 cmd.cli_ctx, namespace, 'redirectConfigurations', namespace.default_redirect_config) 860 861 if hasattr(namespace, 'firewall_policy') and \ 862 namespace.firewall_policy and not is_valid_resource_id(namespace.firewall_policy): 863 namespace.firewall_policy = _generate_ag_subproperty_id( 864 cmd.cli_ctx, namespace, 'firewallPolicy', namespace.firewall_policy 865 ) 866 867 if namespace.default_rewrite_rule_set and not is_valid_resource_id(namespace.default_rewrite_rule_set): 868 namespace.default_rewrite_rule_set = _generate_ag_subproperty_id( 869 cmd.cli_ctx, namespace, 'rewriteRuleSets', namespace.default_rewrite_rule_set) 870 871 if hasattr(namespace, 'rule_name'): 872 process_ag_url_path_map_rule_create_namespace(cmd, namespace) 873 874 875def process_ag_url_path_map_rule_create_namespace(cmd, namespace): # pylint: disable=unused-argument 876 from msrestazure.tools import is_valid_resource_id 877 if namespace.address_pool and not is_valid_resource_id(namespace.address_pool): 878 namespace.address_pool = _generate_ag_subproperty_id( 879 cmd.cli_ctx, namespace, 'backendAddressPools', namespace.address_pool) 880 881 if namespace.http_settings and not is_valid_resource_id(namespace.http_settings): 882 namespace.http_settings = _generate_ag_subproperty_id( 883 cmd.cli_ctx, namespace, 'backendHttpSettingsCollection', namespace.http_settings) 884 885 if namespace.redirect_config and not is_valid_resource_id( 886 namespace.redirect_config): 887 namespace.redirect_config = _generate_ag_subproperty_id( 888 cmd.cli_ctx, namespace, 'redirectConfigurations', namespace.redirect_config) 889 890 if namespace.rewrite_rule_set and not is_valid_resource_id(namespace.rewrite_rule_set): 891 namespace.rewrite_rule_set = _generate_ag_subproperty_id( 892 cmd.cli_ctx, namespace, 'rewriteRuleSets', namespace.rewrite_rule_set) 893 894 895def process_ag_create_namespace(cmd, namespace): 896 get_default_location_from_resource_group(cmd, namespace) 897 get_servers_validator(camel_case=True)(namespace) 898 899 # process folded parameters 900 if namespace.subnet or namespace.virtual_network_name: 901 get_subnet_validator(has_type_field=True, allow_new=True)(cmd, namespace) 902 validate_address_prefixes(namespace) 903 if namespace.public_ip_address: 904 get_public_ip_validator( 905 has_type_field=True, allow_none=True, allow_new=True, default_none=True)(cmd, namespace) 906 validate_ssl_cert(namespace) 907 validate_tags(namespace) 908 validate_custom_error_pages(namespace) 909 validate_waf_policy(cmd, namespace) 910 validate_user_assigned_identity(cmd, namespace) 911 912 913def process_auth_create_namespace(cmd, namespace): 914 ExpressRouteCircuitAuthorization = cmd.get_models('ExpressRouteCircuitAuthorization') 915 namespace.authorization_parameters = ExpressRouteCircuitAuthorization() 916 917 918def process_lb_create_namespace(cmd, namespace): 919 get_default_location_from_resource_group(cmd, namespace) 920 validate_tags(namespace) 921 922 if namespace.subnet and namespace.public_ip_address: 923 raise ValueError( 924 'incorrect usage: --subnet NAME --vnet-name NAME | ' 925 '--subnet ID | --public-ip-address NAME_OR_ID') 926 927 if namespace.subnet: 928 # validation for an internal load balancer 929 get_subnet_validator( 930 has_type_field=True, allow_new=True, allow_none=True, default_none=True)(cmd, namespace) 931 932 namespace.public_ip_address_type = None 933 namespace.public_ip_address = None 934 935 else: 936 # validation for internet facing load balancer 937 get_public_ip_validator(has_type_field=True, allow_none=True, allow_new=True)(cmd, namespace) 938 939 if namespace.public_ip_dns_name and namespace.public_ip_address_type != 'new': 940 raise CLIError( 941 'specify --public-ip-dns-name only if creating a new public IP address.') 942 943 namespace.subnet_type = None 944 namespace.subnet = None 945 namespace.virtual_network_name = None 946 947 948def process_lb_frontend_ip_namespace(cmd, namespace): 949 from msrestazure.tools import is_valid_resource_id, resource_id 950 if namespace.subnet and namespace.public_ip_address: 951 raise ValueError( 952 'incorrect usage: --subnet NAME --vnet-name NAME | ' 953 '--subnet ID | --public-ip NAME_OR_ID') 954 955 if namespace.public_ip_prefix: 956 if not is_valid_resource_id(namespace.public_ip_prefix): 957 namespace.public_ip_prefix = resource_id( 958 subscription=get_subscription_id(cmd.cli_ctx), 959 resource_group=namespace.resource_group_name, 960 namespace='Microsoft.Network', 961 type='publicIpPrefixes', 962 name=namespace.public_ip_prefix) 963 964 if namespace.subnet: 965 get_subnet_validator()(cmd, namespace) 966 else: 967 get_public_ip_validator()(cmd, namespace) 968 969 970def process_cross_region_lb_create_namespace(cmd, namespace): 971 get_default_location_from_resource_group(cmd, namespace) 972 validate_tags(namespace) 973 974 # validation for internet facing load balancer 975 get_public_ip_validator(has_type_field=True, allow_none=True, allow_new=True)(cmd, namespace) 976 977 if namespace.public_ip_dns_name and namespace.public_ip_address_type != 'new': 978 raise CLIError( 979 'specify --public-ip-dns-name only if creating a new public IP address.') 980 981 982def process_cross_region_lb_frontend_ip_namespace(cmd, namespace): 983 from azure.mgmt.core.tools import is_valid_resource_id, resource_id 984 985 if namespace.public_ip_prefix: 986 if not is_valid_resource_id(namespace.public_ip_prefix): 987 namespace.public_ip_prefix = resource_id( 988 subscription=get_subscription_id(cmd.cli_ctx), 989 resource_group=namespace.resource_group_name, 990 namespace='Microsoft.Network', 991 type='publicIpPrefixes', 992 name=namespace.public_ip_prefix) 993 994 get_public_ip_validator()(cmd, namespace) 995 996 997def process_local_gateway_create_namespace(cmd, namespace): 998 ns = namespace 999 get_default_location_from_resource_group(cmd, ns) 1000 validate_tags(ns) 1001 1002 use_bgp_settings = any([ns.asn or ns.bgp_peering_address or ns.peer_weight]) 1003 if use_bgp_settings and (not ns.asn or not ns.bgp_peering_address): 1004 raise ValueError( 1005 'incorrect usage: --bgp-peering-address IP --asn ASN [--peer-weight WEIGHT]') 1006 1007 1008def process_nic_create_namespace(cmd, namespace): 1009 get_default_location_from_resource_group(cmd, namespace) 1010 validate_tags(namespace) 1011 1012 validate_ag_address_pools(cmd, namespace) 1013 validate_address_pool_id_list(cmd, namespace) 1014 validate_inbound_nat_rule_id_list(cmd, namespace) 1015 get_asg_validator(cmd.loader, 'application_security_groups')(cmd, namespace) 1016 1017 # process folded parameters 1018 get_subnet_validator(has_type_field=False)(cmd, namespace) 1019 get_public_ip_validator(has_type_field=False, allow_none=True, default_none=True)(cmd, namespace) 1020 get_nsg_validator(has_type_field=False, allow_none=True, default_none=True)(cmd, namespace) 1021 1022 1023def process_public_ip_create_namespace(cmd, namespace): 1024 get_default_location_from_resource_group(cmd, namespace) 1025 validate_public_ip_prefix(cmd, namespace) 1026 validate_ip_tags(cmd, namespace) 1027 validate_tags(namespace) 1028 _inform_coming_breaking_change_for_public_ip(namespace) 1029 1030 1031def _inform_coming_breaking_change_for_public_ip(namespace): 1032 if namespace.sku == 'Standard' and not namespace.zone: 1033 logger.warning('[Coming breaking change] In the coming release, the default behavior will be changed as follows' 1034 ' when sku is Standard and zone is not provided:' 1035 ' For zonal regions, you will get a zone-redundant IP indicated by zones:["1","2","3"];' 1036 ' For non-zonal regions, you will get a non zone-redundant IP indicated by zones:null.') 1037 1038 1039def process_route_table_create_namespace(cmd, namespace): 1040 get_default_location_from_resource_group(cmd, namespace) 1041 validate_tags(namespace) 1042 1043 1044def process_tm_endpoint_create_namespace(cmd, namespace): 1045 from azure.mgmt.trafficmanager import TrafficManagerManagementClient 1046 1047 client = get_mgmt_service_client(cmd.cli_ctx, TrafficManagerManagementClient).profiles 1048 profile = client.get(namespace.resource_group_name, namespace.profile_name) 1049 1050 routing_type = profile.traffic_routing_method # pylint: disable=no-member 1051 endpoint_type = namespace.endpoint_type 1052 all_options = ['target_resource_id', 'target', 'min_child_endpoints', 'priority', 'weight', 'endpoint_location'] 1053 props_to_options = { 1054 'target_resource_id': '--target-resource-id', 1055 'target': '--target', 1056 'min_child_endpoints': '--min-child-endpoints', 1057 'priority': '--priority', 1058 'weight': '--weight', 1059 'endpoint_location': '--endpoint-location', 1060 'geo_mapping': '--geo-mapping' 1061 } 1062 validate_subnet_ranges(namespace) 1063 validate_custom_headers(namespace) 1064 1065 required_options = [] 1066 1067 # determine which options are required based on profile and routing method 1068 if endpoint_type.lower() == 'externalendpoints': 1069 required_options.append('target') 1070 else: 1071 required_options.append('target_resource_id') 1072 1073 if routing_type.lower() == 'weighted': 1074 required_options.append('weight') 1075 elif routing_type.lower() == 'priority': 1076 required_options.append('priority') 1077 1078 if endpoint_type.lower() == 'nestedendpoints': 1079 required_options.append('min_child_endpoints') 1080 1081 if endpoint_type.lower() in ['nestedendpoints', 'externalendpoints'] and routing_type.lower() == 'performance': 1082 required_options.append('endpoint_location') 1083 1084 if routing_type.lower() == 'geographic': 1085 required_options.append('geo_mapping') 1086 1087 # ensure required options are provided 1088 missing_options = [props_to_options[x] for x in required_options if getattr(namespace, x, None) is None] 1089 extra_options = [props_to_options[x] for x in all_options if 1090 getattr(namespace, x, None) is not None and x not in required_options] 1091 1092 if missing_options or extra_options: 1093 error_message = "Incorrect options for profile routing method '{}' and endpoint type '{}'.".format(routing_type, 1094 endpoint_type) # pylint: disable=line-too-long 1095 if missing_options: 1096 error_message = '{}\nSupply the following: {}'.format(error_message, ', '.join( 1097 missing_options)) 1098 if extra_options: 1099 error_message = '{}\nOmit the following: {}'.format(error_message, ', '.join( 1100 extra_options)) 1101 raise CLIError(error_message) 1102 1103 1104def process_vnet_create_namespace(cmd, namespace): 1105 get_default_location_from_resource_group(cmd, namespace) 1106 validate_ddos_name_or_id(cmd, namespace) 1107 validate_tags(namespace) 1108 get_nsg_validator()(cmd, namespace) 1109 1110 if namespace.subnet_prefix and not namespace.subnet_name: 1111 if cmd.supported_api_version(min_api='2018-08-01'): 1112 raise ValueError('incorrect usage: --subnet-name NAME [--subnet-prefixes PREFIXES]') 1113 raise ValueError('incorrect usage: --subnet-name NAME [--subnet-prefix PREFIX]') 1114 1115 if namespace.subnet_name and not namespace.subnet_prefix: 1116 if isinstance(namespace.vnet_prefixes, str): 1117 namespace.vnet_prefixes = [namespace.vnet_prefixes] 1118 prefix_components = namespace.vnet_prefixes[0].split('/', 1) 1119 address = prefix_components[0] 1120 bit_mask = int(prefix_components[1]) 1121 subnet_mask = 24 if bit_mask < 24 else bit_mask 1122 subnet_prefix = '{}/{}'.format(address, subnet_mask) 1123 namespace.subnet_prefix = [subnet_prefix] if cmd.supported_api_version(min_api='2018-08-01') else subnet_prefix 1124 1125 1126def _validate_cert(namespace, param_name): 1127 attr = getattr(namespace, param_name) 1128 if attr and os.path.isfile(attr): 1129 setattr(namespace, param_name, read_base_64_file(attr)) 1130 1131 1132def process_vnet_gateway_create_namespace(cmd, namespace): 1133 ns = namespace 1134 get_default_location_from_resource_group(cmd, ns) 1135 validate_tags(ns) 1136 1137 _validate_vpn_gateway_generation(ns) 1138 1139 get_virtual_network_validator()(cmd, ns) 1140 1141 get_public_ip_validator()(cmd, ns) 1142 public_ip_count = len(ns.public_ip_address or []) 1143 if public_ip_count > 2: 1144 raise CLIError('Specify a single public IP to create an active-standby gateway or two ' 1145 'public IPs to create an active-active gateway.') 1146 1147 validate_local_gateway(cmd, ns) 1148 1149 enable_bgp = any([ns.asn, ns.bgp_peering_address, ns.peer_weight]) 1150 if enable_bgp and not ns.asn: 1151 raise ValueError( 1152 'incorrect usage: --asn ASN [--peer-weight WEIGHT --bgp-peering-address IP ]') 1153 1154 if cmd.supported_api_version(min_api='2020-11-01'): 1155 _validate_cert(namespace, 'root_cert_data') 1156 1157 1158def process_vnet_gateway_update_namespace(cmd, namespace): 1159 ns = namespace 1160 get_virtual_network_validator()(cmd, ns) 1161 get_public_ip_validator()(cmd, ns) 1162 validate_tags(ns) 1163 if cmd.supported_api_version(min_api='2020-11-01'): 1164 _validate_cert(namespace, 'root_cert_data') 1165 public_ip_count = len(ns.public_ip_address or []) 1166 if public_ip_count > 2: 1167 raise CLIError('Specify a single public IP to create an active-standby gateway or two ' 1168 'public IPs to create an active-active gateway.') 1169 1170 1171def process_vpn_connection_create_namespace(cmd, namespace): 1172 from msrestazure.tools import is_valid_resource_id, resource_id 1173 get_default_location_from_resource_group(cmd, namespace) 1174 validate_tags(namespace) 1175 1176 args = [a for a in [namespace.express_route_circuit2, 1177 namespace.local_gateway2, 1178 namespace.vnet_gateway2] 1179 if a] 1180 if len(args) != 1: 1181 raise ValueError('usage error: --vnet-gateway2 NAME_OR_ID | --local-gateway2 NAME_OR_ID ' 1182 '| --express-route-circuit2 NAME_OR_ID') 1183 1184 def _validate_name_or_id(value, resource_type): 1185 if not is_valid_resource_id(value): 1186 subscription = getattr(namespace, 'subscription', get_subscription_id(cmd.cli_ctx)) 1187 return resource_id( 1188 subscription=subscription, 1189 resource_group=namespace.resource_group_name, 1190 namespace='Microsoft.Network', 1191 type=resource_type, 1192 name=value) 1193 return value 1194 1195 if (namespace.local_gateway2 or namespace.vnet_gateway2) and not namespace.shared_key: 1196 raise CLIError('--shared-key is required for VNET-to-VNET or Site-to-Site connections.') 1197 1198 if namespace.express_route_circuit2 and namespace.shared_key: 1199 raise CLIError('--shared-key cannot be used with an ExpressRoute connection.') 1200 1201 namespace.vnet_gateway1 = \ 1202 _validate_name_or_id(namespace.vnet_gateway1, 'virtualNetworkGateways') 1203 1204 if namespace.express_route_circuit2: 1205 namespace.express_route_circuit2 = \ 1206 _validate_name_or_id( 1207 namespace.express_route_circuit2, 'expressRouteCircuits') 1208 namespace.connection_type = 'ExpressRoute' 1209 elif namespace.local_gateway2: 1210 namespace.local_gateway2 = \ 1211 _validate_name_or_id(namespace.local_gateway2, 'localNetworkGateways') 1212 namespace.connection_type = 'IPSec' 1213 elif namespace.vnet_gateway2: 1214 namespace.vnet_gateway2 = \ 1215 _validate_name_or_id(namespace.vnet_gateway2, 'virtualNetworkGateways') 1216 namespace.connection_type = 'Vnet2Vnet' 1217 1218 1219def load_cert_file(param_name): 1220 def load_cert_validator(namespace): 1221 attr = getattr(namespace, param_name) 1222 if attr and os.path.isfile(attr): 1223 setattr(namespace, param_name, read_base_64_file(attr)) 1224 1225 return load_cert_validator 1226 1227 1228def get_network_watcher_from_vm(cmd, namespace): 1229 from msrestazure.tools import parse_resource_id 1230 1231 compute_client = get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_COMPUTE).virtual_machines 1232 vm_name = parse_resource_id(namespace.vm)['name'] 1233 vm = compute_client.get(namespace.resource_group_name, vm_name) 1234 namespace.location = vm.location # pylint: disable=no-member 1235 get_network_watcher_from_location()(cmd, namespace) 1236 1237 1238def get_network_watcher_from_resource(cmd, namespace): 1239 from azure.cli.core.commands.arm import get_arm_resource_by_id 1240 resource = get_arm_resource_by_id(cmd.cli_ctx, namespace.resource) 1241 namespace.location = resource.location # pylint: disable=no-member 1242 get_network_watcher_from_location(remove=True)(cmd, namespace) 1243 1244 1245def get_network_watcher_from_location(remove=False, watcher_name='watcher_name', 1246 rg_name='watcher_rg'): 1247 def _validator(cmd, namespace): 1248 from msrestazure.tools import parse_resource_id 1249 1250 location = namespace.location 1251 network_client = get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_NETWORK).network_watchers 1252 watcher = next((x for x in network_client.list_all() if x.location.lower() == location.lower()), None) 1253 if not watcher: 1254 raise CLIError("network watcher is not enabled for region '{}'.".format(location)) 1255 id_parts = parse_resource_id(watcher.id) 1256 setattr(namespace, rg_name, id_parts['resource_group']) 1257 setattr(namespace, watcher_name, id_parts['name']) 1258 1259 if remove: 1260 del namespace.location 1261 1262 return _validator 1263 1264 1265def process_nw_cm_v1_create_namespace(cmd, namespace): 1266 from msrestazure.tools import is_valid_resource_id, resource_id, parse_resource_id 1267 1268 validate_tags(namespace) 1269 1270 compute_client = get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_COMPUTE).virtual_machines 1271 vm_name = parse_resource_id(namespace.source_resource)['name'] 1272 rg = namespace.resource_group_name or parse_resource_id(namespace.source_resource).get('resource_group', None) 1273 if not rg: 1274 raise CLIError('usage error: --source-resource ID | --source-resource NAME --resource-group NAME') 1275 vm = compute_client.get(rg, vm_name) 1276 namespace.location = vm.location # pylint: disable=no-member 1277 get_network_watcher_from_location()(cmd, namespace) 1278 1279 if namespace.source_resource and not is_valid_resource_id(namespace.source_resource): 1280 namespace.source_resource = resource_id( 1281 subscription=get_subscription_id(cmd.cli_ctx), 1282 resource_group=rg, 1283 namespace='Microsoft.Compute', 1284 type='virtualMachines', 1285 name=namespace.source_resource) 1286 1287 if namespace.dest_resource and not is_valid_resource_id(namespace.dest_resource): 1288 namespace.dest_resource = resource_id( 1289 subscription=get_subscription_id(cmd.cli_ctx), 1290 resource_group=namespace.resource_group_name, 1291 namespace='Microsoft.Compute', 1292 type='virtualMachines', 1293 name=namespace.dest_resource) 1294 1295 1296def process_nw_cm_v2_create_namespace(cmd, namespace): 1297 if namespace.location is None: # location is None only occurs in creating a V2 connection monitor 1298 endpoint_source_resource_id = namespace.endpoint_source_resource_id 1299 1300 from msrestazure.tools import is_valid_resource_id, parse_resource_id 1301 from azure.mgmt.resource import ResourceManagementClient 1302 1303 # parse and verify endpoint_source_resource_id 1304 if endpoint_source_resource_id is None: 1305 raise CLIError('usage error: ' 1306 '--location/--endpoint-source-resource-id is required to create a V2 connection monitor') 1307 if is_valid_resource_id(endpoint_source_resource_id) is False: 1308 raise CLIError('usage error: "{}" is not a valid resource id'.format(endpoint_source_resource_id)) 1309 1310 resource = parse_resource_id(namespace.endpoint_source_resource_id) 1311 resource_client = get_mgmt_service_client(cmd.cli_ctx, ResourceManagementClient) 1312 resource_api_version = _resolve_api_version(resource_client, 1313 resource['namespace'], 1314 resource['resource_parent'], 1315 resource['resource_type']) 1316 resource = resource_client.resources.get_by_id(namespace.endpoint_source_resource_id, resource_api_version) 1317 1318 namespace.location = resource.location 1319 if namespace.location is None: 1320 raise CLIError("Can not get location from --endpoint-source-resource-id") 1321 1322 v2_required_parameter_set = [ 1323 'endpoint_source_resource_id', 'endpoint_source_name', 'endpoint_dest_name', 'test_config_name' 1324 ] 1325 for p in v2_required_parameter_set: 1326 if not hasattr(namespace, p) or getattr(namespace, p) is None: 1327 raise CLIError( 1328 'usage error: --{} is required to create a V2 connection monitor'.format(p.replace('_', '-'))) 1329 if namespace.test_config_protocol is None: 1330 raise CLIError('usage error: --protocol is required to create a test configuration for V2 connection monitor') 1331 1332 v2_optional_parameter_set = ['workspace_ids'] 1333 if namespace.output_type is not None: 1334 tmp = [p for p in v2_optional_parameter_set if getattr(namespace, p) is None] 1335 if v2_optional_parameter_set == tmp: 1336 raise CLIError('usage error: --output-type is specified but no other resource id provided') 1337 1338 return get_network_watcher_from_location()(cmd, namespace) 1339 1340 1341def process_nw_cm_create_namespace(cmd, namespace): 1342 # V2 parameter set 1343 if namespace.source_resource is None: 1344 return process_nw_cm_v2_create_namespace(cmd, namespace) 1345 1346 # V1 parameter set 1347 return process_nw_cm_v1_create_namespace(cmd, namespace) 1348 1349 1350def process_nw_cm_v2_endpoint_namespace(cmd, namespace): 1351 if hasattr(namespace, 'filter_type') or hasattr(namespace, 'filter_items'): 1352 filter_type, filter_items = namespace.filter_type, namespace.filter_items 1353 if (filter_type and not filter_items) or (not filter_type and filter_items): 1354 raise CLIError('usage error: --filter-type and --filter-item must be present at the same time.') 1355 1356 if hasattr(namespace, 'dest_test_groups') or hasattr(namespace, 'source_test_groups'): 1357 dest_test_groups, source_test_groups = namespace.dest_test_groups, namespace.source_test_groups 1358 if dest_test_groups is None and source_test_groups is None: 1359 raise CLIError('usage error: endpoint has to be referenced from at least one existing test group ' 1360 'via --dest-test-groups/--source-test-groups') 1361 1362 return get_network_watcher_from_location()(cmd, namespace) 1363 1364 1365def process_nw_cm_v2_test_configuration_namespace(cmd, namespace): 1366 return get_network_watcher_from_location()(cmd, namespace) 1367 1368 1369def process_nw_cm_v2_test_group(cmd, namespace): 1370 return get_network_watcher_from_location()(cmd, namespace) 1371 1372 1373def process_nw_cm_v2_output_namespace(cmd, namespace): 1374 v2_output_optional_parameter_set = ['workspace_id'] 1375 if hasattr(namespace, 'out_type') and namespace.out_type is not None: 1376 tmp = [p for p in v2_output_optional_parameter_set if getattr(namespace, p) is None] 1377 if v2_output_optional_parameter_set == tmp: 1378 raise CLIError('usage error: --type is specified but no other resource id provided') 1379 1380 return get_network_watcher_from_location()(cmd, namespace) 1381 1382 1383# pylint: disable=protected-access,too-few-public-methods 1384class NWConnectionMonitorEndpointFilterItemAction(argparse._AppendAction): 1385 def __call__(self, parser, namespace, values, option_string=None): 1386 ConnectionMonitorEndpointFilterItem = namespace._cmd.get_models('ConnectionMonitorEndpointFilterItem') 1387 1388 if not namespace.filter_items: 1389 namespace.filter_items = [] 1390 1391 filter_item = ConnectionMonitorEndpointFilterItem() 1392 1393 for item in values: 1394 try: 1395 key, val = item.split('=', 1) 1396 1397 if hasattr(filter_item, key): 1398 setattr(filter_item, key, val) 1399 else: 1400 raise CLIError( 1401 "usage error: '{}' is not a valid property of ConnectionMonitorEndpointFilterItem".format(key)) 1402 except ValueError: 1403 raise CLIError( 1404 'usage error: {} PropertyName=PropertyValue [PropertyName=PropertyValue ...]'.format(option_string)) 1405 1406 namespace.filter_items.append(filter_item) 1407 1408 1409# pylint: disable=protected-access,too-few-public-methods 1410class NWConnectionMonitorTestConfigurationHTTPRequestHeaderAction(argparse._AppendAction): 1411 def __call__(self, parser, namespace, values, option_string=None): 1412 HTTPHeader = namespace._cmd.get_models('HTTPHeader') 1413 1414 if not namespace.http_request_headers: 1415 namespace.http_request_headers = [] 1416 1417 request_header = HTTPHeader() 1418 1419 for item in values: 1420 try: 1421 key, val = item.split('=', 1) 1422 if hasattr(request_header, key): 1423 setattr(request_header, key, val) 1424 else: 1425 raise CLIError("usage error: '{}' is not a value property of HTTPHeader".format(key)) 1426 except ValueError: 1427 raise CLIError( 1428 'usage error: {} name=HTTPHeader value=HTTPHeaderValue'.format(option_string)) 1429 1430 namespace.http_request_headers.append(request_header) 1431 1432 1433def process_nw_test_connectivity_namespace(cmd, namespace): 1434 from msrestazure.tools import is_valid_resource_id, resource_id, parse_resource_id 1435 1436 compute_client = get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_COMPUTE).virtual_machines 1437 vm_name = parse_resource_id(namespace.source_resource)['name'] 1438 rg = namespace.resource_group_name or parse_resource_id(namespace.source_resource).get('resource_group', None) 1439 if not rg: 1440 raise CLIError('usage error: --source-resource ID | --source-resource NAME --resource-group NAME') 1441 vm = compute_client.get(rg, vm_name) 1442 namespace.location = vm.location # pylint: disable=no-member 1443 get_network_watcher_from_location(remove=True)(cmd, namespace) 1444 1445 if namespace.source_resource and not is_valid_resource_id(namespace.source_resource): 1446 namespace.source_resource = resource_id( 1447 subscription=get_subscription_id(cmd.cli_ctx), 1448 resource_group=rg, 1449 namespace='Microsoft.Compute', 1450 type='virtualMachines', 1451 name=namespace.source_resource) 1452 1453 if namespace.dest_resource and not is_valid_resource_id(namespace.dest_resource): 1454 namespace.dest_resource = resource_id( 1455 subscription=get_subscription_id(cmd.cli_ctx), 1456 resource_group=namespace.resource_group_name, 1457 namespace='Microsoft.Compute', 1458 type='virtualMachines', 1459 name=namespace.dest_resource) 1460 1461 if namespace.headers: 1462 HTTPHeader = cmd.get_models('HTTPHeader') 1463 headers = [] 1464 for item in namespace.headers: 1465 parts = item.split('=') 1466 if len(parts) != 2: 1467 raise CLIError("usage error '{}': --headers KEY=VALUE [KEY=VALUE ...]".format(item)) 1468 headers.append(HTTPHeader(name=parts[0], value=parts[1])) 1469 namespace.headers = headers 1470 1471 1472def process_nw_flow_log_create_namespace(cmd, namespace): 1473 """ 1474 Flow Log is the sub-resource of Network Watcher, they must be in the same region and subscription. 1475 """ 1476 from msrestazure.tools import is_valid_resource_id, resource_id 1477 1478 # for both create and update 1479 if namespace.resource_group_name is None: 1480 err_tpl, err_body = 'usage error: use {} instead.', None 1481 1482 if namespace.nsg and not is_valid_resource_id(namespace.nsg): 1483 err_body = '--nsg ID / --nsg NSD_NAME --resource-group NSD_RESOURCE_GROUP' 1484 1485 if namespace.storage_account and not is_valid_resource_id(namespace.storage_account): 1486 err_body = '--storage-account ID / --storage-account NAME --resource_group STORAGE_ACCOUNT_RESOURCE_GROUP' 1487 1488 if namespace.traffic_analytics_workspace and not is_valid_resource_id(namespace.traffic_analytics_workspace): 1489 err_body = '--workspace ID / --workspace NAME --resource-group WORKSPACE_RESOURCE_GROUP' 1490 1491 if err_body is not None: 1492 raise CLIError(err_tpl.format(err_body)) 1493 1494 # for both create and update 1495 if namespace.nsg and not is_valid_resource_id(namespace.nsg): 1496 kwargs = { 1497 'subscription': get_subscription_id(cmd.cli_ctx), 1498 'resource_group': namespace.resource_group_name, 1499 'namespace': 'Microsoft.Network', 1500 'type': 'networkSecurityGroups', 1501 'name': namespace.nsg 1502 } 1503 namespace.nsg = resource_id(**kwargs) 1504 1505 # for both create and update 1506 if namespace.storage_account and not is_valid_resource_id(namespace.storage_account): 1507 kwargs = { 1508 'subscription': get_subscription_id(cmd.cli_ctx), 1509 'resource_group': namespace.resource_group_name, 1510 'namespace': 'Microsoft.Storage', 1511 'type': 'storageAccounts', 1512 'name': namespace.storage_account 1513 } 1514 namespace.storage_account = resource_id(**kwargs) 1515 1516 # for both create and update 1517 if namespace.traffic_analytics_workspace and not is_valid_resource_id(namespace.traffic_analytics_workspace): 1518 kwargs = { 1519 'subscription': get_subscription_id(cmd.cli_ctx), 1520 'resource_group': namespace.resource_group_name, 1521 'namespace': 'Microsoft.OperationalInsights', 1522 'type': 'workspaces', 1523 'name': namespace.traffic_analytics_workspace 1524 } 1525 namespace.traffic_analytics_workspace = resource_id(**kwargs) 1526 1527 get_network_watcher_from_location(remove=False)(cmd, namespace) 1528 1529 validate_tags(namespace) 1530 1531 1532def process_nw_flow_log_set_namespace(cmd, namespace): 1533 from msrestazure.tools import is_valid_resource_id, resource_id 1534 if namespace.storage_account and not is_valid_resource_id(namespace.storage_account): 1535 namespace.storage_account = resource_id( 1536 subscription=get_subscription_id(cmd.cli_ctx), 1537 resource_group=namespace.resource_group_name, 1538 namespace='Microsoft.Storage', 1539 type='storageAccounts', 1540 name=namespace.storage_account) 1541 if namespace.traffic_analytics_workspace and not is_valid_resource_id(namespace.traffic_analytics_workspace): 1542 namespace.traffic_analytics_workspace = resource_id( 1543 subscription=get_subscription_id(cmd.cli_ctx), 1544 resource_group=namespace.resource_group_name, 1545 namespace='Microsoft.OperationalInsights', 1546 type='workspaces', 1547 name=namespace.traffic_analytics_workspace) 1548 1549 process_nw_flow_log_show_namespace(cmd, namespace) 1550 1551 1552def process_nw_flow_log_show_namespace(cmd, namespace): 1553 from msrestazure.tools import is_valid_resource_id, resource_id 1554 from azure.cli.core.commands.arm import get_arm_resource_by_id 1555 1556 if hasattr(namespace, 'nsg') and namespace.nsg is not None: 1557 if not is_valid_resource_id(namespace.nsg): 1558 namespace.nsg = resource_id( 1559 subscription=get_subscription_id(cmd.cli_ctx), 1560 resource_group=namespace.resource_group_name, 1561 namespace='Microsoft.Network', 1562 type='networkSecurityGroups', 1563 name=namespace.nsg) 1564 1565 nsg = get_arm_resource_by_id(cmd.cli_ctx, namespace.nsg) 1566 namespace.location = nsg.location # pylint: disable=no-member 1567 get_network_watcher_from_location(remove=True)(cmd, namespace) 1568 elif namespace.flow_log_name is not None and namespace.location is not None: 1569 get_network_watcher_from_location(remove=False)(cmd, namespace) 1570 else: 1571 raise CLIError('usage error: --nsg NSG | --location NETWORK_WATCHER_LOCATION --name FLOW_LOW_NAME') 1572 1573 1574def process_nw_topology_namespace(cmd, namespace): 1575 from msrestazure.tools import is_valid_resource_id, resource_id, parse_resource_id 1576 SubResource = cmd.get_models('SubResource') 1577 subscription_id = get_subscription_id(cmd.cli_ctx) 1578 1579 location = namespace.location 1580 rg = namespace.target_resource_group_name 1581 vnet = namespace.target_vnet 1582 subnet = namespace.target_subnet 1583 1584 vnet_id = vnet if is_valid_resource_id(vnet) else None 1585 subnet_id = subnet if is_valid_resource_id(subnet) else None 1586 1587 if rg and not vnet and not subnet: 1588 # targeting resource group - OK 1589 pass 1590 elif subnet: 1591 subnet_usage = CLIError('usage error: --subnet ID | --subnet NAME --resource-group NAME --vnet NAME') 1592 # targeting subnet - OK 1593 if subnet_id and (vnet or rg): 1594 raise subnet_usage 1595 if not subnet_id and (not rg or not vnet or vnet_id): 1596 raise subnet_usage 1597 if subnet_id: 1598 rg = parse_resource_id(subnet_id)['resource_group'] 1599 namespace.target_subnet = SubResource(id=subnet) 1600 else: 1601 subnet_id = subnet_id or resource_id( 1602 subscription=subscription_id, 1603 resource_group=rg, 1604 namespace='Microsoft.Network', 1605 type='virtualNetworks', 1606 name=vnet, 1607 child_type_1='subnets', 1608 child_name_1=subnet 1609 ) 1610 namespace.target_resource_group_name = None 1611 namespace.target_vnet = None 1612 namespace.target_subnet = SubResource(id=subnet_id) 1613 elif vnet: 1614 # targeting vnet - OK 1615 vnet_usage = CLIError('usage error: --vnet ID | --vnet NAME --resource-group NAME') 1616 if vnet_id and (subnet or rg): 1617 raise vnet_usage 1618 if not vnet_id and not rg or subnet: 1619 raise vnet_usage 1620 if vnet_id: 1621 rg = parse_resource_id(vnet_id)['resource_group'] 1622 namespace.target_vnet = SubResource(id=vnet) 1623 else: 1624 vnet_id = vnet_id or resource_id( 1625 subscription=subscription_id, 1626 resource_group=rg, 1627 namespace='Microsoft.Network', 1628 type='virtualNetworks', 1629 name=vnet 1630 ) 1631 namespace.target_resource_group_name = None 1632 namespace.target_vnet = SubResource(id=vnet_id) 1633 else: 1634 raise CLIError('usage error: --resource-group NAME | --vnet NAME_OR_ID | --subnet NAME_OR_ID') 1635 1636 # retrieve location from resource group 1637 if not location: 1638 resource_client = \ 1639 get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES).resource_groups 1640 resource_group = resource_client.get(rg) 1641 namespace.location = resource_group.location # pylint: disable=no-member 1642 1643 get_network_watcher_from_location( 1644 remove=True, watcher_name='network_watcher_name', rg_name='resource_group_name')(cmd, namespace) 1645 1646 1647def process_nw_packet_capture_create_namespace(cmd, namespace): 1648 from msrestazure.tools import is_valid_resource_id, resource_id 1649 get_network_watcher_from_vm(cmd, namespace) 1650 1651 storage_usage = CLIError('usage error: --storage-account NAME_OR_ID [--storage-path ' 1652 'PATH] [--file-path PATH] | --file-path PATH') 1653 if not namespace.storage_account and not namespace.file_path: 1654 raise storage_usage 1655 1656 if namespace.storage_path and not namespace.storage_account: 1657 raise storage_usage 1658 1659 if not is_valid_resource_id(namespace.vm): 1660 namespace.vm = resource_id( 1661 subscription=get_subscription_id(cmd.cli_ctx), 1662 resource_group=namespace.resource_group_name, 1663 namespace='Microsoft.Compute', 1664 type='virtualMachines', 1665 name=namespace.vm) 1666 1667 if namespace.storage_account and not is_valid_resource_id(namespace.storage_account): 1668 namespace.storage_account = resource_id( 1669 subscription=get_subscription_id(cmd.cli_ctx), 1670 resource_group=namespace.resource_group_name, 1671 namespace='Microsoft.Storage', 1672 type='storageAccounts', 1673 name=namespace.storage_account) 1674 1675 if namespace.file_path: 1676 file_path = namespace.file_path 1677 if not file_path.endswith('.cap'): 1678 raise CLIError("usage error: --file-path PATH must end with the '*.cap' extension") 1679 file_path = file_path.replace('/', '\\') 1680 namespace.file_path = file_path 1681 1682 1683def process_nw_troubleshooting_start_namespace(cmd, namespace): 1684 from msrestazure.tools import is_valid_resource_id, resource_id 1685 storage_usage = CLIError('usage error: --storage-account NAME_OR_ID [--storage-path PATH]') 1686 if namespace.storage_path and not namespace.storage_account: 1687 raise storage_usage 1688 1689 if not is_valid_resource_id(namespace.storage_account): 1690 namespace.storage_account = resource_id( 1691 subscription=get_subscription_id(cmd.cli_ctx), 1692 resource_group=namespace.resource_group_name, 1693 namespace='Microsoft.Storage', 1694 type='storageAccounts', 1695 name=namespace.storage_account) 1696 1697 process_nw_troubleshooting_show_namespace(cmd, namespace) 1698 1699 1700def process_nw_troubleshooting_show_namespace(cmd, namespace): 1701 from msrestazure.tools import is_valid_resource_id, resource_id 1702 resource_usage = CLIError('usage error: --resource ID | --resource NAME --resource-type TYPE ' 1703 '--resource-group NAME') 1704 id_params = [namespace.resource_type, namespace.resource_group_name] 1705 if not is_valid_resource_id(namespace.resource): 1706 if not all(id_params): 1707 raise resource_usage 1708 type_map = { 1709 'vnetGateway': 'virtualNetworkGateways', 1710 'vpnConnection': 'connections' 1711 } 1712 namespace.resource = resource_id( 1713 subscription=get_subscription_id(cmd.cli_ctx), 1714 resource_group=namespace.resource_group_name, 1715 namespace='Microsoft.Network', 1716 type=type_map[namespace.resource_type], 1717 name=namespace.resource) 1718 else: 1719 if any(id_params): 1720 raise resource_usage 1721 1722 get_network_watcher_from_resource(cmd, namespace) 1723 1724 1725def process_nw_config_diagnostic_namespace(cmd, namespace): 1726 from msrestazure.tools import is_valid_resource_id, resource_id 1727 1728 # validate target resource 1729 resource_usage = CLIError('usage error: --resource ID | --resource NAME --resource-type TYPE ' 1730 '--resource-group NAME [--parent PATH]') 1731 1732 # omit --parent since it is optional 1733 id_params = [namespace.resource_type, namespace.resource_group_name] 1734 if not is_valid_resource_id(namespace.resource): 1735 if not all(id_params): 1736 raise resource_usage 1737 # infer resource namespace 1738 NAMESPACES = { 1739 'virtualMachines': 'Microsoft.Compute', 1740 'applicationGateways': 'Microsoft.Network', 1741 'networkInterfaces': 'Microsoft.Network' 1742 } 1743 resource_namespace = NAMESPACES[namespace.resource_type] 1744 if namespace.parent: 1745 # special case for virtualMachineScaleSets/NetworkInterfaces, since it is 1746 # the only one to need `--parent`. 1747 resource_namespace = 'Microsoft.Compute' 1748 namespace.resource = resource_id( 1749 subscription=get_subscription_id(cmd.cli_ctx), 1750 resource_group=namespace.resource_group_name, 1751 namespace=resource_namespace, 1752 type=namespace.resource_type, 1753 parent=namespace.parent, 1754 name=namespace.resource) 1755 elif any(id_params) or namespace.parent: 1756 raise resource_usage 1757 1758 # validate query 1759 query_usage = CLIError('usage error: --queries JSON | --destination DEST --source SRC --direction DIR ' 1760 '--port PORT --protocol PROTOCOL') 1761 query_params = [namespace.destination, namespace.source, namespace.direction, namespace.protocol, 1762 namespace.destination_port] 1763 if namespace.queries: 1764 if any(query_params): 1765 raise query_usage 1766 elif not all(query_params): 1767 raise query_usage 1768 1769 get_network_watcher_from_resource(cmd, namespace) 1770 1771 1772def process_lb_outbound_rule_namespace(cmd, namespace): 1773 from msrestazure.tools import is_valid_resource_id 1774 1775 validate_frontend_ip_configs(cmd, namespace) 1776 1777 if namespace.backend_address_pool: 1778 if not is_valid_resource_id(namespace.backend_address_pool): 1779 namespace.backend_address_pool = _generate_lb_subproperty_id( 1780 cmd.cli_ctx, namespace, 'backendAddressPools', namespace.backend_address_pool) 1781 1782 1783def process_list_delegations_namespace(cmd, namespace): 1784 if not namespace.resource_group_name and not namespace.location: 1785 raise CLIError('usage error: --location LOCATION | --resource-group NAME [--location LOCATION]') 1786 1787 if not namespace.location: 1788 get_default_location_from_resource_group(cmd, namespace) 1789 1790 1791def validate_ag_address_pools(cmd, namespace): 1792 from msrestazure.tools import is_valid_resource_id, resource_id 1793 address_pools = namespace.app_gateway_backend_address_pools 1794 gateway_name = namespace.application_gateway_name 1795 delattr(namespace, 'application_gateway_name') 1796 if not address_pools: 1797 return 1798 ids = [] 1799 for item in address_pools: 1800 if not is_valid_resource_id(item): 1801 if not gateway_name: 1802 raise CLIError('usage error: --app-gateway-backend-pools IDS | --gateway-name NAME ' 1803 '--app-gateway-backend-pools NAMES') 1804 item = resource_id( 1805 subscription=get_subscription_id(cmd.cli_ctx), 1806 resource_group=namespace.resource_group_name, 1807 namespace='Microsoft.Network', 1808 type='applicationGateways', 1809 name=gateway_name, 1810 child_type_1='backendAddressPools', 1811 child_name_1=item) 1812 ids.append(item) 1813 namespace.app_gateway_backend_address_pools = ids 1814 1815 1816def validate_custom_error_pages(namespace): 1817 if not namespace.custom_error_pages: 1818 return 1819 1820 values = [] 1821 for item in namespace.custom_error_pages: 1822 try: 1823 (code, url) = item.split('=') 1824 values.append({'statusCode': code, 'customErrorPageUrl': url}) 1825 except (ValueError, TypeError): 1826 raise CLIError('usage error: --custom-error-pages STATUS_CODE=URL [STATUS_CODE=URL ...]') 1827 namespace.custom_error_pages = values 1828 1829 1830def validate_custom_headers(namespace): 1831 if not namespace.monitor_custom_headers: 1832 return 1833 1834 values = [] 1835 for item in namespace.monitor_custom_headers: 1836 try: 1837 item_split = item.split('=', 1) 1838 values.append({'name': item_split[0], 'value': item_split[1]}) 1839 except IndexError: 1840 raise CLIError('usage error: --custom-headers KEY=VALUE') 1841 1842 namespace.monitor_custom_headers = values 1843 1844 1845def validate_status_code_ranges(namespace): 1846 if not namespace.status_code_ranges: 1847 return 1848 1849 values = [] 1850 for item in namespace.status_code_ranges: 1851 item_split = item.split('-', 1) 1852 usage_error = CLIError('usage error: --status-code-ranges VAL | --status-code-ranges MIN-MAX') 1853 try: 1854 if len(item_split) == 1: 1855 values.append({'min': int(item_split[0]), 'max': int(item_split[0])}) 1856 elif len(item_split) == 2: 1857 values.append({'min': int(item_split[0]), 'max': int(item_split[1])}) 1858 else: 1859 raise usage_error 1860 except ValueError: 1861 raise usage_error 1862 1863 namespace.status_code_ranges = values 1864 1865 1866def validate_subnet_ranges(namespace): 1867 if not namespace.subnets: 1868 return 1869 1870 values = [] 1871 for item in namespace.subnets: 1872 try: 1873 item_split = item.split('-', 1) 1874 if len(item_split) == 2: 1875 values.append({'first': item_split[0], 'last': item_split[1]}) 1876 continue 1877 except ValueError: 1878 pass 1879 1880 try: 1881 item_split = item.split(':', 1) 1882 if len(item_split) == 2: 1883 values.append({'first': item_split[0], 'scope': item_split[1]}) 1884 continue 1885 except ValueError: 1886 pass 1887 1888 values.append({'first': item}) 1889 1890 namespace.subnets = values 1891 1892 1893# pylint: disable=too-few-public-methods 1894class WafConfigExclusionAction(argparse.Action): 1895 def __call__(self, parser, namespace, values, option_string=None): 1896 cmd = namespace._cmd # pylint: disable=protected-access 1897 ApplicationGatewayFirewallExclusion = cmd.get_models('ApplicationGatewayFirewallExclusion') 1898 if not namespace.exclusions: 1899 namespace.exclusions = [] 1900 if isinstance(values, list): 1901 values = ' '.join(values) 1902 try: 1903 variable, op, selector = values.split(' ') 1904 except (ValueError, TypeError): 1905 raise CLIError('usage error: --exclusion VARIABLE OPERATOR VALUE') 1906 namespace.exclusions.append(ApplicationGatewayFirewallExclusion( 1907 match_variable=variable, 1908 selector_match_operator=op, 1909 selector=selector 1910 )) 1911 1912 1913def get_header_configuration_validator(dest): 1914 def validator(namespace): 1915 values = getattr(namespace, dest, None) 1916 if not values: 1917 return 1918 1919 results = [] 1920 for item in values: 1921 key, value = item.split('=', 1) 1922 results.append({ 1923 'header_name': key, 1924 'header_value': value 1925 }) 1926 setattr(namespace, dest, results) 1927 1928 return validator 1929 1930 1931def process_private_link_resource_id_argument(cmd, namespace): 1932 if all([namespace.resource_group_name, 1933 namespace.name, 1934 namespace.resource_provider]): 1935 logger.warning("Resource ID will be ignored since other three arguments have been provided.") 1936 del namespace.id 1937 return 1938 1939 if not (namespace.id or all([namespace.resource_group_name, 1940 namespace.name, 1941 namespace.resource_provider])): 1942 raise CLIError("usage error: --id / -g -n --type") 1943 1944 from msrestazure.tools import is_valid_resource_id, parse_resource_id 1945 if not is_valid_resource_id(namespace.id): 1946 raise CLIError("Resource ID is not invalid. Please check it.") 1947 split_resource_id = parse_resource_id(namespace.id) 1948 cmd.cli_ctx.data['subscription_id'] = split_resource_id['subscription'] 1949 namespace.resource_group_name = split_resource_id['resource_group'] 1950 namespace.name = split_resource_id['name'] 1951 namespace.resource_provider = '{}/{}'.format(split_resource_id['namespace'], split_resource_id['type']) 1952 del namespace.id 1953 1954 1955def process_private_endpoint_connection_id_argument(cmd, namespace): 1956 from azure.cli.core.util import parse_proxy_resource_id 1957 if all([namespace.resource_group_name, 1958 namespace.name, 1959 namespace.resource_provider, 1960 namespace.resource_name]): 1961 logger.warning("Resource ID will be ignored since other three arguments have been provided.") 1962 del namespace.connection_id 1963 return 1964 1965 if not (namespace.connection_id or all([namespace.resource_group_name, 1966 namespace.name, 1967 namespace.resource_provider, 1968 namespace.resource_name])): 1969 raise CLIError("usage error: --id / -g -n --type --resource-name") 1970 1971 result = parse_proxy_resource_id(namespace.connection_id) 1972 cmd.cli_ctx.data['subscription_id'] = result['subscription'] 1973 namespace.resource_group_name = result['resource_group'] 1974 namespace.resource_name = result['name'] 1975 namespace.resource_provider = '{}/{}'.format(result['namespace'], result['type']) 1976 namespace.name = result['child_name_1'] 1977 del namespace.connection_id 1978 1979 1980def process_vnet_name_or_id(cmd, namespace): 1981 from azure.mgmt.core.tools import is_valid_resource_id, resource_id 1982 if namespace.vnet and not is_valid_resource_id(namespace.vnet): 1983 namespace.vnet = resource_id( 1984 subscription=get_subscription_id(cmd.cli_ctx), 1985 resource_group=namespace.resource_group_name, 1986 namespace='Microsoft.Network', 1987 type='virtualNetworks', 1988 name=namespace.vnet) 1989 1990 1991def process_appgw_waf_policy_update(cmd, namespace): # pylint: disable=unused-argument 1992 rule_group_name = namespace.rule_group_name 1993 rules = namespace.rules 1994 1995 if rules is None and rule_group_name is not None: 1996 raise CLIError('--rules and --rule-group-name must be provided at the same time') 1997 if rules is not None and rule_group_name is None: 1998 raise CLIError('--rules and --rule-group-name must be provided at the same time') 1999