Skip to content
This repository was archived by the owner on May 13, 2025. It is now read-only.

Commit bd56e41

Browse files
NarayanThirujonathan-innisnreischyuyue9284Yue Yu
authored
Extensions GA changes into Public Branch (#79)
* Add openservicemesh back * OpenServiceMesh import * Update osm with new extension model * Add back private file * Add Azure ML to list of private extensions (#16) * Update k8s-custom-pipelines.yml * Add Microsoft.PolicyInsights extension (#17) * Add Policy extension * Update comment * Update args * Fix linting errors Co-authored-by: Jonathan Innis <[email protected]> * Add HISTORY_private file for private preview * Change versioning scheme * Update the code for supporting both extensions at once * Fix style issue * Remove old consts file * change the resource tag from managed_by:amlk8s to created_by:amlk8s-e… (#22) * change the resource tag from managed_by:amlk8s to created_by:amlk8s-extension * remove the lock when creating resources * fix lint * update version and HISTORY_private.rst * change error message Co-authored-by: Yue Yu <[email protected]> * Update the beta version with upstream * Update the private history file * Add upgrade pip to pipeline * Move pip install within virtualenv * Merge in k8s-extension/public (0.3.1) (#32) * delete resurce in testcase (#29) Co-authored-by: Yue Yu <[email protected]> Co-authored-by: Jonathan Innis <[email protected]> * Check Provider is Registered with Subscription Before Making Requests (#18) * Add check for KubernetesConfiguration * Disable pylint and rename * Update provider registration link * Update version * Remove extra blank line * Fix bug in import * only validate scoring fe when inference is enabled (#31) * only validate scoring fe when inference is enabled * Fix versioning Co-authored-by: Yue Yu <[email protected]> Co-authored-by: jonathan-innis <[email protected]> * Update private release Co-authored-by: yuyue9284 <[email protected]> Co-authored-by: Yue Yu <[email protected]> * Release Version 0.4.0-b1 (#37) * Merge k8s-extension/public into k8s-extension/private * Update the version * Fix testing concurrency * K8s extension/private 0.4.0b2 (#41) * Fix private build (#40) * Update version * Upgrade to v0.5.2 * Fix policy bug * Increase private version * Update consts_private.py * Increase private version * Increase version with public * Add flux to private version * Update models for 2021-05-01-preview * Add async models to version * Add no wait to delete and create * support managed cluster * Bump version * Pin helm version * Add cmd to delete call * Add force deletion * add dapr extension (#78) Signed-off-by: Ji An Liu <[email protected]> * Fix failing integration tests * Adding the GA changes for private branch * Fix confirm prompt * Fix update E2E tests Co-authored-by: jonathan-innis <[email protected]> Co-authored-by: [email protected] <Action - Fork Sync> Co-authored-by: nreisch <[email protected]> Co-authored-by: yuyue9284 <[email protected]> Co-authored-by: Yue Yu <[email protected]> Co-authored-by: anagg929 <[email protected]> Co-authored-by: Ji'an Liu <[email protected]> Co-authored-by: nanthi <nanthi@NANTHI01>
1 parent f721c84 commit bd56e41

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+3906
-1752
lines changed

src/k8s-extension/HISTORY.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
Release History
44
===============
55

6+
1.0.0
7+
++++++++++++++++++
8+
* Switch to GA api-version of Extensions (2021-09-01)
9+
* Support Extensions PATCH
10+
* Enable Dapr extension type
11+
* Enable ManagedClusters clusterType
12+
613
0.7.1
714
++++++++++++++++++
815
* Fix DF resource manager endpoint check

src/k8s-extension/README.rst

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,18 @@ az k8s-extension list \
5656
--cluster-type clusterType
5757
```
5858

59-
If you have issues, please give feedback by opening an issue at https://github.com/Azure/azure-cli-extensions/issues.
59+
##### Update an existing KubernetesExtension of a cluster
60+
```
61+
az k8s-extension update \
62+
--resource-group groupName \
63+
--cluster-name clusterName \
64+
--cluster-type clusterType \
65+
--name extensionName \
66+
--auto-upgrade true/false \
67+
--version extensionVersion \
68+
--release-train releaseTrain \
69+
--configuration-settings settingsKey=settingsValue \
70+
--configuration-protected-settings protectedSettingsKey=protectedValue \
71+
--configuration-settings-file configSettingsFile \
72+
--configuration-protected-settings-file protectedSettingsFile
73+
```

src/k8s-extension/azext_k8s_extension/_format.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ def k8s_extension_show_table_format(result):
1717
def __get_table_row(result):
1818
return OrderedDict([
1919
('name', result['name']),
20-
('extensionType', result['extensionType']),
21-
('version', result['version']),
22-
('installState', result['installState']),
23-
('lastModifiedTime', result['lastModifiedTime'])
20+
('extensionType', result.get('extensionType', '')),
21+
('version', result.get('version', '')),
22+
('provisioningState', result.get('provisioningState', '')),
23+
('lastModifiedAt', result.get('systemData', {}).get('lastModifiedAt', '')),
2424
])

src/k8s-extension/azext_k8s_extension/_help.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@
1919
examples:
2020
- name: Create a Kubernetes Extension
2121
text: |-
22-
az {consts.EXTENSION_NAME} create --resource-group my-resource-group \\
23-
--cluster-name mycluster --cluster-type connectedClusters \\
24-
--name myextension --extension-type microsoft.openservicemesh \\
25-
--scope cluster --release-train stable
22+
az {consts.EXTENSION_NAME} create --resource-group my-resource-group \
23+
--cluster-name mycluster --cluster-type connectedClusters --name myextension \
24+
--extension-type microsoft.openservicemesh --scope cluster --release-train stable
2625
"""
2726

2827
helps[f'{consts.EXTENSION_NAME} list'] = f"""
@@ -31,8 +30,8 @@
3130
examples:
3231
- name: List all Kubernetes Extensions on a cluster
3332
text: |-
34-
az {consts.EXTENSION_NAME} list --resource-group my-resource-group \\
35-
--cluster-name mycluster --cluster-type connectedClusters
33+
az {consts.EXTENSION_NAME} list --resource-group my-resource-group \
34+
--cluster-name mycluster --cluster-type connectedClusters
3635
"""
3736

3837
helps[f'{consts.EXTENSION_NAME} delete'] = f"""
@@ -41,8 +40,8 @@
4140
examples:
4241
- name: Delete an existing Kubernetes Extension
4342
text: |-
44-
az {consts.EXTENSION_NAME} delete --resource-group my-resource-group \\
45-
--cluster-name mycluster --cluster-type connectedClusters --name myextension
43+
az {consts.EXTENSION_NAME} delete --resource-group my-resource-group \
44+
--cluster-name mycluster --cluster-type connectedClusters --name myextension
4645
"""
4746

4847
helps[f'{consts.EXTENSION_NAME} show'] = f"""
@@ -51,6 +50,24 @@
5150
examples:
5251
- name: Show details of a Kubernetes Extension
5352
text: |-
54-
az {consts.EXTENSION_NAME} show --resource-group my-resource-group \\
55-
--cluster-name mycluster --cluster-type connectedClusters --name myextension
53+
az {consts.EXTENSION_NAME} show --resource-group my-resource-group \
54+
--cluster-name mycluster --cluster-type connectedClusters --name myextension
55+
"""
56+
57+
helps[f'{consts.EXTENSION_NAME} update'] = f"""
58+
type: command
59+
short-summary: Update mutable properties of a Kubernetes Extension.
60+
long-summary: For update to ConfigSettings and ConfigProtectedSettings, please \
61+
refer to documentation of the cluster extension service to check update to these \
62+
properties is supported before updating these properties.
63+
examples:
64+
- name: Update a Kubernetes Extension
65+
text: |-
66+
az {consts.EXTENSION_NAME} update --resource-group my-resource-group \
67+
--cluster-name mycluster --cluster-type connectedClusters \
68+
--name myextension --auto-upgrade true/false --version extension-version \
69+
--release-train stable --configuration-settings settings-key=settings-value \
70+
--configuration-protected-settings protected-settings-key=protected-value \
71+
--configuration-settings-file=config-settings-file \
72+
--configuration-protected-settings-file=protected-settings-file
5673
"""

src/k8s-extension/azext_k8s_extension/_params.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55

66
from azure.cli.core.commands.parameters import (
77
get_enum_type,
8-
get_three_state_flag,
9-
tags_type
8+
get_three_state_flag
109
)
1110
from azure.cli.core.commands.validators import get_default_location_from_resource_group
1211
from . import consts
@@ -19,7 +18,6 @@
1918

2019
def load_arguments(self, _):
2120
with self.argument_context(consts.EXTENSION_NAME) as c:
22-
c.argument('tags', tags_type)
2321
c.argument('location',
2422
validator=get_default_location_from_resource_group)
2523
c.argument('name',
@@ -75,7 +73,14 @@ def load_arguments(self, _):
7573
help='Specify the target namespace to install to for the extension instance. This'
7674
' parameter is required if extension scope is set to \'namespace\'')
7775

76+
with self.argument_context(f"{consts.EXTENSION_NAME} update") as c:
77+
c.argument('yes',
78+
options_list=['--yes', '-y'],
79+
help='Ignore confirmation prompts')
80+
7881
with self.argument_context(f"{consts.EXTENSION_NAME} delete") as c:
7982
c.argument('yes',
8083
options_list=['--yes', '-y'],
8184
help='Ignore confirmation prompts')
85+
c.argument('force',
86+
help='Specify whether to force delete the extension from the cluster.')
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
{
2-
"azext.isPreview": true,
32
"azext.minCliCoreVersion": "2.24.0"
43
}

src/k8s-extension/azext_k8s_extension/commands.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ def load_command_table(self, _):
1616
operations_tmpl=consts.EXTENSION_PACKAGE_NAME + '.vendored_sdks.operations#K8sExtensionsOperations.{}',
1717
client_factory=cf_k8s_extension)
1818

19-
with self.command_group(consts.EXTENSION_NAME, k8s_extension_sdk, client_factory=cf_k8s_extension_operation,
20-
is_preview=True) \
19+
with self.command_group(consts.EXTENSION_NAME, k8s_extension_sdk, client_factory=cf_k8s_extension_operation) \
2120
as g:
22-
g.custom_command('create', 'create_k8s_extension')
23-
g.custom_command('delete', 'delete_k8s_extension')
21+
g.custom_command('create', 'create_k8s_extension', supports_no_wait=True)
22+
g.custom_command('delete', 'delete_k8s_extension', supports_no_wait=True)
2423
g.custom_command('list', 'list_k8s_extension', table_transformer=k8s_extension_list_table_format)
2524
g.custom_show_command('show', 'show_k8s_extension', table_transformer=k8s_extension_show_table_format)
25+
g.custom_command('update', 'update_k8s_extension', supports_no_wait=True)

src/k8s-extension/azext_k8s_extension/custom.py

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,23 @@
66
# pylint: disable=unused-argument,too-many-locals
77

88
import json
9-
from knack.log import get_logger
109
from urllib.parse import urlparse
10+
from knack.log import get_logger
1111

1212
from azure.cli.core.azclierror import ResourceNotFoundError, MutuallyExclusiveArgumentError, \
13-
InvalidArgumentValueError, CommandNotFoundError, RequiredArgumentMissingError
13+
InvalidArgumentValueError, RequiredArgumentMissingError
1414
from azure.cli.core.commands.client_factory import get_subscription_id
15+
from azure.cli.core.util import sdk_no_wait
1516
from azure.core.exceptions import HttpResponseError
16-
from .vendored_sdks.models import ConfigurationIdentity, Scope
17+
from .vendored_sdks.models import Identity, Scope
1718
from ._validators import validate_cc_registration
1819

1920
from .partner_extensions.ContainerInsights import ContainerInsights
2021
from .partner_extensions.AzureDefender import AzureDefender
21-
from .partner_extensions.AzureMLKubernetes import AzureMLKubernetes
2222
from .partner_extensions.OpenServiceMesh import OpenServiceMesh
23-
from .partner_extensions.DefaultExtension import DefaultExtension
23+
from .partner_extensions.AzureMLKubernetes import AzureMLKubernetes
24+
from .partner_extensions.Dapr import Dapr
25+
from .partner_extensions.DefaultExtension import DefaultExtension, user_confirmation_factory
2426
from . import consts
2527

2628
from ._client_factory import cf_resources
@@ -35,6 +37,7 @@ def ExtensionFactory(extension_name):
3537
'microsoft.azuredefender.kubernetes': AzureDefender,
3638
'microsoft.openservicemesh': OpenServiceMesh,
3739
'microsoft.azureml.kubernetes': AzureMLKubernetes,
40+
'microsoft.dapr': Dapr,
3841
}
3942

4043
# Return the extension if we find it in the map, else return the default
@@ -43,7 +46,6 @@ def ExtensionFactory(extension_name):
4346

4447
def show_k8s_extension(client, resource_group_name, cluster_name, name, cluster_type):
4548
"""Get an existing K8s Extension.
46-
4749
"""
4850
# Determine ClusterRP
4951
cluster_rp = __get_cluster_rp(cluster_type)
@@ -74,9 +76,8 @@ def create_k8s_extension(cmd, client, resource_group_name, cluster_name, name, c
7476
extension_type, scope=None, auto_upgrade_minor_version=None, release_train=None,
7577
version=None, target_namespace=None, release_namespace=None, configuration_settings=None,
7678
configuration_protected_settings=None, configuration_settings_file=None,
77-
configuration_protected_settings_file=None, tags=None):
79+
configuration_protected_settings_file=None, no_wait=False):
7880
"""Create a new Extension Instance.
79-
8081
"""
8182

8283
extension_type_lower = extension_type.lower()
@@ -140,60 +141,75 @@ def create_k8s_extension(cmd, client, resource_group_name, cluster_name, name, c
140141
# Create identity, if required
141142
# We don't create the identity if we are in DF
142143
if create_identity and not is_dogfood_cluster(cmd):
143-
extension_instance.identity, extension_instance.location = \
144-
__create_identity(cmd, resource_group_name, cluster_name, cluster_type, cluster_rp)
144+
identity_object, location = __create_identity(cmd, resource_group_name, cluster_name, cluster_type, cluster_rp)
145+
if identity_object is not None and location is not None:
146+
extension_instance.identity, extension_instance.location = identity_object, location
145147

146148
# Try to create the resource
147-
return client.create(resource_group_name, cluster_rp, cluster_type, cluster_name, name, extension_instance)
149+
return sdk_no_wait(no_wait, client.begin_create, resource_group_name,
150+
cluster_rp, cluster_type, cluster_name, name, extension_instance)
148151

149152

150153
def list_k8s_extension(client, resource_group_name, cluster_name, cluster_type):
151154
cluster_rp = __get_cluster_rp(cluster_type)
152155
return client.list(resource_group_name, cluster_rp, cluster_type, cluster_name)
153156

154157

155-
def update_k8s_extension(client, resource_group_name, cluster_type, cluster_name, name,
156-
auto_upgrade_minor_version='', release_train='', version='', tags=None):
157-
158+
def update_k8s_extension(cmd, client, resource_group_name, cluster_name, name, cluster_type,
159+
auto_upgrade_minor_version='', release_train='', version='',
160+
configuration_settings=None, configuration_protected_settings=None,
161+
configuration_settings_file=None, configuration_protected_settings_file=None,
162+
no_wait=False, yes=False):
158163
"""Patch an existing Extension Instance.
159-
160164
"""
165+
msg = ('Updating properties in --config-settings or --config-protected-settings may lead to undesirable state'
166+
' if the cluster extension type does not support it. Please refer to the documentation of the'
167+
' cluster extension service to check if updates to these properties is supported.'
168+
' Do you wish to proceed?')
169+
user_confirmation_factory(cmd, yes, msg)
161170

162-
# TODO: Remove this after we eventually get PATCH implemented for update and uncomment
163-
raise CommandNotFoundError(
164-
f"\"{consts.EXTENSION_NAME} update\" currently is not available. "
165-
f"Use \"{consts.EXTENSION_NAME} create\" to update a previously created extension instance."
166-
)
171+
# Determine ClusterRP
172+
cluster_rp = __get_cluster_rp(cluster_type)
167173

168-
# # Ensure some values are provided for update
169-
# if auto_upgrade_minor_version is None and release_train is None and version is None:
170-
# message = "Error! No values provided for update. Provide new value(s) for one or more of these properties:" \
171-
# " auto-upgrade-minor-version, release-train or version."
172-
# raise RequiredArgumentMissingError(message)
174+
# We need to determine the ExtensionType to call ExtensionFactory and create Extension class
175+
extension = show_k8s_extension(client, resource_group_name, cluster_name, name, cluster_type)
176+
extension_type_lower = extension.extension_type.lower()
173177

174-
# # Determine ClusterRP
175-
# cluster_rp = __get_cluster_rp(cluster_type)
178+
__validate_version_and_auto_upgrade(version, auto_upgrade_minor_version)
176179

177-
# # Get the existing extensionInstance
178-
# extension = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name)
180+
config_settings = {}
181+
config_protected_settings = {}
182+
# Get Configuration Settings from file
183+
if configuration_settings_file is not None:
184+
config_settings = __read_config_settings_file(configuration_settings_file)
179185

180-
# extension_type_lower = extension.extension_type.lower()
186+
if configuration_settings is not None:
187+
for dicts in configuration_settings:
188+
for key, value in dicts.items():
189+
config_settings[key] = value
190+
191+
# Get Configuration Protected Settings from file
192+
if configuration_protected_settings_file is not None:
193+
config_protected_settings = __read_config_settings_file(configuration_protected_settings_file)
181194

182-
# # Get the extension class based on the extension name
183-
# extension_class = ExtensionFactory(extension_type_lower)
184-
# upd_extension = extension_class.Update(extension, auto_upgrade_minor_version, release_train, version)
195+
if configuration_protected_settings is not None:
196+
for dicts in configuration_protected_settings:
197+
for key, value in dicts.items():
198+
config_protected_settings[key] = value
185199

186-
# __validate_version_and_auto_upgrade(version, auto_upgrade_minor_version)
200+
# Get the extension class based on the extension type
201+
extension_class = ExtensionFactory(extension_type_lower)
187202

188-
# upd_extension = ExtensionInstanceUpdate(auto_upgrade_minor_version=auto_upgrade_minor_version,
189-
# release_train=release_train, version=version)
203+
upd_extension = extension_class.Update(auto_upgrade_minor_version, release_train, version,
204+
configuration_settings, configuration_protected_settings)
190205

191-
# return client.update(resource_group_name, cluster_rp, cluster_type, cluster_name, name, upd_extension)
206+
return sdk_no_wait(no_wait, client.begin_update, resource_group_name, cluster_rp, cluster_type,
207+
cluster_name, name, upd_extension)
192208

193209

194-
def delete_k8s_extension(cmd, client, resource_group_name, cluster_name, name, cluster_type, yes=False):
210+
def delete_k8s_extension(cmd, client, resource_group_name, cluster_name, name, cluster_type,
211+
no_wait=False, yes=False, force=False):
195212
"""Delete an existing Kubernetes Extension.
196-
197213
"""
198214
# Determine ClusterRP
199215
cluster_rp = __get_cluster_rp(cluster_type)
@@ -206,9 +222,11 @@ def delete_k8s_extension(cmd, client, resource_group_name, cluster_name, name, c
206222
extension_class = ExtensionFactory(extension.extension_type.lower())
207223

208224
# If there is any custom delete logic, this will call the logic
209-
extension_class.Delete(cmd, client, resource_group_name, cluster_name, name, cluster_type, yes)
225+
extension_class.Delete(cmd, client, resource_group_name, cluster_name,
226+
name, cluster_type, yes)
210227

211-
return client.delete(resource_group_name, cluster_rp, cluster_type, cluster_name, name)
228+
return sdk_no_wait(no_wait, client.begin_delete, resource_group_name,
229+
cluster_rp, cluster_type, cluster_name, name, force_delete=force)
212230

213231

214232
def __create_identity(cmd, resource_group_name, cluster_name, cluster_type, cluster_rp):
@@ -226,7 +244,7 @@ def __create_identity(cmd, resource_group_name, cluster_name, cluster_type, clus
226244
elif cluster_rp == 'Microsoft.ResourceConnector':
227245
parent_api_version = '2020-09-15-privatepreview'
228246
elif cluster_rp == 'Microsoft.ContainerService':
229-
parent_api_version = '2017-07-01'
247+
return None, None
230248
else:
231249
raise InvalidArgumentValueError(
232250
"Error! Cluster type '{}' is not supported for extension identity".format(cluster_type)
@@ -239,7 +257,7 @@ def __create_identity(cmd, resource_group_name, cluster_name, cluster_type, clus
239257
raise ex
240258
identity_type = "SystemAssigned"
241259

242-
return ConfigurationIdentity(type=identity_type), location
260+
return Identity(type=identity_type), location
243261

244262

245263
def __get_cluster_rp(cluster_type):
@@ -248,7 +266,7 @@ def __get_cluster_rp(cluster_type):
248266
rp = 'Microsoft.Kubernetes'
249267
elif cluster_type.lower() == 'appliances':
250268
rp = 'Microsoft.ResourceConnector'
251-
elif cluster_type.lower() == '':
269+
elif cluster_type.lower() == '' or cluster_type.lower() == 'managedclusters':
252270
rp = 'Microsoft.ContainerService'
253271
else:
254272
raise InvalidArgumentValueError("Error! Cluster type '{}' is not supported".format(cluster_type))

0 commit comments

Comments
 (0)