Skip to content

Commit

Permalink
Extensions GA changes into Public Branch (#79)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
8 people authored Oct 19, 2021
1 parent f721c84 commit bd56e41
Show file tree
Hide file tree
Showing 49 changed files with 3,906 additions and 1,752 deletions.
7 changes: 7 additions & 0 deletions src/k8s-extension/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
Release History
===============

1.0.0
++++++++++++++++++
* Switch to GA api-version of Extensions (2021-09-01)
* Support Extensions PATCH
* Enable Dapr extension type
* Enable ManagedClusters clusterType

0.7.1
++++++++++++++++++
* Fix DF resource manager endpoint check
Expand Down
16 changes: 15 additions & 1 deletion src/k8s-extension/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,18 @@ az k8s-extension list \
--cluster-type clusterType
```

If you have issues, please give feedback by opening an issue at https://github.com/Azure/azure-cli-extensions/issues.
##### Update an existing KubernetesExtension of a cluster
```
az k8s-extension update \
--resource-group groupName \
--cluster-name clusterName \
--cluster-type clusterType \
--name extensionName \
--auto-upgrade true/false \
--version extensionVersion \
--release-train releaseTrain \
--configuration-settings settingsKey=settingsValue \
--configuration-protected-settings protectedSettingsKey=protectedValue \
--configuration-settings-file configSettingsFile \
--configuration-protected-settings-file protectedSettingsFile
```
8 changes: 4 additions & 4 deletions src/k8s-extension/azext_k8s_extension/_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ def k8s_extension_show_table_format(result):
def __get_table_row(result):
return OrderedDict([
('name', result['name']),
('extensionType', result['extensionType']),
('version', result['version']),
('installState', result['installState']),
('lastModifiedTime', result['lastModifiedTime'])
('extensionType', result.get('extensionType', '')),
('version', result.get('version', '')),
('provisioningState', result.get('provisioningState', '')),
('lastModifiedAt', result.get('systemData', {}).get('lastModifiedAt', '')),
])
37 changes: 27 additions & 10 deletions src/k8s-extension/azext_k8s_extension/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@
examples:
- name: Create a Kubernetes Extension
text: |-
az {consts.EXTENSION_NAME} create --resource-group my-resource-group \\
--cluster-name mycluster --cluster-type connectedClusters \\
--name myextension --extension-type microsoft.openservicemesh \\
--scope cluster --release-train stable
az {consts.EXTENSION_NAME} create --resource-group my-resource-group \
--cluster-name mycluster --cluster-type connectedClusters --name myextension \
--extension-type microsoft.openservicemesh --scope cluster --release-train stable
"""

helps[f'{consts.EXTENSION_NAME} list'] = f"""
Expand All @@ -31,8 +30,8 @@
examples:
- name: List all Kubernetes Extensions on a cluster
text: |-
az {consts.EXTENSION_NAME} list --resource-group my-resource-group \\
--cluster-name mycluster --cluster-type connectedClusters
az {consts.EXTENSION_NAME} list --resource-group my-resource-group \
--cluster-name mycluster --cluster-type connectedClusters
"""

helps[f'{consts.EXTENSION_NAME} delete'] = f"""
Expand All @@ -41,8 +40,8 @@
examples:
- name: Delete an existing Kubernetes Extension
text: |-
az {consts.EXTENSION_NAME} delete --resource-group my-resource-group \\
--cluster-name mycluster --cluster-type connectedClusters --name myextension
az {consts.EXTENSION_NAME} delete --resource-group my-resource-group \
--cluster-name mycluster --cluster-type connectedClusters --name myextension
"""

helps[f'{consts.EXTENSION_NAME} show'] = f"""
Expand All @@ -51,6 +50,24 @@
examples:
- name: Show details of a Kubernetes Extension
text: |-
az {consts.EXTENSION_NAME} show --resource-group my-resource-group \\
--cluster-name mycluster --cluster-type connectedClusters --name myextension
az {consts.EXTENSION_NAME} show --resource-group my-resource-group \
--cluster-name mycluster --cluster-type connectedClusters --name myextension
"""

helps[f'{consts.EXTENSION_NAME} update'] = f"""
type: command
short-summary: Update mutable properties of a Kubernetes Extension.
long-summary: For update to ConfigSettings and ConfigProtectedSettings, please \
refer to documentation of the cluster extension service to check update to these \
properties is supported before updating these properties.
examples:
- name: Update a Kubernetes Extension
text: |-
az {consts.EXTENSION_NAME} update --resource-group my-resource-group \
--cluster-name mycluster --cluster-type connectedClusters \
--name myextension --auto-upgrade true/false --version extension-version \
--release-train stable --configuration-settings settings-key=settings-value \
--configuration-protected-settings protected-settings-key=protected-value \
--configuration-settings-file=config-settings-file \
--configuration-protected-settings-file=protected-settings-file
"""
11 changes: 8 additions & 3 deletions src/k8s-extension/azext_k8s_extension/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

from azure.cli.core.commands.parameters import (
get_enum_type,
get_three_state_flag,
tags_type
get_three_state_flag
)
from azure.cli.core.commands.validators import get_default_location_from_resource_group
from . import consts
Expand All @@ -19,7 +18,6 @@

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

with self.argument_context(f"{consts.EXTENSION_NAME} update") as c:
c.argument('yes',
options_list=['--yes', '-y'],
help='Ignore confirmation prompts')

with self.argument_context(f"{consts.EXTENSION_NAME} delete") as c:
c.argument('yes',
options_list=['--yes', '-y'],
help='Ignore confirmation prompts')
c.argument('force',
help='Specify whether to force delete the extension from the cluster.')
1 change: 0 additions & 1 deletion src/k8s-extension/azext_k8s_extension/azext_metadata.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{
"azext.isPreview": true,
"azext.minCliCoreVersion": "2.24.0"
}
8 changes: 4 additions & 4 deletions src/k8s-extension/azext_k8s_extension/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ def load_command_table(self, _):
operations_tmpl=consts.EXTENSION_PACKAGE_NAME + '.vendored_sdks.operations#K8sExtensionsOperations.{}',
client_factory=cf_k8s_extension)

with self.command_group(consts.EXTENSION_NAME, k8s_extension_sdk, client_factory=cf_k8s_extension_operation,
is_preview=True) \
with self.command_group(consts.EXTENSION_NAME, k8s_extension_sdk, client_factory=cf_k8s_extension_operation) \
as g:
g.custom_command('create', 'create_k8s_extension')
g.custom_command('delete', 'delete_k8s_extension')
g.custom_command('create', 'create_k8s_extension', supports_no_wait=True)
g.custom_command('delete', 'delete_k8s_extension', supports_no_wait=True)
g.custom_command('list', 'list_k8s_extension', table_transformer=k8s_extension_list_table_format)
g.custom_show_command('show', 'show_k8s_extension', table_transformer=k8s_extension_show_table_format)
g.custom_command('update', 'update_k8s_extension', supports_no_wait=True)
106 changes: 62 additions & 44 deletions src/k8s-extension/azext_k8s_extension/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,23 @@
# pylint: disable=unused-argument,too-many-locals

import json
from knack.log import get_logger
from urllib.parse import urlparse
from knack.log import get_logger

from azure.cli.core.azclierror import ResourceNotFoundError, MutuallyExclusiveArgumentError, \
InvalidArgumentValueError, CommandNotFoundError, RequiredArgumentMissingError
InvalidArgumentValueError, RequiredArgumentMissingError
from azure.cli.core.commands.client_factory import get_subscription_id
from azure.cli.core.util import sdk_no_wait
from azure.core.exceptions import HttpResponseError
from .vendored_sdks.models import ConfigurationIdentity, Scope
from .vendored_sdks.models import Identity, Scope
from ._validators import validate_cc_registration

from .partner_extensions.ContainerInsights import ContainerInsights
from .partner_extensions.AzureDefender import AzureDefender
from .partner_extensions.AzureMLKubernetes import AzureMLKubernetes
from .partner_extensions.OpenServiceMesh import OpenServiceMesh
from .partner_extensions.DefaultExtension import DefaultExtension
from .partner_extensions.AzureMLKubernetes import AzureMLKubernetes
from .partner_extensions.Dapr import Dapr
from .partner_extensions.DefaultExtension import DefaultExtension, user_confirmation_factory
from . import consts

from ._client_factory import cf_resources
Expand All @@ -35,6 +37,7 @@ def ExtensionFactory(extension_name):
'microsoft.azuredefender.kubernetes': AzureDefender,
'microsoft.openservicemesh': OpenServiceMesh,
'microsoft.azureml.kubernetes': AzureMLKubernetes,
'microsoft.dapr': Dapr,
}

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

def show_k8s_extension(client, resource_group_name, cluster_name, name, cluster_type):
"""Get an existing K8s Extension.
"""
# Determine ClusterRP
cluster_rp = __get_cluster_rp(cluster_type)
Expand Down Expand Up @@ -74,9 +76,8 @@ def create_k8s_extension(cmd, client, resource_group_name, cluster_name, name, c
extension_type, scope=None, auto_upgrade_minor_version=None, release_train=None,
version=None, target_namespace=None, release_namespace=None, configuration_settings=None,
configuration_protected_settings=None, configuration_settings_file=None,
configuration_protected_settings_file=None, tags=None):
configuration_protected_settings_file=None, no_wait=False):
"""Create a new Extension Instance.
"""

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

# Try to create the resource
return client.create(resource_group_name, cluster_rp, cluster_type, cluster_name, name, extension_instance)
return sdk_no_wait(no_wait, client.begin_create, resource_group_name,
cluster_rp, cluster_type, cluster_name, name, extension_instance)


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


def update_k8s_extension(client, resource_group_name, cluster_type, cluster_name, name,
auto_upgrade_minor_version='', release_train='', version='', tags=None):

def update_k8s_extension(cmd, client, resource_group_name, cluster_name, name, cluster_type,
auto_upgrade_minor_version='', release_train='', version='',
configuration_settings=None, configuration_protected_settings=None,
configuration_settings_file=None, configuration_protected_settings_file=None,
no_wait=False, yes=False):
"""Patch an existing Extension Instance.
"""
msg = ('Updating properties in --config-settings or --config-protected-settings may lead to undesirable state'
' if the cluster extension type does not support it. Please refer to the documentation of the'
' cluster extension service to check if updates to these properties is supported.'
' Do you wish to proceed?')
user_confirmation_factory(cmd, yes, msg)

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

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

# # Determine ClusterRP
# cluster_rp = __get_cluster_rp(cluster_type)
__validate_version_and_auto_upgrade(version, auto_upgrade_minor_version)

# # Get the existing extensionInstance
# extension = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name)
config_settings = {}
config_protected_settings = {}
# Get Configuration Settings from file
if configuration_settings_file is not None:
config_settings = __read_config_settings_file(configuration_settings_file)

# extension_type_lower = extension.extension_type.lower()
if configuration_settings is not None:
for dicts in configuration_settings:
for key, value in dicts.items():
config_settings[key] = value

# Get Configuration Protected Settings from file
if configuration_protected_settings_file is not None:
config_protected_settings = __read_config_settings_file(configuration_protected_settings_file)

# # Get the extension class based on the extension name
# extension_class = ExtensionFactory(extension_type_lower)
# upd_extension = extension_class.Update(extension, auto_upgrade_minor_version, release_train, version)
if configuration_protected_settings is not None:
for dicts in configuration_protected_settings:
for key, value in dicts.items():
config_protected_settings[key] = value

# __validate_version_and_auto_upgrade(version, auto_upgrade_minor_version)
# Get the extension class based on the extension type
extension_class = ExtensionFactory(extension_type_lower)

# upd_extension = ExtensionInstanceUpdate(auto_upgrade_minor_version=auto_upgrade_minor_version,
# release_train=release_train, version=version)
upd_extension = extension_class.Update(auto_upgrade_minor_version, release_train, version,
configuration_settings, configuration_protected_settings)

# return client.update(resource_group_name, cluster_rp, cluster_type, cluster_name, name, upd_extension)
return sdk_no_wait(no_wait, client.begin_update, resource_group_name, cluster_rp, cluster_type,
cluster_name, name, upd_extension)


def delete_k8s_extension(cmd, client, resource_group_name, cluster_name, name, cluster_type, yes=False):
def delete_k8s_extension(cmd, client, resource_group_name, cluster_name, name, cluster_type,
no_wait=False, yes=False, force=False):
"""Delete an existing Kubernetes Extension.
"""
# Determine ClusterRP
cluster_rp = __get_cluster_rp(cluster_type)
Expand All @@ -206,9 +222,11 @@ def delete_k8s_extension(cmd, client, resource_group_name, cluster_name, name, c
extension_class = ExtensionFactory(extension.extension_type.lower())

# If there is any custom delete logic, this will call the logic
extension_class.Delete(cmd, client, resource_group_name, cluster_name, name, cluster_type, yes)
extension_class.Delete(cmd, client, resource_group_name, cluster_name,
name, cluster_type, yes)

return client.delete(resource_group_name, cluster_rp, cluster_type, cluster_name, name)
return sdk_no_wait(no_wait, client.begin_delete, resource_group_name,
cluster_rp, cluster_type, cluster_name, name, force_delete=force)


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

return ConfigurationIdentity(type=identity_type), location
return Identity(type=identity_type), location


def __get_cluster_rp(cluster_type):
Expand All @@ -248,7 +266,7 @@ def __get_cluster_rp(cluster_type):
rp = 'Microsoft.Kubernetes'
elif cluster_type.lower() == 'appliances':
rp = 'Microsoft.ResourceConnector'
elif cluster_type.lower() == '':
elif cluster_type.lower() == '' or cluster_type.lower() == 'managedclusters':
rp = 'Microsoft.ContainerService'
else:
raise InvalidArgumentValueError("Error! Cluster type '{}' is not supported".format(cluster_type))
Expand Down
Loading

0 comments on commit bd56e41

Please sign in to comment.