Skip to content

Commit d2c93aa

Browse files
zhangjacqJacques Zhang
andauthored
add support for bastion developer create (#8366)
* add support for bastion developer create * space-separated ip addresses for network acls * add history * features vars naming * check fix * re-record tests * attempt to fix api-version for vnet PUT * update recording --------- Co-authored-by: Jacques Zhang <[email protected]>
1 parent ba3e6c7 commit d2c93aa

File tree

6 files changed

+1392
-769
lines changed

6 files changed

+1392
-769
lines changed

src/bastion/HISTORY.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
33
Release History
44
===============
5+
1.4.0
6+
++++++
7+
* Add support for bastion developer create.
8+
59
1.3.1
610
++++++
711
* Remove dependency on msazurerest.

src/bastion/azext_bastion/aaz/latest/network/bastion/_create.py

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,17 @@ class Create(AAZCommand):
2020
:example: Create a Azure Bastion host machine.
2121
az network bastion create --location westus2 --name MyBastionHost --public-ip-address MyPublicIpAddress --resource-group MyResourceGroup --vnet-name MyVnet
2222
23-
:example: Create a Azure Bastion host machine with zones.
23+
:example: Create Bastion Host With Zones
2424
az network bastion create --location westus2 --name MyBastionHost --public-ip-address MyPublicIpAddress --resource-group MyResourceGroup --vnet-name MyVnet --zones 1 2 3
25+
26+
:example: Create Bastion Host with Session Recording.
27+
az network bastion create --location westus2 --name MyBastionHost --public-ip-address MyPublicIpAddress --resource-group MyResourceGroup --vnet-name MyVnet --zones 1 2 3 --sku Premium --session-recording
28+
29+
:example: Create Developer SKU Bastion
30+
az network bastion create --name MyBastion --resource-group MyResourceGroup --sku Developer --vnet-name MyVnet
31+
32+
:example: Create Developer SKU Bastion with Network ACLs IP rules
33+
az network bastion create --name MyBastion --resource-group MyResourceGroup --sku Developer --vnet-name MyVnet --network-acls-ips "1.1.1.1/16 100.64.0.0/10"
2534
"""
2635

2736
_aaz_info = {
@@ -57,6 +66,12 @@ def _build_arguments_schema(cls, *args, **kwargs):
5766
help="Resource group name of the Bastion Host.",
5867
required=True,
5968
)
69+
_args_schema.sku = AAZStrArg(
70+
options=["--sku"],
71+
help="The name of the sku of this Bastion Host.",
72+
default="Standard",
73+
enum={"Basic": "Basic", "Developer": "Developer", "Premium": "Premium", "Standard": "Standard"},
74+
)
6075

6176
# define Arg Group "Parameters"
6277

@@ -68,25 +83,18 @@ def _build_arguments_schema(cls, *args, **kwargs):
6883
resource_group_arg="resource_group",
6984
),
7085
)
71-
7286
_args_schema.tags = AAZDictArg(
7387
options=["--tags"],
7488
arg_group="Parameters",
7589
help="Resource tags.",
90+
default={},
7691
)
7792
_args_schema.zones = AAZListArg(
7893
options=["--zones"],
7994
arg_group="Parameters",
8095
help="A list of availability zones denoting where the resource needs to come from.",
8196
)
8297

83-
_args_schema.sku = AAZStrArg(
84-
options=["--sku"],
85-
help="Sku of this Bastion Host.",
86-
default="Standard",
87-
enum={"Basic": "Basic", "Premium": "Premium", "Standard": "Standard"},
88-
)
89-
9098
tags = cls._args_schema.tags
9199
tags.Element = AAZStrArg()
92100

@@ -143,6 +151,11 @@ def _build_arguments_schema(cls, *args, **kwargs):
143151
arg_group="Properties",
144152
help="IP configuration of the Bastion Host resource.",
145153
)
154+
_args_schema.network_acls = AAZListArg(
155+
options=["--network-acls"],
156+
arg_group="Properties",
157+
help="[Supported in Developer SKU only] The Network ACLs IP rules.",
158+
)
146159
_args_schema.scale_units = AAZIntArg(
147160
options=["--scale-units"],
148161
arg_group="Properties",
@@ -153,6 +166,12 @@ def _build_arguments_schema(cls, *args, **kwargs):
153166
minimum=2,
154167
),
155168
)
169+
_args_schema.virtual_network = AAZObjectArg(
170+
options=["--virtual-network"],
171+
arg_group="Properties",
172+
help="Reference to an existing virtual network required for Developer Bastion Host only.",
173+
)
174+
cls._build_args_sub_resource_create(_args_schema.virtual_network)
156175

157176
ip_configurations = cls._args_schema.ip_configurations
158177
ip_configurations.Element = AAZObjectArg()
@@ -182,6 +201,14 @@ def _build_arguments_schema(cls, *args, **kwargs):
182201
)
183202
cls._build_args_sub_resource_create(_element.subnet)
184203

204+
network_acls = cls._args_schema.network_acls
205+
network_acls.Element = AAZObjectArg()
206+
207+
_element = cls._args_schema.network_acls.Element
208+
_element.address_prefix = AAZStrArg(
209+
options=["address-prefix"],
210+
help="Specifies the IP or IP range in CIDR format. Only IPV4 address is allowed.",
211+
)
185212
return cls._args_schema
186213

187214
_args_sub_resource_create = None
@@ -316,15 +343,19 @@ def content(self):
316343

317344
properties = _builder.get(".properties")
318345
if properties is not None:
319-
properties.set_prop("disableCopyPaste", AAZBoolType, ".disable_copy_paste")
320-
properties.set_prop("enableFileCopy", AAZBoolType, ".enable_file_copy")
321-
properties.set_prop("enableIpConnect", AAZBoolType, ".enable_ip_connect")
322-
properties.set_prop("enableKerberos", AAZBoolType, ".enable_kerberos")
323-
properties.set_prop("enableSessionRecording", AAZBoolType, ".enable_session_recording")
324-
properties.set_prop("enableShareableLink", AAZBoolType, ".enable_shareable_link")
325-
properties.set_prop("enableTunneling", AAZBoolType, ".enable_tunneling")
326-
properties.set_prop("ipConfigurations", AAZListType, ".ip_configurations")
327-
properties.set_prop("scaleUnits", AAZIntType, ".scale_units")
346+
if (self.ctx.args.sku == "Developer"):
347+
properties.set_prop("networkAcls", AAZObjectType)
348+
_CreateHelper._build_schema_sub_resource_create(properties.set_prop("virtualNetwork", AAZObjectType, ".virtual_network"))
349+
else:
350+
properties.set_prop("disableCopyPaste", AAZBoolType, ".disable_copy_paste")
351+
properties.set_prop("enableFileCopy", AAZBoolType, ".enable_file_copy")
352+
properties.set_prop("enableIpConnect", AAZBoolType, ".enable_ip_connect")
353+
properties.set_prop("enableKerberos", AAZBoolType, ".enable_kerberos")
354+
properties.set_prop("enableSessionRecording", AAZBoolType, ".enable_session_recording")
355+
properties.set_prop("enableShareableLink", AAZBoolType, ".enable_shareable_link")
356+
properties.set_prop("enableTunneling", AAZBoolType, ".enable_tunneling")
357+
properties.set_prop("ipConfigurations", AAZListType, ".ip_configurations")
358+
properties.set_prop("scaleUnits", AAZIntType, ".scale_units")
328359

329360
ip_configurations = _builder.get(".properties.ipConfigurations")
330361
if ip_configurations is not None:
@@ -342,6 +373,18 @@ def content(self):
342373
_CreateHelper._build_schema_sub_resource_create(properties.set_prop("publicIPAddress", AAZObjectType, ".public_ip_address", typ_kwargs={"flags": {"required": True}}))
343374
_CreateHelper._build_schema_sub_resource_create(properties.set_prop("subnet", AAZObjectType, ".subnet", typ_kwargs={"flags": {"required": True}}))
344375

376+
network_acls = _builder.get(".properties.networkAcls")
377+
if network_acls is not None:
378+
network_acls.set_prop("ipRules", AAZListType, ".network_acls")
379+
380+
ip_rules = _builder.get(".properties.networkAcls.ipRules")
381+
if ip_rules is not None:
382+
ip_rules.set_elements(AAZObjectType, ".")
383+
384+
_elements = _builder.get(".properties.networkAcls.ipRules[]")
385+
if _elements is not None:
386+
_elements.set_prop("addressPrefix", AAZStrType, ".address_prefix")
387+
345388
sku = _builder.get(".sku")
346389
if sku is not None:
347390
sku.set_prop("name", AAZStrType, ".sku")
@@ -420,6 +463,9 @@ def _build_schema_on_200_201(cls):
420463
properties.ip_configurations = AAZListType(
421464
serialized_name="ipConfigurations",
422465
)
466+
properties.network_acls = AAZObjectType(
467+
serialized_name="networkAcls",
468+
)
423469
properties.provisioning_state = AAZStrType(
424470
serialized_name="provisioningState",
425471
flags={"read_only": True},
@@ -465,6 +511,20 @@ def _build_schema_on_200_201(cls):
465511
flags={"required": True},
466512
)
467513
_CreateHelper._build_schema_sub_resource_read(properties.subnet)
514+
515+
network_acls = cls._schema_on_200_201.properties.network_acls
516+
network_acls.ip_rules = AAZListType(
517+
serialized_name="ipRules",
518+
)
519+
520+
ip_rules = cls._schema_on_200_201.properties.network_acls.ip_rules
521+
ip_rules.Element = AAZObjectType()
522+
523+
_element = cls._schema_on_200_201.properties.network_acls.ip_rules.Element
524+
_element.address_prefix = AAZStrType(
525+
serialized_name="addressPrefix",
526+
)
527+
468528
sku = cls._schema_on_200_201.sku
469529
sku.name = AAZStrType()
470530

src/bastion/azext_bastion/custom.py

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
import time
1717
import json
1818
import uuid
19+
import re
1920

2021
import requests
22+
from azure.cli.core.aaz import AAZUndefined
2123
from azure.cli.core.azclierror import ValidationError, InvalidArgumentValueError, RequiredArgumentMissingError, \
2224
UnrecognizedArgumentError, CLIInternalError, ClientRequestError
2325
from azure.cli.core.commands.client_factory import get_subscription_id
@@ -38,26 +40,44 @@ def _build_arguments_schema(cls, *args, **kwargs):
3840
# custom arguments
3941
args_schema.public_ip_address = AAZResourceIdArg(
4042
options=["--public-ip-address"],
41-
help="Name or ID of Azure Public IP. The SKU of the public IP must be Standard.",
42-
required=True,
43+
help="[Required for all SKUs but Developer SKU] " +
44+
"Name or Resource ID of the Public IP. The SKU of the public IP must be Standard.",
45+
required=False,
4346
fmt=AAZResourceIdArgFormat(
4447
template="/subscriptions/{subscription}/resourceGroups/{resource_group}/providers/Microsoft.Network"
4548
"/publicIPAddresses/{}",
4649
),
4750
)
4851
args_schema.vnet_name = AAZStrArg(
4952
options=["--vnet-name"],
50-
help="Name of the virtual network. It must have a subnet called AzureBastionSubnet",
53+
help="Name or Resource ID of the Virtual Network. " +
54+
"For all SKUs but Developer SKU, this virtual network must have a subnet called AzureBastionSubnet.",
5155
required=True,
5256
)
57+
args_schema.network_acls_ips = AAZStrArg(
58+
options=["--network-acls-ips"],
59+
arg_group="Properties",
60+
help="[Supported in Developer SKU only] Network ACLs IP rules. Space-separated list of IP addresses.",
61+
required=False,
62+
)
5363
# filter arguments
5464
args_schema.ip_configurations._registered = False
65+
args_schema.virtual_network._registered = False
66+
args_schema.network_acls._registered = False
5567
return args_schema
5668

5769
def pre_operations(self):
5870
args = self.ctx.args
59-
subnet_id = f"/subscriptions/{self.ctx.subscription_id}/resourceGroups/{args.resource_group}" \
60-
f"/providers/Microsoft.Network/virtualNetworks/{args.vnet_name}/subnets/AzureBastionSubnet"
71+
72+
pattern = r"^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\.Network/virtualNetworks/[^/]+$"
73+
vnet_id = ""
74+
if re.match(pattern, str(args.vnet_name)):
75+
vnet_id = args.vnet_name
76+
else:
77+
vnet_id = f"/subscriptions/{self.ctx.subscription_id}/resourceGroups/{args.resource_group}" \
78+
f"/providers/Microsoft.Network/virtualNetworks/{args.vnet_name}"
79+
80+
subnet_id = f"{vnet_id}/subnets/AzureBastionSubnet"
6181
args.ip_configurations = [{
6282
"name": "bastion_ip_config",
6383
"subnet": {"id": subnet_id}
@@ -66,6 +86,15 @@ def pre_operations(self):
6686
if args.public_ip_address is not None:
6787
args.ip_configurations[0]['public_ip_address'] = {"id": args.public_ip_address}
6888

89+
if args.vnet_name is not None:
90+
args.virtual_network = {
91+
"id": vnet_id
92+
}
93+
94+
if args.network_acls_ips != AAZUndefined:
95+
addresses = str(args.network_acls_ips).split()
96+
args.network_acls = [{"addressPrefix": address} for address in addresses]
97+
6998

7099
SSH_EXTENSION_NAME = "ssh"
71100
SSH_EXTENSION_MODULE = "azext_ssh.custom"

0 commit comments

Comments
 (0)