Skip to content

Commit 4e8df49

Browse files
author
Jacques Zhang
committed
add support for bastion developer create
1 parent cef77fd commit 4e8df49

File tree

2 files changed

+107
-30
lines changed

2 files changed

+107
-30
lines changed

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

Lines changed: 85 additions & 25 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 '[{"addressPrefix":"1.1.1.1/16"},{"addressPrefix":"100.64.0.0/10"}]'
2534
"""
2635

2736
_aaz_info = {
@@ -48,15 +57,21 @@ def _build_arguments_schema(cls, *args, **kwargs):
4857
# define Arg Group ""
4958

5059
_args_schema = cls._args_schema
51-
_args_schema.name = AAZStrArg(
52-
options=["-n", "--name"],
60+
_args_schema.bastion_host_name = AAZStrArg(
61+
options=["-n", "--name", "--bastion-host-name"],
5362
help="The name of the Bastion Host.",
5463
required=True,
5564
)
5665
_args_schema.resource_group = AAZResourceGroupNameArg(
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

@@ -102,7 +110,7 @@ def _build_arguments_schema(cls, *args, **kwargs):
102110
help="Enable/Disable Copy/Paste feature of the Bastion Host resource.",
103111
default=False,
104112
)
105-
_args_schema.enable_file_copy = AAZBoolArg(
113+
_args_schema.file_copy = AAZBoolArg(
106114
options=["--file-copy"],
107115
arg_group="Properties",
108116
help="Enable/Disable File Copy feature of the Bastion Host resource.",
@@ -114,19 +122,19 @@ def _build_arguments_schema(cls, *args, **kwargs):
114122
help="Enable/Disable IP Connect feature of the Bastion Host resource.",
115123
default=False,
116124
)
117-
_args_schema.enable_kerberos = AAZBoolArg(
125+
_args_schema.kerberos = AAZBoolArg(
118126
options=["--kerberos"],
119127
arg_group="Properties",
120128
help="Enable/Disable Kerberos feature of the Bastion Host resource.",
121129
default=False,
122130
)
123-
_args_schema.enable_session_recording = AAZBoolArg(
131+
_args_schema.session_recording = AAZBoolArg(
124132
options=["--session-recording"],
125133
arg_group="Properties",
126134
help="Enable/Disable Session Recording feature of the Bastion Host resource.",
127135
default=False,
128136
)
129-
_args_schema.enable_shareable_link = AAZBoolArg(
137+
_args_schema.shareable_link = AAZBoolArg(
130138
options=["--shareable-link"],
131139
arg_group="Properties",
132140
help="Enable/Disable Shareable Link of the Bastion Host resource.",
@@ -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_ips = AAZListArg(
155+
options=["--network-acls-ips"],
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_ips = cls._args_schema.network_acls_ips
205+
network_acls_ips.Element = AAZObjectArg()
206+
207+
_element = cls._args_schema.network_acls_ips.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
@@ -265,7 +292,7 @@ def error_format(self):
265292
def url_parameters(self):
266293
parameters = {
267294
**self.serialize_url_param(
268-
"bastionHostName", self.ctx.args.name,
295+
"bastionHostName", self.ctx.args.bastion_host_name,
269296
required=True,
270297
),
271298
**self.serialize_url_param(
@@ -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, ".file_copy")
352+
properties.set_prop("enableIpConnect", AAZBoolType, ".enable_ip_connect")
353+
properties.set_prop("enableKerberos", AAZBoolType, ".kerberos")
354+
properties.set_prop("enableSessionRecording", AAZBoolType, ".session_recording")
355+
properties.set_prop("enableShareableLink", AAZBoolType, ".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_ips")
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: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import time
1717
import json
1818
import uuid
19+
import re
1920

2021
import requests
2122
from azure.cli.core.azclierror import ValidationError, InvalidArgumentValueError, RequiredArgumentMissingError, \
@@ -38,26 +39,37 @@ def _build_arguments_schema(cls, *args, **kwargs):
3839
# custom arguments
3940
args_schema.public_ip_address = AAZResourceIdArg(
4041
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,
42+
help="[Required for all SKUs but Developer SKU] " +
43+
"Name or Resource ID of the Public IP. The SKU of the public IP must be Standard.",
44+
required=False,
4345
fmt=AAZResourceIdArgFormat(
4446
template="/subscriptions/{subscription}/resourceGroups/{resource_group}/providers/Microsoft.Network"
4547
"/publicIPAddresses/{}",
4648
),
4749
)
4850
args_schema.vnet_name = AAZStrArg(
4951
options=["--vnet-name"],
50-
help="Name of the virtual network. It must have a subnet called AzureBastionSubnet",
52+
help="Name or Resource ID of the Virtual Network. " +
53+
"For all SKUs but Developer SKU, this virtual network must have a subnet called AzureBastionSubnet.",
5154
required=True,
5255
)
5356
# filter arguments
5457
args_schema.ip_configurations._registered = False
58+
args_schema.virtual_network._registered = False
5559
return args_schema
5660

5761
def pre_operations(self):
5862
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"
63+
64+
pattern = r"^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\.Network/virtualNetworks/[^/]+$"
65+
vnet_id = ""
66+
if re.match(pattern, str(args.vnet_name)):
67+
vnet_id = args.vnet_name
68+
else:
69+
vnet_id = f"/subscriptions/{self.ctx.subscription_id}/resourceGroups/{args.resource_group}" \
70+
f"/providers/Microsoft.Network/virtualNetworks/{args.vnet_name}"
71+
72+
subnet_id = f"{vnet_id}/subnets/AzureBastionSubnet"
6173
args.ip_configurations = [{
6274
"name": "bastion_ip_config",
6375
"subnet": {"id": subnet_id}
@@ -66,6 +78,11 @@ def pre_operations(self):
6678
if args.public_ip_address is not None:
6779
args.ip_configurations[0]['public_ip_address'] = {"id": args.public_ip_address}
6880

81+
if args.vnet_name is not None:
82+
args.virtual_network = {
83+
"id": vnet_id
84+
}
85+
6986

7087
SSH_EXTENSION_NAME = "ssh"
7188
SSH_EXTENSION_MODULE = "azext_ssh.custom"

0 commit comments

Comments
 (0)