Skip to content

Commit ac06e81

Browse files
joshharrinJosh Harrington
andauthored
[ml] NMS workspace managed network outbound rule operations updates (Azure#31663)
* docstrings, set rules, expose rule operations * updates * remove duplicate import * remove duplicate import * fix format complaints * more pylint * fix another pylint --------- Co-authored-by: Josh Harrington <joharrington@microsoft.com>
1 parent 14a864a commit ac06e81

File tree

6 files changed

+7027
-23
lines changed

6 files changed

+7027
-23
lines changed

sdk/ml/azure-ai-ml/azure/ai/ml/_ml_client.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,15 @@ def workspaces(self) -> WorkspaceOperations:
665665
"""
666666
return self._workspaces
667667

668+
@property
669+
def workspace_outbound_rules(self) -> WorkspaceOutboundRuleOperations:
670+
"""A collection of workspace outbound rule related operations.
671+
672+
:return: Workspace outbound rule operations
673+
:rtype: ~azure.ai.ml.operations.WorkspaceOutboundRuleOperations
674+
"""
675+
return self._workspace_outbound_rules
676+
668677
@property
669678
@experimental
670679
def registries(self) -> RegistryOperations:

sdk/ml/azure-ai-ml/azure/ai/ml/entities/_workspace/networking.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from typing import Any, Dict, Optional, List
66

7+
from abc import ABC
78
from azure.ai.ml._restclient.v2023_06_01_preview.models import (
89
ManagedNetworkSettings as RestManagedNetwork,
910
FqdnOutboundRule as RestFqdnOutboundRule,
@@ -18,9 +19,8 @@
1819
from azure.ai.ml._utils._experimental import experimental
1920

2021

21-
@experimental
22-
class OutboundRule:
23-
"""Base class for Outbound Rules, should not be instantiated directly.
22+
class OutboundRule(ABC):
23+
"""Base class for Outbound Rules, cannot be instantiated directly.
2424
2525
:param name: Name of the outbound rule.
2626
:type name: str
@@ -74,6 +74,15 @@ def _from_rest_object(cls, rest_obj: Any, name: str) -> Optional["OutboundRule"]
7474

7575
@experimental
7676
class FqdnDestination(OutboundRule):
77+
"""Class representing a FQDN outbound rule.
78+
79+
:param name: Name of the outbound rule.
80+
:type name: str
81+
:param destination: Fully qualified domain name to which outbound connections are allowed.
82+
For example: “*.contoso.com”.
83+
:type destination: str
84+
"""
85+
7786
def __init__(self, *, name: str, destination: str, **kwargs) -> None:
7887
self.destination = destination
7988
OutboundRule.__init__(self, type=OutboundRuleType.FQDN, name=name, **kwargs)
@@ -93,6 +102,18 @@ def _to_dict(self) -> Dict:
93102

94103
@experimental
95104
class PrivateEndpointDestination(OutboundRule):
105+
"""Class representing a Private Endpoint outbound rule.
106+
107+
:param name: Name of the outbound rule.
108+
:type name: str
109+
:param service_resource_id: The resource URI of the root service that supports creation of the private link.
110+
:type service_resource_id: str
111+
:param subresource_target: The target endpoint of the subresource of the service.
112+
:type subresource_target: str
113+
:param spark_enabled: Indicates if the private endpoint can be used for Spark jobs, default is “false”.
114+
:type spark_enabled: bool
115+
"""
116+
96117
def __init__(
97118
self,
98119
*,
@@ -134,6 +155,19 @@ def _to_dict(self) -> Dict:
134155

135156
@experimental
136157
class ServiceTagDestination(OutboundRule):
158+
"""Class representing a Service Tag outbound rule.
159+
160+
:param name: Name of the outbound rule.
161+
:type name: str
162+
:param service_tag: Service Tag of an Azure service, maps to predefined IP addresses for its service endpoints.
163+
:type service_tag: str
164+
:param protocol: Allowed transport protocol, can be "TCP", "UDP", "ICMP" or "*" for all supported protocols.
165+
:type protocol: str
166+
:param port_ranges: A comma-separated list of single ports and/or range of ports, such as "80,1024-65535".
167+
Traffics should be allowed to these port ranges.
168+
:type port_ranges: str
169+
"""
170+
137171
def __init__(
138172
self,
139173
*,

sdk/ml/azure-ai-ml/azure/ai/ml/operations/_workspace_operations_base.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from azure.ai.ml._version import VERSION
3232
from azure.ai.ml.constants import ManagedServiceIdentityType
3333
from azure.ai.ml.constants._common import ArmConstants, LROConfigurations, WorkspaceResourceConstants
34-
from azure.ai.ml.constants._workspace import IsolationMode
34+
from azure.ai.ml.constants._workspace import IsolationMode, OutboundRuleCategory
3535
from azure.ai.ml.entities import Workspace
3636
from azure.ai.ml.entities._credentials import IdentityConfiguration
3737
from azure.ai.ml.entities._workspace.networking import ManagedNetwork
@@ -264,6 +264,14 @@ def begin_update(
264264
)
265265
)
266266

267+
if workspace.managed_network is not None and workspace.managed_network.outbound_rules is not None:
268+
# drop recommended and required rules from the update request since it would result in bad request
269+
workspace.managed_network.outbound_rules = [
270+
rule
271+
for rule in workspace.managed_network.outbound_rules
272+
if rule.category not in (OutboundRuleCategory.REQUIRED, OutboundRuleCategory.RECOMMENDED)
273+
]
274+
267275
update_role_assignment = (
268276
kwargs.get("update_workspace_role_assignment", None)
269277
or kwargs.get("update_offline_store_role_assignment", None)

sdk/ml/azure-ai-ml/azure/ai/ml/operations/_workspace_outbound_rule_operations.py

Lines changed: 101 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
# ---------------------------------------------------------
44

55
from typing import Dict, Iterable
6-
from azure.ai.ml._restclient.v2023_04_01_preview import AzureMachineLearningWorkspaces as ServiceClient122022Preview
6+
from azure.ai.ml._restclient.v2023_04_01_preview import AzureMachineLearningWorkspaces as ServiceClient042023Preview
7+
from azure.ai.ml._restclient.v2023_04_01_preview.models import OutboundRuleBasicResource
78
from azure.ai.ml._scope_dependent_operations import OperationsContainer, OperationScope
89

910
from azure.ai.ml._telemetry import ActivityType, monitor_with_activity
@@ -18,10 +19,16 @@
1819

1920

2021
class WorkspaceOutboundRuleOperations:
22+
"""WorkspaceOutboundRuleOperations.
23+
24+
You should not instantiate this class directly. Instead, you should create an MLClient instance that instantiates it
25+
for you and attaches it as an attribute.
26+
"""
27+
2128
def __init__(
2229
self,
2330
operation_scope: OperationScope,
24-
service_client: ServiceClient122022Preview,
31+
service_client: ServiceClient042023Preview,
2532
all_operations: OperationsContainer,
2633
credentials: TokenCredential = None,
2734
**kwargs: Dict,
@@ -36,16 +43,92 @@ def __init__(
3643
self._init_kwargs = kwargs
3744

3845
@monitor_with_activity(logger, "WorkspaceOutboundRule.Get", ActivityType.PUBLICAPI)
39-
def get(self, resource_group: str, ws_name: str, outbound_rule_name: str, **kwargs) -> OutboundRule:
40-
workspace_name = self._check_workspace_name(ws_name)
46+
def get(self, workspace_name: str, outbound_rule_name: str, **kwargs) -> OutboundRule:
47+
"""Get a workspace OutboundRule by name.
48+
49+
:param workspace_name: Name of the workspace.
50+
:type workspace_name: str
51+
:param outbound_rule_name: Name of the outbound rule.
52+
:type outbound_rule_name: str
53+
:return: The OutboundRule with the provided name for the workspace.
54+
:rtype: OutboundRule
55+
"""
56+
57+
workspace_name = self._check_workspace_name(workspace_name)
4158
resource_group = kwargs.get("resource_group") or self._resource_group_name
4259

4360
obj = self._rule_operation.get(resource_group, workspace_name, outbound_rule_name)
4461
return OutboundRule._from_rest_object(obj.properties, name=obj.name) # pylint: disable=protected-access
4562

63+
@monitor_with_activity(logger, "WorkspaceOutboundRule.BeginCreate", ActivityType.PUBLICAPI)
64+
def begin_create(self, workspace_name: str, rule: OutboundRule, **kwargs) -> LROPoller[OutboundRule]:
65+
"""Create a Workspace OutboundRule.
66+
67+
:param workspace_name: Name of the workspace.
68+
:type workspace_name: str
69+
:param rule: OutboundRule definition (FqdnDestination, PrivateEndpointDestination, or ServiceTagDestination).
70+
:type rule: OutboundRule
71+
:return: An instance of LROPoller that returns an OutboundRule.
72+
:rtype: ~azure.core.polling.LROPoller[~azure.ai.ml.entities.OutboundRule]
73+
"""
74+
75+
workspace_name = self._check_workspace_name(workspace_name)
76+
resource_group = kwargs.get("resource_group") or self._resource_group_name
77+
78+
rule_params = OutboundRuleBasicResource(properties=rule._to_rest_object()) # pylint: disable=protected-access
79+
80+
# pylint: disable=unused-argument
81+
def callback(_, deserialized, args):
82+
properties = deserialized.properties
83+
name = deserialized.name
84+
return OutboundRule._from_rest_object(properties, name=name) # pylint: disable=protected-access
85+
86+
poller = self._rule_operation.begin_create_or_update(
87+
resource_group, workspace_name, rule.name, rule_params, polling=True, cls=callback
88+
)
89+
module_logger.info("Create request initiated for outbound rule with name: %s\n", rule.name)
90+
return poller
91+
92+
@monitor_with_activity(logger, "WorkspaceOutboundRule.BeginUpdate", ActivityType.PUBLICAPI)
93+
def begin_update(self, workspace_name: str, rule: OutboundRule, **kwargs) -> LROPoller[OutboundRule]:
94+
"""Update a Workspace OutboundRule.
95+
96+
:param workspace_name: Name of the workspace.
97+
:type workspace_name: str
98+
:param rule: OutboundRule definition (FqdnDestination, PrivateEndpointDestination, or ServiceTagDestination).
99+
:type rule: OutboundRule
100+
:return: An instance of LROPoller that returns an OutboundRule.
101+
:rtype: ~azure.core.polling.LROPoller[~azure.ai.ml.entities.OutboundRule]
102+
"""
103+
104+
workspace_name = self._check_workspace_name(workspace_name)
105+
resource_group = kwargs.get("resource_group") or self._resource_group_name
106+
107+
rule_params = OutboundRuleBasicResource(properties=rule._to_rest_object()) # pylint: disable=protected-access
108+
109+
# pylint: disable=unused-argument
110+
def callback(_, deserialized, args):
111+
properties = deserialized.properties
112+
name = deserialized.name
113+
return OutboundRule._from_rest_object(properties, name=name) # pylint: disable=protected-access
114+
115+
poller = self._rule_operation.begin_create_or_update(
116+
resource_group, workspace_name, rule.name, rule_params, polling=True, cls=callback
117+
)
118+
module_logger.info("Update request initiated for outbound rule with name: %s\n", rule.name)
119+
return poller
120+
46121
@monitor_with_activity(logger, "WorkspaceOutboundRule.List", ActivityType.PUBLICAPI)
47-
def list(self, resource_group: str, ws_name: str, **kwargs) -> Iterable[OutboundRule]:
48-
workspace_name = self._check_workspace_name(ws_name)
122+
def list(self, workspace_name: str, **kwargs) -> Iterable[OutboundRule]:
123+
"""List Workspace OutboundRules.
124+
125+
:param workspace_name: Name of the workspace.
126+
:type workspace_name: str
127+
:return: An Iterable of OutboundRule.
128+
:rtype: Iterable[OutboundRule]
129+
"""
130+
131+
workspace_name = self._check_workspace_name(workspace_name)
49132
resource_group = kwargs.get("resource_group") or self._resource_group_name
50133

51134
rest_rules = self._rule_operation.list(resource_group, workspace_name)
@@ -57,8 +140,18 @@ def list(self, resource_group: str, ws_name: str, **kwargs) -> Iterable[Outbound
57140
return result
58141

59142
@monitor_with_activity(logger, "WorkspaceOutboundRule.Remove", ActivityType.PUBLICAPI)
60-
def begin_remove(self, resource_group: str, ws_name: str, outbound_rule_name: str, **kwargs) -> LROPoller[None]:
61-
workspace_name = self._check_workspace_name(ws_name)
143+
def begin_remove(self, workspace_name: str, outbound_rule_name: str, **kwargs) -> LROPoller[None]:
144+
"""Remove a Workspace OutboundRule.
145+
146+
:param workspace_name: Name of the workspace.
147+
:type workspace_name: str
148+
:param outbound_rule_name: Name of the outbound rule to remove.
149+
:type outbound_rule_name: str
150+
:return: An Iterable of OutboundRule.
151+
:rtype: Iterable[OutboundRule]
152+
"""
153+
154+
workspace_name = self._check_workspace_name(workspace_name)
62155
resource_group = kwargs.get("resource_group") or self._resource_group_name
63156

64157
poller = self._rule_operation.begin_delete(

0 commit comments

Comments
 (0)