From 828f9d3321effe01fbe74b754a9a1f61fab65f71 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Wed, 10 Mar 2021 13:25:37 -0800 Subject: [PATCH 01/80] Create pull.yml --- .github/pull.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/pull.yml diff --git a/.github/pull.yml b/.github/pull.yml new file mode 100644 index 00000000000..7201bb6d18b --- /dev/null +++ b/.github/pull.yml @@ -0,0 +1,12 @@ +version: "1" +rules: # Array of rules + - base: master # Required. Target branch + upstream: wei:master # Required. Must be in the same fork network. + mergeMethod: hardreset # Optional, one of [none, merge, squash, rebase, hardreset], Default: none. + mergeUnstable: false # Optional, merge pull request even when the mergeable_state is not clean. Default: false + - base: k8s-configuration + upstream: master # Required. Can be a branch in the same forked repo. + - base: k8s-extension/private-preview + upstream: master # Required. Can be a branch in the same forked repo. + - base: k8s-extension/public-preview + upstream: master # Required. Can be a branch in the same forked repo. From 1436bfc8859e33ea69b06e0b746cbd9ef5fe7825 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Wed, 10 Mar 2021 14:00:34 -0800 Subject: [PATCH 02/80] Update pull.yml --- .github/pull.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/pull.yml b/.github/pull.yml index 7201bb6d18b..8f65923a382 100644 --- a/.github/pull.yml +++ b/.github/pull.yml @@ -10,3 +10,5 @@ rules: # Array of rules upstream: master # Required. Can be a branch in the same forked repo. - base: k8s-extension/public-preview upstream: master # Required. Can be a branch in the same forked repo. + - base: release + upstream: master # Required. Can be a branch in the same forked repo. From 6cffd965b4061d66bad7e637a4a55bb93c9440d1 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Wed, 10 Mar 2021 14:15:10 -0800 Subject: [PATCH 03/80] Update azure-pipelines.yml --- azure-pipelines.yml | 405 ++++++++++++++++++++++++++++---------------- 1 file changed, 259 insertions(+), 146 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d43ef5102f0..77ff718d967 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,128 +1,157 @@ resources: -- repo: self + repositories: + - repository: K8sPartnerExtensionTest + type: git + endpoint: AzureReposConnection + name: One/compute-HybridMgmt-K8sPartnerExtensionTest trigger: batch: true branches: include: - - '*' - + - k8s-extension/public-preview + - k8s-extension/private-preview pr: branches: include: - - '*' - -jobs: -- job: CredScan - displayName: "Credential Scan" - pool: - vmImage: "windows-2019" - steps: - - task: ms-codeanalysis.vss-microsoft-security-code-analysis-devops.build-task-credscan.CredScan@2 - displayName: 'Run Credential Scanner' - inputs: - toolMajorVersion: V2 - suppressionsFile: './scripts/ci/credscan/CredScanSuppressions.json' - - task: ms-codeanalysis.vss-microsoft-security-code-analysis-devops.build-task-postanalysis.PostAnalysis@1 - displayName: 'Post Analysis' - inputs: - AllTools: false - BinSkim: false - CredScan: true - RoslynAnalyzers: false - TSLint: false - ToolLogsNotFoundAction: 'Standard' - -- job: CheckLicenseHeader - displayName: "Check License" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - python -m venv env/ - - chmod +x ./env/bin/activate - source ./env/bin/activate - - # clone azure-cli - git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install -q azdev - - azdev setup -c ../azure-cli -r ./ - - azdev --version - az --version - - azdev verify license - -- job: StaticAnalysis - displayName: "Static Analysis" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests - displayName: 'Install wheel, pylint, flake8, requests' - - bash: python scripts/ci/source_code_static_analysis.py - displayName: "Static Analysis" - -- job: IndexVerify - displayName: "Verify Extensions Index" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: | - #!/usr/bin/env bash - set -ev - pip install wheel==0.30.0 requests packaging - export CI="ADO" - python ./scripts/ci/test_index.py -v - displayName: "Verify Extensions Index" + - k8s-extension/public-preview + - k8s-extension/private-preview -- job: SourceTests - displayName: "Integration Tests, Build Tests" - pool: - vmImage: 'ubuntu-16.04' - strategy: - matrix: - Python36: - python.version: '3.6' - Python38: - python.version: '3.8' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python $(python.version)' - inputs: - versionSpec: '$(python.version)' - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - bash: ./scripts/ci/test_source.sh - displayName: 'Run integration test and build test' - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - -- job: LintModifiedExtensions - displayName: "CLI Linter on Modified Extensions" - condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest')) - pool: - vmImage: 'ubuntu-16.04' - steps: +stages: +- stage: K8sExtensionTestSuite + displayName: "K8s-Extension Test Suite" + variables: + K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest + CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions-pr + EXTENSION_NAME: "k8s-extension" + EXTENSION_FILE_NAME: "k8s_extension" + SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" + RESOURCE_GROUP: "K8sPartnerExtensionTest" + BASE_CLUSTER_NAME: "k8s-extension-cluster" + jobs: + - job: K8sExtensionTestSuite + displayName: "Run the Test Suite" + pool: + vmImage: 'ubuntu-16.04' + steps: + - checkout: self + - checkout: K8sPartnerExtensionTest + + - bash: | + echo "Installing helm3" + curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 + chmod 700 get_helm.sh + ./get_helm.sh + + echo "Installing kubectl" + curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin/kubectl + kubectl version --client + displayName: "Setup the VM with helm3 and kubectl" + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build $(EXTENSION_NAME) with azdev" + + - bash: | + K8S_EXTENSION_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) + echo "##vso[task.setvariable variable=K8S_EXTENSION_VERSION]$K8S_EXTENSION_VERSION" + cp * $(K8S_EXTENSION_REPO_PATH)/extensions + workingDirectory: $(CLI_REPO_PATH)/dist + displayName: "Copy the Built .whl to Extension Test Path" + + - bash: | + RAND_STR=$RANDOM + AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" + ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" + + JSON_STRING=$(jq -n \ + --arg SUB_ID "$SUBSCRIPTION_ID" \ + --arg RG "$RESOURCE_GROUP" \ + --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ + --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ + --arg K8S_EXTENSION_VERSION "$K8S_EXTENSION_VERSION" \ + '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-extension": $K8S_EXTENSION_VERSION, connectedk8s: "1.0.0"}}') + echo $JSON_STRING > settings.json + cat settings.json + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + displayName: "Generate a settings.json file" + + - bash : | + echo "Downloading the kind script" + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64 + chmod +x ./kind + ./kind create cluster + displayName: "Create and Start the Kind cluster" + + - task: AzureCLI@2 + displayName: Bootstrap + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Bootstrap.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + + - task: AzureCLI@2 + displayName: Run the Test Suite + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Test.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + continueOnError: true + + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TestResults.xml' + failTaskOnFailedTests: true + condition: succeededOrFailed() + + - task: AzureCLI@2 + displayName: Cleanup + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Cleanup.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + condition: succeededOrFailed() + +- stage: AzureCLIOfficial + displayName: "Azure Official CLI Code Checks" + dependsOn: [] + jobs: + - job: CheckLicenseHeader + displayName: "Check License" + pool: + vmImage: 'ubuntu-16.04' + steps: - task: UsePythonVersion@0 displayName: 'Use Python 3.6' inputs: @@ -131,41 +160,125 @@ jobs: set -ev # prepare and activate virtualenv - pip install virtualenv - python -m virtualenv venv/ - source ./venv/bin/activate + python -m venv env/ + + chmod +x ./env/bin/activate + source ./env/bin/activate # clone azure-cli - git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - pip install azdev + pip install -q azdev + + azdev setup -c ../azure-cli -r ./ azdev --version + az --version - azdev setup -c ../azure-cli -r ./ + azdev verify license + + - job: StaticAnalysis + displayName: "Static Analysis" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests + displayName: 'Install wheel, pylint, flake8, requests' + - bash: python scripts/ci/source_code_static_analysis.py + displayName: "Static Analysis" + + - job: IndexVerify + displayName: "Verify Extensions Index" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: | + #!/usr/bin/env bash + set -ev + pip install wheel==0.30.0 requests packaging + export CI="ADO" + python ./scripts/ci/test_index.py -v + displayName: "Verify Extensions Index" + + - job: SourceTests + displayName: "Integration Tests, Build Tests" + pool: + vmImage: 'ubuntu-16.04' + strategy: + matrix: + Python36: + python.version: '3.6' + Python38: + python.version: '3.8' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python $(python.version)' + inputs: + versionSpec: '$(python.version)' + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - bash: ./scripts/ci/test_source.sh + displayName: 'Run integration test and build test' + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: LintModifiedExtensions + displayName: "CLI Linter on Modified Extensions" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev - # overwrite the default AZURE_EXTENSION_DIR set by ADO - AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version - - AZURE_EXTENSION_DIR=~/.azure/cliextensions python scripts/ci/verify_linter.py - displayName: "CLI Linter on Modified Extension" - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - -- job: IndexRefDocVerify - displayName: "Verify Ref Docs" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - task: Bash@3 - displayName: "Verify Extension Ref Docs" - inputs: - targetType: 'filePath' - filePath: scripts/ci/test_index_ref_doc.sh + # prepare and activate virtualenv + pip install virtualenv + python -m virtualenv venv/ + source ./venv/bin/activate + + # clone azure-cli + git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install azdev + + azdev --version + + azdev setup -c ../azure-cli -r ./ -e k8s-extension + + # overwrite the default AZURE_EXTENSION_DIR set by ADO + AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version + + AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-extension + displayName: "CLI Linter on Modified Extension" + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: IndexRefDocVerify + displayName: "Verify Ref Docs" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - task: Bash@3 + displayName: "Verify Extension Ref Docs" + inputs: + targetType: 'filePath' + filePath: scripts/ci/test_index_ref_doc.sh From db0f4bd7b188c2aa1388ed9366994e5508061483 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 10 Mar 2021 14:19:45 -0800 Subject: [PATCH 04/80] Initial commit of k8s-extension --- src/k8s-extension/HISTORY.rst | 83 +++ src/k8s-extension/README.rst | 5 + .../azext_k8s_extension/__init__.py | 32 + .../azext_k8s_extension/_client_factory.py | 31 + .../azext_k8s_extension/_help.py | 38 ++ .../azext_k8s_extension/_params.py | 73 +++ .../azext_k8s_extension/_validators.py | 21 + .../azext_k8s_extension/action.py | 37 ++ .../azext_k8s_extension/azext_metadata.json | 4 + .../azext_k8s_extension/commands.py | 24 + .../azext_k8s_extension/custom.py | 275 ++++++++ .../partner_extensions/AzureDefender.py | 73 +++ .../partner_extensions/ContainerInsights.py | 460 ++++++++++++++ .../partner_extensions/DefaultExtension.py | 62 ++ .../partner_extensions/OpenServiceMesh.py | 95 +++ .../PartnerExtensionModel.py | 19 + .../partner_extensions/__init__.py | 0 .../azext_k8s_extension/tests/__init__.py | 5 + .../tests/latest/__init__.py | 5 + .../latest/recordings/test_k8s_extension.yaml | 270 ++++++++ .../latest/test_k8s_extension_scenario.py | 67 ++ .../vendored_sdks/__init__.py | 19 + .../vendored_sdks/_configuration.py | 49 ++ .../vendored_sdks/_k8s_extension_client.py | 50 ++ .../vendored_sdks/models/__init__.py | 70 +++ .../models/_k8s_extension_client_enums.py | 68 ++ .../vendored_sdks/models/_models.py | 587 ++++++++++++++++++ .../vendored_sdks/models/_models_py3.py | 587 ++++++++++++++++++ .../vendored_sdks/models/_paged_models.py | 40 ++ .../vendored_sdks/operations/__init__.py | 16 + .../operations/_k8s_extensions_operations.py | 452 ++++++++++++++ .../vendored_sdks/version.py | 13 + src/k8s-extension/setup.cfg | 2 + src/k8s-extension/setup.py | 58 ++ 34 files changed, 3690 insertions(+) create mode 100644 src/k8s-extension/HISTORY.rst create mode 100644 src/k8s-extension/README.rst create mode 100644 src/k8s-extension/azext_k8s_extension/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/_client_factory.py create mode 100644 src/k8s-extension/azext_k8s_extension/_help.py create mode 100644 src/k8s-extension/azext_k8s_extension/_params.py create mode 100644 src/k8s-extension/azext_k8s_extension/_validators.py create mode 100644 src/k8s-extension/azext_k8s_extension/action.py create mode 100644 src/k8s-extension/azext_k8s_extension/azext_metadata.json create mode 100644 src/k8s-extension/azext_k8s_extension/commands.py create mode 100644 src/k8s-extension/azext_k8s_extension/custom.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/OpenServiceMesh.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/tests/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/tests/latest/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/tests/latest/recordings/test_k8s_extension.yaml create mode 100644 src/k8s-extension/azext_k8s_extension/tests/latest/test_k8s_extension_scenario.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/_k8s_extension_client.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_k8s_extension_client_enums.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_k8s_extensions_operations.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py create mode 100644 src/k8s-extension/setup.cfg create mode 100644 src/k8s-extension/setup.py diff --git a/src/k8s-extension/HISTORY.rst b/src/k8s-extension/HISTORY.rst new file mode 100644 index 00000000000..695f549b1a2 --- /dev/null +++ b/src/k8s-extension/HISTORY.rst @@ -0,0 +1,83 @@ +.. :changelog: + +Release History +=============== + +0.1.0 +++++++++++++++++++ +* Initial release. + +0.1.1 +++++++++++++++++++ +* Add support for microsoft-azure-defender extension type + +0.1.2 +++++++++++++++++++ + +* Add support for Arc Appliance cluster type + +0.1.3 +++++++++++++++++++ + +* Customization for microsoft.openservicemesh + +0.1PP.4 +++++++++++++++++++ + +* Refactor for clear separation of extension-type specific customizations +* Introduce new versioning scheme to allow Preview releases by Partners + +0.1PP.5 +++++++++++++++++++ + +* OpenServiceMesh customization. +* If Version is passed in, accept None for AutoUpgradeMinorVersion, and not require it to be False. + +0.1PP.6 +++++++++++++++++++ + +* OpenServiceMesh customization. +* Scope is always cluster. Version is mandatory for staging and pilot release-trains. + +0.1PP.7 +++++++++++++++++++ + +* Fix clusterType of Microsoft.ResourceConnector resource + +0.1PP.8 +++++++++++++++++++ + +* Update clusterType validation to allow 'appliances' +* Update identity creation to use the appropriate parent resource's type and api-version +* Throw error if cluster type is not one of the 3 supported types + +0.1PP.9 +++++++++++++++++++ + +* Rename azuremonitor-containers extension type to microsoft.azuremonitor.containers + +0.1PP.10 +++++++++++++++++++ + +* Add azuremonitor-containers back with alternative microsoft.azuremonitor.containers + +0.1PP.11 +++++++++++++++++++ + +* Add shorter aliases for long parameter names + +0.1PP.12 +++++++++++++++++++ + +* Remove support for azuremonitor-containers extension type naming + +0.1PP.13 +++++++++++++++++++ + +* Move CLI errors to non-deprecated error types +* Remove support for update + +0.1PP.14 +++++++++++++++++++ + +* Update help text, group CLI arguments diff --git a/src/k8s-extension/README.rst b/src/k8s-extension/README.rst new file mode 100644 index 00000000000..e91e1b13229 --- /dev/null +++ b/src/k8s-extension/README.rst @@ -0,0 +1,5 @@ +Microsoft Azure CLI 'k8s-extension' Extension +============================================= + +This package is for the 'k8s-extension' extension. +i.e. 'az k8s-extension' diff --git a/src/k8s-extension/azext_k8s_extension/__init__.py b/src/k8s-extension/azext_k8s_extension/__init__.py new file mode 100644 index 00000000000..e2301227d45 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/__init__.py @@ -0,0 +1,32 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.core import AzCommandsLoader + +from azext_k8s_extension._help import helps # pylint: disable=unused-import + + +class K8sExtensionCommandsLoader(AzCommandsLoader): + + def __init__(self, cli_ctx=None): + from azure.cli.core.commands import CliCommandType + from azext_k8s_extension._client_factory import cf_k8s_extension + k8s_extension_custom = CliCommandType( + operations_tmpl='azext_k8s_extension.custom#{}', + client_factory=cf_k8s_extension) + super(K8sExtensionCommandsLoader, self).__init__(cli_ctx=cli_ctx, + custom_command_type=k8s_extension_custom) + + def load_command_table(self, args): + from azext_k8s_extension.commands import load_command_table + load_command_table(self, args) + return self.command_table + + def load_arguments(self, command): + from azext_k8s_extension._params import load_arguments + load_arguments(self, command) + + +COMMAND_LOADER_CLS = K8sExtensionCommandsLoader diff --git a/src/k8s-extension/azext_k8s_extension/_client_factory.py b/src/k8s-extension/azext_k8s_extension/_client_factory.py new file mode 100644 index 00000000000..a4ec83ee0cb --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_client_factory.py @@ -0,0 +1,31 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.core.commands.client_factory import get_mgmt_service_client +from azure.cli.core.profiles import ResourceType + + +def cf_k8s_extension(cli_ctx, *_): + from azext_k8s_extension.vendored_sdks import K8sExtensionClient + return get_mgmt_service_client(cli_ctx, K8sExtensionClient) + + +def cf_k8s_extension_operation(cli_ctx, _): + return cf_k8s_extension(cli_ctx).k8s_extensions + + +def cf_resource_groups(cli_ctx, subscription_id=None): + return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES, + subscription_id=subscription_id).resource_groups + + +def cf_resources(cli_ctx, subscription_id=None): + return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES, + subscription_id=subscription_id).resources + + +def cf_log_analytics(cli_ctx, subscription_id=None): + from azure.mgmt.loganalytics import LogAnalyticsManagementClient # pylint: disable=no-name-in-module + return get_mgmt_service_client(cli_ctx, LogAnalyticsManagementClient, subscription_id=subscription_id) diff --git a/src/k8s-extension/azext_k8s_extension/_help.py b/src/k8s-extension/azext_k8s_extension/_help.py new file mode 100644 index 00000000000..69011bb9d92 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_help.py @@ -0,0 +1,38 @@ +# coding=utf-8 +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from knack.help_files import helps # pylint: disable=unused-import + + +helps['k8s-extension'] = """ + type: group + short-summary: Commands to manage K8s-extensions. +""" + +helps['k8s-extension create'] = """ + type: command + short-summary: Create a K8s-extension. +""" + +helps['k8s-extension list'] = """ + type: command + short-summary: List K8s-extensions. +""" + +helps['k8s-extension delete'] = """ + type: command + short-summary: Delete a K8s-extension. +""" + +helps['k8s-extension show'] = """ + type: command + short-summary: Show details of a K8s-extension. +""" + +helps['k8s-extension update'] = """ + type: command + short-summary: Update a K8s-extension. +""" diff --git a/src/k8s-extension/azext_k8s_extension/_params.py b/src/k8s-extension/azext_k8s_extension/_params.py new file mode 100644 index 00000000000..0e870204887 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_params.py @@ -0,0 +1,73 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.core.commands.parameters import ( + get_enum_type, + get_three_state_flag, + tags_type +) +from azure.cli.core.commands.validators import get_default_location_from_resource_group + +from azext_k8s_extension.action import ( + AddConfigurationSettings, + AddConfigurationProtectedSettings +) + + +def load_arguments(self, _): + with self.argument_context('k8s-extension') as c: + c.argument('tags', tags_type) + c.argument('location', + validator=get_default_location_from_resource_group) + c.argument('name', + options_list=['--name', '-n'], + help='Name of the extension instance') + c.argument('extension_type', + help='Name of the extension type.') + c.argument('cluster_name', + options_list=['--cluster-name', '-c'], + help='Name of the Kubernetes cluster') + c.argument('cluster_type', + arg_type=get_enum_type(['connectedClusters', 'managedClusters', 'appliances']), + help='Specify Arc clusters or AKS managed clusters or Arc appliances.') + c.argument('scope', + arg_type=get_enum_type(['cluster', 'namespace']), + help='Specify the extension scope.') + c.argument('auto_upgrade_minor_version', + arg_group="Version", + options_list=['--auto-upgrade-minor-version', '--auto-upgrade'], + arg_type=get_three_state_flag(), + help='Automatically upgrade minor version of the extension instance.') + c.argument('version', + arg_group="Version", + help='Specify the version to install for the extension instance if' + ' --auto-upgrade-minor-version is not enabled.') + c.argument('configuration_settings', + arg_group="Configuration", + options_list=['--configuration-settings', '--config'], + action=AddConfigurationSettings, + nargs='+', + help='Configuration Settings as key=value pair. Repeat parameter for each setting') + c.argument('configuration_protected_settings', + arg_group="Configuration", + options_list=['--configuration-protected-settings', '--config-protected'], + action=AddConfigurationProtectedSettings, + nargs='+', + help='Configuration Protected Settings as key=value pair. Repeat parameter for each setting') + c.argument('configuration_settings_file', + arg_group="Configuration", + options_list=['--configuration-settings-file', '--config-file'], + help='JSON file path for configuration-settings') + c.argument('configuration_protected_settings_file', + arg_group="Configuration", + options_list=['--configuration-protected-settings-file', '--config-protected-file'], + help='JSON file path for configuration-protected-settings') + c.argument('release_namespace', + help='Specify the namespace to install the extension release.') + c.argument('release_train', + help='Specify the release train for the extension type.') + c.argument('target_namespace', + help='Specify the target namespace to install to for the extension instance. This' + ' parameter is required if extension scope is set to \'namespace\'') diff --git a/src/k8s-extension/azext_k8s_extension/_validators.py b/src/k8s-extension/azext_k8s_extension/_validators.py new file mode 100644 index 00000000000..72270dab104 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_validators.py @@ -0,0 +1,21 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + + +def example_name_or_id_validator(cmd, namespace): + # Example of a storage account name or ID validator. + # See: https://github.com/Azure/azure-cli/blob/dev/doc/authoring_command_modules/authoring_commands.md#supporting-name-or-id-parameters # pylint: disable=line-too-long + + from azure.cli.core.commands.client_factory import get_subscription_id + from msrestazure.tools import is_valid_resource_id, resource_id + if namespace.storage_account: + if not is_valid_resource_id(namespace.RESOURCE): + namespace.storage_account = resource_id( + subscription=get_subscription_id(cmd.cli_ctx), + resource_group=namespace.resource_group_name, + namespace='Microsoft.Storage', + type='storageAccounts', + name=namespace.storage_account + ) diff --git a/src/k8s-extension/azext_k8s_extension/action.py b/src/k8s-extension/azext_k8s_extension/action.py new file mode 100644 index 00000000000..4afbbbcd611 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/action.py @@ -0,0 +1,37 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import argparse +from azure.cli.core.azclierror import ArgumentUsageError + + +# pylint: disable=protected-access, too-few-public-methods +class AddConfigurationSettings(argparse._AppendAction): + + def __call__(self, parser, namespace, values, option_string=None): + settings = {} + for item in values: + try: + key, value = item.split('=', 1) + settings[key] = value + except ValueError: + raise ArgumentUsageError('Usage error: {} configuration_setting_key=configuration_setting_value'. + format(option_string)) + super(AddConfigurationSettings, self).__call__(parser, namespace, settings, option_string) + + +# pylint: disable=protected-access, too-few-public-methods +class AddConfigurationProtectedSettings(argparse._AppendAction): + + def __call__(self, parser, namespace, values, option_string=None): + prot_settings = {} + for item in values: + try: + key, value = item.split('=', 1) + prot_settings[key] = value + except ValueError: + raise ArgumentUsageError('Usage error: {} configuration_protected_setting_key=' + 'configuration_protected_setting_value'.format(option_string)) + super(AddConfigurationProtectedSettings, self).__call__(parser, namespace, prot_settings, option_string) diff --git a/src/k8s-extension/azext_k8s_extension/azext_metadata.json b/src/k8s-extension/azext_k8s_extension/azext_metadata.json new file mode 100644 index 00000000000..30fdaf614ee --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/azext_metadata.json @@ -0,0 +1,4 @@ +{ + "azext.isPreview": true, + "azext.minCliCoreVersion": "2.15.0" +} \ No newline at end of file diff --git a/src/k8s-extension/azext_k8s_extension/commands.py b/src/k8s-extension/azext_k8s_extension/commands.py new file mode 100644 index 00000000000..63fe78f7d2a --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/commands.py @@ -0,0 +1,24 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=line-too-long +from azure.cli.core.commands import CliCommandType +from azext_k8s_extension._client_factory import (cf_k8s_extension, cf_k8s_extension_operation) + + +def load_command_table(self, _): + + k8s_extension_sdk = CliCommandType( + operations_tmpl='azext_k8s_extension.vendored_sdks.operations#K8sExtensionsOperations.{}', + client_factory=cf_k8s_extension) + + with self.command_group('k8s-extension', k8s_extension_sdk, client_factory=cf_k8s_extension_operation, + is_preview=True) \ + as g: + g.custom_command('create', 'create_k8s_extension') + g.custom_command('update', 'update_k8s_extension') + g.custom_command('delete', 'delete_k8s_extension', confirmation=True) + g.custom_command('list', 'list_k8s_extension') + g.custom_show_command('show', 'show_k8s_extension') diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py new file mode 100644 index 00000000000..469b4059dee --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -0,0 +1,275 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument,too-many-locals + +import json +from knack.log import get_logger + +from msrestazure.azure_exceptions import CloudError + +from azure.cli.core.azclierror import ResourceNotFoundError, MutuallyExclusiveArgumentError, \ + InvalidArgumentValueError, CommandNotFoundError +from azure.cli.core.commands.client_factory import get_subscription_id +from azext_k8s_extension.vendored_sdks.models import ConfigurationIdentity +# from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate +from azext_k8s_extension.vendored_sdks.models import ErrorResponseException + +from .partner_extensions.ContainerInsights import ContainerInsights +from .partner_extensions.AzureDefender import AzureDefender +from .partner_extensions.OpenServiceMesh import OpenServiceMesh +from .partner_extensions.DefaultExtension import DefaultExtension + +from ._client_factory import cf_resources + +logger = get_logger(__name__) + + +# A factory method to return the correct extension class based off of the extension name +def ExtensionFactory(extension_name): + extension_map = { + 'microsoft.azuremonitor.containers': ContainerInsights, + 'microsoft.azuredefender.kubernetes': AzureDefender, + 'microsoft.openservicemesh': OpenServiceMesh, + } + + # Return the extension if we find it in the map, else return the default + return extension_map.get(extension_name, DefaultExtension)() + + +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) + + try: + extension = client.get(resource_group_name, + cluster_rp, cluster_type, cluster_name, name) + return extension + except ErrorResponseException as ex: + # Customize the error message for resources not found + if ex.response.status_code == 404: + # If Cluster not found + if ex.message.__contains__("(ResourceNotFound)"): + message = "{0} Verify that the cluster-type is correct and the resource exists.".format( + ex.message) + # If Configuration not found + elif ex.message.__contains__("Operation returned an invalid status code 'Not Found'"): + message = "(ExtensionNotFound) The Resource {0}/{1}/{2}/Microsoft.KubernetesConfiguration/" \ + "extensions/{3} could not be found!".format( + cluster_rp, cluster_type, cluster_name, name) + else: + message = ex.message + raise ResourceNotFoundError(message) + + +def create_k8s_extension(cmd, client, resource_group_name, cluster_name, name, cluster_type, + extension_type, scope='cluster', 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): + """Create a new Extension Instance. + + """ + extension_type_lower = extension_type.lower() + + # Determine ClusterRP + cluster_rp = __get_cluster_rp(cluster_type) + + # Configuration Settings & Configuration Protected Settings + if configuration_settings is not None and configuration_settings_file is not None: + raise MutuallyExclusiveArgumentError( + 'Error! Both configuration-settings and configuration-settings-file cannot be provided.' + ) + + if configuration_protected_settings is not None and configuration_protected_settings_file is not None: + raise MutuallyExclusiveArgumentError( + 'Error! Both configuration-protected-settings and configuration-protected-settings-file ' + 'cannot be provided.' + ) + + config_settings = {} + config_protected_settings = {} + # Get Configuration Settings from file + if configuration_settings_file is not None: + config_settings = __get_config_settings_from_file(configuration_settings_file) + + 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 = __get_config_settings_from_file(configuration_protected_settings_file) + + if configuration_protected_settings is not None: + for dicts in configuration_protected_settings: + for key, value in dicts.items(): + config_protected_settings[key] = value + + # Identity is not created by default. Extension type must specify if identity is required. + create_identity = False + + extension_instance = None + + # Scope & Namespace validation - common to all extension-types + __validate_scope_and_namespace(scope, release_namespace, target_namespace) + + # Give Partners a chance to their extensionType specific validations and to set value over-rides. + + # Get the extension class based on the extension name + extension_class = ExtensionFactory(extension_type_lower) + extension_instance, name, create_identity = extension_class.Create( + cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type_lower, scope, + auto_upgrade_minor_version, release_train, version, target_namespace, release_namespace, config_settings, + config_protected_settings, configuration_settings_file, configuration_protected_settings_file) + + # Common validations + __validate_version_and_auto_upgrade(extension_instance.version, extension_instance.auto_upgrade_minor_version) + + # Create identity, if required + if create_identity: + extension_instance.identity, extension_instance.location = \ + __create_identity(cmd, resource_group_name, cluster_name, cluster_type, cluster_rp) + + # Try to create the resource + return client.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): + + """Patch an existing Extension Instance. + + """ + + # TODO: Remove this after we eventually get PATCH implemented for update and uncomment + raise CommandNotFoundError( + "\"k8s-extension update\" currently is not available. " + "Use \"k8s-extension create\" to update a previously created extension instance." + ) + + # # 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) + + # # Determine ClusterRP + # cluster_rp = __get_cluster_rp(cluster_type) + + # # Get the existing extensionInstance + # extension = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + + # extension_type_lower = extension.extension_type.lower() + + # # 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) + + # __validate_version_and_auto_upgrade(version, auto_upgrade_minor_version) + + # upd_extension = ExtensionInstanceUpdate(auto_upgrade_minor_version=auto_upgrade_minor_version, + # release_train=release_train, version=version) + + # return client.update(resource_group_name, cluster_rp, cluster_type, cluster_name, name, upd_extension) + + +def delete_k8s_extension(client, resource_group_name, cluster_name, name, cluster_type): + """Delete an existing Kubernetes Extension. + + """ + # Determine ClusterRP + cluster_rp = __get_cluster_rp(cluster_type) + + k8s_extension_instance_name = name + + return client.delete(resource_group_name, cluster_rp, cluster_type, cluster_name, k8s_extension_instance_name) + + +def __create_identity(cmd, resource_group_name, cluster_name, cluster_type, cluster_rp): + subscription_id = get_subscription_id(cmd.cli_ctx) + resources = cf_resources(cmd.cli_ctx, subscription_id) + + cluster_resource_id = '/subscriptions/{0}/resourceGroups/{1}/providers/{2}/{3}/{4}'.format(subscription_id, + resource_group_name, + cluster_rp, + cluster_type, + cluster_name) + + if cluster_rp == 'Microsoft.Kubernetes': + parent_api_version = '2020-01-01-preview' + elif cluster_rp == 'Microsoft.ResourceConnector': + parent_api_version = '2020-09-15-privatepreview' + elif cluster_rp == 'Microsoft.ContainerService': + parent_api_version = '2017-07-01' + else: + raise InvalidArgumentValueError( + "Error! Cluster type '{}' is not supported for extension identity".format(cluster_type) + ) + + try: + resource = resources.get_by_id(cluster_resource_id, parent_api_version) + location = str(resource.location.lower()) + except CloudError as ex: + raise ex + identity_type = "SystemAssigned" + + return ConfigurationIdentity(type=identity_type), location + + +def __get_cluster_rp(cluster_type): + rp = "" + if cluster_type.lower() == 'connectedclusters': + rp = 'Microsoft.Kubernetes' + elif cluster_type.lower() == 'appliances': + rp = 'Microsoft.ResourceConnector' + elif cluster_type.lower() == '': + rp = 'Microsoft.ContainerService' + else: + raise InvalidArgumentValueError("Error! Cluster type '{}' is not supported".format(cluster_type)) + return rp + + +def __validate_scope_and_namespace(scope, release_namespace, target_namespace): + if scope == 'cluster': + if target_namespace is not None: + message = "When Scope is 'cluster', target-namespace must not be given." + raise MutuallyExclusiveArgumentError(message) + else: + if release_namespace is not None: + message = "When Scope is 'namespace', release-namespace must not be given." + raise MutuallyExclusiveArgumentError(message) + + +def __validate_version_and_auto_upgrade(version, auto_upgrade_minor_version): + if version is not None: + if auto_upgrade_minor_version: + message = "To pin to specific version, auto-upgrade-minor-version must be set to 'false'." + raise MutuallyExclusiveArgumentError(message) + + auto_upgrade_minor_version = False + + +def __get_config_settings_from_file(file_path): + try: + config_file = open(file_path,) + settings = json.load(config_file) + except ValueError: + raise Exception("File {} is not a valid JSON file".format(file_path)) + + files = len(settings) + if files == 0: + raise Exception("File {} is empty".format(file_path)) + + return settings diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py new file mode 100644 index 00000000000..172662f4e57 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py @@ -0,0 +1,73 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument + +from knack.log import get_logger + +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceForCreate +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate +from azext_k8s_extension.vendored_sdks.models import ScopeCluster +from azext_k8s_extension.vendored_sdks.models import Scope + +from .PartnerExtensionModel import PartnerExtensionModel +from .ContainerInsights import _get_container_insights_settings + +logger = get_logger(__name__) + + +class AzureDefender(PartnerExtensionModel): + def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, + scope, auto_upgrade_minor_version, release_train, version, target_namespace, + release_namespace, configuration_settings, configuration_protected_settings, + configuration_settings_file, configuration_protected_settings_file): + + """ExtensionType 'microsoft.azuredefender.kubernetes' specific validations & defaults for Create + Must create and return a valid 'ExtensionInstanceForCreate' object. + + """ + # NOTE-1: Replace default scope creation with your customization! + ext_scope = None + # Hardcoding name, release_namespace and scope since ci only supports one instance and cluster scope + # and platform doesnt have support yet extension specific constraints like this + name = extension_type.lower() + release_namespace = "azuredefender" + # Scope is always cluster + scope_cluster = ScopeCluster(release_namespace=release_namespace) + ext_scope = Scope(cluster=scope_cluster, namespace=None) + + is_ci_extension_type = False + + logger.warning('Ignoring name, release-namespace and scope parameters since %s ' + 'only supports cluster scope and single instance of this extension', extension_type) + + _get_container_insights_settings(cmd, resource_group_name, cluster_name, configuration_settings, + configuration_protected_settings, is_ci_extension_type) + + # NOTE-2: Return a valid ExtensionInstanceForCreate object, Instance name and flag for Identity + create_identity = True + extension_instance = ExtensionInstanceForCreate( + extension_type=extension_type, + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version, + scope=ext_scope, + configuration_settings=configuration_settings, + configuration_protected_settings=configuration_protected_settings, + identity=None, + location="" + ) + return extension_instance, name, create_identity + + def Update(self, extension, auto_upgrade_minor_version, release_train, version): + """ExtensionType 'microsoft.azuredefender.kubernetes' specific validations & defaults for Update + Must create and return a valid 'ExtensionInstanceUpdate' object. + + """ + return ExtensionInstanceUpdate( + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version + ) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py new file mode 100644 index 00000000000..ada94d985a9 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py @@ -0,0 +1,460 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument + +import datetime +import json + +from knack.log import get_logger + +from azure.cli.core.azclierror import InvalidArgumentValueError +from azure.cli.core.commands import LongRunningOperation +from azure.cli.core.commands.client_factory import get_mgmt_service_client, get_subscription_id +from azure.cli.core.util import sdk_no_wait +from msrestazure.azure_exceptions import CloudError +from msrestazure.tools import parse_resource_id, is_valid_resource_id + +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceForCreate +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate +from azext_k8s_extension.vendored_sdks.models import ScopeCluster +from azext_k8s_extension.vendored_sdks.models import Scope + +from .PartnerExtensionModel import PartnerExtensionModel + +from .._client_factory import ( + cf_resources, cf_resource_groups, cf_log_analytics) + +logger = get_logger(__name__) + + +class ContainerInsights(PartnerExtensionModel): + def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, + scope, auto_upgrade_minor_version, release_train, version, target_namespace, + release_namespace, configuration_settings, configuration_protected_settings, + configuration_settings_file, configuration_protected_settings_file): + + """ExtensionType 'microsoft.azuremonitor.containers' specific validations & defaults for Create + Must create and return a valid 'ExtensionInstanceForCreate' object. + + """ + # NOTE-1: Replace default scope creation with your customization! + ext_scope = None + # Hardcoding name, release_namespace and scope since container-insights only supports one instance and cluster + # scope and platform doesnt have support yet extension specific constraints like this + name = 'azuremonitor-containers' + release_namespace = 'azuremonitor-containers' + # Scope is always cluster + scope_cluster = ScopeCluster(release_namespace=release_namespace) + ext_scope = Scope(cluster=scope_cluster, namespace=None) + + is_ci_extension_type = True + + logger.warning('Ignoring name, release-namespace and scope parameters since %s ' + 'only supports cluster scope and single instance of this extension', extension_type) + + _get_container_insights_settings(cmd, resource_group_name, cluster_name, configuration_settings, + configuration_protected_settings, is_ci_extension_type) + + # NOTE-2: Return a valid ExtensionInstanceForCreate object, Instance name and flag for Identity + create_identity = True + extension_instance = ExtensionInstanceForCreate( + extension_type=extension_type, + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version, + scope=ext_scope, + configuration_settings=configuration_settings, + configuration_protected_settings=configuration_protected_settings, + identity=None, + location="" + ) + return extension_instance, name, create_identity + + def Update(self, extension, auto_upgrade_minor_version, release_train, version): + """ExtensionType 'microsoft.azuremonitor.containers' specific validations & defaults for Update + Must create and return a valid 'ExtensionInstanceUpdate' object. + + """ + return ExtensionInstanceUpdate( + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version + ) + + +# Custom Validation Logic for Container Insights + +def _invoke_deployment(cmd, resource_group_name, deployment_name, template, parameters, validate, no_wait, + subscription_id=None): + from azure.cli.core.profiles import ResourceType + deployment_properties = cmd.get_models('DeploymentProperties', resource_type=ResourceType.MGMT_RESOURCE_RESOURCES) + properties = deployment_properties(template=template, parameters=parameters, mode='incremental') + smc = get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES, + subscription_id=subscription_id).deployments + if validate: + logger.info('==== BEGIN TEMPLATE ====') + logger.info(json.dumps(template, indent=2)) + logger.info('==== END TEMPLATE ====') + + if cmd.supported_api_version(min_api='2019-10-01', resource_type=ResourceType.MGMT_RESOURCE_RESOURCES): + deployment_temp = cmd.get_models('Deployment', resource_type=ResourceType.MGMT_RESOURCE_RESOURCES) + deployment = deployment_temp(properties=properties) + + if validate: + validation_poller = smc.validate(resource_group_name, deployment_name, deployment) + return LongRunningOperation(cmd.cli_ctx)(validation_poller) + return sdk_no_wait(no_wait, smc.create_or_update, resource_group_name, deployment_name, deployment) + + if validate: + return smc.validate(resource_group_name, deployment_name, properties) + return sdk_no_wait(no_wait, smc.create_or_update, resource_group_name, deployment_name, properties) + + +def _ensure_default_log_analytics_workspace_for_monitoring(cmd, subscription_id, + cluster_resource_group_name, cluster_name): + # mapping for azure public cloud + # log analytics workspaces cannot be created in WCUS region due to capacity limits + # so mapped to EUS per discussion with log analytics team + # pylint: disable=too-many-locals,too-many-statements + + azurecloud_location_to_oms_region_code_map = { + "australiasoutheast": "ASE", + "australiaeast": "EAU", + "australiacentral": "CAU", + "canadacentral": "CCA", + "centralindia": "CIN", + "centralus": "CUS", + "eastasia": "EA", + "eastus": "EUS", + "eastus2": "EUS2", + "eastus2euap": "EAP", + "francecentral": "PAR", + "japaneast": "EJP", + "koreacentral": "SE", + "northeurope": "NEU", + "southcentralus": "SCUS", + "southeastasia": "SEA", + "uksouth": "SUK", + "usgovvirginia": "USGV", + "westcentralus": "EUS", + "westeurope": "WEU", + "westus": "WUS", + "westus2": "WUS2" + } + azurecloud_region_to_oms_region_map = { + "australiacentral": "australiacentral", + "australiacentral2": "australiacentral", + "australiaeast": "australiaeast", + "australiasoutheast": "australiasoutheast", + "brazilsouth": "southcentralus", + "canadacentral": "canadacentral", + "canadaeast": "canadacentral", + "centralus": "centralus", + "centralindia": "centralindia", + "eastasia": "eastasia", + "eastus": "eastus", + "eastus2": "eastus2", + "francecentral": "francecentral", + "francesouth": "francecentral", + "japaneast": "japaneast", + "japanwest": "japaneast", + "koreacentral": "koreacentral", + "koreasouth": "koreacentral", + "northcentralus": "eastus", + "northeurope": "northeurope", + "southafricanorth": "westeurope", + "southafricawest": "westeurope", + "southcentralus": "southcentralus", + "southeastasia": "southeastasia", + "southindia": "centralindia", + "uksouth": "uksouth", + "ukwest": "uksouth", + "westcentralus": "eastus", + "westeurope": "westeurope", + "westindia": "centralindia", + "westus": "westus", + "westus2": "westus2" + } + + # mapping for azure china cloud + # currently log analytics supported only China East 2 region + azurechina_location_to_oms_region_code_map = { + "chinaeast": "EAST2", + "chinaeast2": "EAST2", + "chinanorth": "EAST2", + "chinanorth2": "EAST2" + } + azurechina_region_to_oms_region_map = { + "chinaeast": "chinaeast2", + "chinaeast2": "chinaeast2", + "chinanorth": "chinaeast2", + "chinanorth2": "chinaeast2" + } + + # mapping for azure us governmner cloud + azurefairfax_location_to_oms_region_code_map = { + "usgovvirginia": "USGV" + } + azurefairfax_region_to_oms_region_map = { + "usgovvirginia": "usgovvirginia" + } + + cluster_location = '' + resources = cf_resources(cmd.cli_ctx, subscription_id) + + cluster_resource_id = '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Kubernetes' \ + '/connectedClusters/{2}'.format(subscription_id, cluster_resource_group_name, cluster_name) + try: + resource = resources.get_by_id(cluster_resource_id, '2020-01-01-preview') + cluster_location = resource.location.lower() + except CloudError as ex: + raise ex + + cloud_name = cmd.cli_ctx.cloud.name.lower() + workspace_region = "eastus" + workspace_region_code = "EUS" + + # sanity check that locations and clouds match. + if ((cloud_name == 'azurecloud' and azurechina_region_to_oms_region_map.get(cluster_location, False)) or + (cloud_name == 'azurecloud' and azurefairfax_region_to_oms_region_map.get(cluster_location, False))): + raise InvalidArgumentValueError( + 'Wrong cloud (azurecloud) setting for region {}, please use "az cloud set ..."' + .format(cluster_location) + ) + + if ((cloud_name == 'azurechinacloud' and azurecloud_region_to_oms_region_map.get(cluster_location, False)) or + (cloud_name == 'azurechinacloud' and azurefairfax_region_to_oms_region_map.get(cluster_location, False))): + raise InvalidArgumentValueError( + 'Wrong cloud (azurechinacloud) setting for region {}, please use "az cloud set ..."' + .format(cluster_location) + ) + + if ((cloud_name == 'azureusgovernment' and azurecloud_region_to_oms_region_map.get(cluster_location, False)) or + (cloud_name == 'azureusgovernment' and azurechina_region_to_oms_region_map.get(cluster_location, False))): + raise InvalidArgumentValueError( + 'Wrong cloud (azureusgovernment) setting for region {}, please use "az cloud set ..."' + .format(cluster_location) + ) + + if cloud_name == 'azurecloud': + workspace_region = azurecloud_region_to_oms_region_map.get(cluster_location, "eastus") + workspace_region_code = azurecloud_location_to_oms_region_code_map.get(workspace_region, "EUS") + elif cloud_name == 'azurechinacloud': + workspace_region = azurechina_region_to_oms_region_map.get(cluster_location, "chinaeast2") + workspace_region_code = azurechina_location_to_oms_region_code_map.get(workspace_region, "EAST2") + elif cloud_name == 'azureusgovernment': + workspace_region = azurefairfax_region_to_oms_region_map.get(cluster_location, "usgovvirginia") + workspace_region_code = azurefairfax_location_to_oms_region_code_map.get(workspace_region, "USGV") + else: + logger.error("AKS Monitoring addon not supported in cloud : %s", cloud_name) + + default_workspace_resource_group = 'DefaultResourceGroup-' + workspace_region_code + default_workspace_name = 'DefaultWorkspace-{0}-{1}'.format(subscription_id, workspace_region_code) + default_workspace_resource_id = '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.OperationalInsights' \ + '/workspaces/{2}'.format(subscription_id, default_workspace_resource_group, default_workspace_name) + resource_groups = cf_resource_groups(cmd.cli_ctx, subscription_id) + + # check if default RG exists + if resource_groups.check_existence(default_workspace_resource_group): + try: + resource = resources.get_by_id(default_workspace_resource_id, '2015-11-01-preview') + return resource.id + except CloudError as ex: + if ex.status_code != 404: + raise ex + else: + resource_groups.create_or_update(default_workspace_resource_group, { + 'location': workspace_region}) + + default_workspace_params = { + 'location': workspace_region, + 'properties': { + 'sku': { + 'name': 'standalone' + } + } + } + async_poller = resources.create_or_update_by_id(default_workspace_resource_id, '2015-11-01-preview', + default_workspace_params) + + ws_resource_id = '' + while True: + result = async_poller.result(15) + if async_poller.done(): + ws_resource_id = result.id + break + + return ws_resource_id + + +def _ensure_container_insights_for_monitoring(cmd, workspace_resource_id): + # extract subscription ID and resource group from workspace_resource_id URL + parsed = parse_resource_id(workspace_resource_id) + subscription_id, resource_group = parsed["subscription"], parsed["resource_group"] + + resources = cf_resources(cmd.cli_ctx, subscription_id) + try: + resource = resources.get_by_id(workspace_resource_id, '2015-11-01-preview') + location = resource.location + except CloudError as ex: + raise ex + + unix_time_in_millis = int( + (datetime.datetime.utcnow() - datetime.datetime.utcfromtimestamp(0)).total_seconds() * 1000.0) + + solution_deployment_name = 'ContainerInsights-{}'.format(unix_time_in_millis) + + # pylint: disable=line-too-long + template = { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Azure Monitor Log Analytics Resource ID" + } + }, + "workspaceRegion": { + "type": "string", + "metadata": { + "description": "Azure Monitor Log Analytics workspace region" + } + }, + "solutionDeploymentName": { + "type": "string", + "metadata": { + "description": "Name of the solution deployment" + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "name": "[parameters('solutionDeploymentName')]", + "apiVersion": "2017-05-10", + "subscriptionId": "[split(parameters('workspaceResourceId'),'/')[2]]", + "resourceGroup": "[split(parameters('workspaceResourceId'),'/')[4]]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "variables": {}, + "resources": [ + { + "apiVersion": "2015-11-01-preview", + "type": "Microsoft.OperationsManagement/solutions", + "location": "[parameters('workspaceRegion')]", + "name": "[Concat('ContainerInsights', '(', split(parameters('workspaceResourceId'),'/')" + "[8], ')')]", + "properties": { + "workspaceResourceId": "[parameters('workspaceResourceId')]" + }, + "plan": { + "name": "[Concat('ContainerInsights', '(', split(parameters('workspaceResourceId')," + "'/')[8], ')')]", + "product": "[Concat('OMSGallery/', 'ContainerInsights')]", + "promotionCode": "", + "publisher": "Microsoft" + } + } + ] + }, + "parameters": {} + } + } + ] + } + + params = { + "workspaceResourceId": { + "value": workspace_resource_id + }, + "workspaceRegion": { + "value": location + }, + "solutionDeploymentName": { + "value": solution_deployment_name + } + } + + deployment_name = 'arc-k8s-monitoring-{}'.format(unix_time_in_millis) + # publish the Container Insights solution to the Log Analytics workspace + return _invoke_deployment(cmd, resource_group, deployment_name, template, params, + validate=False, no_wait=False, subscription_id=subscription_id) + + +def _get_container_insights_settings(cmd, cluster_resource_group_name, cluster_name, configuration_settings, + configuration_protected_settings, is_ci_extension_type): + + subscription_id = get_subscription_id(cmd.cli_ctx) + workspace_resource_id = '' + + if configuration_settings is not None: + if 'loganalyticsworkspaceresourceid' in configuration_settings: + configuration_settings['logAnalyticsWorkspaceResourceID'] = \ + configuration_settings.pop('loganalyticsworkspaceresourceid') + + if 'logAnalyticsWorkspaceResourceID' in configuration_settings: + workspace_resource_id = configuration_settings['logAnalyticsWorkspaceResourceID'] + + workspace_resource_id = workspace_resource_id.strip() + + if configuration_protected_settings is not None: + if 'proxyEndpoint' in configuration_protected_settings: + # current supported format for proxy endpoint is http(s)://:@: + # do some basic validation since the ci agent does the complete validation + proxy = configuration_protected_settings['proxyEndpoint'].strip().lower() + proxy_parts = proxy.split('://') + if (not proxy) or (not proxy.startswith('http://') and not proxy.startswith('https://')) or \ + (len(proxy_parts) != 2): + raise InvalidArgumentValueError( + 'proxyEndpoint url should in this format http(s)://:@:' + ) + logger.info("successfully validated proxyEndpoint url hence passing proxy endpoint to extension") + configuration_protected_settings['omsagent.proxy'] = configuration_protected_settings['proxyEndpoint'] + + if not workspace_resource_id: + workspace_resource_id = _ensure_default_log_analytics_workspace_for_monitoring( + cmd, subscription_id, cluster_resource_group_name, cluster_name) + else: + if not is_valid_resource_id(workspace_resource_id): + raise InvalidArgumentValueError('{} is not a valid Azure resource ID.'.format(workspace_resource_id)) + + if is_ci_extension_type: + _ensure_container_insights_for_monitoring(cmd, workspace_resource_id).result() + + # extract subscription ID and resource group from workspace_resource_id URL + parsed = parse_resource_id(workspace_resource_id) + workspace_sub_id, workspace_rg_name, workspace_name = \ + parsed["subscription"], parsed["resource_group"], parsed["name"] + + log_analytics_client = cf_log_analytics(cmd.cli_ctx, workspace_sub_id) + log_analytics_workspace = log_analytics_client.workspaces.get(workspace_rg_name, workspace_name) + if not log_analytics_workspace: + raise InvalidArgumentValueError( + 'Fails to retrieve workspace by {}'.format(workspace_name)) + + shared_keys = log_analytics_client.shared_keys.get_shared_keys( + workspace_rg_name, workspace_name) + if not shared_keys: + raise InvalidArgumentValueError('Fails to retrieve shared key for workspace {}'.format( + log_analytics_workspace)) + configuration_protected_settings['omsagent.secret.wsid'] = log_analytics_workspace.customer_id + configuration_settings['logAnalyticsWorkspaceResourceID'] = workspace_resource_id + configuration_protected_settings['omsagent.secret.key'] = shared_keys.primary_shared_key + # set the domain for the ci agent for non azure public clouds + cloud_name = cmd.cli_ctx.cloud.name + if cloud_name.lower() == 'azurechinacloud': + configuration_settings['omsagent.domain'] = 'opinsights.azure.cn' + elif cloud_name.lower() == 'azureusgovernment': + configuration_settings['omsagent.domain'] = 'opinsights.azure.us' + elif cloud_name.lower() == 'usnat': + configuration_settings['omsagent.domain'] = 'opinsights.azure.eaglex.ic.gov' + elif cloud_name.lower() == 'ussec': + configuration_settings['omsagent.domain'] = 'opinsights.azure.microsoft.scloud' diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py new file mode 100644 index 00000000000..243371e47b7 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py @@ -0,0 +1,62 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument + +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceForCreate +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate +from azext_k8s_extension.vendored_sdks.models import ScopeCluster +from azext_k8s_extension.vendored_sdks.models import ScopeNamespace +from azext_k8s_extension.vendored_sdks.models import Scope + +from .PartnerExtensionModel import PartnerExtensionModel + + +class DefaultExtension(PartnerExtensionModel): + def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, + scope, auto_upgrade_minor_version, release_train, version, target_namespace, + release_namespace, configuration_settings, configuration_protected_settings, + configuration_settings_file, configuration_protected_settings_file): + + """Default validations & defaults for Create + Must create and return a valid 'ExtensionInstanceForCreate' object. + + """ + ext_scope = None + if scope is None or scope.lower() == 'cluster': + scope_cluster = ScopeCluster(release_namespace=release_namespace) + ext_scope = Scope(cluster=scope_cluster, namespace=None) + else: + scope_namespace = ScopeNamespace(target_namespace=target_namespace) + ext_scope = Scope(namespace=scope_namespace, cluster=None) + + # If release-train is not input, set it to 'stable' + if release_train is None: + release_train = 'stable' + + create_identity = False + extension_instance = ExtensionInstanceForCreate( + extension_type=extension_type, + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version, + scope=ext_scope, + configuration_settings=configuration_settings, + configuration_protected_settings=configuration_protected_settings, + identity=None, + location="" + ) + return extension_instance, name, create_identity + + def Update(self, extension, auto_upgrade_minor_version, release_train, version): + """Default validations & defaults for Update + Must create and return a valid 'ExtensionInstanceUpdate' object. + + """ + return ExtensionInstanceUpdate( + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version + ) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/OpenServiceMesh.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/OpenServiceMesh.py new file mode 100644 index 00000000000..b9e530877dc --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/OpenServiceMesh.py @@ -0,0 +1,95 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument + +from azure.cli.core.azclierror import InvalidArgumentValueError, RequiredArgumentMissingError +from knack.log import get_logger + +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceForCreate +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate +from azext_k8s_extension.vendored_sdks.models import ScopeCluster +from azext_k8s_extension.vendored_sdks.models import Scope + +from .PartnerExtensionModel import PartnerExtensionModel + +logger = get_logger(__name__) + + +class OpenServiceMesh(PartnerExtensionModel): + def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, + scope, auto_upgrade_minor_version, release_train, version, target_namespace, + release_namespace, configuration_settings, configuration_protected_settings, + configuration_settings_file, configuration_protected_settings_file): + + """ExtensionType 'microsoft.openservicemesh' specific validations & defaults for Create + Must create and return a valid 'ExtensionInstanceForCreate' object. + + """ + # NOTE-1: Replace default scope creation with your customization, if required + # Scope must always be cluster + ext_scope = None + if scope == 'namespace': + raise InvalidArgumentValueError("Invalid scope '{}'. This extension can be installed " + "only at 'cluster' scope.".format(scope)) + + scope_cluster = ScopeCluster(release_namespace=release_namespace) + ext_scope = Scope(cluster=scope_cluster, namespace=None) + + valid_release_trains = ['staging', 'pilot'] + # If release-train is not input, set it to 'stable' + if release_train is None: + raise RequiredArgumentMissingError( + "A release-train must be provided. Valid values are 'staging', 'pilot'." + ) + + if release_train.lower() in valid_release_trains: + # version is a mandatory if release-train is staging or pilot + if version is None: + raise RequiredArgumentMissingError( + "A version must be provided for release-train {}.".format(release_train) + ) + # If the release-train is 'staging' or 'pilot' then auto-upgrade-minor-version MUST be set to False + if auto_upgrade_minor_version or auto_upgrade_minor_version is None: + auto_upgrade_minor_version = False + logger.warning("Setting auto-upgrade-minor-version to False since release-train is '%s'", release_train) + else: + raise InvalidArgumentValueError( + "Invalid release-train '{}'. Valid values are 'staging', 'pilot'.".format(release_train) + ) + + # NOTE-2: Return a valid ExtensionInstanceForCreate object, Instance name and flag for Identity + create_identity = False + extension_instance = ExtensionInstanceForCreate( + extension_type=extension_type, + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version, + scope=ext_scope, + configuration_settings=configuration_settings, + configuration_protected_settings=configuration_protected_settings, + identity=None, + location="" + ) + return extension_instance, name, create_identity + + def Update(self, extension, auto_upgrade_minor_version, release_train, version): + """ExtensionType 'microsoft.openservicemesh' specific validations & defaults for Update + Must create and return a valid 'ExtensionInstanceUpdate' object. + + """ + # auto-upgrade-minor-version MUST be set to False if release_train is staging or pilot + if release_train.lower() in 'staging' 'pilot': + if auto_upgrade_minor_version or auto_upgrade_minor_version is None: + auto_upgrade_minor_version = False + # Set version to None to always get the latest version - user cannot override + version = None + logger.warning("Setting auto-upgrade-minor-version to False since release-train is '%s'", release_train) + + return ExtensionInstanceUpdate( + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version + ) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py new file mode 100644 index 00000000000..c863a8d3833 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py @@ -0,0 +1,19 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from abc import ABC, abstractmethod + + +class PartnerExtensionModel(ABC): + @abstractmethod + def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, + scope, auto_upgrade_minor_version, release_train, version, target_namespace, + release_namespace, configuration_settings, configuration_protected_settings, + configuration_settings_file, configuration_protected_settings_file): + pass + + @abstractmethod + def Update(self, extension, auto_upgrade_minor_version, release_train, version): + pass diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/k8s-extension/azext_k8s_extension/tests/__init__.py b/src/k8s-extension/azext_k8s_extension/tests/__init__.py new file mode 100644 index 00000000000..99c0f28cd71 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/tests/__init__.py @@ -0,0 +1,5 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ----------------------------------------------------------------------------- diff --git a/src/k8s-extension/azext_k8s_extension/tests/latest/__init__.py b/src/k8s-extension/azext_k8s_extension/tests/latest/__init__.py new file mode 100644 index 00000000000..99c0f28cd71 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/tests/latest/__init__.py @@ -0,0 +1,5 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ----------------------------------------------------------------------------- diff --git a/src/k8s-extension/azext_k8s_extension/tests/latest/recordings/test_k8s_extension.yaml b/src/k8s-extension/azext_k8s_extension/tests/latest/recordings/test_k8s_extension.yaml new file mode 100644 index 00000000000..127b21ac873 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/tests/latest/recordings/test_k8s_extension.yaml @@ -0,0 +1,270 @@ +interactions: +- request: + body: '{"properties": {"extensionType": "microsoft.openservicemesh", "autoUpgradeMinorVersion": + false, "releaseTrain": "staging", "version": "0.1.0", "scope": {"cluster": {}}, + "configurationSettings": {}, "configurationProtectedSettings": {}}, "location": + ""}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-extension create + Connection: + - keep-alive + Content-Length: + - '252' + Content-Type: + - application/json; charset=utf-8 + ParameterSetName: + - -g -n -c --cluster-type --extension-type --release-train --version + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.1.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh?api-version=2020-07-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh","name":"openservice-mesh","type":"Microsoft.KubernetesConfiguration/extensions","properties":{"configurationSettings":{},"statuses":[],"extensionType":"microsoft.openservicemesh","autoUpgradeMinorVersion":false,"releaseTrain":"staging","version":"0.1.0","scope":{"cluster":{"releaseNamespace":"arc-osm-system"}},"installState":"Pending","lastStatusTime":null,"errorInfo":{},"creationTime":"2021-03-08T23:14:12.4010326+00:00","lastModifiedTime":"2021-03-08T23:14:12.4010327+00:00"}}' + headers: + api-supported-versions: + - 2020-07-01-Preview + cache-control: + - no-cache + content-length: + - '708' + content-type: + - application/json; charset=utf-8 + date: + - Mon, 08 Mar 2021 23:14:11 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding,Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-extension list + Connection: + - keep-alive + ParameterSetName: + - -c -g --cluster-type + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.1.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions?api-version=2020-07-01-preview + response: + body: + string: '{"value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh","name":"openservice-mesh","type":"Microsoft.KubernetesConfiguration/extensions","properties":{"extensionType":"microsoft.openservicemesh","autoUpgradeMinorVersion":false,"releaseTrain":"staging","version":"0.1.0","scope":{"cluster":{"releaseNamespace":"arc-osm-system"}},"installState":"Pending","lastStatusTime":null,"errorInfo":{},"creationTime":"2021-03-08T23:14:12.4010326+00:00","lastModifiedTime":"2021-03-08T23:14:12.4010327+00:00"}},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/hci22jan21","name":"hci22jan21","type":"Microsoft.KubernetesConfiguration/extensions","properties":{"extensionType":"microsoft.azstackhci.operator","autoUpgradeMinorVersion":true,"releaseTrain":"stable","version":"1.0.0","scope":{"cluster":{"releaseNamespace":null}},"installState":"Pending","lastStatusTime":null,"errorInfo":{},"creationTime":"2021-01-22T20:49:34.3336157+00:00","lastModifiedTime":"2021-01-22T20:49:34.3336249+00:00"}}],"nextLink":null}' + headers: + api-supported-versions: + - 2020-07-01-Preview + cache-control: + - no-cache + content-length: + - '1341' + content-type: + - application/json; charset=utf-8 + date: + - Mon, 08 Mar 2021 23:14:13 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding,Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-extension show + Connection: + - keep-alive + ParameterSetName: + - -c -g -n --cluster-type + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.1.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh?api-version=2020-07-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh","name":"openservice-mesh","type":"Microsoft.KubernetesConfiguration/extensions","properties":{"configurationSettings":{},"statuses":[],"extensionType":"microsoft.openservicemesh","autoUpgradeMinorVersion":false,"releaseTrain":"staging","version":"0.1.0","scope":{"cluster":{"releaseNamespace":"arc-osm-system"}},"installState":"Pending","lastStatusTime":null,"errorInfo":{},"creationTime":"2021-03-08T23:14:12.4010326+00:00","lastModifiedTime":"2021-03-08T23:14:12.4010327+00:00"}}' + headers: + api-supported-versions: + - 2020-07-01-Preview + cache-control: + - no-cache + content-length: + - '708' + content-type: + - application/json; charset=utf-8 + date: + - Mon, 08 Mar 2021 23:14:14 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding,Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-extension delete + Connection: + - keep-alive + Content-Length: + - '0' + ParameterSetName: + - -g -c -n --cluster-type -y + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.1.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh?api-version=2020-07-01-preview + response: + body: + string: '{"content":null,"statusCode":200,"headers":[],"version":"1.1","reasonPhrase":"OK","trailingHeaders":[],"requestMessage":null,"isSuccessStatusCode":true}' + headers: + api-supported-versions: + - 2020-07-01-Preview + cache-control: + - no-cache + content-length: + - '152' + content-type: + - application/json; charset=utf-8 + date: + - Mon, 08 Mar 2021 23:14:14 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-deletes: + - '14999' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-extension list + Connection: + - keep-alive + ParameterSetName: + - -c -g --cluster-type + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.1.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions?api-version=2020-07-01-preview + response: + body: + string: '{"value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/hci22jan21","name":"hci22jan21","type":"Microsoft.KubernetesConfiguration/extensions","properties":{"extensionType":"microsoft.azstackhci.operator","autoUpgradeMinorVersion":true,"releaseTrain":"stable","version":"1.0.0","scope":{"cluster":{"releaseNamespace":null}},"installState":"Pending","lastStatusTime":null,"errorInfo":{},"creationTime":"2021-01-22T20:49:34.3336157+00:00","lastModifiedTime":"2021-01-22T20:49:34.3336249+00:00"}}],"nextLink":null}' + headers: + api-supported-versions: + - 2020-07-01-Preview + cache-control: + - no-cache + content-length: + - '673' + content-type: + - application/json; charset=utf-8 + date: + - Mon, 08 Mar 2021 23:14:16 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding,Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +version: 1 diff --git a/src/k8s-extension/azext_k8s_extension/tests/latest/test_k8s_extension_scenario.py b/src/k8s-extension/azext_k8s_extension/tests/latest/test_k8s_extension_scenario.py new file mode 100644 index 00000000000..0e53c9e6691 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/tests/latest/test_k8s_extension_scenario.py @@ -0,0 +1,67 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import os +import unittest + +from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer, record_only) + + +TEST_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '..')) + + +class K8sExtensionScenarioTest(ScenarioTest): + @record_only() + @ResourceGroupPreparer(name_prefix='cli_test_k8s_extension') + def test_k8s_extension(self): + resource_type = 'microsoft.openservicemesh' + self.kwargs.update({ + 'name': 'openservice-mesh', + 'rg': 'nanthirg0923', + 'cluster_name': 'nanthicluster0923', + 'cluster_type': 'connectedClusters', + 'extension_type': resource_type, + 'release_train': 'staging', + 'version': '0.1.0' + }) + + self.cmd('k8s-extension create -g {rg} -n {name} -c {cluster_name} --cluster-type {cluster_type} --extension-type {extension_type} --release-train {release_train} --version {version}', checks=[ + self.check('name', '{name}'), + self.check('releaseTrain', '{release_train}'), + self.check('version', '{version}'), + self.check('resourceGroup', '{rg}'), + self.check('extensionType', '{extension_type}') + ]) + + # Update is disabled for now + # self.cmd('k8s-extension update -g {rg} -n {name} --tags foo=boo', checks=[ + # self.check('tags.foo', 'boo') + # ]) + + installed_exts = self.cmd('k8s-extension list -c {cluster_name} -g {rg} --cluster-type {cluster_type}').get_output_in_json() + found_extension = False + for item in installed_exts: + if item['extensionType'] == resource_type: + found_extension = True + break + self.assertTrue(found_extension) + + self.cmd('k8s-extension show -c {cluster_name} -g {rg} -n {name} --cluster-type {cluster_type}', checks=[ + self.check('name', '{name}'), + self.check('releaseTrain', '{release_train}'), + self.check('version', '{version}'), + self.check('resourceGroup', '{rg}'), + self.check('extensionType', '{extension_type}') + ]) + + self.cmd('k8s-extension delete -g {rg} -c {cluster_name} -n {name} --cluster-type {cluster_type} -y') + + installed_exts = self.cmd('k8s-extension list -c {cluster_name} -g {rg} --cluster-type {cluster_type}').get_output_in_json() + found_extension = False + for item in installed_exts: + if item['extensionType'] == resource_type: + found_extension = True + break + self.assertFalse(found_extension) diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py new file mode 100644 index 00000000000..d94dccac4c2 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from ._configuration import K8sExtensionClientConfiguration +from ._k8s_extension_client import K8sExtensionClient +__all__ = ['K8sExtensionClient', 'K8sExtensionClientConfiguration'] + +from .version import VERSION + +__version__ = VERSION + diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py new file mode 100644 index 00000000000..48080b2ee7d --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py @@ -0,0 +1,49 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- +from msrestazure import AzureConfiguration + +from .version import VERSION + + +class K8sExtensionClientConfiguration(AzureConfiguration): + """Configuration for K8sExtensionClient + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credentials: Credentials needed for the client to connect to Azure. + :type credentials: :mod:`A msrestazure Credentials + object` + :param subscription_id: The Azure subscription ID. This is a + GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000) + :type subscription_id: str + :param str base_url: Service URL + """ + + def __init__( + self, credentials, subscription_id, base_url=None): + + if credentials is None: + raise ValueError("Parameter 'credentials' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + if not base_url: + base_url = 'https://management.azure.com' + + super(K8sExtensionClientConfiguration, self).__init__(base_url) + + # Starting Autorest.Python 4.0.64, make connection pool activated by default + self.keep_alive = True + + self.add_user_agent('azure-mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self.add_user_agent('Azure-SDK-For-Python') + + self.credentials = credentials + self.subscription_id = subscription_id diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/_k8s_extension_client.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_k8s_extension_client.py new file mode 100644 index 00000000000..1b63ebfd1ac --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_k8s_extension_client.py @@ -0,0 +1,50 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.service_client import SDKClient +from msrest import Serializer, Deserializer + +from ._configuration import K8sExtensionClientConfiguration +from .operations import K8sExtensionsOperations +from . import models + + +class K8sExtensionClient(SDKClient): + """K8sExtension Client + + :ivar config: Configuration for client. + :vartype config: K8sExtensionClientConfiguration + + :ivar k8s_extensions: K8sExtensions operations + :vartype k8s_extensions: azure.mgmt.kubernetesconfiguration.operations.K8sExtensionsOperations + + :param credentials: Credentials needed for the client to connect to Azure. + :type credentials: :mod:`A msrestazure Credentials + object` + :param subscription_id: The Azure subscription ID. This is a + GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000) + :type subscription_id: str + :param str base_url: Service URL + """ + + def __init__( + self, credentials, subscription_id, base_url=None): + + self.config = K8sExtensionClientConfiguration(credentials, subscription_id, base_url) + super(K8sExtensionClient, self).__init__(self.config.credentials, self.config) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self.api_version = '2020-07-01-preview' + self._serialize = Serializer(client_models) + self._deserialize = Deserializer(client_models) + + self.k8s_extensions = K8sExtensionsOperations( + self._client, self.config, self._serialize, self._deserialize) diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py new file mode 100644 index 00000000000..166f80c01ea --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py @@ -0,0 +1,70 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +try: + from ._models_py3 import ErrorDefinition + from ._models_py3 import ErrorResponse, ErrorResponseException + from ._models_py3 import ExtensionInstance + from ._models_py3 import ExtensionInstanceForCreate + from ._models_py3 import ExtensionInstanceForList + from ._models_py3 import ExtensionInstanceUpdate + from ._models_py3 import ExtensionStatus + from ._models_py3 import ProxyResource + from ._models_py3 import Resource + from ._models_py3 import Result + from ._models_py3 import Scope + from ._models_py3 import ScopeCluster + from ._models_py3 import ScopeNamespace + from ._models_py3 import ConfigurationIdentity +except (SyntaxError, ImportError): + from ._models import ErrorDefinition + from ._models import ErrorResponse, ErrorResponseException + from ._models import ExtensionInstance + from ._models import ExtensionInstanceForCreate + from ._models import ExtensionInstanceForList + from ._models import ExtensionInstanceUpdate + from ._models import ExtensionStatus + from ._models import ProxyResource + from ._models import Resource + from ._models import Result + from ._models import Scope + from ._models import ScopeCluster + from ._models import ScopeNamespace + from ._models import ConfigurationIdentity +from ._paged_models import ExtensionInstanceForListPaged +from ._k8s_extension_client_enums import ( + MessageLevelType, + InstallStateType, + LevelType, + ResourceIdentityType, +) + +__all__ = [ + 'ErrorDefinition', + 'ErrorResponse', 'ErrorResponseException', + 'ExtensionInstance', + 'ExtensionInstanceForCreate', + 'ExtensionInstanceForList', + 'ConfigurationIdentity', + 'ExtensionInstanceUpdate', + 'ExtensionStatus', + 'ProxyResource', + 'Resource', + 'Result', + 'Scope', + 'ScopeCluster', + 'ScopeNamespace', + 'ExtensionInstanceForListPaged', + 'MessageLevelType', + 'InstallStateType', + 'LevelType', + 'ResourceIdentityType', +] diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_k8s_extension_client_enums.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_k8s_extension_client_enums.py new file mode 100644 index 00000000000..7be14a4b085 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_k8s_extension_client_enums.py @@ -0,0 +1,68 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from enum import Enum + + +class ComplianceStateType(str, Enum): + + pending = "Pending" + compliant = "Compliant" + noncompliant = "Noncompliant" + installed = "Installed" + failed = "Failed" + + +class MessageLevelType(str, Enum): + + error = "Error" + warning = "Warning" + information = "Information" + + +class OperatorType(str, Enum): + + flux = "Flux" + + +class OperatorScopeType(str, Enum): + + cluster = "cluster" + namespace = "namespace" + + +class ProvisioningStateType(str, Enum): + + accepted = "Accepted" + deleting = "Deleting" + running = "Running" + succeeded = "Succeeded" + failed = "Failed" + + +class InstallStateType(str, Enum): + + pending = "Pending" + installed = "Installed" + failed = "Failed" + + +class LevelType(str, Enum): + + error = "Error" + warning = "Warning" + information = "Information" + + +class ResourceIdentityType(str, Enum): + + system_assigned = "SystemAssigned" + none = "None" diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py new file mode 100644 index 00000000000..0a11097a24f --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py @@ -0,0 +1,587 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.serialization import Model +from msrest.exceptions import HttpOperationError + + +class CloudError(Model): + """CloudError. + """ + + _attribute_map = { + } + +class ConfigurationIdentity(Model): + """Identity for the managed cluster. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar principal_id: The principal id of the system assigned identity which + is used by the configuration. + :vartype principal_id: str + :ivar tenant_id: The tenant id of the system assigned identity which is + used by the configuration. + :vartype tenant_id: str + :param type: The type of identity used for the configuration. Type + 'SystemAssigned' will use an implicitly created identity. Type 'None' will + not use Managed Identity for the configuration. Possible values include: + 'SystemAssigned', 'None' + :type type: str or + ~azure.mgmt.kubernetesconfiguration.models.ResourceIdentityType + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'ResourceIdentityType'}, + } + + def __init__(self, **kwargs): + super(ConfigurationIdentity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = kwargs.get('type', None) + + +class ErrorDefinition(Model): + """Error definition. + + All required parameters must be populated in order to send to Azure. + + :param code: Required. Service specific error code which serves as the + substatus for the HTTP error code. + :type code: str + :param message: Required. Description of the error. + :type message: str + """ + + _validation = { + 'code': {'required': True}, + 'message': {'required': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ErrorDefinition, self).__init__(**kwargs) + self.code = kwargs.get('code', None) + self.message = kwargs.get('message', None) + + +class ErrorResponse(Model): + """Error response. + + :param error: Error definition. + :type error: ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDefinition'}, + } + + def __init__(self, **kwargs): + super(ErrorResponse, self).__init__(**kwargs) + self.error = kwargs.get('error', None) + + +class ErrorResponseException(HttpOperationError): + """Server responsed with exception of type: 'ErrorResponse'. + + :param deserialize: A deserializer + :param response: Server response to be deserialized. + """ + + def __init__(self, deserialize, response, *args): + + super(ErrorResponseException, self).__init__(deserialize, response, 'ErrorResponse', *args) + + +class Resource(Model): + """The Resource model definition. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class ProxyResource(Resource): + """ARM proxy resource. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ProxyResource, self).__init__(**kwargs) + + +class ExtensionInstance(ProxyResource): + """The Extension Instance object. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param extension_type: Type of the Extension, of which this resource is an + instance of. It must be one of the Extension Types registered with + Microsoft.KubernetesConfiguration by the Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this instance + participates in auto upgrade of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension instance, if + it is 'pinned' to a specific version. autoUpgradeMinorVersion must be + 'false'. + :type version: str + :param scope: Scope at which the extension instance is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs + for configuring this instance of the extension. + :type configuration_settings: dict[str, str] + :param install_state: Status of installation of this instance of the + extension. Possible values include: 'Pending', 'Installed', 'Failed' + :type install_state: str or + ~azure.mgmt.kubernetesconfiguration.models.InstallStateType + :param statuses: Status from this instance of the extension. + :type statuses: + list[~azure.mgmt.kubernetesconfiguration.models.ExtensionStatus] + :ivar creation_time: DateLiteral (per ISO8601) noting the time the + resource was created by the client (user). + :vartype creation_time: str + :ivar last_modified_time: DateLiteral (per ISO8601) noting the time the + resource was modified by the client (user). + :vartype last_modified_time: str + :ivar last_status_time: DateLiteral (per ISO8601) noting the time of last + status from the agent. + :vartype last_status_time: str + :ivar error_info: Error information from the Agent - e.g. errors during + installation. + :vartype error_info: + ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + :param identity: The identity of the configuration. + :type identity: + ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'creation_time': {'readonly': True}, + 'last_modified_time': {'readonly': True}, + 'last_status_time': {'readonly': True}, + 'error_info': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'install_state': {'key': 'properties.installState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, + 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, + 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, + 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, + } + + def __init__(self, **kwargs): + super(ExtensionInstance, self).__init__(**kwargs) + self.extension_type = kwargs.get('extension_type', None) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', None) + self.release_train = kwargs.get('release_train', None) + self.version = kwargs.get('version', None) + self.scope = kwargs.get('scope', None) + self.configuration_settings = kwargs.get('configuration_settings', None) + self.install_state = kwargs.get('install_state', None) + self.statuses = kwargs.get('statuses', None) + self.creation_time = None + self.last_modified_time = None + self.last_status_time = None + self.error_info = None + self.identity = kwargs.get('identity', None) + + +class ExtensionInstanceForCreate(ProxyResource): + """Object to create a new Extension Instance. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param extension_type: Type of the Extension, of which this resource is an + instance of. It must be one of the Extension Types registered with + Microsoft.KubernetesConfiguration by the Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this instance + participates in auto upgrade of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension instance, if + it is 'pinned' to a specific version. autoUpgradeMinorVersion must be + 'false'. + :type version: str + :param scope: Scope at which the extension instance is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs + for configuring this instance of the extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are + sensitive, as name-value pairs for configuring this instance of the + extension. + :type configuration_protected_settings: dict[str, str] + :param identity: The identity of the configuration. + :type identity: + ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity + :type location: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, + 'location': {'key': 'location', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ExtensionInstanceForCreate, self).__init__(**kwargs) + self.extension_type = kwargs.get('extension_type', None) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', None) + self.release_train = kwargs.get('release_train', None) + self.version = kwargs.get('version', None) + self.scope = kwargs.get('scope', None) + self.configuration_settings = kwargs.get('configuration_settings', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.identity = kwargs.get('identity', None) + self.location = kwargs.get('location', None) + + +class ExtensionInstanceForList(ProxyResource): + """The Extension Instance object. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param extension_type: Type of the Extension, of which this resource is an + instance of. It must be one of the Extension Types registered with + Microsoft.KubernetesConfiguration by the Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this instance + participates in auto upgrade of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension instance, if + it is 'pinned' to a specific version. + :type version: str + :param scope: Scope at which the extension instance is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope + :param install_state: Status of installation of this instance of the + extension. Possible values include: 'Pending', 'Installed', 'Failed' + :type install_state: str or + ~azure.mgmt.kubernetesconfiguration.models.InstallStateType + :ivar creation_time: DateLiteral (per ISO8601) noting the time the + resource was created by the client (user). + :vartype creation_time: str + :ivar last_modified_time: DateLiteral (per ISO8601) noting the time the + resource was modified by the client (user). + :vartype last_modified_time: str + :ivar last_status_time: DateLiteral (per ISO8601) noting the time of last + status from the agent. + :vartype last_status_time: str + :ivar error_info: Error information from the Agent - e.g. errors during + installation. + :vartype error_info: + ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + :param identity: The identity of the configuration. + :type identity: + ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'creation_time': {'readonly': True}, + 'last_modified_time': {'readonly': True}, + 'last_status_time': {'readonly': True}, + 'error_info': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'install_state': {'key': 'properties.installState', 'type': 'str'}, + 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, + 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, + 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, + 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, + } + + def __init__(self, **kwargs): + super(ExtensionInstanceForList, self).__init__(**kwargs) + self.extension_type = kwargs.get('extension_type', None) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', None) + self.release_train = kwargs.get('release_train', None) + self.version = kwargs.get('version', None) + self.scope = kwargs.get('scope', None) + self.install_state = kwargs.get('install_state', None) + self.creation_time = None + self.last_modified_time = None + self.last_status_time = None + self.error_info = None + self.identity = kwargs.get('identity', None) + + +class ExtensionInstanceUpdate(Model): + """Update Extension Instance request object. + + :param auto_upgrade_minor_version: Flag to note if this instance + participates in Extension Lifecycle Management or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version number of extension, to 'pin' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + """ + + _attribute_map = { + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ExtensionInstanceUpdate, self).__init__(**kwargs) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', None) + self.release_train = kwargs.get('release_train', None) + self.version = kwargs.get('version', None) + + +class ExtensionStatus(Model): + """Status from this instance of the extension. + + :param code: Status code provided by the Extension + :type code: str + :param display_status: Short description of status of this instance of the + extension. + :type display_status: str + :param level: Level of the status. Possible values include: 'Error', + 'Warning', 'Information'. Default value: "Information" . + :type level: str or ~azure.mgmt.kubernetesconfiguration.models.LevelType + :param message: Detailed message of the status from the Extension + instance. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation + status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ExtensionStatus, self).__init__(**kwargs) + self.code = kwargs.get('code', None) + self.display_status = kwargs.get('display_status', None) + self.level = kwargs.get('level', "Information") + self.message = kwargs.get('message', None) + self.time = kwargs.get('time', None) + + +class Result(Model): + """Sample result definition. + + :param sample_property: Sample property of type string + :type sample_property: str + """ + + _attribute_map = { + 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(Result, self).__init__(**kwargs) + self.sample_property = kwargs.get('sample_property', None) + + +class Scope(Model): + """Scope of the extensionInstance. It can be either Cluster or Namespace; but + not both. + + :param cluster: Specifies that the scope of the extensionInstance is + Cluster + :type cluster: ~azure.mgmt.kubernetesconfiguration.models.ScopeCluster + :param namespace: Specifies that the scope of the extensionInstance is + Namespace + :type namespace: ~azure.mgmt.kubernetesconfiguration.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__(self, **kwargs): + super(Scope, self).__init__(**kwargs) + self.cluster = kwargs.get('cluster', None) + self.namespace = kwargs.get('namespace', None) + + +class ScopeCluster(Model): + """Specifies that the scope of the extensionInstance is Cluster. + + :param release_namespace: Namespace where the extension Release must be + placed, for a Cluster scoped extensionInstance. If this namespace does + not exist, it will be created + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = kwargs.get('release_namespace', None) + + +class ScopeNamespace(Model): + """Specifies that the scope of the extensionInstance is Namespace. + + :param target_namespace: Namespace where the extensionInstance will be + created for an Namespace scoped extensionInstance. If this namespace does + not exist, it will be created + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = kwargs.get('target_namespace', None) diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py new file mode 100644 index 00000000000..16b408963ab --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py @@ -0,0 +1,587 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.serialization import Model +from msrest.exceptions import HttpOperationError + + +class CloudError(Model): + """CloudError. + """ + + _attribute_map = { + } + +class ConfigurationIdentity(Model): + """Identity for the managed cluster. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar principal_id: The principal id of the system assigned identity which + is used by the configuration. + :vartype principal_id: str + :ivar tenant_id: The tenant id of the system assigned identity which is + used by the configuration. + :vartype tenant_id: str + :param type: The type of identity used for the configuration. Type + 'SystemAssigned' will use an implicitly created identity. Type 'None' will + not use Managed Identity for the configuration. Possible values include: + 'SystemAssigned', 'None' + :type type: str or + ~azure.mgmt.kubernetesconfiguration.models.ResourceIdentityType + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'ResourceIdentityType'}, + } + + def __init__(self, *, type=None, **kwargs) -> None: + super(ConfigurationIdentity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = type + + +class ErrorDefinition(Model): + """Error definition. + + All required parameters must be populated in order to send to Azure. + + :param code: Required. Service specific error code which serves as the + substatus for the HTTP error code. + :type code: str + :param message: Required. Description of the error. + :type message: str + """ + + _validation = { + 'code': {'required': True}, + 'message': {'required': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + } + + def __init__(self, *, code: str, message: str, **kwargs) -> None: + super(ErrorDefinition, self).__init__(**kwargs) + self.code = code + self.message = message + + +class ErrorResponse(Model): + """Error response. + + :param error: Error definition. + :type error: ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDefinition'}, + } + + def __init__(self, *, error=None, **kwargs) -> None: + super(ErrorResponse, self).__init__(**kwargs) + self.error = error + + +class ErrorResponseException(HttpOperationError): + """Server responsed with exception of type: 'ErrorResponse'. + + :param deserialize: A deserializer + :param response: Server response to be deserialized. + """ + + def __init__(self, deserialize, response, *args): + + super(ErrorResponseException, self).__init__(deserialize, response, 'ErrorResponse', *args) + + +class Resource(Model): + """The Resource model definition. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__(self, **kwargs) -> None: + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class ProxyResource(Resource): + """ARM proxy resource. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__(self, **kwargs) -> None: + super(ProxyResource, self).__init__(**kwargs) + + +class ExtensionInstance(ProxyResource): + """The Extension Instance object. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param extension_type: Type of the Extension, of which this resource is an + instance of. It must be one of the Extension Types registered with + Microsoft.KubernetesConfiguration by the Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this instance + participates in auto upgrade of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension instance, if + it is 'pinned' to a specific version. autoUpgradeMinorVersion must be + 'false'. + :type version: str + :param scope: Scope at which the extension instance is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs + for configuring this instance of the extension. + :type configuration_settings: dict[str, str] + :param install_state: Status of installation of this instance of the + extension. Possible values include: 'Pending', 'Installed', 'Failed' + :type install_state: str or + ~azure.mgmt.kubernetesconfiguration.models.InstallStateType + :param statuses: Status from this instance of the extension. + :type statuses: + list[~azure.mgmt.kubernetesconfiguration.models.ExtensionStatus] + :ivar creation_time: DateLiteral (per ISO8601) noting the time the + resource was created by the client (user). + :vartype creation_time: str + :ivar last_modified_time: DateLiteral (per ISO8601) noting the time the + resource was modified by the client (user). + :vartype last_modified_time: str + :ivar last_status_time: DateLiteral (per ISO8601) noting the time of last + status from the agent. + :vartype last_status_time: str + :ivar error_info: Error information from the Agent - e.g. errors during + installation. + :vartype error_info: + ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + :param identity: The identity of the configuration. + :type identity: + ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'creation_time': {'readonly': True}, + 'last_modified_time': {'readonly': True}, + 'last_status_time': {'readonly': True}, + 'error_info': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'install_state': {'key': 'properties.installState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, + 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, + 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, + 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, + } + + def __init__(self, *, extension_type: str=None, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, scope=None, configuration_settings=None, install_state=None, statuses=None, identity=None, **kwargs) -> None: + super(ExtensionInstance, self).__init__(**kwargs) + self.extension_type = extension_type + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + self.scope = scope + self.configuration_settings = configuration_settings + self.install_state = install_state + self.statuses = statuses + self.creation_time = None + self.last_modified_time = None + self.last_status_time = None + self.error_info = None + self.identity = identity + + +class ExtensionInstanceForCreate(ProxyResource): + """Object to create a new Extension Instance. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param extension_type: Type of the Extension, of which this resource is an + instance of. It must be one of the Extension Types registered with + Microsoft.KubernetesConfiguration by the Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this instance + participates in auto upgrade of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension instance, if + it is 'pinned' to a specific version. autoUpgradeMinorVersion must be + 'false'. + :type version: str + :param scope: Scope at which the extension instance is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs + for configuring this instance of the extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are + sensitive, as name-value pairs for configuring this instance of the + extension. + :type configuration_protected_settings: dict[str, str] + :param identity: The identity of the configuration. + :type identity: + ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity + :type location: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, + 'location': {'key': 'location', 'type': 'str'}, + } + + def __init__(self, *, extension_type: str=None, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, scope=None, configuration_settings=None, configuration_protected_settings=None, identity=None, location=None, **kwargs) -> None: + super(ExtensionInstanceForCreate, self).__init__(location=location,**kwargs) + self.extension_type = extension_type + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + self.scope = scope + self.configuration_settings = configuration_settings + self.configuration_protected_settings = configuration_protected_settings + self.identity = identity + self.location = location + + +class ExtensionInstanceForList(ProxyResource): + """The Extension Instance object. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param extension_type: Type of the Extension, of which this resource is an + instance of. It must be one of the Extension Types registered with + Microsoft.KubernetesConfiguration by the Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this instance + participates in auto upgrade of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension instance, if + it is 'pinned' to a specific version. + :type version: str + :param scope: Scope at which the extension instance is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope + :param install_state: Status of installation of this instance of the + extension. Possible values include: 'Pending', 'Installed', 'Failed' + :type install_state: str or + ~azure.mgmt.kubernetesconfiguration.models.InstallStateType + :ivar creation_time: DateLiteral (per ISO8601) noting the time the + resource was created by the client (user). + :vartype creation_time: str + :ivar last_modified_time: DateLiteral (per ISO8601) noting the time the + resource was modified by the client (user). + :vartype last_modified_time: str + :ivar last_status_time: DateLiteral (per ISO8601) noting the time of last + status from the agent. + :vartype last_status_time: str + :ivar error_info: Error information from the Agent - e.g. errors during + installation. + :vartype error_info: + ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + :param identity: The identity of the configuration. + :type identity: + ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'creation_time': {'readonly': True}, + 'last_modified_time': {'readonly': True}, + 'last_status_time': {'readonly': True}, + 'error_info': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'install_state': {'key': 'properties.installState', 'type': 'str'}, + 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, + 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, + 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, + 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, + } + + def __init__(self, *, extension_type: str=None, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, scope=None, install_state=None, identity=None, **kwargs) -> None: + super(ExtensionInstanceForList, self).__init__(**kwargs) + self.extension_type = extension_type + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + self.scope = scope + self.install_state = install_state + self.creation_time = None + self.last_modified_time = None + self.last_status_time = None + self.error_info = None + self.identity = identity + + +class ExtensionInstanceUpdate(Model): + """Update Extension Instance request object. + + :param auto_upgrade_minor_version: Flag to note if this instance + participates in Extension Lifecycle Management or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version number of extension, to 'pin' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + """ + + _attribute_map = { + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + } + + def __init__(self, *, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, **kwargs) -> None: + super(ExtensionInstanceUpdate, self).__init__(**kwargs) + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + + +class ExtensionStatus(Model): + """Status from this instance of the extension. + + :param code: Status code provided by the Extension + :type code: str + :param display_status: Short description of status of this instance of the + extension. + :type display_status: str + :param level: Level of the status. Possible values include: 'Error', + 'Warning', 'Information'. Default value: "Information" . + :type level: str or ~azure.mgmt.kubernetesconfiguration.models.LevelType + :param message: Detailed message of the status from the Extension + instance. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation + status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__(self, *, code: str=None, display_status: str=None, level="Information", message: str=None, time: str=None, **kwargs) -> None: + super(ExtensionStatus, self).__init__(**kwargs) + self.code = code + self.display_status = display_status + self.level = level + self.message = message + self.time = time + + +class Result(Model): + """Sample result definition. + + :param sample_property: Sample property of type string + :type sample_property: str + """ + + _attribute_map = { + 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, + } + + def __init__(self, *, sample_property: str=None, **kwargs) -> None: + super(Result, self).__init__(**kwargs) + self.sample_property = sample_property + + +class Scope(Model): + """Scope of the extensionInstance. It can be either Cluster or Namespace; but + not both. + + :param cluster: Specifies that the scope of the extensionInstance is + Cluster + :type cluster: ~azure.mgmt.kubernetesconfiguration.models.ScopeCluster + :param namespace: Specifies that the scope of the extensionInstance is + Namespace + :type namespace: ~azure.mgmt.kubernetesconfiguration.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__(self, *, cluster=None, namespace=None, **kwargs) -> None: + super(Scope, self).__init__(**kwargs) + self.cluster = cluster + self.namespace = namespace + + +class ScopeCluster(Model): + """Specifies that the scope of the extensionInstance is Cluster. + + :param release_namespace: Namespace where the extension Release must be + placed, for a Cluster scoped extensionInstance. If this namespace does + not exist, it will be created + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__(self, *, release_namespace: str=None, **kwargs) -> None: + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = release_namespace + + +class ScopeNamespace(Model): + """Specifies that the scope of the extensionInstance is Namespace. + + :param target_namespace: Namespace where the extensionInstance will be + created for an Namespace scoped extensionInstance. If this namespace does + not exist, it will be created + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__(self, *, target_namespace: str=None, **kwargs) -> None: + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = target_namespace diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py new file mode 100644 index 00000000000..8f2e7eca24e --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py @@ -0,0 +1,40 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.paging import Paged + + +class ResourceProviderOperationPaged(Paged): + """ + A paging container for iterating over a list of :class:`ResourceProviderOperation ` object + """ + + _attribute_map = { + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'current_page': {'key': 'value', 'type': '[ResourceProviderOperation]'} + } + + def __init__(self, *args, **kwargs): + + super(ResourceProviderOperationPaged, self).__init__(*args, **kwargs) +class ExtensionInstanceForListPaged(Paged): + """ + A paging container for iterating over a list of :class:`ExtensionInstanceForList ` object + """ + + _attribute_map = { + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'current_page': {'key': 'value', 'type': '[ExtensionInstanceForList]'} + } + + def __init__(self, *args, **kwargs): + + super(ExtensionInstanceForListPaged, self).__init__(*args, **kwargs) diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py new file mode 100644 index 00000000000..e8f158b24a3 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py @@ -0,0 +1,16 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from ._k8s_extensions_operations import K8sExtensionsOperations + +__all__ = [ + 'K8sExtensionsOperations', +] diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_k8s_extensions_operations.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_k8s_extensions_operations.py new file mode 100644 index 00000000000..716aefd7b06 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_k8s_extensions_operations.py @@ -0,0 +1,452 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +import uuid +from msrest.pipeline import ClientRawResponse + +from .. import models + + +class K8sExtensionsOperations(object): + """K8sExtensionsOperations operations. + + You should not instantiate directly this class, but create a Client instance that will create it for you and attach + it as attribute. + + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + :ivar api_version: The API version to be used with the HTTP request. Constant value: "2020-07-01-preview". + """ + + models = models + + def __init__(self, client, config, serializer, deserializer): + + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self.api_version = "2020-07-01-preview" + + self.config = config + + def get( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, + custom_headers=None, raw=False, **operation_config): + """Gets details of the Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters) or appliances (for Arc Appliances). Possible + values include: 'managedClusters','connectedClusters', 'appliances' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: ExtensionInstance or ClientRawResponse if raw=true + :rtype: ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstance + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.get.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", + self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('ExtensionInstance', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} + + def create( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, + extension_instance, custom_headers=None, raw=False, **operation_config): + """Create a new Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters) or appliances (for Arc Appliances). Possible + values include: 'managedClusters','connectedClusters', 'appliances' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param extension_instance: Properties necessary to Create an Extension + Instance. + :type extension_instance: + ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstanceForCreate + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: ExtensionInstance or ClientRawResponse if raw=true + :rtype: ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstance + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.create.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", + self.config.accept_language, 'str') + + # Construct body + body_content = self._serialize.body(extension_instance, 'ExtensionInstanceForCreate') + + # Construct and send request + request = self._client.put(url, query_parameters, header_parameters, body_content) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('ExtensionInstance', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}' + '/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/' + 'extensions/{extensionInstanceName}'} + + def update( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, + extension_instance, custom_headers=None, raw=False, **operation_config): + """Update an existing Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters) or appliances (for Arc Appliances). Possible + values include: 'managedClusters','connectedClusters', 'appliances' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param extension_instance: Properties to Update in the Extension + Instance. + :type extension_instance: + ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstanceUpdate + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: ExtensionInstance or ClientRawResponse if raw=true + :rtype: ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstance + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.update.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", + self.config.accept_language, 'str') + + # Construct body + body_content = self._serialize.body(extension_instance, 'ExtensionInstanceUpdate') + + # Construct and send request + request = self._client.patch(url, query_parameters, header_parameters, body_content) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('ExtensionInstance', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}' + '/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/' + 'extensions/{extensionInstanceName}'} + + def delete( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, + custom_headers=None, raw=False, **operation_config): + """Delete a Kubernetes Cluster Extension Instance. This will cause the + Agent to Uninstall the extension instance from the cluster. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters) or appliances (for Arc Appliances). Possible + values include: 'managedClusters','connectedClusters', 'appliances' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: None or ClientRawResponse if raw=true + :rtype: None or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.delete.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", + self.config.accept_language, 'str') + + # Construct and send request + request = self._client.delete(url, query_parameters, header_parameters) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200, 204]: + raise models.ErrorResponseException(self._deserialize, response) + + if raw: + client_raw_response = ClientRawResponse(None, response) + return client_raw_response + delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}' + '/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/' + 'extensions/{extensionInstanceName}'} + + def list( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, custom_headers=None, raw=False, + **operation_config): + """List all Extension Instances. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters) or appliances (for Arc Appliances). Possible + values include: 'managedClusters','connectedClusters', 'appliances' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: An iterator like instance of ExtensionInstanceForList + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstanceForListPaged[~azure.mgmt.kubernetesconfiguration.models.ExtensionInstanceForList] + :raises: + :class:`ErrorResponseException` + """ + def prepare_request(next_link=None): + if not next_link: + # Construct URL + url = self.list.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, + 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + else: + url = next_link + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", + self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + return request + + def internal_paging(next_link=None): + request = prepare_request(next_link) + + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + return response + + # Deserialize response + header_dict = None + if raw: + header_dict = {} + deserialized = models.ExtensionInstanceForListPaged(internal_paging, self._deserialize.dependencies, + header_dict) + + return deserialized + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}' + '/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/' + 'extensions'} diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py new file mode 100644 index 00000000000..e0ec669828c --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py @@ -0,0 +1,13 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +VERSION = "0.1.0" + diff --git a/src/k8s-extension/setup.cfg b/src/k8s-extension/setup.cfg new file mode 100644 index 00000000000..5eab412034f --- /dev/null +++ b/src/k8s-extension/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 diff --git a/src/k8s-extension/setup.py b/src/k8s-extension/setup.py new file mode 100644 index 00000000000..c5fdcbfc5a8 --- /dev/null +++ b/src/k8s-extension/setup.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + + +from codecs import open +from setuptools import setup, find_packages +try: + from azure_bdist_wheel import cmdclass +except ImportError: + from distutils import log as logger + logger.warn("Wheel is not available, disabling bdist_wheel hook") + +# TODO: Confirm this is the right version number you want and it matches your +# HISTORY.rst entry. +VERSION = '0.1PP.14' + +# The full list of classifiers is available at +# https://pypi.python.org/pypi?%3Aaction=list_classifiers +CLASSIFIERS = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'License :: OSI Approved :: MIT License', +] + +# TODO: Add any additional SDK dependencies here +DEPENDENCIES = [] + +with open('README.rst', 'r', encoding='utf-8') as f: + README = f.read() +with open('HISTORY.rst', 'r', encoding='utf-8') as f: + HISTORY = f.read() + +setup( + name='k8s-extension', + version=VERSION, + description='Microsoft Azure Command-Line Tools K8s-extension Extension', + # TODO: Update author and email, if applicable + author='Microsoft Corporation', + author_email='azpycli@microsoft.com', + # TODO: consider pointing directly to your source code instead of the generic repo + url='https://github.com/Azure/azure-cli-extensions', + long_description=README + '\n\n' + HISTORY, + license='MIT', + classifiers=CLASSIFIERS, + packages=find_packages(), + install_requires=DEPENDENCIES, + package_data={'azext_k8s_extension': ['azext_metadata.json']}, +) From 4293a801c886f5425cbbad327ff13cc5b8eb091e Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Wed, 10 Mar 2021 14:57:51 -0800 Subject: [PATCH 05/80] Update CODEOWNERS --- .github/CODEOWNERS | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 66f026834e8..435dbbae79f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -124,9 +124,11 @@ /src/ssh/ @rlrossiter @danybeam @arrownj -/src/k8sconfiguration/ @NarayanThiru +/src/k8sconfiguration/ @NarayanThiru @jonathan-innis -/src/k8s-configuration/ @NarayanThiru +/src/k8s-configuration/ @NarayanThiru @jonathan-innis + +/src/k8s-extension/ @NarayanThiru @jonathan-innis /src/log-analytics-solution/ @zhoxing-ms From 1b398606680a323aaf54c36d60283b796cce1d66 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Wed, 10 Mar 2021 15:02:09 -0800 Subject: [PATCH 06/80] Update azure-pipelines.yml --- azure-pipelines.yml | 405 ++++++++++++++++++++++++++++---------------- 1 file changed, 259 insertions(+), 146 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d43ef5102f0..3e1ef1ccca5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,128 +1,157 @@ resources: -- repo: self + repositories: + - repository: K8sPartnerExtensionTest + type: git + endpoint: AzureReposConnection + name: One/compute-HybridMgmt-K8sPartnerExtensionTest trigger: batch: true branches: include: - - '*' - + - k8s-extension/public-preview + - k8s-extension/private-preview pr: branches: include: - - '*' - -jobs: -- job: CredScan - displayName: "Credential Scan" - pool: - vmImage: "windows-2019" - steps: - - task: ms-codeanalysis.vss-microsoft-security-code-analysis-devops.build-task-credscan.CredScan@2 - displayName: 'Run Credential Scanner' - inputs: - toolMajorVersion: V2 - suppressionsFile: './scripts/ci/credscan/CredScanSuppressions.json' - - task: ms-codeanalysis.vss-microsoft-security-code-analysis-devops.build-task-postanalysis.PostAnalysis@1 - displayName: 'Post Analysis' - inputs: - AllTools: false - BinSkim: false - CredScan: true - RoslynAnalyzers: false - TSLint: false - ToolLogsNotFoundAction: 'Standard' - -- job: CheckLicenseHeader - displayName: "Check License" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - python -m venv env/ - - chmod +x ./env/bin/activate - source ./env/bin/activate - - # clone azure-cli - git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install -q azdev - - azdev setup -c ../azure-cli -r ./ - - azdev --version - az --version - - azdev verify license - -- job: StaticAnalysis - displayName: "Static Analysis" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests - displayName: 'Install wheel, pylint, flake8, requests' - - bash: python scripts/ci/source_code_static_analysis.py - displayName: "Static Analysis" - -- job: IndexVerify - displayName: "Verify Extensions Index" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: | - #!/usr/bin/env bash - set -ev - pip install wheel==0.30.0 requests packaging - export CI="ADO" - python ./scripts/ci/test_index.py -v - displayName: "Verify Extensions Index" + - k8s-extension/public-preview + - k8s-extension/private-preview -- job: SourceTests - displayName: "Integration Tests, Build Tests" - pool: - vmImage: 'ubuntu-16.04' - strategy: - matrix: - Python36: - python.version: '3.6' - Python38: - python.version: '3.8' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python $(python.version)' - inputs: - versionSpec: '$(python.version)' - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - bash: ./scripts/ci/test_source.sh - displayName: 'Run integration test and build test' - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - -- job: LintModifiedExtensions - displayName: "CLI Linter on Modified Extensions" - condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest')) - pool: - vmImage: 'ubuntu-16.04' - steps: +stages: +- stage: K8sExtensionTestSuite + displayName: "K8s-Extension Test Suite" + variables: + K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest + CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions + EXTENSION_NAME: "k8s-extension" + EXTENSION_FILE_NAME: "k8s_extension" + SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" + RESOURCE_GROUP: "K8sPartnerExtensionTest" + BASE_CLUSTER_NAME: "k8s-extension-cluster" + jobs: + - job: K8sExtensionTestSuite + displayName: "Run the Test Suite" + pool: + vmImage: 'ubuntu-16.04' + steps: + - checkout: self + - checkout: K8sPartnerExtensionTest + + - bash: | + echo "Installing helm3" + curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 + chmod 700 get_helm.sh + ./get_helm.sh + + echo "Installing kubectl" + curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin/kubectl + kubectl version --client + displayName: "Setup the VM with helm3 and kubectl" + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build $(EXTENSION_NAME) with azdev" + + - bash: | + K8S_EXTENSION_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) + echo "##vso[task.setvariable variable=K8S_EXTENSION_VERSION]$K8S_EXTENSION_VERSION" + cp * $(K8S_EXTENSION_REPO_PATH)/extensions + workingDirectory: $(CLI_REPO_PATH)/dist + displayName: "Copy the Built .whl to Extension Test Path" + + - bash: | + RAND_STR=$RANDOM + AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" + ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" + + JSON_STRING=$(jq -n \ + --arg SUB_ID "$SUBSCRIPTION_ID" \ + --arg RG "$RESOURCE_GROUP" \ + --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ + --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ + --arg K8S_EXTENSION_VERSION "$K8S_EXTENSION_VERSION" \ + '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-extension": $K8S_EXTENSION_VERSION, connectedk8s: "1.0.0"}}') + echo $JSON_STRING > settings.json + cat settings.json + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + displayName: "Generate a settings.json file" + + - bash : | + echo "Downloading the kind script" + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64 + chmod +x ./kind + ./kind create cluster + displayName: "Create and Start the Kind cluster" + + - task: AzureCLI@2 + displayName: Bootstrap + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Bootstrap.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + + - task: AzureCLI@2 + displayName: Run the Test Suite + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Test.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + continueOnError: true + + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TestResults.xml' + failTaskOnFailedTests: true + condition: succeededOrFailed() + + - task: AzureCLI@2 + displayName: Cleanup + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Cleanup.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + condition: succeededOrFailed() + +- stage: AzureCLIOfficial + displayName: "Azure Official CLI Code Checks" + dependsOn: [] + jobs: + - job: CheckLicenseHeader + displayName: "Check License" + pool: + vmImage: 'ubuntu-16.04' + steps: - task: UsePythonVersion@0 displayName: 'Use Python 3.6' inputs: @@ -131,41 +160,125 @@ jobs: set -ev # prepare and activate virtualenv - pip install virtualenv - python -m virtualenv venv/ - source ./venv/bin/activate + python -m venv env/ + + chmod +x ./env/bin/activate + source ./env/bin/activate # clone azure-cli - git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - pip install azdev + pip install -q azdev + + azdev setup -c ../azure-cli -r ./ azdev --version + az --version - azdev setup -c ../azure-cli -r ./ + azdev verify license + + - job: StaticAnalysis + displayName: "Static Analysis" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests + displayName: 'Install wheel, pylint, flake8, requests' + - bash: python scripts/ci/source_code_static_analysis.py + displayName: "Static Analysis" + + - job: IndexVerify + displayName: "Verify Extensions Index" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: | + #!/usr/bin/env bash + set -ev + pip install wheel==0.30.0 requests packaging + export CI="ADO" + python ./scripts/ci/test_index.py -v + displayName: "Verify Extensions Index" + + - job: SourceTests + displayName: "Integration Tests, Build Tests" + pool: + vmImage: 'ubuntu-16.04' + strategy: + matrix: + Python36: + python.version: '3.6' + Python38: + python.version: '3.8' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python $(python.version)' + inputs: + versionSpec: '$(python.version)' + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - bash: ./scripts/ci/test_source.sh + displayName: 'Run integration test and build test' + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: LintModifiedExtensions + displayName: "CLI Linter on Modified Extensions" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev - # overwrite the default AZURE_EXTENSION_DIR set by ADO - AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version - - AZURE_EXTENSION_DIR=~/.azure/cliextensions python scripts/ci/verify_linter.py - displayName: "CLI Linter on Modified Extension" - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - -- job: IndexRefDocVerify - displayName: "Verify Ref Docs" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - task: Bash@3 - displayName: "Verify Extension Ref Docs" - inputs: - targetType: 'filePath' - filePath: scripts/ci/test_index_ref_doc.sh + # prepare and activate virtualenv + pip install virtualenv + python -m virtualenv venv/ + source ./venv/bin/activate + + # clone azure-cli + git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install azdev + + azdev --version + + azdev setup -c ../azure-cli -r ./ -e k8s-extension + + # overwrite the default AZURE_EXTENSION_DIR set by ADO + AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version + + AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-extension + displayName: "CLI Linter on Modified Extension" + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: IndexRefDocVerify + displayName: "Verify Ref Docs" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - task: Bash@3 + displayName: "Verify Extension Ref Docs" + inputs: + targetType: 'filePath' + filePath: scripts/ci/test_index_ref_doc.sh From eba804c72b2eab3fbb3a990a761315ba3306b758 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Wed, 10 Mar 2021 15:04:28 -0800 Subject: [PATCH 07/80] Create pull.yml --- .github/pull.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/pull.yml diff --git a/.github/pull.yml b/.github/pull.yml new file mode 100644 index 00000000000..2aa62599fc7 --- /dev/null +++ b/.github/pull.yml @@ -0,0 +1,5 @@ +version: "1" +rules: + - base: master + upstream: Azure:master + mergeMethod: hardreset From acc9c7e85cb3a99cbd6cdd467716dde32684c3aa Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Wed, 10 Mar 2021 15:06:40 -0800 Subject: [PATCH 08/80] Update pull.yml --- .github/pull.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/pull.yml b/.github/pull.yml index 2aa62599fc7..f995650de92 100644 --- a/.github/pull.yml +++ b/.github/pull.yml @@ -3,3 +3,6 @@ rules: - base: master upstream: Azure:master mergeMethod: hardreset + - base: release + upstream: Azure:master + mergeMethod: hardreset From 65074465e5c82959f42dc2a5cf190d97f1fed9ee Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Wed, 10 Mar 2021 15:10:06 -0800 Subject: [PATCH 09/80] Update pull.yml --- .github/pull.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull.yml b/.github/pull.yml index f995650de92..71e1e286c72 100644 --- a/.github/pull.yml +++ b/.github/pull.yml @@ -1,4 +1,4 @@ -version: "1" +version: 1 rules: - base: master upstream: Azure:master From a0761d9b8f045b71d311683aec55262a6c996501 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 10 Mar 2021 15:49:00 -0800 Subject: [PATCH 10/80] Update pipelines file --- azure-pipelines.yml | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3e1ef1ccca5..9cc1270ff4f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -4,32 +4,31 @@ resources: type: git endpoint: AzureReposConnection name: One/compute-HybridMgmt-K8sPartnerExtensionTest + ref: joinnis/scc-testing trigger: batch: true branches: include: - - k8s-extension/public-preview - - k8s-extension/private-preview + - k8s-configuration pr: branches: include: - - k8s-extension/public-preview - - k8s-extension/private-preview + - k8s-configuration stages: -- stage: K8sExtensionTestSuite +- stage: K8sConfigurationTestSuite displayName: "K8s-Extension Test Suite" variables: K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions - EXTENSION_NAME: "k8s-extension" - EXTENSION_FILE_NAME: "k8s_extension" + EXTENSION_NAME: "k8s-configuration" + EXTENSION_FILE_NAME: "k8s_configuration" SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" RESOURCE_GROUP: "K8sPartnerExtensionTest" - BASE_CLUSTER_NAME: "k8s-extension-cluster" + BASE_CLUSTER_NAME: "k8s-configuration-cluster" jobs: - - job: K8sExtensionTestSuite + - job: K8sConfigurationTestSuite displayName: "Run the Test Suite" pool: vmImage: 'ubuntu-16.04' @@ -74,8 +73,8 @@ stages: displayName: "Setup and Build $(EXTENSION_NAME) with azdev" - bash: | - K8S_EXTENSION_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) - echo "##vso[task.setvariable variable=K8S_EXTENSION_VERSION]$K8S_EXTENSION_VERSION" + K8S_CONFIG_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) + echo "##vso[task.setvariable variable=K8S_CONFIG_VERSION]$K8S_CONFIG_VERSION" cp * $(K8S_EXTENSION_REPO_PATH)/extensions workingDirectory: $(CLI_REPO_PATH)/dist displayName: "Copy the Built .whl to Extension Test Path" @@ -90,8 +89,8 @@ stages: --arg RG "$RESOURCE_GROUP" \ --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ - --arg K8S_EXTENSION_VERSION "$K8S_EXTENSION_VERSION" \ - '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-extension": $K8S_EXTENSION_VERSION, connectedk8s: "1.0.0"}}') + --arg K8S_CONFIG_VERSION "$K8S_CONFIG_VERSION" \ + '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-configuration": $K8S_CONFIG_VERSION, connectedk8s: "1.0.0"}}') echo $JSON_STRING > settings.json cat settings.json workingDirectory: $(K8S_EXTENSION_REPO_PATH) From 4c4ea52e2fe81aca8e9beaf27a628e51e4a684b3 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 10 Mar 2021 15:50:27 -0800 Subject: [PATCH 11/80] Update k8s-configuration name --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9cc1270ff4f..7203fa057db 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,7 +18,7 @@ pr: stages: - stage: K8sConfigurationTestSuite - displayName: "K8s-Extension Test Suite" + displayName: "K8s-Configuration Test Suite" variables: K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions From 007e0d30a71600133a6f9d3909dc940e8407ef77 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 10 Mar 2021 15:51:06 -0800 Subject: [PATCH 12/80] Update test script params --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7203fa057db..3165781adef 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -120,7 +120,7 @@ stages: scriptType: pscore scriptLocation: inlineScript inlineScript: | - .\Test.ps1 -CI + .\Test.ps1 -Type Configuration -CI workingDirectory: $(K8S_EXTENSION_REPO_PATH) continueOnError: true From f461b7f3b584d7dbebf757e96fe67b738ea3cefc Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 10 Mar 2021 15:53:27 -0800 Subject: [PATCH 13/80] Update pipeline file --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3165781adef..ca06b5f3807 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -254,12 +254,12 @@ stages: azdev --version - azdev setup -c ../azure-cli -r ./ -e k8s-extension + azdev setup -c ../azure-cli -r ./ -e k8s-configuration # overwrite the default AZURE_EXTENSION_DIR set by ADO AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version - AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-extension + AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-configuration displayName: "CLI Linter on Modified Extension" env: ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) From 556f54554e240ce73f5720f7c58abc8ea320e938 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 10 Mar 2021 15:58:47 -0800 Subject: [PATCH 14/80] Remove codeowners --- .github/CODEOWNERS | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 435dbbae79f..eea39dc6f66 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -128,8 +128,6 @@ /src/k8s-configuration/ @NarayanThiru @jonathan-innis -/src/k8s-extension/ @NarayanThiru @jonathan-innis - /src/log-analytics-solution/ @zhoxing-ms /src/kusto/ @ilayr @orhasban @astauben From 3e2ea64c089ece94daa605788d308fc4193a064f Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 10 Mar 2021 14:22:56 -0800 Subject: [PATCH 15/80] Update pipelines file --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 77ff718d967..3e1ef1ccca5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,7 +22,7 @@ stages: displayName: "K8s-Extension Test Suite" variables: K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest - CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions-pr + CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions EXTENSION_NAME: "k8s-extension" EXTENSION_FILE_NAME: "k8s_extension" SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" From 9bbc0e462fd0d027ff32099b2657c530522b268c Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Wed, 10 Mar 2021 14:57:51 -0800 Subject: [PATCH 16/80] Update CODEOWNERS --- .github/CODEOWNERS | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 66f026834e8..435dbbae79f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -124,9 +124,11 @@ /src/ssh/ @rlrossiter @danybeam @arrownj -/src/k8sconfiguration/ @NarayanThiru +/src/k8sconfiguration/ @NarayanThiru @jonathan-innis -/src/k8s-configuration/ @NarayanThiru +/src/k8s-configuration/ @NarayanThiru @jonathan-innis + +/src/k8s-extension/ @NarayanThiru @jonathan-innis /src/log-analytics-solution/ @zhoxing-ms From 8d46cbc41b4469cb5795889c32ed28fa348528a5 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 11 Mar 2021 11:35:18 -0800 Subject: [PATCH 17/80] Update private preview pipelines --- azure-pipelines.yml | 72 +++++++++++++++++-- .../azext_k8s_extension/_consts.py | 7 ++ .../azext_k8s_extension/_consts_private.py | 7 ++ .../azext_k8s_extension/_help.py | 13 ++-- .../azext_k8s_extension/_params.py | 3 +- .../azext_k8s_extension/commands.py | 3 +- src/k8s-extension/setup.py | 3 +- 7 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 src/k8s-extension/azext_k8s_extension/_consts.py create mode 100644 src/k8s-extension/azext_k8s_extension/_consts_private.py diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3e1ef1ccca5..203370976cf 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -23,11 +23,12 @@ stages: variables: K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions - EXTENSION_NAME: "k8s-extension" - EXTENSION_FILE_NAME: "k8s_extension" SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" RESOURCE_GROUP: "K8sPartnerExtensionTest" BASE_CLUSTER_NAME: "k8s-extension-cluster" + + EXTENSION_NAME: "k8s-extension" + EXTENSION_FILE_NAME: "k8s_extension" jobs: - job: K8sExtensionTestSuite displayName: "Run the Test Suite" @@ -36,7 +37,6 @@ stages: steps: - checkout: self - checkout: K8sPartnerExtensionTest - - bash: | echo "Installing helm3" curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 @@ -55,6 +55,7 @@ stages: versionSpec: 3.6 - bash: | set -ev + echo "Building extension ${EXTENSION_NAME}..." # prepare and activate virtualenv pip install virtualenv @@ -71,12 +72,12 @@ stages: azdev extension build $(EXTENSION_NAME) workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build $(EXTENSION_NAME) with azdev" + displayName: "Setup and Build Extension with azdev" - bash: | K8S_EXTENSION_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) echo "##vso[task.setvariable variable=K8S_EXTENSION_VERSION]$K8S_EXTENSION_VERSION" - cp * $(K8S_EXTENSION_REPO_PATH)/extensions + cp * $(K8S_EXTENSION_REPO_PATH)/bin workingDirectory: $(CLI_REPO_PATH)/dist displayName: "Copy the Built .whl to Extension Test Path" @@ -142,6 +143,67 @@ stages: .\Cleanup.ps1 -CI workingDirectory: $(K8S_EXTENSION_REPO_PATH) condition: succeededOrFailed() + +- stage: BuildPublishExtension + dependsOn: [] + displayName: "Build and Publish the Extension Artifact" + variables: + CLI_REPO_PATH: $(Agent.BuildDirectory)/s + IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranchName'], 'refs/heads/k8s-extension/private-preview'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private-preview'))] + jobs: + - job: BuildPublishExtension + displayName: "Build and Publish the Extension Artifact" + pool: + vmImage: 'ubuntu-16.04' + steps: + - bash: | + if [[ $IS_PRIVATE_BRANCH ]]; then + echo "Using the private preview of k8s-extension to build..." + + cp $(CLI_REPO_PATH)/src/k8s-extension $(CLI_REPO_PATH)/src/k8s-extension-private -r + cp $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts.py + + EXTENSION_NAME="k8s-extension-private" + EXTENSION_FILE_NAME="k8s_extension_private" + + echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" + echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" + else + echo "Using the public version of k8s-extension to build..." + + EXTENSION_NAME="k8s-extension" + EXTENSION_FILE_NAME="k8s_extension" + + echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" + echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" + fi + displayName: "Copy Files, Set Variables based on Private Branch" + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + echo "Building extension ${EXTENSION_NAME}..." + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build Extension with azdev" + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: $(CLI_REPO_PATH)/dist - stage: AzureCLIOfficial displayName: "Azure Official CLI Code Checks" diff --git a/src/k8s-extension/azext_k8s_extension/_consts.py b/src/k8s-extension/azext_k8s_extension/_consts.py new file mode 100644 index 00000000000..e9f8156f307 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_consts.py @@ -0,0 +1,7 @@ +# coding=utf-8 +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +EXTENSION_NAME = 'k8s-extension' diff --git a/src/k8s-extension/azext_k8s_extension/_consts_private.py b/src/k8s-extension/azext_k8s_extension/_consts_private.py new file mode 100644 index 00000000000..18a01637c2d --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_consts_private.py @@ -0,0 +1,7 @@ +# coding=utf-8 +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +EXTENSION_NAME = 'k8s-extension-private' diff --git a/src/k8s-extension/azext_k8s_extension/_help.py b/src/k8s-extension/azext_k8s_extension/_help.py index 69011bb9d92..64e4be612ea 100644 --- a/src/k8s-extension/azext_k8s_extension/_help.py +++ b/src/k8s-extension/azext_k8s_extension/_help.py @@ -5,34 +5,35 @@ # -------------------------------------------------------------------------------------------- from knack.help_files import helps # pylint: disable=unused-import +import azext_k8s_extension._consts as consts -helps['k8s-extension'] = """ +helps[f'{consts.EXTENSION_NAME}'] = """ type: group short-summary: Commands to manage K8s-extensions. """ -helps['k8s-extension create'] = """ +helps[f'{consts.EXTENSION_NAME} create'] = """ type: command short-summary: Create a K8s-extension. """ -helps['k8s-extension list'] = """ +helps[f'{consts.EXTENSION_NAME} list'] = """ type: command short-summary: List K8s-extensions. """ -helps['k8s-extension delete'] = """ +helps[f'{consts.EXTENSION_NAME} delete'] = """ type: command short-summary: Delete a K8s-extension. """ -helps['k8s-extension show'] = """ +helps[f'{consts.EXTENSION_NAME} show'] = """ type: command short-summary: Show details of a K8s-extension. """ -helps['k8s-extension update'] = """ +helps[f'{consts.EXTENSION_NAME} update'] = """ type: command short-summary: Update a K8s-extension. """ diff --git a/src/k8s-extension/azext_k8s_extension/_params.py b/src/k8s-extension/azext_k8s_extension/_params.py index 0e870204887..d96fe3c2ba7 100644 --- a/src/k8s-extension/azext_k8s_extension/_params.py +++ b/src/k8s-extension/azext_k8s_extension/_params.py @@ -9,6 +9,7 @@ tags_type ) from azure.cli.core.commands.validators import get_default_location_from_resource_group +import azext_k8s_extension._consts as consts from azext_k8s_extension.action import ( AddConfigurationSettings, @@ -17,7 +18,7 @@ def load_arguments(self, _): - with self.argument_context('k8s-extension') as c: + with self.argument_context(consts.EXTENSION_NAME) as c: c.argument('tags', tags_type) c.argument('location', validator=get_default_location_from_resource_group) diff --git a/src/k8s-extension/azext_k8s_extension/commands.py b/src/k8s-extension/azext_k8s_extension/commands.py index 63fe78f7d2a..ff72ab62e08 100644 --- a/src/k8s-extension/azext_k8s_extension/commands.py +++ b/src/k8s-extension/azext_k8s_extension/commands.py @@ -6,6 +6,7 @@ # pylint: disable=line-too-long from azure.cli.core.commands import CliCommandType from azext_k8s_extension._client_factory import (cf_k8s_extension, cf_k8s_extension_operation) +import azext_k8s_extension._consts as consts def load_command_table(self, _): @@ -14,7 +15,7 @@ def load_command_table(self, _): operations_tmpl='azext_k8s_extension.vendored_sdks.operations#K8sExtensionsOperations.{}', client_factory=cf_k8s_extension) - with self.command_group('k8s-extension', k8s_extension_sdk, client_factory=cf_k8s_extension_operation, + with self.command_group(consts.EXTENSION_NAME, k8s_extension_sdk, client_factory=cf_k8s_extension_operation, is_preview=True) \ as g: g.custom_command('create', 'create_k8s_extension') diff --git a/src/k8s-extension/setup.py b/src/k8s-extension/setup.py index c5fdcbfc5a8..878f7f8d87a 100644 --- a/src/k8s-extension/setup.py +++ b/src/k8s-extension/setup.py @@ -8,6 +8,7 @@ from codecs import open from setuptools import setup, find_packages +import azext_k8s_extension._consts as consts try: from azure_bdist_wheel import cmdclass except ImportError: @@ -41,7 +42,7 @@ HISTORY = f.read() setup( - name='k8s-extension', + name=consts.EXTENSION_NAME, version=VERSION, description='Microsoft Azure Command-Line Tools K8s-extension Extension', # TODO: Update author and email, if applicable From 6c3ba419f9e0c5d191d0ba4fdce431455c1c5c47 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 11 Mar 2021 14:56:20 -0800 Subject: [PATCH 18/80] Remove open service mesh from public release --- .../azext_k8s_extension/custom.py | 2 - .../partner_extensions/OpenServiceMesh.py | 95 ------------------- 2 files changed, 97 deletions(-) delete mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/OpenServiceMesh.py diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py index 469b4059dee..4b0657c1814 100644 --- a/src/k8s-extension/azext_k8s_extension/custom.py +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -19,7 +19,6 @@ from .partner_extensions.ContainerInsights import ContainerInsights from .partner_extensions.AzureDefender import AzureDefender -from .partner_extensions.OpenServiceMesh import OpenServiceMesh from .partner_extensions.DefaultExtension import DefaultExtension from ._client_factory import cf_resources @@ -32,7 +31,6 @@ def ExtensionFactory(extension_name): extension_map = { 'microsoft.azuremonitor.containers': ContainerInsights, 'microsoft.azuredefender.kubernetes': AzureDefender, - 'microsoft.openservicemesh': OpenServiceMesh, } # Return the extension if we find it in the map, else return the default diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/OpenServiceMesh.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/OpenServiceMesh.py deleted file mode 100644 index b9e530877dc..00000000000 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/OpenServiceMesh.py +++ /dev/null @@ -1,95 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -# pylint: disable=unused-argument - -from azure.cli.core.azclierror import InvalidArgumentValueError, RequiredArgumentMissingError -from knack.log import get_logger - -from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceForCreate -from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate -from azext_k8s_extension.vendored_sdks.models import ScopeCluster -from azext_k8s_extension.vendored_sdks.models import Scope - -from .PartnerExtensionModel import PartnerExtensionModel - -logger = get_logger(__name__) - - -class OpenServiceMesh(PartnerExtensionModel): - def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, - scope, auto_upgrade_minor_version, release_train, version, target_namespace, - release_namespace, configuration_settings, configuration_protected_settings, - configuration_settings_file, configuration_protected_settings_file): - - """ExtensionType 'microsoft.openservicemesh' specific validations & defaults for Create - Must create and return a valid 'ExtensionInstanceForCreate' object. - - """ - # NOTE-1: Replace default scope creation with your customization, if required - # Scope must always be cluster - ext_scope = None - if scope == 'namespace': - raise InvalidArgumentValueError("Invalid scope '{}'. This extension can be installed " - "only at 'cluster' scope.".format(scope)) - - scope_cluster = ScopeCluster(release_namespace=release_namespace) - ext_scope = Scope(cluster=scope_cluster, namespace=None) - - valid_release_trains = ['staging', 'pilot'] - # If release-train is not input, set it to 'stable' - if release_train is None: - raise RequiredArgumentMissingError( - "A release-train must be provided. Valid values are 'staging', 'pilot'." - ) - - if release_train.lower() in valid_release_trains: - # version is a mandatory if release-train is staging or pilot - if version is None: - raise RequiredArgumentMissingError( - "A version must be provided for release-train {}.".format(release_train) - ) - # If the release-train is 'staging' or 'pilot' then auto-upgrade-minor-version MUST be set to False - if auto_upgrade_minor_version or auto_upgrade_minor_version is None: - auto_upgrade_minor_version = False - logger.warning("Setting auto-upgrade-minor-version to False since release-train is '%s'", release_train) - else: - raise InvalidArgumentValueError( - "Invalid release-train '{}'. Valid values are 'staging', 'pilot'.".format(release_train) - ) - - # NOTE-2: Return a valid ExtensionInstanceForCreate object, Instance name and flag for Identity - create_identity = False - extension_instance = ExtensionInstanceForCreate( - extension_type=extension_type, - auto_upgrade_minor_version=auto_upgrade_minor_version, - release_train=release_train, - version=version, - scope=ext_scope, - configuration_settings=configuration_settings, - configuration_protected_settings=configuration_protected_settings, - identity=None, - location="" - ) - return extension_instance, name, create_identity - - def Update(self, extension, auto_upgrade_minor_version, release_train, version): - """ExtensionType 'microsoft.openservicemesh' specific validations & defaults for Update - Must create and return a valid 'ExtensionInstanceUpdate' object. - - """ - # auto-upgrade-minor-version MUST be set to False if release_train is staging or pilot - if release_train.lower() in 'staging' 'pilot': - if auto_upgrade_minor_version or auto_upgrade_minor_version is None: - auto_upgrade_minor_version = False - # Set version to None to always get the latest version - user cannot override - version = None - logger.warning("Setting auto-upgrade-minor-version to False since release-train is '%s'", release_train) - - return ExtensionInstanceUpdate( - auto_upgrade_minor_version=auto_upgrade_minor_version, - release_train=release_train, - version=version - ) From 43c67964d19c0a41ef29ebf56b44cad64bc4f7f3 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 11 Mar 2021 15:10:35 -0800 Subject: [PATCH 19/80] Update pipeline files --- azure-pipelines.yml | 459 ++++++++++++--------------------------- k8s-custom-pipelines.yml | 346 +++++++++++++++++++++++++++++ 2 files changed, 488 insertions(+), 317 deletions(-) create mode 100644 k8s-custom-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 203370976cf..565e9c56793 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,219 +1,128 @@ resources: - repositories: - - repository: K8sPartnerExtensionTest - type: git - endpoint: AzureReposConnection - name: One/compute-HybridMgmt-K8sPartnerExtensionTest +- repo: self trigger: batch: true branches: include: - - k8s-extension/public-preview - - k8s-extension/private-preview + - '*' + pr: branches: include: - - k8s-extension/public-preview - - k8s-extension/private-preview - -stages: -- stage: K8sExtensionTestSuite - displayName: "K8s-Extension Test Suite" - variables: - K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest - CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions - SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" - RESOURCE_GROUP: "K8sPartnerExtensionTest" - BASE_CLUSTER_NAME: "k8s-extension-cluster" - - EXTENSION_NAME: "k8s-extension" - EXTENSION_FILE_NAME: "k8s_extension" - jobs: - - job: K8sExtensionTestSuite - displayName: "Run the Test Suite" - pool: - vmImage: 'ubuntu-16.04' - steps: - - checkout: self - - checkout: K8sPartnerExtensionTest - - bash: | - echo "Installing helm3" - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 - chmod 700 get_helm.sh - ./get_helm.sh - - echo "Installing kubectl" - curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x ./kubectl - sudo mv ./kubectl /usr/local/bin/kubectl - kubectl version --client - displayName: "Setup the VM with helm3 and kubectl" - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - echo "Building extension ${EXTENSION_NAME}..." - - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - - # clone azure-cli - pip install azdev - - ls $(CLI_REPO_PATH) - - azdev --version - azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build Extension with azdev" - - - bash: | - K8S_EXTENSION_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) - echo "##vso[task.setvariable variable=K8S_EXTENSION_VERSION]$K8S_EXTENSION_VERSION" - cp * $(K8S_EXTENSION_REPO_PATH)/bin - workingDirectory: $(CLI_REPO_PATH)/dist - displayName: "Copy the Built .whl to Extension Test Path" - - - bash: | - RAND_STR=$RANDOM - AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" - ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" - - JSON_STRING=$(jq -n \ - --arg SUB_ID "$SUBSCRIPTION_ID" \ - --arg RG "$RESOURCE_GROUP" \ - --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ - --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ - --arg K8S_EXTENSION_VERSION "$K8S_EXTENSION_VERSION" \ - '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-extension": $K8S_EXTENSION_VERSION, connectedk8s: "1.0.0"}}') - echo $JSON_STRING > settings.json - cat settings.json - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - displayName: "Generate a settings.json file" - - - bash : | - echo "Downloading the kind script" - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64 - chmod +x ./kind - ./kind create cluster - displayName: "Create and Start the Kind cluster" - - - task: AzureCLI@2 - displayName: Bootstrap - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Bootstrap.ps1 -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - - - task: AzureCLI@2 - displayName: Run the Test Suite - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Test.ps1 -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - continueOnError: true - - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'JUnit' - testResultsFiles: '**/TestResults.xml' - failTaskOnFailedTests: true - condition: succeededOrFailed() - - - task: AzureCLI@2 - displayName: Cleanup - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Cleanup.ps1 -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - condition: succeededOrFailed() - -- stage: BuildPublishExtension - dependsOn: [] - displayName: "Build and Publish the Extension Artifact" - variables: - CLI_REPO_PATH: $(Agent.BuildDirectory)/s - IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranchName'], 'refs/heads/k8s-extension/private-preview'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private-preview'))] - jobs: - - job: BuildPublishExtension - displayName: "Build and Publish the Extension Artifact" - pool: - vmImage: 'ubuntu-16.04' - steps: - - bash: | - if [[ $IS_PRIVATE_BRANCH ]]; then - echo "Using the private preview of k8s-extension to build..." - - cp $(CLI_REPO_PATH)/src/k8s-extension $(CLI_REPO_PATH)/src/k8s-extension-private -r - cp $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts.py - - EXTENSION_NAME="k8s-extension-private" - EXTENSION_FILE_NAME="k8s_extension_private" - - echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" - echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" - else - echo "Using the public version of k8s-extension to build..." - - EXTENSION_NAME="k8s-extension" - EXTENSION_FILE_NAME="k8s_extension" - - echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" - echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" - fi - displayName: "Copy Files, Set Variables based on Private Branch" + - '*' + +jobs: +- job: CredScan + displayName: "Credential Scan" + pool: + vmImage: "windows-2019" + steps: + - task: ms-codeanalysis.vss-microsoft-security-code-analysis-devops.build-task-credscan.CredScan@2 + displayName: 'Run Credential Scanner' + inputs: + toolMajorVersion: V2 + suppressionsFile: './scripts/ci/credscan/CredScanSuppressions.json' + - task: ms-codeanalysis.vss-microsoft-security-code-analysis-devops.build-task-postanalysis.PostAnalysis@1 + displayName: 'Post Analysis' + inputs: + AllTools: false + BinSkim: false + CredScan: true + RoslynAnalyzers: false + TSLint: false + ToolLogsNotFoundAction: 'Standard' + +- job: CheckLicenseHeader + displayName: "Check License" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + python -m venv env/ + + chmod +x ./env/bin/activate + source ./env/bin/activate + + # clone azure-cli + git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install -q azdev + + azdev setup -c ../azure-cli -r ./ + + azdev --version + az --version + + azdev verify license + +- job: StaticAnalysis + displayName: "Static Analysis" + pool: + vmImage: 'ubuntu-16.04' + steps: - task: UsePythonVersion@0 displayName: 'Use Python 3.6' inputs: versionSpec: 3.6 - - bash: | - set -ev - echo "Building extension ${EXTENSION_NAME}..." - - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - - # clone azure-cli - pip install azdev - - ls $(CLI_REPO_PATH) + - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests + displayName: 'Install wheel, pylint, flake8, requests' + - bash: python scripts/ci/source_code_static_analysis.py + displayName: "Static Analysis" + +- job: IndexVerify + displayName: "Verify Extensions Index" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: | + #!/usr/bin/env bash + set -ev + pip install wheel==0.30.0 requests packaging + export CI="ADO" + python ./scripts/ci/test_index.py -v + displayName: "Verify Extensions Index" - azdev --version - azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build Extension with azdev" - - task: PublishBuildArtifacts@1 - inputs: - pathToPublish: $(CLI_REPO_PATH)/dist - -- stage: AzureCLIOfficial - displayName: "Azure Official CLI Code Checks" - dependsOn: [] - jobs: - - job: CheckLicenseHeader - displayName: "Check License" - pool: - vmImage: 'ubuntu-16.04' - steps: +- job: SourceTests + displayName: "Integration Tests, Build Tests" + pool: + vmImage: 'ubuntu-16.04' + strategy: + matrix: + Python36: + python.version: '3.6' + Python38: + python.version: '3.8' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python $(python.version)' + inputs: + versionSpec: '$(python.version)' + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - bash: ./scripts/ci/test_source.sh + displayName: 'Run integration test and build test' + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + +- job: LintModifiedExtensions + displayName: "CLI Linter on Modified Extensions" + condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest')) + pool: + vmImage: 'ubuntu-16.04' + steps: - task: UsePythonVersion@0 displayName: 'Use Python 3.6' inputs: @@ -222,125 +131,41 @@ stages: set -ev # prepare and activate virtualenv - python -m venv env/ - - chmod +x ./env/bin/activate - source ./env/bin/activate + pip install virtualenv + python -m virtualenv venv/ + source ./venv/bin/activate # clone azure-cli - git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install -q azdev + git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - azdev setup -c ../azure-cli -r ./ + pip install azdev azdev --version - az --version - - azdev verify license - - - job: StaticAnalysis - displayName: "Static Analysis" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests - displayName: 'Install wheel, pylint, flake8, requests' - - bash: python scripts/ci/source_code_static_analysis.py - displayName: "Static Analysis" - - - job: IndexVerify - displayName: "Verify Extensions Index" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: | - #!/usr/bin/env bash - set -ev - pip install wheel==0.30.0 requests packaging - export CI="ADO" - python ./scripts/ci/test_index.py -v - displayName: "Verify Extensions Index" - - - job: SourceTests - displayName: "Integration Tests, Build Tests" - pool: - vmImage: 'ubuntu-16.04' - strategy: - matrix: - Python36: - python.version: '3.6' - Python38: - python.version: '3.8' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python $(python.version)' - inputs: - versionSpec: '$(python.version)' - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - bash: ./scripts/ci/test_source.sh - displayName: 'Run integration test and build test' - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - - - job: LintModifiedExtensions - displayName: "CLI Linter on Modified Extensions" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - pip install virtualenv - python -m virtualenv venv/ - source ./venv/bin/activate - - # clone azure-cli - git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install azdev - - azdev --version - azdev setup -c ../azure-cli -r ./ -e k8s-extension - - # overwrite the default AZURE_EXTENSION_DIR set by ADO - AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version - - AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-extension - displayName: "CLI Linter on Modified Extension" - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + azdev setup -c ../azure-cli -r ./ - - job: IndexRefDocVerify - displayName: "Verify Ref Docs" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - task: Bash@3 - displayName: "Verify Extension Ref Docs" - inputs: - targetType: 'filePath' - filePath: scripts/ci/test_index_ref_doc.sh + # overwrite the default AZURE_EXTENSION_DIR set by ADO + AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version + + AZURE_EXTENSION_DIR=~/.azure/cliextensions python scripts/ci/verify_linter.py + displayName: "CLI Linter on Modified Extension" + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + +- job: IndexRefDocVerify + displayName: "Verify Ref Docs" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - task: Bash@3 + displayName: "Verify Extension Ref Docs" + inputs: + targetType: 'filePath' + filePath: scripts/ci/test_index_ref_doc.sh \ No newline at end of file diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml new file mode 100644 index 00000000000..b0fa1857598 --- /dev/null +++ b/k8s-custom-pipelines.yml @@ -0,0 +1,346 @@ +resources: + repositories: + - repository: K8sPartnerExtensionTest + type: git + endpoint: AzureReposConnection + name: One/compute-HybridMgmt-K8sPartnerExtensionTest + +trigger: + batch: true + branches: + include: + - k8s-extension/public-preview + - k8s-extension/private-preview +pr: + branches: + include: + - k8s-extension/public-preview + - k8s-extension/private-preview + +stages: +- stage: K8sExtensionTestSuite + displayName: "K8s-Extension Test Suite" + variables: + K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest + CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions + SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" + RESOURCE_GROUP: "K8sPartnerExtensionTest" + BASE_CLUSTER_NAME: "k8s-extension-cluster" + + EXTENSION_NAME: "k8s-extension" + EXTENSION_FILE_NAME: "k8s_extension" + jobs: + - job: K8sExtensionTestSuite + displayName: "Run the Test Suite" + pool: + vmImage: 'ubuntu-16.04' + steps: + - checkout: self + - checkout: K8sPartnerExtensionTest + - bash: | + echo "Installing helm3" + curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 + chmod 700 get_helm.sh + ./get_helm.sh + + echo "Installing kubectl" + curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin/kubectl + kubectl version --client + displayName: "Setup the VM with helm3 and kubectl" + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + echo "Building extension ${EXTENSION_NAME}..." + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build Extension with azdev" + + - bash: | + K8S_EXTENSION_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) + echo "##vso[task.setvariable variable=K8S_EXTENSION_VERSION]$K8S_EXTENSION_VERSION" + cp * $(K8S_EXTENSION_REPO_PATH)/bin + workingDirectory: $(CLI_REPO_PATH)/dist + displayName: "Copy the Built .whl to Extension Test Path" + + - bash: | + RAND_STR=$RANDOM + AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" + ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" + + JSON_STRING=$(jq -n \ + --arg SUB_ID "$SUBSCRIPTION_ID" \ + --arg RG "$RESOURCE_GROUP" \ + --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ + --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ + --arg K8S_EXTENSION_VERSION "$K8S_EXTENSION_VERSION" \ + '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-extension": $K8S_EXTENSION_VERSION, connectedk8s: "1.0.0"}}') + echo $JSON_STRING > settings.json + cat settings.json + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + displayName: "Generate a settings.json file" + + - bash : | + echo "Downloading the kind script" + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64 + chmod +x ./kind + ./kind create cluster + displayName: "Create and Start the Kind cluster" + + - task: AzureCLI@2 + displayName: Bootstrap + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Bootstrap.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + + - task: AzureCLI@2 + displayName: Run the Test Suite + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Test.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + continueOnError: true + + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TestResults.xml' + failTaskOnFailedTests: true + condition: succeededOrFailed() + + - task: AzureCLI@2 + displayName: Cleanup + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Cleanup.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + condition: succeededOrFailed() + +- stage: BuildPublishExtension + dependsOn: [] + displayName: "Build and Publish the Extension Artifact" + variables: + CLI_REPO_PATH: $(Agent.BuildDirectory)/s + IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranchName'], 'refs/heads/k8s-extension/private-preview'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private-preview'))] + jobs: + - job: BuildPublishExtension + displayName: "Build and Publish the Extension Artifact" + pool: + vmImage: 'ubuntu-16.04' + steps: + - bash: | + if [[ $IS_PRIVATE_BRANCH ]]; then + echo "Using the private preview of k8s-extension to build..." + + cp $(CLI_REPO_PATH)/src/k8s-extension $(CLI_REPO_PATH)/src/k8s-extension-private -r + cp $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts.py + + EXTENSION_NAME="k8s-extension-private" + EXTENSION_FILE_NAME="k8s_extension_private" + + echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" + echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" + else + echo "Using the public version of k8s-extension to build..." + + EXTENSION_NAME="k8s-extension" + EXTENSION_FILE_NAME="k8s_extension" + + echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" + echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" + fi + displayName: "Copy Files, Set Variables based on Private Branch" + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + echo "Building extension ${EXTENSION_NAME}..." + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build Extension with azdev" + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: $(CLI_REPO_PATH)/dist + +- stage: AzureCLIOfficial + displayName: "Azure Official CLI Code Checks" + dependsOn: [] + jobs: + - job: CheckLicenseHeader + displayName: "Check License" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + python -m venv env/ + + chmod +x ./env/bin/activate + source ./env/bin/activate + + # clone azure-cli + git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install -q azdev + + azdev setup -c ../azure-cli -r ./ + + azdev --version + az --version + + azdev verify license + + - job: StaticAnalysis + displayName: "Static Analysis" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests + displayName: 'Install wheel, pylint, flake8, requests' + - bash: python scripts/ci/source_code_static_analysis.py + displayName: "Static Analysis" + + - job: IndexVerify + displayName: "Verify Extensions Index" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: | + #!/usr/bin/env bash + set -ev + pip install wheel==0.30.0 requests packaging + export CI="ADO" + python ./scripts/ci/test_index.py -v + displayName: "Verify Extensions Index" + + - job: SourceTests + displayName: "Integration Tests, Build Tests" + pool: + vmImage: 'ubuntu-16.04' + strategy: + matrix: + Python36: + python.version: '3.6' + Python38: + python.version: '3.8' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python $(python.version)' + inputs: + versionSpec: '$(python.version)' + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - bash: ./scripts/ci/test_source.sh + displayName: 'Run integration test and build test' + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: LintModifiedExtensions + displayName: "CLI Linter on Modified Extensions" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + pip install virtualenv + python -m virtualenv venv/ + source ./venv/bin/activate + + # clone azure-cli + git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install azdev + + azdev --version + + azdev setup -c ../azure-cli -r ./ -e k8s-extension + + # overwrite the default AZURE_EXTENSION_DIR set by ADO + AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version + + AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-extension + displayName: "CLI Linter on Modified Extension" + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: IndexRefDocVerify + displayName: "Verify Ref Docs" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - task: Bash@3 + displayName: "Verify Extension Ref Docs" + inputs: + targetType: 'filePath' + filePath: scripts/ci/test_index_ref_doc.sh \ No newline at end of file From c88876f27472c918b93211fa60a2d0614eaa781b Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 11 Mar 2021 15:12:33 -0800 Subject: [PATCH 20/80] Update custom pipelines files --- azure-pipelines.yml | 454 +++++++++++++++------------------------ k8s-custom-pipelines.yml | 283 ++++++++++++++++++++++++ 2 files changed, 454 insertions(+), 283 deletions(-) create mode 100644 k8s-custom-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ca06b5f3807..99e89b79803 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,283 +1,171 @@ -resources: - repositories: - - repository: K8sPartnerExtensionTest - type: git - endpoint: AzureReposConnection - name: One/compute-HybridMgmt-K8sPartnerExtensionTest - ref: joinnis/scc-testing - -trigger: - batch: true - branches: - include: - - k8s-configuration -pr: - branches: - include: - - k8s-configuration - -stages: -- stage: K8sConfigurationTestSuite - displayName: "K8s-Configuration Test Suite" - variables: - K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest - CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions - EXTENSION_NAME: "k8s-configuration" - EXTENSION_FILE_NAME: "k8s_configuration" - SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" - RESOURCE_GROUP: "K8sPartnerExtensionTest" - BASE_CLUSTER_NAME: "k8s-configuration-cluster" - jobs: - - job: K8sConfigurationTestSuite - displayName: "Run the Test Suite" - pool: - vmImage: 'ubuntu-16.04' - steps: - - checkout: self - - checkout: K8sPartnerExtensionTest - - - bash: | - echo "Installing helm3" - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 - chmod 700 get_helm.sh - ./get_helm.sh - - echo "Installing kubectl" - curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x ./kubectl - sudo mv ./kubectl /usr/local/bin/kubectl - kubectl version --client - displayName: "Setup the VM with helm3 and kubectl" - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - - # clone azure-cli - pip install azdev - - ls $(CLI_REPO_PATH) - - azdev --version - azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build $(EXTENSION_NAME) with azdev" - - - bash: | - K8S_CONFIG_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) - echo "##vso[task.setvariable variable=K8S_CONFIG_VERSION]$K8S_CONFIG_VERSION" - cp * $(K8S_EXTENSION_REPO_PATH)/extensions - workingDirectory: $(CLI_REPO_PATH)/dist - displayName: "Copy the Built .whl to Extension Test Path" - - - bash: | - RAND_STR=$RANDOM - AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" - ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" - - JSON_STRING=$(jq -n \ - --arg SUB_ID "$SUBSCRIPTION_ID" \ - --arg RG "$RESOURCE_GROUP" \ - --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ - --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ - --arg K8S_CONFIG_VERSION "$K8S_CONFIG_VERSION" \ - '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-configuration": $K8S_CONFIG_VERSION, connectedk8s: "1.0.0"}}') - echo $JSON_STRING > settings.json - cat settings.json - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - displayName: "Generate a settings.json file" - - - bash : | - echo "Downloading the kind script" - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64 - chmod +x ./kind - ./kind create cluster - displayName: "Create and Start the Kind cluster" - - - task: AzureCLI@2 - displayName: Bootstrap - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Bootstrap.ps1 -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - - - task: AzureCLI@2 - displayName: Run the Test Suite - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Test.ps1 -Type Configuration -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - continueOnError: true - - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'JUnit' - testResultsFiles: '**/TestResults.xml' - failTaskOnFailedTests: true - condition: succeededOrFailed() - - - task: AzureCLI@2 - displayName: Cleanup - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Cleanup.ps1 -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - condition: succeededOrFailed() - -- stage: AzureCLIOfficial - displayName: "Azure Official CLI Code Checks" - dependsOn: [] - jobs: - - job: CheckLicenseHeader - displayName: "Check License" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - python -m venv env/ - - chmod +x ./env/bin/activate - source ./env/bin/activate - - # clone azure-cli - git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install -q azdev - - azdev setup -c ../azure-cli -r ./ - - azdev --version - az --version - - azdev verify license - - - job: StaticAnalysis - displayName: "Static Analysis" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests - displayName: 'Install wheel, pylint, flake8, requests' - - bash: python scripts/ci/source_code_static_analysis.py - displayName: "Static Analysis" - - - job: IndexVerify - displayName: "Verify Extensions Index" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: | - #!/usr/bin/env bash - set -ev - pip install wheel==0.30.0 requests packaging - export CI="ADO" - python ./scripts/ci/test_index.py -v - displayName: "Verify Extensions Index" - - - job: SourceTests - displayName: "Integration Tests, Build Tests" - pool: - vmImage: 'ubuntu-16.04' - strategy: - matrix: - Python36: - python.version: '3.6' - Python38: - python.version: '3.8' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python $(python.version)' - inputs: - versionSpec: '$(python.version)' - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - bash: ./scripts/ci/test_source.sh - displayName: 'Run integration test and build test' - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - - - job: LintModifiedExtensions - displayName: "CLI Linter on Modified Extensions" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - pip install virtualenv - python -m virtualenv venv/ - source ./venv/bin/activate - - # clone azure-cli - git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install azdev - - azdev --version - - azdev setup -c ../azure-cli -r ./ -e k8s-configuration - - # overwrite the default AZURE_EXTENSION_DIR set by ADO - AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version - - AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-configuration - displayName: "CLI Linter on Modified Extension" - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - - - job: IndexRefDocVerify - displayName: "Verify Ref Docs" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - task: Bash@3 - displayName: "Verify Extension Ref Docs" - inputs: - targetType: 'filePath' - filePath: scripts/ci/test_index_ref_doc.sh +resources: +- repo: self + +trigger: + batch: true + branches: + include: + - '*' + +pr: + branches: + include: + - '*' + +jobs: +- job: CredScan + displayName: "Credential Scan" + pool: + vmImage: "windows-2019" + steps: + - task: ms-codeanalysis.vss-microsoft-security-code-analysis-devops.build-task-credscan.CredScan@2 + displayName: 'Run Credential Scanner' + inputs: + toolMajorVersion: V2 + suppressionsFile: './scripts/ci/credscan/CredScanSuppressions.json' + - task: ms-codeanalysis.vss-microsoft-security-code-analysis-devops.build-task-postanalysis.PostAnalysis@1 + displayName: 'Post Analysis' + inputs: + AllTools: false + BinSkim: false + CredScan: true + RoslynAnalyzers: false + TSLint: false + ToolLogsNotFoundAction: 'Standard' + +- job: CheckLicenseHeader + displayName: "Check License" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + python -m venv env/ + + chmod +x ./env/bin/activate + source ./env/bin/activate + + # clone azure-cli + git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install -q azdev + + azdev setup -c ../azure-cli -r ./ + + azdev --version + az --version + + azdev verify license + +- job: StaticAnalysis + displayName: "Static Analysis" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests + displayName: 'Install wheel, pylint, flake8, requests' + - bash: python scripts/ci/source_code_static_analysis.py + displayName: "Static Analysis" + +- job: IndexVerify + displayName: "Verify Extensions Index" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: | + #!/usr/bin/env bash + set -ev + pip install wheel==0.30.0 requests packaging + export CI="ADO" + python ./scripts/ci/test_index.py -v + displayName: "Verify Extensions Index" + +- job: SourceTests + displayName: "Integration Tests, Build Tests" + pool: + vmImage: 'ubuntu-16.04' + strategy: + matrix: + Python36: + python.version: '3.6' + Python38: + python.version: '3.8' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python $(python.version)' + inputs: + versionSpec: '$(python.version)' + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - bash: ./scripts/ci/test_source.sh + displayName: 'Run integration test and build test' + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + +- job: LintModifiedExtensions + displayName: "CLI Linter on Modified Extensions" + condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest')) + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + pip install virtualenv + python -m virtualenv venv/ + source ./venv/bin/activate + + # clone azure-cli + git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install azdev + + azdev --version + + azdev setup -c ../azure-cli -r ./ + + # overwrite the default AZURE_EXTENSION_DIR set by ADO + AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version + + AZURE_EXTENSION_DIR=~/.azure/cliextensions python scripts/ci/verify_linter.py + displayName: "CLI Linter on Modified Extension" + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + +- job: IndexRefDocVerify + displayName: "Verify Ref Docs" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - task: Bash@3 + displayName: "Verify Extension Ref Docs" + inputs: + targetType: 'filePath' + filePath: scripts/ci/test_index_ref_doc.sh \ No newline at end of file diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml new file mode 100644 index 00000000000..ca06b5f3807 --- /dev/null +++ b/k8s-custom-pipelines.yml @@ -0,0 +1,283 @@ +resources: + repositories: + - repository: K8sPartnerExtensionTest + type: git + endpoint: AzureReposConnection + name: One/compute-HybridMgmt-K8sPartnerExtensionTest + ref: joinnis/scc-testing + +trigger: + batch: true + branches: + include: + - k8s-configuration +pr: + branches: + include: + - k8s-configuration + +stages: +- stage: K8sConfigurationTestSuite + displayName: "K8s-Configuration Test Suite" + variables: + K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest + CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions + EXTENSION_NAME: "k8s-configuration" + EXTENSION_FILE_NAME: "k8s_configuration" + SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" + RESOURCE_GROUP: "K8sPartnerExtensionTest" + BASE_CLUSTER_NAME: "k8s-configuration-cluster" + jobs: + - job: K8sConfigurationTestSuite + displayName: "Run the Test Suite" + pool: + vmImage: 'ubuntu-16.04' + steps: + - checkout: self + - checkout: K8sPartnerExtensionTest + + - bash: | + echo "Installing helm3" + curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 + chmod 700 get_helm.sh + ./get_helm.sh + + echo "Installing kubectl" + curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin/kubectl + kubectl version --client + displayName: "Setup the VM with helm3 and kubectl" + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build $(EXTENSION_NAME) with azdev" + + - bash: | + K8S_CONFIG_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) + echo "##vso[task.setvariable variable=K8S_CONFIG_VERSION]$K8S_CONFIG_VERSION" + cp * $(K8S_EXTENSION_REPO_PATH)/extensions + workingDirectory: $(CLI_REPO_PATH)/dist + displayName: "Copy the Built .whl to Extension Test Path" + + - bash: | + RAND_STR=$RANDOM + AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" + ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" + + JSON_STRING=$(jq -n \ + --arg SUB_ID "$SUBSCRIPTION_ID" \ + --arg RG "$RESOURCE_GROUP" \ + --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ + --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ + --arg K8S_CONFIG_VERSION "$K8S_CONFIG_VERSION" \ + '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-configuration": $K8S_CONFIG_VERSION, connectedk8s: "1.0.0"}}') + echo $JSON_STRING > settings.json + cat settings.json + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + displayName: "Generate a settings.json file" + + - bash : | + echo "Downloading the kind script" + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64 + chmod +x ./kind + ./kind create cluster + displayName: "Create and Start the Kind cluster" + + - task: AzureCLI@2 + displayName: Bootstrap + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Bootstrap.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + + - task: AzureCLI@2 + displayName: Run the Test Suite + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Test.ps1 -Type Configuration -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + continueOnError: true + + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TestResults.xml' + failTaskOnFailedTests: true + condition: succeededOrFailed() + + - task: AzureCLI@2 + displayName: Cleanup + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Cleanup.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + condition: succeededOrFailed() + +- stage: AzureCLIOfficial + displayName: "Azure Official CLI Code Checks" + dependsOn: [] + jobs: + - job: CheckLicenseHeader + displayName: "Check License" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + python -m venv env/ + + chmod +x ./env/bin/activate + source ./env/bin/activate + + # clone azure-cli + git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install -q azdev + + azdev setup -c ../azure-cli -r ./ + + azdev --version + az --version + + azdev verify license + + - job: StaticAnalysis + displayName: "Static Analysis" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests + displayName: 'Install wheel, pylint, flake8, requests' + - bash: python scripts/ci/source_code_static_analysis.py + displayName: "Static Analysis" + + - job: IndexVerify + displayName: "Verify Extensions Index" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: | + #!/usr/bin/env bash + set -ev + pip install wheel==0.30.0 requests packaging + export CI="ADO" + python ./scripts/ci/test_index.py -v + displayName: "Verify Extensions Index" + + - job: SourceTests + displayName: "Integration Tests, Build Tests" + pool: + vmImage: 'ubuntu-16.04' + strategy: + matrix: + Python36: + python.version: '3.6' + Python38: + python.version: '3.8' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python $(python.version)' + inputs: + versionSpec: '$(python.version)' + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - bash: ./scripts/ci/test_source.sh + displayName: 'Run integration test and build test' + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: LintModifiedExtensions + displayName: "CLI Linter on Modified Extensions" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + pip install virtualenv + python -m virtualenv venv/ + source ./venv/bin/activate + + # clone azure-cli + git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install azdev + + azdev --version + + azdev setup -c ../azure-cli -r ./ -e k8s-configuration + + # overwrite the default AZURE_EXTENSION_DIR set by ADO + AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version + + AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-configuration + displayName: "CLI Linter on Modified Extension" + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: IndexRefDocVerify + displayName: "Verify Ref Docs" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - task: Bash@3 + displayName: "Verify Extension Ref Docs" + inputs: + targetType: 'filePath' + filePath: scripts/ci/test_index_ref_doc.sh From ea8aa7d25fea7ee62276c479d6c658b4d23642fa Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 11 Mar 2021 15:16:22 -0800 Subject: [PATCH 21/80] Add publish step to k8s-configuration --- k8s-custom-pipelines.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index ca06b5f3807..f100ef6a9be 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -141,6 +141,15 @@ stages: .\Cleanup.ps1 -CI workingDirectory: $(K8S_EXTENSION_REPO_PATH) condition: succeededOrFailed() + + - job: BuildPublishExtension + displayName: "Build and Publish the Extension Artifact" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: $(CLI_REPO_PATH)/dist - stage: AzureCLIOfficial displayName: "Azure Official CLI Code Checks" From f9874d63a042b107e2ecb260dcbd1d61f0048998 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 11 Mar 2021 15:47:16 -0800 Subject: [PATCH 22/80] Update pipeline to publish extension --- k8s-custom-pipelines.yml | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index f100ef6a9be..05c2f6e23e5 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -143,10 +143,36 @@ stages: condition: succeededOrFailed() - job: BuildPublishExtension - displayName: "Build and Publish the Extension Artifact" pool: vmImage: 'ubuntu-16.04' + displayName: "Build and Publish the Extension Artifact" + variables: + CLI_REPO_PATH: $(Agent.BuildDirectory)/s + EXTENSION_NAME: "k8s-configuration" steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + echo "Building extension ${EXTENSION_NAME}..." + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build Extension with azdev" - task: PublishBuildArtifacts@1 inputs: pathToPublish: $(CLI_REPO_PATH)/dist From 009a83e95da65566623e25b4ca43c5553ae58cc2 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 11 Mar 2021 16:17:09 -0800 Subject: [PATCH 23/80] Update public extension pipeline --- k8s-custom-pipelines.yml | 49 +++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index b0fa1857598..a5dbceabea2 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -18,8 +18,8 @@ pr: - k8s-extension/private-preview stages: -- stage: K8sExtensionTestSuite - displayName: "K8s-Extension Test Suite" +- stage: BuildTestPublishExtension + displayName: "Build, Test, and Publish Extension" variables: K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions @@ -144,40 +144,37 @@ stages: workingDirectory: $(K8S_EXTENSION_REPO_PATH) condition: succeededOrFailed() -- stage: BuildPublishExtension - dependsOn: [] - displayName: "Build and Publish the Extension Artifact" - variables: - CLI_REPO_PATH: $(Agent.BuildDirectory)/s - IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranchName'], 'refs/heads/k8s-extension/private-preview'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private-preview'))] - jobs: - job: BuildPublishExtension - displayName: "Build and Publish the Extension Artifact" pool: vmImage: 'ubuntu-16.04' + displayName: "Build and Publish the Extension Artifact" + variables: + CLI_REPO_PATH: $(Agent.BuildDirectory)/s + IS_PRIVATE_BRANCH: $[or(and(eq(variables['Build.SourceBranchName'], 'refs/heads/k8s-extension/private-preview'), ne(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/public-preview')), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private-preview'))] steps: - bash: | - if [[ $IS_PRIVATE_BRANCH ]]; then - echo "Using the private preview of k8s-extension to build..." + echo "Using the private preview of k8s-extension to build..." - cp $(CLI_REPO_PATH)/src/k8s-extension $(CLI_REPO_PATH)/src/k8s-extension-private -r - cp $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts.py + cp $(CLI_REPO_PATH)/src/k8s-extension $(CLI_REPO_PATH)/src/k8s-extension-private -r + cp $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts.py - EXTENSION_NAME="k8s-extension-private" - EXTENSION_FILE_NAME="k8s_extension_private" + EXTENSION_NAME="k8s-extension-private" + EXTENSION_FILE_NAME="k8s_extension_private" - echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" - echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" - else - echo "Using the public version of k8s-extension to build..." + echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" + echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" + condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'True')) + displayName: "Copy Files, Set Variables for k8s-extension-private" + - bash: | + echo "Using the public version of k8s-extension to build..." - EXTENSION_NAME="k8s-extension" - EXTENSION_FILE_NAME="k8s_extension" + EXTENSION_NAME="k8s-extension" + EXTENSION_FILE_NAME="k8s_extension" - echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" - echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" - fi - displayName: "Copy Files, Set Variables based on Private Branch" + echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" + echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" + condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'False')) + displayName: "Copy Files, Set Variables for k8s-extension" - task: UsePythonVersion@0 displayName: 'Use Python 3.6' inputs: From 8e058c595946f45740c87ef6576349235d41ca76 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 11 Mar 2021 16:23:38 -0800 Subject: [PATCH 24/80] Change condition variable --- k8s-custom-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index a5dbceabea2..5bf0489f053 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -150,7 +150,7 @@ stages: displayName: "Build and Publish the Extension Artifact" variables: CLI_REPO_PATH: $(Agent.BuildDirectory)/s - IS_PRIVATE_BRANCH: $[or(and(eq(variables['Build.SourceBranchName'], 'refs/heads/k8s-extension/private-preview'), ne(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/public-preview')), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private-preview'))] + IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranch'], 'refs/heads/k8s-extension/private-preview'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private-preview'))] steps: - bash: | echo "Using the private preview of k8s-extension to build..." From 664009c78189a41ee5934f4ddbb7d9674b9c9672 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 11 Mar 2021 16:49:02 -0800 Subject: [PATCH 25/80] Update pipeline naming --- k8s-custom-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 05c2f6e23e5..7b510de2852 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -17,8 +17,8 @@ pr: - k8s-configuration stages: -- stage: K8sConfigurationTestSuite - displayName: "K8s-Configuration Test Suite" +- stage: BuildTestPublishExtension + displayName: "Build, Test, and Publish Extension" variables: K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions From dea40c19ce9c5371ea7527f120c492ab2e6f6619 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 11 Mar 2021 17:47:00 -0800 Subject: [PATCH 26/80] Add version to public preview/private preview --- src/k8s-extension/azext_k8s_extension/_consts.py | 1 + src/k8s-extension/azext_k8s_extension/_consts_private.py | 1 + src/k8s-extension/setup.py | 6 +----- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/k8s-extension/azext_k8s_extension/_consts.py b/src/k8s-extension/azext_k8s_extension/_consts.py index e9f8156f307..820e38af31c 100644 --- a/src/k8s-extension/azext_k8s_extension/_consts.py +++ b/src/k8s-extension/azext_k8s_extension/_consts.py @@ -5,3 +5,4 @@ # -------------------------------------------------------------------------------------------- EXTENSION_NAME = 'k8s-extension' +VERSION = "0.1.1" diff --git a/src/k8s-extension/azext_k8s_extension/_consts_private.py b/src/k8s-extension/azext_k8s_extension/_consts_private.py index 18a01637c2d..bc4c8a2b694 100644 --- a/src/k8s-extension/azext_k8s_extension/_consts_private.py +++ b/src/k8s-extension/azext_k8s_extension/_consts_private.py @@ -5,3 +5,4 @@ # -------------------------------------------------------------------------------------------- EXTENSION_NAME = 'k8s-extension-private' +VERSION = "0.1PP.14" diff --git a/src/k8s-extension/setup.py b/src/k8s-extension/setup.py index 878f7f8d87a..d3d491fd48c 100644 --- a/src/k8s-extension/setup.py +++ b/src/k8s-extension/setup.py @@ -15,10 +15,6 @@ from distutils import log as logger logger.warn("Wheel is not available, disabling bdist_wheel hook") -# TODO: Confirm this is the right version number you want and it matches your -# HISTORY.rst entry. -VERSION = '0.1PP.14' - # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers CLASSIFIERS = [ @@ -43,7 +39,7 @@ setup( name=consts.EXTENSION_NAME, - version=VERSION, + version=consts.VERSION, description='Microsoft Azure Command-Line Tools K8s-extension Extension', # TODO: Update author and email, if applicable author='Microsoft Corporation', From e81e0101493c99a361576211c95d3e118449b1dd Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Fri, 12 Mar 2021 12:10:48 -0800 Subject: [PATCH 27/80] Update pipelines --- k8s-custom-pipelines.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 5bf0489f053..a4be34c3e7b 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -9,13 +9,13 @@ trigger: batch: true branches: include: - - k8s-extension/public-preview - - k8s-extension/private-preview + - k8s-extension/public + - k8s-extension/private pr: branches: include: - - k8s-extension/public-preview - - k8s-extension/private-preview + - k8s-extension/public + - k8s-extension/private stages: - stage: BuildTestPublishExtension @@ -150,7 +150,7 @@ stages: displayName: "Build and Publish the Extension Artifact" variables: CLI_REPO_PATH: $(Agent.BuildDirectory)/s - IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranch'], 'refs/heads/k8s-extension/private-preview'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private-preview'))] + IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranch'], 'refs/heads/k8s-extension/private'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private'))] steps: - bash: | echo "Using the private preview of k8s-extension to build..." From 9621a48df1feda8134be4a98df3a41d2b44e08b2 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Fri, 12 Mar 2021 13:13:39 -0800 Subject: [PATCH 28/80] Add different testing based on private branch --- k8s-custom-pipelines.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index a4be34c3e7b..3bdfd70eb99 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -26,6 +26,7 @@ stages: SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" RESOURCE_GROUP: "K8sPartnerExtensionTest" BASE_CLUSTER_NAME: "k8s-extension-cluster" + IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranch'], 'refs/heads/k8s-extension/private'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private'))] EXTENSION_NAME: "k8s-extension" EXTENSION_FILE_NAME: "k8s_extension" @@ -116,7 +117,19 @@ stages: workingDirectory: $(K8S_EXTENSION_REPO_PATH) - task: AzureCLI@2 - displayName: Run the Test Suite + displayName: Run the Test Suite Public Extensions Only + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Test.ps1 -CI -Public + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + continueOnError: true + condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'False')) + + - task: AzureCLI@2 + displayName: Run the Test Suite on Private + Public Extensions inputs: azureSubscription: AzureResourceConnection scriptType: pscore @@ -125,6 +138,7 @@ stages: .\Test.ps1 -CI workingDirectory: $(K8S_EXTENSION_REPO_PATH) continueOnError: true + condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'True')) - task: PublishTestResults@2 inputs: @@ -150,7 +164,6 @@ stages: displayName: "Build and Publish the Extension Artifact" variables: CLI_REPO_PATH: $(Agent.BuildDirectory)/s - IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranch'], 'refs/heads/k8s-extension/private'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private'))] steps: - bash: | echo "Using the private preview of k8s-extension to build..." From 862a0355c54da89a13169de57dc92e07655e7a14 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Fri, 12 Mar 2021 13:22:30 -0800 Subject: [PATCH 29/80] Add annotations to extension model --- src/k8s-extension/azext_k8s_extension/custom.py | 6 +++--- .../partner_extensions/AzureDefender.py | 4 ++-- .../partner_extensions/ContainerInsights.py | 4 ++-- .../partner_extensions/DefaultExtension.py | 2 +- .../partner_extensions/PartnerExtensionModel.py | 14 +++++++++----- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py index 4b0657c1814..b06567aca0b 100644 --- a/src/k8s-extension/azext_k8s_extension/custom.py +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -17,9 +17,9 @@ # from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate from azext_k8s_extension.vendored_sdks.models import ErrorResponseException -from .partner_extensions.ContainerInsights import ContainerInsights -from .partner_extensions.AzureDefender import AzureDefender -from .partner_extensions.DefaultExtension import DefaultExtension +from azext_k8s_extension.partner_extensions.ContainerInsights import ContainerInsights +from azext_k8s_extension.partner_extensions.AzureDefender import AzureDefender +from azext_k8s_extension.partner_extensions.DefaultExtension import DefaultExtension from ._client_factory import cf_resources diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py index 172662f4e57..39329cc36cb 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py @@ -12,8 +12,8 @@ from azext_k8s_extension.vendored_sdks.models import ScopeCluster from azext_k8s_extension.vendored_sdks.models import Scope -from .PartnerExtensionModel import PartnerExtensionModel -from .ContainerInsights import _get_container_insights_settings +from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel +from azext_k8s_extension.partner_extensions.ContainerInsights import _get_container_insights_settings logger = get_logger(__name__) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py index ada94d985a9..f6662c29611 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py @@ -22,9 +22,9 @@ from azext_k8s_extension.vendored_sdks.models import ScopeCluster from azext_k8s_extension.vendored_sdks.models import Scope -from .PartnerExtensionModel import PartnerExtensionModel +from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel -from .._client_factory import ( +from azext_k8s_extension._client_factory import ( cf_resources, cf_resource_groups, cf_log_analytics) logger = get_logger(__name__) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py index 243371e47b7..d3e9a6827c2 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py @@ -11,7 +11,7 @@ from azext_k8s_extension.vendored_sdks.models import ScopeNamespace from azext_k8s_extension.vendored_sdks.models import Scope -from .PartnerExtensionModel import PartnerExtensionModel +from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel class DefaultExtension(PartnerExtensionModel): diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py index c863a8d3833..c0bf3b6e657 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py @@ -4,16 +4,20 @@ # -------------------------------------------------------------------------------------------- from abc import ABC, abstractmethod +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceForCreate +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate class PartnerExtensionModel(ABC): @abstractmethod - def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, - scope, auto_upgrade_minor_version, release_train, version, target_namespace, - release_namespace, configuration_settings, configuration_protected_settings, - configuration_settings_file, configuration_protected_settings_file): + def Create(self, cmd, client, resource_group_name: str, cluster_name: str, name: str, cluster_type: str, + extension_type: str, scope: str, auto_upgrade_minor_version: bool, release_train: str, version: str, + target_namespace: str, release_namespace: str, configuration_settings: dict, + configuration_protected_settings: dict, configuration_settings_file: str, + configuration_protected_settings_file: str) -> ExtensionInstanceForCreate: pass @abstractmethod - def Update(self, extension, auto_upgrade_minor_version, release_train, version): + def Update(self, extension: ExtensionInstanceForCreate, auto_upgrade_minor_version: bool, + release_train: str, version: str) -> ExtensionInstanceUpdate: pass From e1c3d12cd8a58e98cd5d2e9575d3d96fdc585bc3 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Mon, 15 Mar 2021 11:41:42 -0700 Subject: [PATCH 30/80] Update k8s-custom-pipelines.yml --- k8s-custom-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 3bdfd70eb99..f4e2984ddf2 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -123,7 +123,7 @@ stages: scriptType: pscore scriptLocation: inlineScript inlineScript: | - .\Test.ps1 -CI -Public + .\Test.ps1 -CI -ExtensionType Public -OnlyPublicTests workingDirectory: $(K8S_EXTENSION_REPO_PATH) continueOnError: true condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'False')) @@ -135,7 +135,7 @@ stages: scriptType: pscore scriptLocation: inlineScript inlineScript: | - .\Test.ps1 -CI + .\Test.ps1 -CI -ExtensionType Public workingDirectory: $(K8S_EXTENSION_REPO_PATH) continueOnError: true condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'True')) @@ -353,4 +353,4 @@ stages: displayName: "Verify Extension Ref Docs" inputs: targetType: 'filePath' - filePath: scripts/ci/test_index_ref_doc.sh \ No newline at end of file + filePath: scripts/ci/test_index_ref_doc.sh From 3e309bf8d1218994b3135a9614e03b0e2cf41e88 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Tue, 16 Mar 2021 11:01:39 -0700 Subject: [PATCH 31/80] Update SDKs with Updated Swagger Spec for 2020-07-01-preview (#13) * Update sdks with updated swagger spec * Update version and history rst * Reorder release history timeline * Fix ExtensionInstanceForCreate for import --- src/k8s-extension/HISTORY.rst | 70 +-- .../azext_k8s_extension/_client_factory.py | 6 +- .../azext_k8s_extension/_consts.py | 2 +- .../partner_extensions/AzureDefender.py | 8 +- .../partner_extensions/ContainerInsights.py | 8 +- .../partner_extensions/DefaultExtension.py | 6 +- .../PartnerExtensionModel.py | 6 +- .../vendored_sdks/__init__.py | 6 +- .../vendored_sdks/_configuration.py | 6 +- .../_source_control_configuration_client.py | 60 +++ .../vendored_sdks/models/__init__.py | 48 +- .../vendored_sdks/models/_models.py | 473 +++++++++++------ .../vendored_sdks/models/_models_py3.py | 483 +++++++++++------- .../vendored_sdks/models/_paged_models.py | 21 +- ...rce_control_configuration_client_enums.py} | 0 .../vendored_sdks/operations/__init__.py | 8 +- ...perations.py => _extensions_operations.py} | 119 ++--- .../vendored_sdks/operations/_operations.py | 101 ++++ ...ource_control_configurations_operations.py | 386 ++++++++++++++ .../vendored_sdks/version.py | 2 +- 20 files changed, 1304 insertions(+), 515 deletions(-) create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/_source_control_configuration_client.py rename src/k8s-extension/azext_k8s_extension/vendored_sdks/models/{_k8s_extension_client_enums.py => _source_control_configuration_client_enums.py} (100%) rename src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/{_k8s_extensions_operations.py => _extensions_operations.py} (84%) create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_operations.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_source_control_configurations_operations.py diff --git a/src/k8s-extension/HISTORY.rst b/src/k8s-extension/HISTORY.rst index 695f549b1a2..54c1e375f6f 100644 --- a/src/k8s-extension/HISTORY.rst +++ b/src/k8s-extension/HISTORY.rst @@ -3,81 +3,33 @@ Release History =============== -0.1.0 -++++++++++++++++++ -* Initial release. - -0.1.1 -++++++++++++++++++ -* Add support for microsoft-azure-defender extension type - -0.1.2 -++++++++++++++++++ - -* Add support for Arc Appliance cluster type - -0.1.3 -++++++++++++++++++ - -* Customization for microsoft.openservicemesh - -0.1PP.4 +0.2.0 ++++++++++++++++++ * Refactor for clear separation of extension-type specific customizations -* Introduce new versioning scheme to allow Preview releases by Partners - -0.1PP.5 -++++++++++++++++++ - -* OpenServiceMesh customization. -* If Version is passed in, accept None for AutoUpgradeMinorVersion, and not require it to be False. - -0.1PP.6 -++++++++++++++++++ - * OpenServiceMesh customization. -* Scope is always cluster. Version is mandatory for staging and pilot release-trains. - -0.1PP.7 -++++++++++++++++++ - * Fix clusterType of Microsoft.ResourceConnector resource - -0.1PP.8 -++++++++++++++++++ - * Update clusterType validation to allow 'appliances' * Update identity creation to use the appropriate parent resource's type and api-version * Throw error if cluster type is not one of the 3 supported types - -0.1PP.9 -++++++++++++++++++ - * Rename azuremonitor-containers extension type to microsoft.azuremonitor.containers +* Move CLI errors to non-deprecated error types +* Remove support for update -0.1PP.10 -++++++++++++++++++ - -* Add azuremonitor-containers back with alternative microsoft.azuremonitor.containers - -0.1PP.11 +0.1.3 ++++++++++++++++++ -* Add shorter aliases for long parameter names +* Customization for microsoft.openservicemesh -0.1PP.12 +0.1.2 ++++++++++++++++++ -* Remove support for azuremonitor-containers extension type naming +* Add support for Arc Appliance cluster type -0.1PP.13 +0.1.1 ++++++++++++++++++ +* Add support for microsoft-azure-defender extension type -* Move CLI errors to non-deprecated error types -* Remove support for update - -0.1PP.14 +0.1.0 ++++++++++++++++++ - -* Update help text, group CLI arguments +* Initial release. diff --git a/src/k8s-extension/azext_k8s_extension/_client_factory.py b/src/k8s-extension/azext_k8s_extension/_client_factory.py index a4ec83ee0cb..1a9a10c2615 100644 --- a/src/k8s-extension/azext_k8s_extension/_client_factory.py +++ b/src/k8s-extension/azext_k8s_extension/_client_factory.py @@ -8,12 +8,12 @@ def cf_k8s_extension(cli_ctx, *_): - from azext_k8s_extension.vendored_sdks import K8sExtensionClient - return get_mgmt_service_client(cli_ctx, K8sExtensionClient) + from azext_k8s_extension.vendored_sdks import SourceControlConfigurationClient + return get_mgmt_service_client(cli_ctx, SourceControlConfigurationClient) def cf_k8s_extension_operation(cli_ctx, _): - return cf_k8s_extension(cli_ctx).k8s_extensions + return cf_k8s_extension(cli_ctx).extensions def cf_resource_groups(cli_ctx, subscription_id=None): diff --git a/src/k8s-extension/azext_k8s_extension/_consts.py b/src/k8s-extension/azext_k8s_extension/_consts.py index 820e38af31c..d0fdaf7775f 100644 --- a/src/k8s-extension/azext_k8s_extension/_consts.py +++ b/src/k8s-extension/azext_k8s_extension/_consts.py @@ -5,4 +5,4 @@ # -------------------------------------------------------------------------------------------- EXTENSION_NAME = 'k8s-extension' -VERSION = "0.1.1" +VERSION = "0.2.0" diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py index 39329cc36cb..7721ea8c638 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py @@ -7,7 +7,7 @@ from knack.log import get_logger -from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceForCreate +from azext_k8s_extension.vendored_sdks.models import ExtensionInstance from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate from azext_k8s_extension.vendored_sdks.models import ScopeCluster from azext_k8s_extension.vendored_sdks.models import Scope @@ -25,7 +25,7 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t configuration_settings_file, configuration_protected_settings_file): """ExtensionType 'microsoft.azuredefender.kubernetes' specific validations & defaults for Create - Must create and return a valid 'ExtensionInstanceForCreate' object. + Must create and return a valid 'ExtensionInstance' object. """ # NOTE-1: Replace default scope creation with your customization! @@ -46,9 +46,9 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t _get_container_insights_settings(cmd, resource_group_name, cluster_name, configuration_settings, configuration_protected_settings, is_ci_extension_type) - # NOTE-2: Return a valid ExtensionInstanceForCreate object, Instance name and flag for Identity + # NOTE-2: Return a valid ExtensionInstance object, Instance name and flag for Identity create_identity = True - extension_instance = ExtensionInstanceForCreate( + extension_instance = ExtensionInstance( extension_type=extension_type, auto_upgrade_minor_version=auto_upgrade_minor_version, release_train=release_train, diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py index f6662c29611..a90b807020d 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py @@ -17,7 +17,7 @@ from msrestazure.azure_exceptions import CloudError from msrestazure.tools import parse_resource_id, is_valid_resource_id -from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceForCreate +from azext_k8s_extension.vendored_sdks.models import ExtensionInstance from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate from azext_k8s_extension.vendored_sdks.models import ScopeCluster from azext_k8s_extension.vendored_sdks.models import Scope @@ -37,7 +37,7 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t configuration_settings_file, configuration_protected_settings_file): """ExtensionType 'microsoft.azuremonitor.containers' specific validations & defaults for Create - Must create and return a valid 'ExtensionInstanceForCreate' object. + Must create and return a valid 'ExtensionInstance' object. """ # NOTE-1: Replace default scope creation with your customization! @@ -58,9 +58,9 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t _get_container_insights_settings(cmd, resource_group_name, cluster_name, configuration_settings, configuration_protected_settings, is_ci_extension_type) - # NOTE-2: Return a valid ExtensionInstanceForCreate object, Instance name and flag for Identity + # NOTE-2: Return a valid ExtensionInstance object, Instance name and flag for Identity create_identity = True - extension_instance = ExtensionInstanceForCreate( + extension_instance = ExtensionInstance( extension_type=extension_type, auto_upgrade_minor_version=auto_upgrade_minor_version, release_train=release_train, diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py index d3e9a6827c2..8e813502edd 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py @@ -5,7 +5,7 @@ # pylint: disable=unused-argument -from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceForCreate +from azext_k8s_extension.vendored_sdks.models import ExtensionInstance from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate from azext_k8s_extension.vendored_sdks.models import ScopeCluster from azext_k8s_extension.vendored_sdks.models import ScopeNamespace @@ -21,7 +21,7 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t configuration_settings_file, configuration_protected_settings_file): """Default validations & defaults for Create - Must create and return a valid 'ExtensionInstanceForCreate' object. + Must create and return a valid 'ExtensionInstance' object. """ ext_scope = None @@ -37,7 +37,7 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t release_train = 'stable' create_identity = False - extension_instance = ExtensionInstanceForCreate( + extension_instance = ExtensionInstance( extension_type=extension_type, auto_upgrade_minor_version=auto_upgrade_minor_version, release_train=release_train, diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py index c0bf3b6e657..96c489644e7 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py @@ -4,7 +4,7 @@ # -------------------------------------------------------------------------------------------- from abc import ABC, abstractmethod -from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceForCreate +from azext_k8s_extension.vendored_sdks.models import ExtensionInstance from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate @@ -14,10 +14,10 @@ def Create(self, cmd, client, resource_group_name: str, cluster_name: str, name: extension_type: str, scope: str, auto_upgrade_minor_version: bool, release_train: str, version: str, target_namespace: str, release_namespace: str, configuration_settings: dict, configuration_protected_settings: dict, configuration_settings_file: str, - configuration_protected_settings_file: str) -> ExtensionInstanceForCreate: + configuration_protected_settings_file: str) -> ExtensionInstance: pass @abstractmethod - def Update(self, extension: ExtensionInstanceForCreate, auto_upgrade_minor_version: bool, + def Update(self, extension: ExtensionInstance, auto_upgrade_minor_version: bool, release_train: str, version: str) -> ExtensionInstanceUpdate: pass diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py index d94dccac4c2..874177b4d34 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py @@ -9,9 +9,9 @@ # regenerated. # -------------------------------------------------------------------------- -from ._configuration import K8sExtensionClientConfiguration -from ._k8s_extension_client import K8sExtensionClient -__all__ = ['K8sExtensionClient', 'K8sExtensionClientConfiguration'] +from ._configuration import SourceControlConfigurationClientConfiguration +from ._source_control_configuration_client import SourceControlConfigurationClient +__all__ = ['SourceControlConfigurationClient', 'SourceControlConfigurationClientConfiguration'] from .version import VERSION diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py index 48080b2ee7d..5043ed69594 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py @@ -13,8 +13,8 @@ from .version import VERSION -class K8sExtensionClientConfiguration(AzureConfiguration): - """Configuration for K8sExtensionClient +class SourceControlConfigurationClientConfiguration(AzureConfiguration): + """Configuration for SourceControlConfigurationClient Note that all parameters used to create this instance are saved as instance attributes. @@ -37,7 +37,7 @@ def __init__( if not base_url: base_url = 'https://management.azure.com' - super(K8sExtensionClientConfiguration, self).__init__(base_url) + super(SourceControlConfigurationClientConfiguration, self).__init__(base_url) # Starting Autorest.Python 4.0.64, make connection pool activated by default self.keep_alive = True diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/_source_control_configuration_client.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_source_control_configuration_client.py new file mode 100644 index 00000000000..a77176d8cb1 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_source_control_configuration_client.py @@ -0,0 +1,60 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.service_client import SDKClient +from msrest import Serializer, Deserializer + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from .operations import ExtensionsOperations +from . import models + + +class SourceControlConfigurationClient(SDKClient): + """KubernetesConfiguration Client + + :ivar config: Configuration for client. + :vartype config: SourceControlConfigurationClientConfiguration + + :ivar source_control_configurations: SourceControlConfigurations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.operations.Operations + :ivar extensions: Extensions operations + :vartype extensions: azure.mgmt.kubernetesconfiguration.operations.ExtensionsOperations + + :param credentials: Credentials needed for the client to connect to Azure. + :type credentials: :mod:`A msrestazure Credentials + object` + :param subscription_id: The Azure subscription ID. This is a + GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000) + :type subscription_id: str + :param str base_url: Service URL + """ + + def __init__( + self, credentials, subscription_id, base_url=None): + + self.config = SourceControlConfigurationClientConfiguration(credentials, subscription_id, base_url) + super(SourceControlConfigurationClient, self).__init__(self.config.credentials, self.config) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self.api_version = '2020-07-01-preview' + self._serialize = Serializer(client_models) + self._deserialize = Deserializer(client_models) + + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self.config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self.config, self._serialize, self._deserialize) + self.extensions = ExtensionsOperations( + self._client, self.config, self._serialize, self._deserialize) diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py index 166f80c01ea..e74cb56832b 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py @@ -10,60 +10,84 @@ # -------------------------------------------------------------------------- try: + from ._models_py3 import ComplianceStatus + from ._models_py3 import ConfigurationIdentity from ._models_py3 import ErrorDefinition from ._models_py3 import ErrorResponse, ErrorResponseException from ._models_py3 import ExtensionInstance - from ._models_py3 import ExtensionInstanceForCreate - from ._models_py3 import ExtensionInstanceForList from ._models_py3 import ExtensionInstanceUpdate from ._models_py3 import ExtensionStatus + from ._models_py3 import HelmOperatorProperties from ._models_py3 import ProxyResource from ._models_py3 import Resource + from ._models_py3 import ResourceProviderOperation + from ._models_py3 import ResourceProviderOperationDisplay from ._models_py3 import Result from ._models_py3 import Scope from ._models_py3 import ScopeCluster from ._models_py3 import ScopeNamespace - from ._models_py3 import ConfigurationIdentity + from ._models_py3 import SourceControlConfiguration + from ._models_py3 import SystemData except (SyntaxError, ImportError): + from ._models import ComplianceStatus + from ._models import ConfigurationIdentity from ._models import ErrorDefinition from ._models import ErrorResponse, ErrorResponseException from ._models import ExtensionInstance - from ._models import ExtensionInstanceForCreate - from ._models import ExtensionInstanceForList from ._models import ExtensionInstanceUpdate from ._models import ExtensionStatus + from ._models import HelmOperatorProperties from ._models import ProxyResource from ._models import Resource + from ._models import ResourceProviderOperation + from ._models import ResourceProviderOperationDisplay from ._models import Result from ._models import Scope from ._models import ScopeCluster from ._models import ScopeNamespace - from ._models import ConfigurationIdentity -from ._paged_models import ExtensionInstanceForListPaged -from ._k8s_extension_client_enums import ( + from ._models import SourceControlConfiguration + from ._models import SystemData +from ._paged_models import ExtensionInstancePaged +from ._paged_models import ResourceProviderOperationPaged +from ._paged_models import SourceControlConfigurationPaged +from ._source_control_configuration_client_enums import ( + ComplianceStateType, MessageLevelType, + OperatorType, + OperatorScopeType, + ProvisioningStateType, InstallStateType, LevelType, ResourceIdentityType, ) __all__ = [ + 'ComplianceStatus', + 'ConfigurationIdentity', 'ErrorDefinition', 'ErrorResponse', 'ErrorResponseException', 'ExtensionInstance', - 'ExtensionInstanceForCreate', - 'ExtensionInstanceForList', - 'ConfigurationIdentity', 'ExtensionInstanceUpdate', 'ExtensionStatus', + 'HelmOperatorProperties', 'ProxyResource', 'Resource', + 'ResourceProviderOperation', + 'ResourceProviderOperationDisplay', 'Result', 'Scope', 'ScopeCluster', 'ScopeNamespace', - 'ExtensionInstanceForListPaged', + 'SourceControlConfiguration', + 'SystemData', + 'SourceControlConfigurationPaged', + 'ResourceProviderOperationPaged', + 'ExtensionInstancePaged', + 'ComplianceStateType', 'MessageLevelType', + 'OperatorType', + 'OperatorScopeType', + 'ProvisioningStateType', 'InstallStateType', 'LevelType', 'ResourceIdentityType', diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py index 0a11097a24f..da1b94606cd 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py @@ -20,6 +20,47 @@ class CloudError(Model): _attribute_map = { } + +class ComplianceStatus(Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar compliance_state: The compliance state of the configuration. + Possible values include: 'Pending', 'Compliant', 'Noncompliant', + 'Installed', 'Failed' + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: + 'Error', 'Warning', 'Information' + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = kwargs.get('last_config_applied', None) + self.message = kwargs.get('message', None) + self.message_level = kwargs.get('message_level', None) + + class ConfigurationIdentity(Model): """Identity for the managed cluster. @@ -126,6 +167,9 @@ class Resource(Model): :vartype name: str :ivar type: Resource type :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData """ _validation = { @@ -138,6 +182,7 @@ class Resource(Model): 'id': {'key': 'id', 'type': 'str'}, 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, } def __init__(self, **kwargs): @@ -145,6 +190,7 @@ def __init__(self, **kwargs): self.id = None self.name = None self.type = None + self.system_data = kwargs.get('system_data', None) class ProxyResource(Resource): @@ -159,6 +205,9 @@ class ProxyResource(Resource): :vartype name: str :ivar type: Resource type :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData """ _validation = { @@ -171,6 +220,7 @@ class ProxyResource(Resource): 'id': {'key': 'id', 'type': 'str'}, 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, } def __init__(self, **kwargs): @@ -189,6 +239,9 @@ class ExtensionInstance(ProxyResource): :vartype name: str :ivar type: Resource type :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData :param extension_type: Type of the Extension, of which this resource is an instance of. It must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the Extension publisher. @@ -209,6 +262,10 @@ class ExtensionInstance(ProxyResource): :param configuration_settings: Configuration settings, as name-value pairs for configuring this instance of the extension. :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are + sensitive, as name-value pairs for configuring this instance of the + extension. + :type configuration_protected_settings: dict[str, str] :param install_state: Status of installation of this instance of the extension. Possible values include: 'Pending', 'Installed', 'Failed' :type install_state: str or @@ -248,19 +305,21 @@ class ExtensionInstance(ProxyResource): 'id': {'key': 'id', 'type': 'str'}, 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, 'version': {'key': 'properties.version', 'type': 'str'}, 'scope': {'key': 'properties.scope', 'type': 'Scope'}, 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, 'install_state': {'key': 'properties.installState', 'type': 'str'}, 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, - 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, + 'identity': {'key': 'properties.identity', 'type': 'ConfigurationIdentity'}, } def __init__(self, **kwargs): @@ -271,176 +330,9 @@ def __init__(self, **kwargs): self.version = kwargs.get('version', None) self.scope = kwargs.get('scope', None) self.configuration_settings = kwargs.get('configuration_settings', None) - self.install_state = kwargs.get('install_state', None) - self.statuses = kwargs.get('statuses', None) - self.creation_time = None - self.last_modified_time = None - self.last_status_time = None - self.error_info = None - self.identity = kwargs.get('identity', None) - - -class ExtensionInstanceForCreate(ProxyResource): - """Object to create a new Extension Instance. - - Variables are only populated by the server, and will be ignored when - sending a request. - - :ivar id: Resource Id - :vartype id: str - :ivar name: Resource name - :vartype name: str - :ivar type: Resource type - :vartype type: str - :param extension_type: Type of the Extension, of which this resource is an - instance of. It must be one of the Extension Types registered with - Microsoft.KubernetesConfiguration by the Extension publisher. - :type extension_type: str - :param auto_upgrade_minor_version: Flag to note if this instance - participates in auto upgrade of minor version, or not. - :type auto_upgrade_minor_version: bool - :param release_train: ReleaseTrain this extension instance participates in - for auto-upgrade (e.g. Stable, Preview, etc.) - only if - autoUpgradeMinorVersion is 'true'. - :type release_train: str - :param version: Version of the extension for this extension instance, if - it is 'pinned' to a specific version. autoUpgradeMinorVersion must be - 'false'. - :type version: str - :param scope: Scope at which the extension instance is installed. - :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope - :param configuration_settings: Configuration settings, as name-value pairs - for configuring this instance of the extension. - :type configuration_settings: dict[str, str] - :param configuration_protected_settings: Configuration settings that are - sensitive, as name-value pairs for configuring this instance of the - extension. - :type configuration_protected_settings: dict[str, str] - :param identity: The identity of the configuration. - :type identity: - ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity - :type location: str - """ - - _validation = { - 'id': {'readonly': True}, - 'name': {'readonly': True}, - 'type': {'readonly': True}, - } - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, - 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, - 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, - 'version': {'key': 'properties.version', 'type': 'str'}, - 'scope': {'key': 'properties.scope', 'type': 'Scope'}, - 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, - 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, - 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, - 'location': {'key': 'location', 'type': 'str'}, - } - - def __init__(self, **kwargs): - super(ExtensionInstanceForCreate, self).__init__(**kwargs) - self.extension_type = kwargs.get('extension_type', None) - self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', None) - self.release_train = kwargs.get('release_train', None) - self.version = kwargs.get('version', None) - self.scope = kwargs.get('scope', None) - self.configuration_settings = kwargs.get('configuration_settings', None) self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) - self.identity = kwargs.get('identity', None) - self.location = kwargs.get('location', None) - - -class ExtensionInstanceForList(ProxyResource): - """The Extension Instance object. - - Variables are only populated by the server, and will be ignored when - sending a request. - - :ivar id: Resource Id - :vartype id: str - :ivar name: Resource name - :vartype name: str - :ivar type: Resource type - :vartype type: str - :param extension_type: Type of the Extension, of which this resource is an - instance of. It must be one of the Extension Types registered with - Microsoft.KubernetesConfiguration by the Extension publisher. - :type extension_type: str - :param auto_upgrade_minor_version: Flag to note if this instance - participates in auto upgrade of minor version, or not. - :type auto_upgrade_minor_version: bool - :param release_train: ReleaseTrain this extension instance participates in - for auto-upgrade (e.g. Stable, Preview, etc.) - only if - autoUpgradeMinorVersion is 'true'. - :type release_train: str - :param version: Version of the extension for this extension instance, if - it is 'pinned' to a specific version. - :type version: str - :param scope: Scope at which the extension instance is installed. - :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope - :param install_state: Status of installation of this instance of the - extension. Possible values include: 'Pending', 'Installed', 'Failed' - :type install_state: str or - ~azure.mgmt.kubernetesconfiguration.models.InstallStateType - :ivar creation_time: DateLiteral (per ISO8601) noting the time the - resource was created by the client (user). - :vartype creation_time: str - :ivar last_modified_time: DateLiteral (per ISO8601) noting the time the - resource was modified by the client (user). - :vartype last_modified_time: str - :ivar last_status_time: DateLiteral (per ISO8601) noting the time of last - status from the agent. - :vartype last_status_time: str - :ivar error_info: Error information from the Agent - e.g. errors during - installation. - :vartype error_info: - ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition - :param identity: The identity of the configuration. - :type identity: - ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity - """ - - _validation = { - 'id': {'readonly': True}, - 'name': {'readonly': True}, - 'type': {'readonly': True}, - 'creation_time': {'readonly': True}, - 'last_modified_time': {'readonly': True}, - 'last_status_time': {'readonly': True}, - 'error_info': {'readonly': True}, - } - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, - 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, - 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, - 'version': {'key': 'properties.version', 'type': 'str'}, - 'scope': {'key': 'properties.scope', 'type': 'Scope'}, - 'install_state': {'key': 'properties.installState', 'type': 'str'}, - 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, - 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, - 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, - 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, - 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, - } - - def __init__(self, **kwargs): - super(ExtensionInstanceForList, self).__init__(**kwargs) - self.extension_type = kwargs.get('extension_type', None) - self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', None) - self.release_train = kwargs.get('release_train', None) - self.version = kwargs.get('version', None) - self.scope = kwargs.get('scope', None) self.install_state = kwargs.get('install_state', None) + self.statuses = kwargs.get('statuses', None) self.creation_time = None self.last_modified_time = None self.last_status_time = None @@ -512,6 +404,88 @@ def __init__(self, **kwargs): self.time = kwargs.get('time', None) +class HelmOperatorProperties(Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = kwargs.get('chart_version', None) + self.chart_values = kwargs.get('chart_values', None) + + +class ResourceProviderOperation(Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :param name: Operation name, in format of + {provider}/{resource}/{operation} + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation + applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__(self, **kwargs): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = kwargs.get('name', None) + self.display = kwargs.get('display', None) + self.is_data_action = None + + +class ResourceProviderOperationDisplay(Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = kwargs.get('provider', None) + self.resource = kwargs.get('resource', None) + self.operation = kwargs.get('operation', None) + self.description = kwargs.get('description', None) + + class Result(Model): """Sample result definition. @@ -585,3 +559,164 @@ class ScopeNamespace(Model): def __init__(self, **kwargs): super(ScopeNamespace, self).__init__(**kwargs) self.target_namespace = kwargs.get('target_namespace', None) + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is + installed to. Maximum of 253 lower case alphanumeric characters, hyphen + and period only. Default value: "default" . + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying + the specific configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: + 'Flux' + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string + format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected + configuration settings for the configuration + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. + Possible values include: 'cluster', 'namespace'. Default value: "cluster" + . + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl + configuration (either generated within the cluster or provided by the + user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents + containing public SSH keys required to access private Git instances + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git + configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. + Possible values include: 'Accepted', 'Deleting', 'Running', 'Succeeded', + 'Failed' + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__(self, **kwargs): + super(SourceControlConfiguration, self).__init__(**kwargs) + self.repository_url = kwargs.get('repository_url', None) + self.operator_namespace = kwargs.get('operator_namespace', "default") + self.operator_instance_name = kwargs.get('operator_instance_name', None) + self.operator_type = kwargs.get('operator_type', None) + self.operator_params = kwargs.get('operator_params', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.operator_scope = kwargs.get('operator_scope', "cluster") + self.repository_public_key = None + self.ssh_known_hosts_contents = kwargs.get('ssh_known_hosts_contents', None) + self.enable_helm_operator = kwargs.get('enable_helm_operator', None) + self.helm_operator_properties = kwargs.get('helm_operator_properties', None) + self.provisioning_state = None + self.compliance_status = None + + +class SystemData(Model): + """Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar created_by: A string identifier for the identity that created the + resource + :vartype created_by: str + :ivar created_by_type: The type of identity that created the resource: + user, application, managedIdentity, key + :vartype created_by_type: str + :ivar created_at: The timestamp of resource creation (UTC) + :vartype created_at: datetime + :ivar last_modified_by: A string identifier for the identity that last + modified the resource + :vartype last_modified_by: str + :ivar last_modified_by_type: The type of identity that last modified the + resource: user, application, managedIdentity, key + :vartype last_modified_by_type: str + :ivar last_modified_at: The timestamp of resource last modification (UTC) + :vartype last_modified_at: datetime + """ + + _validation = { + 'created_by': {'readonly': True}, + 'created_by_type': {'readonly': True}, + 'created_at': {'readonly': True}, + 'last_modified_by': {'readonly': True}, + 'last_modified_by_type': {'readonly': True}, + 'last_modified_at': {'readonly': True}, + } + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__(self, **kwargs): + super(SystemData, self).__init__(**kwargs) + self.created_by = None + self.created_by_type = None + self.created_at = None + self.last_modified_by = None + self.last_modified_by_type = None + self.last_modified_at = None diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py index 16b408963ab..36fe12c02ce 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py @@ -20,6 +20,47 @@ class CloudError(Model): _attribute_map = { } + +class ComplianceStatus(Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar compliance_state: The compliance state of the configuration. + Possible values include: 'Pending', 'Compliant', 'Noncompliant', + 'Installed', 'Failed' + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: + 'Error', 'Warning', 'Information' + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__(self, *, last_config_applied=None, message: str=None, message_level=None, **kwargs) -> None: + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = last_config_applied + self.message = message + self.message_level = message_level + + class ConfigurationIdentity(Model): """Identity for the managed cluster. @@ -126,6 +167,9 @@ class Resource(Model): :vartype name: str :ivar type: Resource type :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData """ _validation = { @@ -138,13 +182,15 @@ class Resource(Model): 'id': {'key': 'id', 'type': 'str'}, 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, } - def __init__(self, **kwargs) -> None: + def __init__(self, *, system_data=None, **kwargs) -> None: super(Resource, self).__init__(**kwargs) self.id = None self.name = None self.type = None + self.system_data = system_data class ProxyResource(Resource): @@ -159,6 +205,9 @@ class ProxyResource(Resource): :vartype name: str :ivar type: Resource type :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData """ _validation = { @@ -171,10 +220,11 @@ class ProxyResource(Resource): 'id': {'key': 'id', 'type': 'str'}, 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, } - def __init__(self, **kwargs) -> None: - super(ProxyResource, self).__init__(**kwargs) + def __init__(self, *, system_data=None, **kwargs) -> None: + super(ProxyResource, self).__init__(system_data=system_data, **kwargs) class ExtensionInstance(ProxyResource): @@ -189,6 +239,9 @@ class ExtensionInstance(ProxyResource): :vartype name: str :ivar type: Resource type :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData :param extension_type: Type of the Extension, of which this resource is an instance of. It must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the Extension publisher. @@ -209,6 +262,10 @@ class ExtensionInstance(ProxyResource): :param configuration_settings: Configuration settings, as name-value pairs for configuring this instance of the extension. :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are + sensitive, as name-value pairs for configuring this instance of the + extension. + :type configuration_protected_settings: dict[str, str] :param install_state: Status of installation of this instance of the extension. Possible values include: 'Pending', 'Installed', 'Failed' :type install_state: str or @@ -248,103 +305,25 @@ class ExtensionInstance(ProxyResource): 'id': {'key': 'id', 'type': 'str'}, 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, 'version': {'key': 'properties.version', 'type': 'str'}, 'scope': {'key': 'properties.scope', 'type': 'Scope'}, 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, 'install_state': {'key': 'properties.installState', 'type': 'str'}, 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, - 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, - } - - def __init__(self, *, extension_type: str=None, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, scope=None, configuration_settings=None, install_state=None, statuses=None, identity=None, **kwargs) -> None: - super(ExtensionInstance, self).__init__(**kwargs) - self.extension_type = extension_type - self.auto_upgrade_minor_version = auto_upgrade_minor_version - self.release_train = release_train - self.version = version - self.scope = scope - self.configuration_settings = configuration_settings - self.install_state = install_state - self.statuses = statuses - self.creation_time = None - self.last_modified_time = None - self.last_status_time = None - self.error_info = None - self.identity = identity - - -class ExtensionInstanceForCreate(ProxyResource): - """Object to create a new Extension Instance. - - Variables are only populated by the server, and will be ignored when - sending a request. - - :ivar id: Resource Id - :vartype id: str - :ivar name: Resource name - :vartype name: str - :ivar type: Resource type - :vartype type: str - :param extension_type: Type of the Extension, of which this resource is an - instance of. It must be one of the Extension Types registered with - Microsoft.KubernetesConfiguration by the Extension publisher. - :type extension_type: str - :param auto_upgrade_minor_version: Flag to note if this instance - participates in auto upgrade of minor version, or not. - :type auto_upgrade_minor_version: bool - :param release_train: ReleaseTrain this extension instance participates in - for auto-upgrade (e.g. Stable, Preview, etc.) - only if - autoUpgradeMinorVersion is 'true'. - :type release_train: str - :param version: Version of the extension for this extension instance, if - it is 'pinned' to a specific version. autoUpgradeMinorVersion must be - 'false'. - :type version: str - :param scope: Scope at which the extension instance is installed. - :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope - :param configuration_settings: Configuration settings, as name-value pairs - for configuring this instance of the extension. - :type configuration_settings: dict[str, str] - :param configuration_protected_settings: Configuration settings that are - sensitive, as name-value pairs for configuring this instance of the - extension. - :type configuration_protected_settings: dict[str, str] - :param identity: The identity of the configuration. - :type identity: - ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity - :type location: str - """ - - _validation = { - 'id': {'readonly': True}, - 'name': {'readonly': True}, - 'type': {'readonly': True}, - } - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, - 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, - 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, - 'version': {'key': 'properties.version', 'type': 'str'}, - 'scope': {'key': 'properties.scope', 'type': 'Scope'}, - 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, - 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, - 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, - 'location': {'key': 'location', 'type': 'str'}, + 'identity': {'key': 'properties.identity', 'type': 'ConfigurationIdentity'}, } - def __init__(self, *, extension_type: str=None, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, scope=None, configuration_settings=None, configuration_protected_settings=None, identity=None, location=None, **kwargs) -> None: - super(ExtensionInstanceForCreate, self).__init__(location=location,**kwargs) + def __init__(self, *, system_data=None, extension_type: str=None, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, scope=None, configuration_settings=None, configuration_protected_settings=None, install_state=None, statuses=None, identity=None, **kwargs) -> None: + super(ExtensionInstance, self).__init__(system_data=system_data, **kwargs) self.extension_type = extension_type self.auto_upgrade_minor_version = auto_upgrade_minor_version self.release_train = release_train @@ -352,95 +331,8 @@ def __init__(self, *, extension_type: str=None, auto_upgrade_minor_version: bool self.scope = scope self.configuration_settings = configuration_settings self.configuration_protected_settings = configuration_protected_settings - self.identity = identity - self.location = location - - -class ExtensionInstanceForList(ProxyResource): - """The Extension Instance object. - - Variables are only populated by the server, and will be ignored when - sending a request. - - :ivar id: Resource Id - :vartype id: str - :ivar name: Resource name - :vartype name: str - :ivar type: Resource type - :vartype type: str - :param extension_type: Type of the Extension, of which this resource is an - instance of. It must be one of the Extension Types registered with - Microsoft.KubernetesConfiguration by the Extension publisher. - :type extension_type: str - :param auto_upgrade_minor_version: Flag to note if this instance - participates in auto upgrade of minor version, or not. - :type auto_upgrade_minor_version: bool - :param release_train: ReleaseTrain this extension instance participates in - for auto-upgrade (e.g. Stable, Preview, etc.) - only if - autoUpgradeMinorVersion is 'true'. - :type release_train: str - :param version: Version of the extension for this extension instance, if - it is 'pinned' to a specific version. - :type version: str - :param scope: Scope at which the extension instance is installed. - :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope - :param install_state: Status of installation of this instance of the - extension. Possible values include: 'Pending', 'Installed', 'Failed' - :type install_state: str or - ~azure.mgmt.kubernetesconfiguration.models.InstallStateType - :ivar creation_time: DateLiteral (per ISO8601) noting the time the - resource was created by the client (user). - :vartype creation_time: str - :ivar last_modified_time: DateLiteral (per ISO8601) noting the time the - resource was modified by the client (user). - :vartype last_modified_time: str - :ivar last_status_time: DateLiteral (per ISO8601) noting the time of last - status from the agent. - :vartype last_status_time: str - :ivar error_info: Error information from the Agent - e.g. errors during - installation. - :vartype error_info: - ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition - :param identity: The identity of the configuration. - :type identity: - ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity - """ - - _validation = { - 'id': {'readonly': True}, - 'name': {'readonly': True}, - 'type': {'readonly': True}, - 'creation_time': {'readonly': True}, - 'last_modified_time': {'readonly': True}, - 'last_status_time': {'readonly': True}, - 'error_info': {'readonly': True}, - } - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, - 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, - 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, - 'version': {'key': 'properties.version', 'type': 'str'}, - 'scope': {'key': 'properties.scope', 'type': 'Scope'}, - 'install_state': {'key': 'properties.installState', 'type': 'str'}, - 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, - 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, - 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, - 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, - 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, - } - - def __init__(self, *, extension_type: str=None, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, scope=None, install_state=None, identity=None, **kwargs) -> None: - super(ExtensionInstanceForList, self).__init__(**kwargs) - self.extension_type = extension_type - self.auto_upgrade_minor_version = auto_upgrade_minor_version - self.release_train = release_train - self.version = version - self.scope = scope self.install_state = install_state + self.statuses = statuses self.creation_time = None self.last_modified_time = None self.last_status_time = None @@ -512,6 +404,88 @@ def __init__(self, *, code: str=None, display_status: str=None, level="Informati self.time = time +class HelmOperatorProperties(Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__(self, *, chart_version: str=None, chart_values: str=None, **kwargs) -> None: + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = chart_version + self.chart_values = chart_values + + +class ResourceProviderOperation(Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :param name: Operation name, in format of + {provider}/{resource}/{operation} + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation + applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__(self, *, name: str=None, display=None, **kwargs) -> None: + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = name + self.display = display + self.is_data_action = None + + +class ResourceProviderOperationDisplay(Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__(self, *, provider: str=None, resource: str=None, operation: str=None, description: str=None, **kwargs) -> None: + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = provider + self.resource = resource + self.operation = operation + self.description = description + + class Result(Model): """Sample result definition. @@ -585,3 +559,164 @@ class ScopeNamespace(Model): def __init__(self, *, target_namespace: str=None, **kwargs) -> None: super(ScopeNamespace, self).__init__(**kwargs) self.target_namespace = target_namespace + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is + installed to. Maximum of 253 lower case alphanumeric characters, hyphen + and period only. Default value: "default" . + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying + the specific configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: + 'Flux' + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string + format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected + configuration settings for the configuration + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. + Possible values include: 'cluster', 'namespace'. Default value: "cluster" + . + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl + configuration (either generated within the cluster or provided by the + user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents + containing public SSH keys required to access private Git instances + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git + configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. + Possible values include: 'Accepted', 'Deleting', 'Running', 'Succeeded', + 'Failed' + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__(self, *, system_data=None, repository_url: str=None, operator_namespace: str="default", operator_instance_name: str=None, operator_type=None, operator_params: str=None, configuration_protected_settings=None, operator_scope="cluster", ssh_known_hosts_contents: str=None, enable_helm_operator: bool=None, helm_operator_properties=None, **kwargs) -> None: + super(SourceControlConfiguration, self).__init__(system_data=system_data, **kwargs) + self.repository_url = repository_url + self.operator_namespace = operator_namespace + self.operator_instance_name = operator_instance_name + self.operator_type = operator_type + self.operator_params = operator_params + self.configuration_protected_settings = configuration_protected_settings + self.operator_scope = operator_scope + self.repository_public_key = None + self.ssh_known_hosts_contents = ssh_known_hosts_contents + self.enable_helm_operator = enable_helm_operator + self.helm_operator_properties = helm_operator_properties + self.provisioning_state = None + self.compliance_status = None + + +class SystemData(Model): + """Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar created_by: A string identifier for the identity that created the + resource + :vartype created_by: str + :ivar created_by_type: The type of identity that created the resource: + user, application, managedIdentity, key + :vartype created_by_type: str + :ivar created_at: The timestamp of resource creation (UTC) + :vartype created_at: datetime + :ivar last_modified_by: A string identifier for the identity that last + modified the resource + :vartype last_modified_by: str + :ivar last_modified_by_type: The type of identity that last modified the + resource: user, application, managedIdentity, key + :vartype last_modified_by_type: str + :ivar last_modified_at: The timestamp of resource last modification (UTC) + :vartype last_modified_at: datetime + """ + + _validation = { + 'created_by': {'readonly': True}, + 'created_by_type': {'readonly': True}, + 'created_at': {'readonly': True}, + 'last_modified_by': {'readonly': True}, + 'last_modified_by_type': {'readonly': True}, + 'last_modified_at': {'readonly': True}, + } + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__(self, **kwargs) -> None: + super(SystemData, self).__init__(**kwargs) + self.created_by = None + self.created_by_type = None + self.created_at = None + self.last_modified_by = None + self.last_modified_by_type = None + self.last_modified_at = None diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py index 8f2e7eca24e..c545286fe54 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py @@ -12,6 +12,19 @@ from msrest.paging import Paged +class SourceControlConfigurationPaged(Paged): + """ + A paging container for iterating over a list of :class:`SourceControlConfiguration ` object + """ + + _attribute_map = { + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'current_page': {'key': 'value', 'type': '[SourceControlConfiguration]'} + } + + def __init__(self, *args, **kwargs): + + super(SourceControlConfigurationPaged, self).__init__(*args, **kwargs) class ResourceProviderOperationPaged(Paged): """ A paging container for iterating over a list of :class:`ResourceProviderOperation ` object @@ -25,16 +38,16 @@ class ResourceProviderOperationPaged(Paged): def __init__(self, *args, **kwargs): super(ResourceProviderOperationPaged, self).__init__(*args, **kwargs) -class ExtensionInstanceForListPaged(Paged): +class ExtensionInstancePaged(Paged): """ - A paging container for iterating over a list of :class:`ExtensionInstanceForList ` object + A paging container for iterating over a list of :class:`ExtensionInstance ` object """ _attribute_map = { 'next_link': {'key': 'nextLink', 'type': 'str'}, - 'current_page': {'key': 'value', 'type': '[ExtensionInstanceForList]'} + 'current_page': {'key': 'value', 'type': '[ExtensionInstance]'} } def __init__(self, *args, **kwargs): - super(ExtensionInstanceForListPaged, self).__init__(*args, **kwargs) + super(ExtensionInstancePaged, self).__init__(*args, **kwargs) diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_k8s_extension_client_enums.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_source_control_configuration_client_enums.py similarity index 100% rename from src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_k8s_extension_client_enums.py rename to src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_source_control_configuration_client_enums.py diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py index e8f158b24a3..6be16d2582d 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py @@ -9,8 +9,12 @@ # regenerated. # -------------------------------------------------------------------------- -from ._k8s_extensions_operations import K8sExtensionsOperations +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._operations import Operations +from ._extensions_operations import ExtensionsOperations __all__ = [ - 'K8sExtensionsOperations', + 'SourceControlConfigurationsOperations', + 'Operations', + 'ExtensionsOperations', ] diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_k8s_extensions_operations.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_extensions_operations.py similarity index 84% rename from src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_k8s_extensions_operations.py rename to src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_extensions_operations.py index 716aefd7b06..e99f3328816 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_k8s_extensions_operations.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_extensions_operations.py @@ -15,11 +15,10 @@ from .. import models -class K8sExtensionsOperations(object): - """K8sExtensionsOperations operations. +class ExtensionsOperations(object): + """ExtensionsOperations operations. - You should not instantiate directly this class, but create a Client instance that will create it for you and attach - it as attribute. + You should not instantiate directly this class, but create a Client instance that will create it for you and attach it as attribute. :param client: Client for service requests. :param config: Configuration of service client. @@ -39,10 +38,9 @@ def __init__(self, client, config, serializer, deserializer): self.config = config - def get( - self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, - custom_headers=None, raw=False, **operation_config): - """Gets details of the Kubernetes Cluster Extension Instance. + def create( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, extension_instance, custom_headers=None, raw=False, **operation_config): + """Create a new Kubernetes Cluster Extension Instance. :param resource_group_name: The name of the resource group. :type resource_group_name: str @@ -53,13 +51,17 @@ def get( :type cluster_rp: str :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters (for AKS clusters) or connectedClusters (for - OnPrem K8S clusters) or appliances (for Arc Appliances). Possible - values include: 'managedClusters','connectedClusters', 'appliances' + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' :type cluster_resource_name: str :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str :param extension_instance_name: Name of an instance of the Extension. :type extension_instance_name: str + :param extension_instance: Properties necessary to Create an Extension + Instance. + :type extension_instance: + ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstance :param dict custom_headers: headers that will be added to the request :param bool raw: returns the direct response alongside the deserialized response @@ -72,7 +74,7 @@ def get( :class:`ErrorResponseException` """ # Construct URL - url = self.get.metadata['url'] + url = self.create.metadata['url'] path_format_arguments = { 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), @@ -90,16 +92,19 @@ def get( # Construct headers header_parameters = {} header_parameters['Accept'] = 'application/json' + header_parameters['Content-Type'] = 'application/json; charset=utf-8' if self.config.generate_client_request_id: header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) if custom_headers: header_parameters.update(custom_headers) if self.config.accept_language is not None: - header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", - self.config.accept_language, 'str') + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct body + body_content = self._serialize.body(extension_instance, 'ExtensionInstance') # Construct and send request - request = self._client.get(url, query_parameters, header_parameters) + request = self._client.put(url, query_parameters, header_parameters, body_content) response = self._client.send(request, stream=False, **operation_config) if response.status_code not in [200]: @@ -114,12 +119,11 @@ def get( return client_raw_response return deserialized - get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} + create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} - def create( - self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, - extension_instance, custom_headers=None, raw=False, **operation_config): - """Create a new Kubernetes Cluster Extension Instance. + def get( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, custom_headers=None, raw=False, **operation_config): + """Gets details of the Kubernetes Cluster Extension Instance. :param resource_group_name: The name of the resource group. :type resource_group_name: str @@ -130,17 +134,13 @@ def create( :type cluster_rp: str :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters (for AKS clusters) or connectedClusters (for - OnPrem K8S clusters) or appliances (for Arc Appliances). Possible - values include: 'managedClusters','connectedClusters', 'appliances' + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' :type cluster_resource_name: str :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str :param extension_instance_name: Name of an instance of the Extension. :type extension_instance_name: str - :param extension_instance: Properties necessary to Create an Extension - Instance. - :type extension_instance: - ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstanceForCreate :param dict custom_headers: headers that will be added to the request :param bool raw: returns the direct response alongside the deserialized response @@ -153,7 +153,7 @@ def create( :class:`ErrorResponseException` """ # Construct URL - url = self.create.metadata['url'] + url = self.get.metadata['url'] path_format_arguments = { 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), @@ -171,20 +171,15 @@ def create( # Construct headers header_parameters = {} header_parameters['Accept'] = 'application/json' - header_parameters['Content-Type'] = 'application/json; charset=utf-8' if self.config.generate_client_request_id: header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) if custom_headers: header_parameters.update(custom_headers) if self.config.accept_language is not None: - header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", - self.config.accept_language, 'str') - - # Construct body - body_content = self._serialize.body(extension_instance, 'ExtensionInstanceForCreate') + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') # Construct and send request - request = self._client.put(url, query_parameters, header_parameters, body_content) + request = self._client.get(url, query_parameters, header_parameters) response = self._client.send(request, stream=False, **operation_config) if response.status_code not in [200]: @@ -199,13 +194,10 @@ def create( return client_raw_response return deserialized - create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}' - '/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/' - 'extensions/{extensionInstanceName}'} + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} def update( - self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, - extension_instance, custom_headers=None, raw=False, **operation_config): + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, extension_instance, custom_headers=None, raw=False, **operation_config): """Update an existing Kubernetes Cluster Extension Instance. :param resource_group_name: The name of the resource group. @@ -217,8 +209,8 @@ def update( :type cluster_rp: str :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters (for AKS clusters) or connectedClusters (for - OnPrem K8S clusters) or appliances (for Arc Appliances). Possible - values include: 'managedClusters','connectedClusters', 'appliances' + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' :type cluster_resource_name: str :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str @@ -264,8 +256,7 @@ def update( if custom_headers: header_parameters.update(custom_headers) if self.config.accept_language is not None: - header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", - self.config.accept_language, 'str') + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') # Construct body body_content = self._serialize.body(extension_instance, 'ExtensionInstanceUpdate') @@ -286,13 +277,10 @@ def update( return client_raw_response return deserialized - update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}' - '/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/' - 'extensions/{extensionInstanceName}'} + update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} def delete( - self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, - custom_headers=None, raw=False, **operation_config): + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, custom_headers=None, raw=False, **operation_config): """Delete a Kubernetes Cluster Extension Instance. This will cause the Agent to Uninstall the extension instance from the cluster. @@ -305,8 +293,8 @@ def delete( :type cluster_rp: str :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters (for AKS clusters) or connectedClusters (for - OnPrem K8S clusters) or appliances (for Arc Appliances). Possible - values include: 'managedClusters','connectedClusters', 'appliances' + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' :type cluster_resource_name: str :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str @@ -345,8 +333,7 @@ def delete( if custom_headers: header_parameters.update(custom_headers) if self.config.accept_language is not None: - header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", - self.config.accept_language, 'str') + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') # Construct and send request request = self._client.delete(url, query_parameters, header_parameters) @@ -358,14 +345,11 @@ def delete( if raw: client_raw_response = ClientRawResponse(None, response) return client_raw_response - delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}' - '/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/' - 'extensions/{extensionInstanceName}'} + delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} def list( - self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, custom_headers=None, raw=False, - **operation_config): - """List all Extension Instances. + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, custom_headers=None, raw=False, **operation_config): + """List all Source Control Configurations. :param resource_group_name: The name of the resource group. :type resource_group_name: str @@ -376,8 +360,8 @@ def list( :type cluster_rp: str :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters (for AKS clusters) or connectedClusters (for - OnPrem K8S clusters) or appliances (for Arc Appliances). Possible - values include: 'managedClusters','connectedClusters', 'appliances' + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' :type cluster_resource_name: str :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str @@ -386,9 +370,9 @@ def list( deserialized response :param operation_config: :ref:`Operation configuration overrides`. - :return: An iterator like instance of ExtensionInstanceForList + :return: An iterator like instance of ExtensionInstance :rtype: - ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstanceForListPaged[~azure.mgmt.kubernetesconfiguration.models.ExtensionInstanceForList] + ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstancePaged[~azure.mgmt.kubernetesconfiguration.models.ExtensionInstance] :raises: :class:`ErrorResponseException` """ @@ -397,8 +381,7 @@ def prepare_request(next_link=None): # Construct URL url = self.list.metadata['url'] path_format_arguments = { - 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, - 'str'), + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), @@ -422,8 +405,7 @@ def prepare_request(next_link=None): if custom_headers: header_parameters.update(custom_headers) if self.config.accept_language is not None: - header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", - self.config.accept_language, 'str') + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') # Construct and send request request = self._client.get(url, query_parameters, header_parameters) @@ -443,10 +425,7 @@ def internal_paging(next_link=None): header_dict = None if raw: header_dict = {} - deserialized = models.ExtensionInstanceForListPaged(internal_paging, self._deserialize.dependencies, - header_dict) + deserialized = models.ExtensionInstancePaged(internal_paging, self._deserialize.dependencies, header_dict) return deserialized - list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}' - '/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/' - 'extensions'} + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions'} diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_operations.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_operations.py new file mode 100644 index 00000000000..245a93c8294 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_operations.py @@ -0,0 +1,101 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +import uuid +from msrest.pipeline import ClientRawResponse + +from .. import models + + +class Operations(object): + """Operations operations. + + You should not instantiate directly this class, but create a Client instance that will create it for you and attach it as attribute. + + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + :ivar api_version: The API version to be used with the HTTP request. Constant value: "2020-07-01-preview". + """ + + models = models + + def __init__(self, client, config, serializer, deserializer): + + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self.api_version = "2020-07-01-preview" + + self.config = config + + def list( + self, custom_headers=None, raw=False, **operation_config): + """List all the available operations the KubernetesConfiguration resource + provider supports. + + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: An iterator like instance of ResourceProviderOperation + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationPaged[~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperation] + :raises: + :class:`ErrorResponseException` + """ + def prepare_request(next_link=None): + if not next_link: + # Construct URL + url = self.list.metadata['url'] + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + else: + url = next_link + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + return request + + def internal_paging(next_link=None): + request = prepare_request(next_link) + + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + return response + + # Deserialize response + header_dict = None + if raw: + header_dict = {} + deserialized = models.ResourceProviderOperationPaged(internal_paging, self._deserialize.dependencies, header_dict) + + return deserialized + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_source_control_configurations_operations.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..83a49e32146 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_source_control_configurations_operations.py @@ -0,0 +1,386 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +import uuid +from msrest.pipeline import ClientRawResponse +from msrest.polling import LROPoller, NoPolling +from msrestazure.polling.arm_polling import ARMPolling + +from .. import models + + +class SourceControlConfigurationsOperations(object): + """SourceControlConfigurationsOperations operations. + + You should not instantiate directly this class, but create a Client instance that will create it for you and attach it as attribute. + + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + :ivar api_version: The API version to be used with the HTTP request. Constant value: "2020-07-01-preview". + """ + + models = models + + def __init__(self, client, config, serializer, deserializer): + + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self.api_version = "2020-07-01-preview" + + self.config = config + + def get( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, **operation_config): + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control + Configuration. + :type source_control_configuration_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: SourceControlConfiguration or ClientRawResponse if raw=true + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.get.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} + + def create_or_update( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, source_control_configuration, custom_headers=None, raw=False, **operation_config): + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control + Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create + KubernetesConfiguration. + :type source_control_configuration: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: SourceControlConfiguration or ClientRawResponse if raw=true + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.create_or_update.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct body + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + + # Construct and send request + request = self._client.put(url, query_parameters, header_parameters, body_content) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200, 201]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', response) + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} + + + def _delete_initial( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, **operation_config): + # Construct URL + url = self.delete.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.delete(url, query_parameters, header_parameters) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200, 204]: + raise models.ErrorResponseException(self._deserialize, response) + + if raw: + client_raw_response = ClientRawResponse(None, response) + return client_raw_response + + def delete( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, polling=True, **operation_config): + """This will delete the YAML file used to set up the Source control + configuration, thus stopping future sync from the source repo. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control + Configuration. + :type source_control_configuration_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: The poller return type is ClientRawResponse, the + direct response alongside the deserialized response + :param polling: True for ARMPolling, False for no polling, or a + polling object for personal polling strategy + :return: An instance of LROPoller that returns None or + ClientRawResponse if raw==True + :rtype: ~msrestazure.azure_operation.AzureOperationPoller[None] or + ~msrestazure.azure_operation.AzureOperationPoller[~msrest.pipeline.ClientRawResponse[None]] + :raises: + :class:`ErrorResponseException` + """ + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + custom_headers=custom_headers, + raw=True, + **operation_config + ) + + def get_long_running_output(response): + if raw: + client_raw_response = ClientRawResponse(None, response) + return client_raw_response + + lro_delay = operation_config.get( + 'long_running_operation_timeout', + self.config.long_running_operation_timeout) + if polling is True: polling_method = ARMPolling(lro_delay, **operation_config) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} + + def list( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, custom_headers=None, raw=False, **operation_config): + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: An iterator like instance of SourceControlConfiguration + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfigurationPaged[~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration] + :raises: + :class:`ErrorResponseException` + """ + def prepare_request(next_link=None): + if not next_link: + # Construct URL + url = self.list.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + else: + url = next_link + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + return request + + def internal_paging(next_link=None): + request = prepare_request(next_link) + + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + return response + + # Deserialize response + header_dict = None + if raw: + header_dict = {} + deserialized = models.SourceControlConfigurationPaged(internal_paging, self._deserialize.dependencies, header_dict) + + return deserialized + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py index e0ec669828c..3e682bbd5fb 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py @@ -9,5 +9,5 @@ # regenerated. # -------------------------------------------------------------------------- -VERSION = "0.1.0" +VERSION = "0.3.0" From 1df2ef5cebee34e490b40a79981bd2d199a1c50f Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Tue, 16 Mar 2021 11:39:04 -0700 Subject: [PATCH 32/80] remove py2 bdist support --- src/k8s-extension/setup.cfg | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/k8s-extension/setup.cfg b/src/k8s-extension/setup.cfg index 5eab412034f..e69de29bb2d 100644 --- a/src/k8s-extension/setup.cfg +++ b/src/k8s-extension/setup.cfg @@ -1,2 +0,0 @@ -[bdist_wheel] -universal=1 From 054a903db08bb126410ba538f553c2420fb2989e Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Tue, 16 Mar 2021 12:30:38 -0700 Subject: [PATCH 33/80] Add custom table formatting --- .../azext_k8s_extension/_format.py | 24 +++++++++++++++++++ .../azext_k8s_extension/commands.py | 5 ++-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/k8s-extension/azext_k8s_extension/_format.py diff --git a/src/k8s-extension/azext_k8s_extension/_format.py b/src/k8s-extension/azext_k8s_extension/_format.py new file mode 100644 index 00000000000..ef96f7cf88f --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_format.py @@ -0,0 +1,24 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from collections import OrderedDict + + +def k8s_extension_list_table_format(results): + return [__get_table_row(result) for result in results] + + +def k8s_extension_show_table_format(result): + return __get_table_row(result) + + +def __get_table_row(result): + return OrderedDict([ + ('name', result['name']), + ('extensionType', result['extensionType']), + ('version', result['version']), + ('installState', result['installState']), + ('lastModifiedTime', result['lastModifiedTime']) + ]) diff --git a/src/k8s-extension/azext_k8s_extension/commands.py b/src/k8s-extension/azext_k8s_extension/commands.py index ff72ab62e08..931662814c0 100644 --- a/src/k8s-extension/azext_k8s_extension/commands.py +++ b/src/k8s-extension/azext_k8s_extension/commands.py @@ -6,6 +6,7 @@ # pylint: disable=line-too-long from azure.cli.core.commands import CliCommandType from azext_k8s_extension._client_factory import (cf_k8s_extension, cf_k8s_extension_operation) +from azext_k8s_extension._format import k8s_extension_list_table_format, k8s_extension_show_table_format import azext_k8s_extension._consts as consts @@ -21,5 +22,5 @@ def load_command_table(self, _): g.custom_command('create', 'create_k8s_extension') g.custom_command('update', 'update_k8s_extension') g.custom_command('delete', 'delete_k8s_extension', confirmation=True) - g.custom_command('list', 'list_k8s_extension') - g.custom_show_command('show', 'show_k8s_extension') + 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) From b2982523471694f5bc056d1b9a15e405cddc3932 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Tue, 16 Mar 2021 15:27:43 -0700 Subject: [PATCH 34/80] Remove unnecessary files --- .github/pull.yml | 14 ------ .../azext_k8s_extension/_validators.py | 21 -------- .../partner_extensions/__init__.py | 5 ++ .../vendored_sdks/_k8s_extension_client.py | 50 ------------------- 4 files changed, 5 insertions(+), 85 deletions(-) delete mode 100644 .github/pull.yml delete mode 100644 src/k8s-extension/azext_k8s_extension/_validators.py delete mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/_k8s_extension_client.py diff --git a/.github/pull.yml b/.github/pull.yml deleted file mode 100644 index 8f65923a382..00000000000 --- a/.github/pull.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: "1" -rules: # Array of rules - - base: master # Required. Target branch - upstream: wei:master # Required. Must be in the same fork network. - mergeMethod: hardreset # Optional, one of [none, merge, squash, rebase, hardreset], Default: none. - mergeUnstable: false # Optional, merge pull request even when the mergeable_state is not clean. Default: false - - base: k8s-configuration - upstream: master # Required. Can be a branch in the same forked repo. - - base: k8s-extension/private-preview - upstream: master # Required. Can be a branch in the same forked repo. - - base: k8s-extension/public-preview - upstream: master # Required. Can be a branch in the same forked repo. - - base: release - upstream: master # Required. Can be a branch in the same forked repo. diff --git a/src/k8s-extension/azext_k8s_extension/_validators.py b/src/k8s-extension/azext_k8s_extension/_validators.py deleted file mode 100644 index 72270dab104..00000000000 --- a/src/k8s-extension/azext_k8s_extension/_validators.py +++ /dev/null @@ -1,21 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - - -def example_name_or_id_validator(cmd, namespace): - # Example of a storage account name or ID validator. - # See: https://github.com/Azure/azure-cli/blob/dev/doc/authoring_command_modules/authoring_commands.md#supporting-name-or-id-parameters # pylint: disable=line-too-long - - from azure.cli.core.commands.client_factory import get_subscription_id - from msrestazure.tools import is_valid_resource_id, resource_id - if namespace.storage_account: - if not is_valid_resource_id(namespace.RESOURCE): - namespace.storage_account = resource_id( - subscription=get_subscription_id(cmd.cli_ctx), - resource_group=namespace.resource_group_name, - namespace='Microsoft.Storage', - type='storageAccounts', - name=namespace.storage_account - ) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py index e69de29bb2d..eaff94925e3 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py @@ -0,0 +1,5 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/_k8s_extension_client.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_k8s_extension_client.py deleted file mode 100644 index 1b63ebfd1ac..00000000000 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/_k8s_extension_client.py +++ /dev/null @@ -1,50 +0,0 @@ -# coding=utf-8 -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. -# -------------------------------------------------------------------------- - -from msrest.service_client import SDKClient -from msrest import Serializer, Deserializer - -from ._configuration import K8sExtensionClientConfiguration -from .operations import K8sExtensionsOperations -from . import models - - -class K8sExtensionClient(SDKClient): - """K8sExtension Client - - :ivar config: Configuration for client. - :vartype config: K8sExtensionClientConfiguration - - :ivar k8s_extensions: K8sExtensions operations - :vartype k8s_extensions: azure.mgmt.kubernetesconfiguration.operations.K8sExtensionsOperations - - :param credentials: Credentials needed for the client to connect to Azure. - :type credentials: :mod:`A msrestazure Credentials - object` - :param subscription_id: The Azure subscription ID. This is a - GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000) - :type subscription_id: str - :param str base_url: Service URL - """ - - def __init__( - self, credentials, subscription_id, base_url=None): - - self.config = K8sExtensionClientConfiguration(credentials, subscription_id, base_url) - super(K8sExtensionClient, self).__init__(self.config.credentials, self.config) - - client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} - self.api_version = '2020-07-01-preview' - self._serialize = Serializer(client_models) - self._deserialize = Deserializer(client_models) - - self.k8s_extensions = K8sExtensionsOperations( - self._client, self.config, self._serialize, self._deserialize) From afb4046a7e5d966cf48c968b00c878eb1ec8a50d Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Tue, 16 Mar 2021 15:34:00 -0700 Subject: [PATCH 35/80] Fix style issues --- .../azext_k8s_extension/partner_extensions/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py index eaff94925e3..9ccaff6c1b8 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py @@ -2,4 +2,4 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for # license information. -# ----------------------------------------------------------------------------- \ No newline at end of file +# ----------------------------------------------------------------------------- From 21dff06eae89e8acf628ee463a834ac64e116b5b Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Tue, 16 Mar 2021 20:33:16 -0700 Subject: [PATCH 36/80] Fix branch based on comments --- azure-pipelines.yml | 2 +- src/k8s-extension/azext_k8s_extension/azext_metadata.json | 2 +- src/k8s-extension/azext_k8s_extension/custom.py | 1 - src/k8s-extension/setup.cfg | 0 4 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 src/k8s-extension/setup.cfg diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 565e9c56793..d43ef5102f0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -168,4 +168,4 @@ jobs: displayName: "Verify Extension Ref Docs" inputs: targetType: 'filePath' - filePath: scripts/ci/test_index_ref_doc.sh \ No newline at end of file + filePath: scripts/ci/test_index_ref_doc.sh diff --git a/src/k8s-extension/azext_k8s_extension/azext_metadata.json b/src/k8s-extension/azext_k8s_extension/azext_metadata.json index 30fdaf614ee..cf7b8927a07 100644 --- a/src/k8s-extension/azext_k8s_extension/azext_metadata.json +++ b/src/k8s-extension/azext_k8s_extension/azext_metadata.json @@ -1,4 +1,4 @@ { "azext.isPreview": true, "azext.minCliCoreVersion": "2.15.0" -} \ No newline at end of file +} diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py index b06567aca0b..2b578a301ce 100644 --- a/src/k8s-extension/azext_k8s_extension/custom.py +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -14,7 +14,6 @@ InvalidArgumentValueError, CommandNotFoundError from azure.cli.core.commands.client_factory import get_subscription_id from azext_k8s_extension.vendored_sdks.models import ConfigurationIdentity -# from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate from azext_k8s_extension.vendored_sdks.models import ErrorResponseException from azext_k8s_extension.partner_extensions.ContainerInsights import ContainerInsights diff --git a/src/k8s-extension/setup.cfg b/src/k8s-extension/setup.cfg deleted file mode 100644 index e69de29bb2d..00000000000 From 93919f2457af6f244ec8ab7da500591060ee7a06 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 17 Mar 2021 08:30:49 -0700 Subject: [PATCH 37/80] Update identity piece manually --- .../azext_k8s_extension/vendored_sdks/models/_models.py | 2 +- .../azext_k8s_extension/vendored_sdks/models/_models_py3.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py index da1b94606cd..c821dfc362a 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py @@ -306,6 +306,7 @@ class ExtensionInstance(ProxyResource): 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, @@ -319,7 +320,6 @@ class ExtensionInstance(ProxyResource): 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, - 'identity': {'key': 'properties.identity', 'type': 'ConfigurationIdentity'}, } def __init__(self, **kwargs): diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py index 36fe12c02ce..1ca6a98a35a 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py @@ -306,6 +306,7 @@ class ExtensionInstance(ProxyResource): 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, @@ -318,8 +319,7 @@ class ExtensionInstance(ProxyResource): 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, - 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, - 'identity': {'key': 'properties.identity', 'type': 'ConfigurationIdentity'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'} } def __init__(self, *, system_data=None, extension_type: str=None, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, scope=None, configuration_settings=None, configuration_protected_settings=None, install_state=None, statuses=None, identity=None, **kwargs) -> None: From 7e40b3ad2eee2ae66e4b4f73c92b88b42fda7fe3 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 17 Mar 2021 09:33:16 -0700 Subject: [PATCH 38/80] Don't handle defaults at the CLI level --- src/k8s-extension/azext_k8s_extension/custom.py | 2 +- .../partner_extensions/DefaultExtension.py | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py index 2b578a301ce..0ae0247a4b7 100644 --- a/src/k8s-extension/azext_k8s_extension/custom.py +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -65,7 +65,7 @@ def show_k8s_extension(client, resource_group_name, cluster_name, name, cluster_ def create_k8s_extension(cmd, client, resource_group_name, cluster_name, name, cluster_type, - extension_type, scope='cluster', auto_upgrade_minor_version=None, release_train=None, + 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): diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py index 8e813502edd..3117734116f 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py @@ -25,16 +25,13 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t """ ext_scope = None - if scope is None or scope.lower() == 'cluster': - scope_cluster = ScopeCluster(release_namespace=release_namespace) - ext_scope = Scope(cluster=scope_cluster, namespace=None) - else: - scope_namespace = ScopeNamespace(target_namespace=target_namespace) - ext_scope = Scope(namespace=scope_namespace, cluster=None) - - # If release-train is not input, set it to 'stable' - if release_train is None: - release_train = 'stable' + if scope is not None: + if scope.lower() == 'cluster': + scope_cluster = ScopeCluster(release_namespace=release_namespace) + ext_scope = Scope(cluster=scope_cluster, namespace=None) + elif scope.lower() == 'namespace': + scope_namespace = ScopeNamespace(target_namespace=target_namespace) + ext_scope = Scope(namespace=scope_namespace, cluster=None) create_identity = False extension_instance = ExtensionInstance( From d1befa8fd237e75cfb2a0582bb71b0e21aae1df3 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 17 Mar 2021 10:20:59 -0700 Subject: [PATCH 39/80] Remove defaults from CLI client --- src/k8s-extension/azext_k8s_extension/custom.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py index 0ae0247a4b7..007e3ba0c07 100644 --- a/src/k8s-extension/azext_k8s_extension/custom.py +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -19,6 +19,7 @@ from azext_k8s_extension.partner_extensions.ContainerInsights import ContainerInsights from azext_k8s_extension.partner_extensions.AzureDefender import AzureDefender from azext_k8s_extension.partner_extensions.DefaultExtension import DefaultExtension +import azext_k8s_extension._consts as consts from ._client_factory import cf_resources @@ -111,7 +112,6 @@ def create_k8s_extension(cmd, client, resource_group_name, cluster_name, name, c # Identity is not created by default. Extension type must specify if identity is required. create_identity = False - extension_instance = None # Scope & Namespace validation - common to all extension-types @@ -152,8 +152,8 @@ def update_k8s_extension(client, resource_group_name, cluster_type, cluster_name # TODO: Remove this after we eventually get PATCH implemented for update and uncomment raise CommandNotFoundError( - "\"k8s-extension update\" currently is not available. " - "Use \"k8s-extension create\" to update a previously created extension instance." + f"\"{consts.EXTENSION_NAME} update\" currently is not available. " + f"Use \"{consts.EXTENSION_NAME} create\" to update a previously created extension instance." ) # # Ensure some values are provided for update @@ -188,10 +188,7 @@ def delete_k8s_extension(client, resource_group_name, cluster_name, name, cluste """ # Determine ClusterRP cluster_rp = __get_cluster_rp(cluster_type) - - k8s_extension_instance_name = name - - return client.delete(resource_group_name, cluster_rp, cluster_type, cluster_name, k8s_extension_instance_name) + return client.delete(resource_group_name, cluster_rp, cluster_type, cluster_name, name) def __create_identity(cmd, resource_group_name, cluster_name, cluster_type, cluster_rp): From 076827cb9e052a83c372805087332f9bce5bd29d Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 17 Mar 2021 12:29:46 -0700 Subject: [PATCH 40/80] Check null target namespace with namespace scope --- src/k8s-extension/azext_k8s_extension/custom.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py index 007e3ba0c07..92e5e5513a0 100644 --- a/src/k8s-extension/azext_k8s_extension/custom.py +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -11,10 +11,11 @@ from msrestazure.azure_exceptions import CloudError from azure.cli.core.azclierror import ResourceNotFoundError, MutuallyExclusiveArgumentError, \ - InvalidArgumentValueError, CommandNotFoundError + InvalidArgumentValueError, CommandNotFoundError, RequiredArgumentMissingError from azure.cli.core.commands.client_factory import get_subscription_id from azext_k8s_extension.vendored_sdks.models import ConfigurationIdentity from azext_k8s_extension.vendored_sdks.models import ErrorResponseException +from azext_k8s_extension.vendored_sdks.models import Scope from azext_k8s_extension.partner_extensions.ContainerInsights import ContainerInsights from azext_k8s_extension.partner_extensions.AzureDefender import AzureDefender @@ -128,6 +129,7 @@ def create_k8s_extension(cmd, client, resource_group_name, cluster_name, name, c # Common validations __validate_version_and_auto_upgrade(extension_instance.version, extension_instance.auto_upgrade_minor_version) + __validate_scope_after_customization(extension_instance.scope) # Create identity, if required if create_identity: @@ -238,13 +240,17 @@ def __get_cluster_rp(cluster_type): def __validate_scope_and_namespace(scope, release_namespace, target_namespace): if scope == 'cluster': if target_namespace is not None: - message = "When Scope is 'cluster', target-namespace must not be given." + message = "When --scope is 'cluster', --target-namespace must not be given." raise MutuallyExclusiveArgumentError(message) else: if release_namespace is not None: - message = "When Scope is 'namespace', release-namespace must not be given." + message = "When --scope is 'namespace', --release-namespace must not be given." raise MutuallyExclusiveArgumentError(message) +def __validate_scope_after_customization(scope_obj: Scope): + if scope_obj is not None and scope_obj.namespace is not None and scope_obj.namespace.target_namespace is None: + message = "When --scope is 'namespace', --target-namespace must be given." + raise RequiredArgumentMissingError(message) def __validate_version_and_auto_upgrade(version, auto_upgrade_minor_version): if version is not None: From 550eea1b30279f2058d900c561f8851b44ce4c8a Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 17 Mar 2021 12:30:27 -0700 Subject: [PATCH 41/80] Update style --- src/k8s-extension/azext_k8s_extension/custom.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py index 92e5e5513a0..2b29cd036c0 100644 --- a/src/k8s-extension/azext_k8s_extension/custom.py +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -247,11 +247,13 @@ def __validate_scope_and_namespace(scope, release_namespace, target_namespace): message = "When --scope is 'namespace', --release-namespace must not be given." raise MutuallyExclusiveArgumentError(message) + def __validate_scope_after_customization(scope_obj: Scope): if scope_obj is not None and scope_obj.namespace is not None and scope_obj.namespace.target_namespace is None: message = "When --scope is 'namespace', --target-namespace must be given." raise RequiredArgumentMissingError(message) + def __validate_version_and_auto_upgrade(version, auto_upgrade_minor_version): if version is not None: if auto_upgrade_minor_version: From fbab3be6fe097d7e2db815954175ca6d45baa796 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 17 Mar 2021 13:39:49 -0700 Subject: [PATCH 42/80] Add cassandra operator and location to model --- .../azext_k8s_extension/custom.py | 2 + .../partner_extensions/AzureDefender.py | 4 +- .../partner_extensions/Cassandra.py | 57 +++++++++++++++++++ .../partner_extensions/ContainerInsights.py | 4 +- .../partner_extensions/DefaultExtension.py | 4 +- .../vendored_sdks/models/_models.py | 4 ++ .../vendored_sdks/models/_models_py3.py | 6 +- 7 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py index 2b29cd036c0..ba9dbfce501 100644 --- a/src/k8s-extension/azext_k8s_extension/custom.py +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -19,6 +19,7 @@ from azext_k8s_extension.partner_extensions.ContainerInsights import ContainerInsights from azext_k8s_extension.partner_extensions.AzureDefender import AzureDefender +from azext_k8s_extension.partner_extensions.Cassandra import Cassandra from azext_k8s_extension.partner_extensions.DefaultExtension import DefaultExtension import azext_k8s_extension._consts as consts @@ -32,6 +33,7 @@ def ExtensionFactory(extension_name): extension_map = { 'microsoft.azuremonitor.containers': ContainerInsights, 'microsoft.azuredefender.kubernetes': AzureDefender, + 'cassandradatacentersoperator': Cassandra } # Return the extension if we find it in the map, else return the default diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py index 7721ea8c638..dcd2853affc 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py @@ -55,9 +55,7 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t version=version, scope=ext_scope, configuration_settings=configuration_settings, - configuration_protected_settings=configuration_protected_settings, - identity=None, - location="" + configuration_protected_settings=configuration_protected_settings ) return extension_instance, name, create_identity diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py new file mode 100644 index 00000000000..2a609ce125a --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py @@ -0,0 +1,57 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument + +from azext_k8s_extension.vendored_sdks.models import ExtensionInstance +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate +from azext_k8s_extension.vendored_sdks.models import ScopeCluster +from azext_k8s_extension.vendored_sdks.models import ScopeNamespace +from azext_k8s_extension.vendored_sdks.models import Scope + +from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel + + +class Cassandra(PartnerExtensionModel): + def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, + scope, auto_upgrade_minor_version, release_train, version, target_namespace, + release_namespace, configuration_settings, configuration_protected_settings, + configuration_settings_file, configuration_protected_settings_file): + + """Default validations & defaults for Create + Must create and return a valid 'ExtensionInstance' object. + + """ + ext_scope = None + if scope is not None: + if scope.lower() == 'cluster': + scope_cluster = ScopeCluster(release_namespace=release_namespace) + ext_scope = Scope(cluster=scope_cluster, namespace=None) + elif scope.lower() == 'namespace': + scope_namespace = ScopeNamespace(target_namespace=target_namespace) + ext_scope = Scope(namespace=scope_namespace, cluster=None) + + create_identity = True + extension_instance = ExtensionInstance( + extension_type=extension_type, + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version, + scope=ext_scope, + configuration_settings=configuration_settings, + configuration_protected_settings=configuration_protected_settings, + ) + return extension_instance, name, create_identity + + def Update(self, extension, auto_upgrade_minor_version, release_train, version): + """Default validations & defaults for Update + Must create and return a valid 'ExtensionInstanceUpdate' object. + + """ + return ExtensionInstanceUpdate( + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version + ) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py index a90b807020d..8c678b34915 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py @@ -67,9 +67,7 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t version=version, scope=ext_scope, configuration_settings=configuration_settings, - configuration_protected_settings=configuration_protected_settings, - identity=None, - location="" + configuration_protected_settings=configuration_protected_settings ) return extension_instance, name, create_identity diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py index 3117734116f..9a69199f838 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py @@ -41,9 +41,7 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t version=version, scope=ext_scope, configuration_settings=configuration_settings, - configuration_protected_settings=configuration_protected_settings, - identity=None, - location="" + configuration_protected_settings=configuration_protected_settings ) return extension_instance, name, create_identity diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py index c821dfc362a..f74ea5d809e 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py @@ -239,6 +239,8 @@ class ExtensionInstance(ProxyResource): :vartype name: str :ivar type: Resource type :vartype type: str + :param location: Location of resource type + :type location: str :param system_data: Top level metadata https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData @@ -305,6 +307,7 @@ class ExtensionInstance(ProxyResource): 'id': {'key': 'id', 'type': 'str'}, 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, + 'location': {'key': 'location', 'type': 'str'}, 'system_data': {'key': 'systemData', 'type': 'SystemData'}, 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, @@ -324,6 +327,7 @@ class ExtensionInstance(ProxyResource): def __init__(self, **kwargs): super(ExtensionInstance, self).__init__(**kwargs) + self.location = kwargs.get('location', None) self.extension_type = kwargs.get('extension_type', None) self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', None) self.release_train = kwargs.get('release_train', None) diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py index 1ca6a98a35a..57f42c85edd 100644 --- a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py @@ -239,6 +239,8 @@ class ExtensionInstance(ProxyResource): :vartype name: str :ivar type: Resource type :vartype type: str + :param location: Location of resource type + :type location: str :param system_data: Top level metadata https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData @@ -305,6 +307,7 @@ class ExtensionInstance(ProxyResource): 'id': {'key': 'id', 'type': 'str'}, 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, + 'location': {'key': 'location', 'type': 'str'}, 'system_data': {'key': 'systemData', 'type': 'SystemData'}, 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, @@ -322,8 +325,9 @@ class ExtensionInstance(ProxyResource): 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'} } - def __init__(self, *, system_data=None, extension_type: str=None, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, scope=None, configuration_settings=None, configuration_protected_settings=None, install_state=None, statuses=None, identity=None, **kwargs) -> None: + def __init__(self, *, system_data=None, location: str=None, extension_type: str=None, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, scope=None, configuration_settings=None, configuration_protected_settings=None, install_state=None, statuses=None, identity=None, **kwargs) -> None: super(ExtensionInstance, self).__init__(system_data=system_data, **kwargs) + self.location = location self.extension_type = extension_type self.auto_upgrade_minor_version = auto_upgrade_minor_version self.release_train = release_train From 9aade9f1c5210d2a79ad425f9908b2e73b60faba Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Wed, 17 Mar 2021 17:50:55 -0700 Subject: [PATCH 43/80] Stage Public Version of k8s-extension 0.2.0 for official release (#15) * Create pull.yml * Update pull.yml * Update azure-pipelines.yml * Initial commit of k8s-extension * Update pipelines file * Update CODEOWNERS * Update private preview pipelines * Remove open service mesh from public release * Update pipeline files * Update public extension pipeline * Change condition variable * Add version to public preview/private preview * Update pipelines * Add different testing based on private branch * Add annotations to extension model * Update k8s-custom-pipelines.yml * Update SDKs with Updated Swagger Spec for 2020-07-01-preview (#13) * Update sdks with updated swagger spec * Update version and history rst * Reorder release history timeline * Fix ExtensionInstanceForCreate for import * remove py2 bdist support * Add custom table formatting * Remove unnecessary files * Fix style issues * Fix branch based on comments * Update identity piece manually * Don't handle defaults at the CLI level * Remove defaults from CLI client * Check null target namespace with namespace scope * Update style * Add cassandra operator and location to model Co-authored-by: action@github.com --- .github/CODEOWNERS | 6 +- k8s-custom-pipelines.yml | 356 +++++++++ src/k8s-extension/HISTORY.rst | 35 + src/k8s-extension/README.rst | 5 + .../azext_k8s_extension/__init__.py | 32 + .../azext_k8s_extension/_client_factory.py | 31 + .../azext_k8s_extension/_consts.py | 8 + .../azext_k8s_extension/_consts_private.py | 8 + .../azext_k8s_extension/_format.py | 24 + .../azext_k8s_extension/_help.py | 39 + .../azext_k8s_extension/_params.py | 74 ++ .../azext_k8s_extension/action.py | 37 + .../azext_k8s_extension/azext_metadata.json | 4 + .../azext_k8s_extension/commands.py | 26 + .../azext_k8s_extension/custom.py | 279 +++++++ .../partner_extensions/AzureDefender.py | 71 ++ .../partner_extensions/Cassandra.py | 57 ++ .../partner_extensions/ContainerInsights.py | 458 +++++++++++ .../partner_extensions/DefaultExtension.py | 57 ++ .../PartnerExtensionModel.py | 23 + .../partner_extensions/__init__.py | 5 + .../azext_k8s_extension/tests/__init__.py | 5 + .../tests/latest/__init__.py | 5 + .../latest/recordings/test_k8s_extension.yaml | 270 +++++++ .../latest/test_k8s_extension_scenario.py | 67 ++ .../vendored_sdks/__init__.py | 19 + .../vendored_sdks/_configuration.py | 49 ++ .../_source_control_configuration_client.py | 60 ++ .../vendored_sdks/models/__init__.py | 94 +++ .../vendored_sdks/models/_models.py | 726 ++++++++++++++++++ .../vendored_sdks/models/_models_py3.py | 726 ++++++++++++++++++ .../vendored_sdks/models/_paged_models.py | 53 ++ ...urce_control_configuration_client_enums.py | 68 ++ .../vendored_sdks/operations/__init__.py | 20 + .../operations/_extensions_operations.py | 431 +++++++++++ .../vendored_sdks/operations/_operations.py | 101 +++ ...ource_control_configurations_operations.py | 386 ++++++++++ .../vendored_sdks/version.py | 13 + src/k8s-extension/setup.py | 55 ++ 39 files changed, 4781 insertions(+), 2 deletions(-) create mode 100644 k8s-custom-pipelines.yml create mode 100644 src/k8s-extension/HISTORY.rst create mode 100644 src/k8s-extension/README.rst create mode 100644 src/k8s-extension/azext_k8s_extension/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/_client_factory.py create mode 100644 src/k8s-extension/azext_k8s_extension/_consts.py create mode 100644 src/k8s-extension/azext_k8s_extension/_consts_private.py create mode 100644 src/k8s-extension/azext_k8s_extension/_format.py create mode 100644 src/k8s-extension/azext_k8s_extension/_help.py create mode 100644 src/k8s-extension/azext_k8s_extension/_params.py create mode 100644 src/k8s-extension/azext_k8s_extension/action.py create mode 100644 src/k8s-extension/azext_k8s_extension/azext_metadata.json create mode 100644 src/k8s-extension/azext_k8s_extension/commands.py create mode 100644 src/k8s-extension/azext_k8s_extension/custom.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/tests/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/tests/latest/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/tests/latest/recordings/test_k8s_extension.yaml create mode 100644 src/k8s-extension/azext_k8s_extension/tests/latest/test_k8s_extension_scenario.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/_source_control_configuration_client.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_source_control_configuration_client_enums.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_extensions_operations.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_operations.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_source_control_configurations_operations.py create mode 100644 src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py create mode 100644 src/k8s-extension/setup.py diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 66f026834e8..435dbbae79f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -124,9 +124,11 @@ /src/ssh/ @rlrossiter @danybeam @arrownj -/src/k8sconfiguration/ @NarayanThiru +/src/k8sconfiguration/ @NarayanThiru @jonathan-innis -/src/k8s-configuration/ @NarayanThiru +/src/k8s-configuration/ @NarayanThiru @jonathan-innis + +/src/k8s-extension/ @NarayanThiru @jonathan-innis /src/log-analytics-solution/ @zhoxing-ms diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml new file mode 100644 index 00000000000..f4e2984ddf2 --- /dev/null +++ b/k8s-custom-pipelines.yml @@ -0,0 +1,356 @@ +resources: + repositories: + - repository: K8sPartnerExtensionTest + type: git + endpoint: AzureReposConnection + name: One/compute-HybridMgmt-K8sPartnerExtensionTest + +trigger: + batch: true + branches: + include: + - k8s-extension/public + - k8s-extension/private +pr: + branches: + include: + - k8s-extension/public + - k8s-extension/private + +stages: +- stage: BuildTestPublishExtension + displayName: "Build, Test, and Publish Extension" + variables: + K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest + CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions + SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" + RESOURCE_GROUP: "K8sPartnerExtensionTest" + BASE_CLUSTER_NAME: "k8s-extension-cluster" + IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranch'], 'refs/heads/k8s-extension/private'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private'))] + + EXTENSION_NAME: "k8s-extension" + EXTENSION_FILE_NAME: "k8s_extension" + jobs: + - job: K8sExtensionTestSuite + displayName: "Run the Test Suite" + pool: + vmImage: 'ubuntu-16.04' + steps: + - checkout: self + - checkout: K8sPartnerExtensionTest + - bash: | + echo "Installing helm3" + curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 + chmod 700 get_helm.sh + ./get_helm.sh + + echo "Installing kubectl" + curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin/kubectl + kubectl version --client + displayName: "Setup the VM with helm3 and kubectl" + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + echo "Building extension ${EXTENSION_NAME}..." + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build Extension with azdev" + + - bash: | + K8S_EXTENSION_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) + echo "##vso[task.setvariable variable=K8S_EXTENSION_VERSION]$K8S_EXTENSION_VERSION" + cp * $(K8S_EXTENSION_REPO_PATH)/bin + workingDirectory: $(CLI_REPO_PATH)/dist + displayName: "Copy the Built .whl to Extension Test Path" + + - bash: | + RAND_STR=$RANDOM + AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" + ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" + + JSON_STRING=$(jq -n \ + --arg SUB_ID "$SUBSCRIPTION_ID" \ + --arg RG "$RESOURCE_GROUP" \ + --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ + --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ + --arg K8S_EXTENSION_VERSION "$K8S_EXTENSION_VERSION" \ + '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-extension": $K8S_EXTENSION_VERSION, connectedk8s: "1.0.0"}}') + echo $JSON_STRING > settings.json + cat settings.json + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + displayName: "Generate a settings.json file" + + - bash : | + echo "Downloading the kind script" + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64 + chmod +x ./kind + ./kind create cluster + displayName: "Create and Start the Kind cluster" + + - task: AzureCLI@2 + displayName: Bootstrap + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Bootstrap.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + + - task: AzureCLI@2 + displayName: Run the Test Suite Public Extensions Only + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Test.ps1 -CI -ExtensionType Public -OnlyPublicTests + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + continueOnError: true + condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'False')) + + - task: AzureCLI@2 + displayName: Run the Test Suite on Private + Public Extensions + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Test.ps1 -CI -ExtensionType Public + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + continueOnError: true + condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'True')) + + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TestResults.xml' + failTaskOnFailedTests: true + condition: succeededOrFailed() + + - task: AzureCLI@2 + displayName: Cleanup + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Cleanup.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + condition: succeededOrFailed() + + - job: BuildPublishExtension + pool: + vmImage: 'ubuntu-16.04' + displayName: "Build and Publish the Extension Artifact" + variables: + CLI_REPO_PATH: $(Agent.BuildDirectory)/s + steps: + - bash: | + echo "Using the private preview of k8s-extension to build..." + + cp $(CLI_REPO_PATH)/src/k8s-extension $(CLI_REPO_PATH)/src/k8s-extension-private -r + cp $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts.py + + EXTENSION_NAME="k8s-extension-private" + EXTENSION_FILE_NAME="k8s_extension_private" + + echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" + echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" + condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'True')) + displayName: "Copy Files, Set Variables for k8s-extension-private" + - bash: | + echo "Using the public version of k8s-extension to build..." + + EXTENSION_NAME="k8s-extension" + EXTENSION_FILE_NAME="k8s_extension" + + echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" + echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" + condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'False')) + displayName: "Copy Files, Set Variables for k8s-extension" + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + echo "Building extension ${EXTENSION_NAME}..." + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build Extension with azdev" + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: $(CLI_REPO_PATH)/dist + +- stage: AzureCLIOfficial + displayName: "Azure Official CLI Code Checks" + dependsOn: [] + jobs: + - job: CheckLicenseHeader + displayName: "Check License" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + python -m venv env/ + + chmod +x ./env/bin/activate + source ./env/bin/activate + + # clone azure-cli + git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install -q azdev + + azdev setup -c ../azure-cli -r ./ + + azdev --version + az --version + + azdev verify license + + - job: StaticAnalysis + displayName: "Static Analysis" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests + displayName: 'Install wheel, pylint, flake8, requests' + - bash: python scripts/ci/source_code_static_analysis.py + displayName: "Static Analysis" + + - job: IndexVerify + displayName: "Verify Extensions Index" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: | + #!/usr/bin/env bash + set -ev + pip install wheel==0.30.0 requests packaging + export CI="ADO" + python ./scripts/ci/test_index.py -v + displayName: "Verify Extensions Index" + + - job: SourceTests + displayName: "Integration Tests, Build Tests" + pool: + vmImage: 'ubuntu-16.04' + strategy: + matrix: + Python36: + python.version: '3.6' + Python38: + python.version: '3.8' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python $(python.version)' + inputs: + versionSpec: '$(python.version)' + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - bash: ./scripts/ci/test_source.sh + displayName: 'Run integration test and build test' + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: LintModifiedExtensions + displayName: "CLI Linter on Modified Extensions" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + pip install virtualenv + python -m virtualenv venv/ + source ./venv/bin/activate + + # clone azure-cli + git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install azdev + + azdev --version + + azdev setup -c ../azure-cli -r ./ -e k8s-extension + + # overwrite the default AZURE_EXTENSION_DIR set by ADO + AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version + + AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-extension + displayName: "CLI Linter on Modified Extension" + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: IndexRefDocVerify + displayName: "Verify Ref Docs" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - task: Bash@3 + displayName: "Verify Extension Ref Docs" + inputs: + targetType: 'filePath' + filePath: scripts/ci/test_index_ref_doc.sh diff --git a/src/k8s-extension/HISTORY.rst b/src/k8s-extension/HISTORY.rst new file mode 100644 index 00000000000..54c1e375f6f --- /dev/null +++ b/src/k8s-extension/HISTORY.rst @@ -0,0 +1,35 @@ +.. :changelog: + +Release History +=============== + +0.2.0 +++++++++++++++++++ + +* Refactor for clear separation of extension-type specific customizations +* OpenServiceMesh customization. +* Fix clusterType of Microsoft.ResourceConnector resource +* Update clusterType validation to allow 'appliances' +* Update identity creation to use the appropriate parent resource's type and api-version +* Throw error if cluster type is not one of the 3 supported types +* Rename azuremonitor-containers extension type to microsoft.azuremonitor.containers +* Move CLI errors to non-deprecated error types +* Remove support for update + +0.1.3 +++++++++++++++++++ + +* Customization for microsoft.openservicemesh + +0.1.2 +++++++++++++++++++ + +* Add support for Arc Appliance cluster type + +0.1.1 +++++++++++++++++++ +* Add support for microsoft-azure-defender extension type + +0.1.0 +++++++++++++++++++ +* Initial release. diff --git a/src/k8s-extension/README.rst b/src/k8s-extension/README.rst new file mode 100644 index 00000000000..e91e1b13229 --- /dev/null +++ b/src/k8s-extension/README.rst @@ -0,0 +1,5 @@ +Microsoft Azure CLI 'k8s-extension' Extension +============================================= + +This package is for the 'k8s-extension' extension. +i.e. 'az k8s-extension' diff --git a/src/k8s-extension/azext_k8s_extension/__init__.py b/src/k8s-extension/azext_k8s_extension/__init__.py new file mode 100644 index 00000000000..e2301227d45 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/__init__.py @@ -0,0 +1,32 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.core import AzCommandsLoader + +from azext_k8s_extension._help import helps # pylint: disable=unused-import + + +class K8sExtensionCommandsLoader(AzCommandsLoader): + + def __init__(self, cli_ctx=None): + from azure.cli.core.commands import CliCommandType + from azext_k8s_extension._client_factory import cf_k8s_extension + k8s_extension_custom = CliCommandType( + operations_tmpl='azext_k8s_extension.custom#{}', + client_factory=cf_k8s_extension) + super(K8sExtensionCommandsLoader, self).__init__(cli_ctx=cli_ctx, + custom_command_type=k8s_extension_custom) + + def load_command_table(self, args): + from azext_k8s_extension.commands import load_command_table + load_command_table(self, args) + return self.command_table + + def load_arguments(self, command): + from azext_k8s_extension._params import load_arguments + load_arguments(self, command) + + +COMMAND_LOADER_CLS = K8sExtensionCommandsLoader diff --git a/src/k8s-extension/azext_k8s_extension/_client_factory.py b/src/k8s-extension/azext_k8s_extension/_client_factory.py new file mode 100644 index 00000000000..1a9a10c2615 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_client_factory.py @@ -0,0 +1,31 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.core.commands.client_factory import get_mgmt_service_client +from azure.cli.core.profiles import ResourceType + + +def cf_k8s_extension(cli_ctx, *_): + from azext_k8s_extension.vendored_sdks import SourceControlConfigurationClient + return get_mgmt_service_client(cli_ctx, SourceControlConfigurationClient) + + +def cf_k8s_extension_operation(cli_ctx, _): + return cf_k8s_extension(cli_ctx).extensions + + +def cf_resource_groups(cli_ctx, subscription_id=None): + return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES, + subscription_id=subscription_id).resource_groups + + +def cf_resources(cli_ctx, subscription_id=None): + return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES, + subscription_id=subscription_id).resources + + +def cf_log_analytics(cli_ctx, subscription_id=None): + from azure.mgmt.loganalytics import LogAnalyticsManagementClient # pylint: disable=no-name-in-module + return get_mgmt_service_client(cli_ctx, LogAnalyticsManagementClient, subscription_id=subscription_id) diff --git a/src/k8s-extension/azext_k8s_extension/_consts.py b/src/k8s-extension/azext_k8s_extension/_consts.py new file mode 100644 index 00000000000..d0fdaf7775f --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_consts.py @@ -0,0 +1,8 @@ +# coding=utf-8 +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +EXTENSION_NAME = 'k8s-extension' +VERSION = "0.2.0" diff --git a/src/k8s-extension/azext_k8s_extension/_consts_private.py b/src/k8s-extension/azext_k8s_extension/_consts_private.py new file mode 100644 index 00000000000..bc4c8a2b694 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_consts_private.py @@ -0,0 +1,8 @@ +# coding=utf-8 +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +EXTENSION_NAME = 'k8s-extension-private' +VERSION = "0.1PP.14" diff --git a/src/k8s-extension/azext_k8s_extension/_format.py b/src/k8s-extension/azext_k8s_extension/_format.py new file mode 100644 index 00000000000..ef96f7cf88f --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_format.py @@ -0,0 +1,24 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from collections import OrderedDict + + +def k8s_extension_list_table_format(results): + return [__get_table_row(result) for result in results] + + +def k8s_extension_show_table_format(result): + return __get_table_row(result) + + +def __get_table_row(result): + return OrderedDict([ + ('name', result['name']), + ('extensionType', result['extensionType']), + ('version', result['version']), + ('installState', result['installState']), + ('lastModifiedTime', result['lastModifiedTime']) + ]) diff --git a/src/k8s-extension/azext_k8s_extension/_help.py b/src/k8s-extension/azext_k8s_extension/_help.py new file mode 100644 index 00000000000..64e4be612ea --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_help.py @@ -0,0 +1,39 @@ +# coding=utf-8 +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from knack.help_files import helps # pylint: disable=unused-import +import azext_k8s_extension._consts as consts + + +helps[f'{consts.EXTENSION_NAME}'] = """ + type: group + short-summary: Commands to manage K8s-extensions. +""" + +helps[f'{consts.EXTENSION_NAME} create'] = """ + type: command + short-summary: Create a K8s-extension. +""" + +helps[f'{consts.EXTENSION_NAME} list'] = """ + type: command + short-summary: List K8s-extensions. +""" + +helps[f'{consts.EXTENSION_NAME} delete'] = """ + type: command + short-summary: Delete a K8s-extension. +""" + +helps[f'{consts.EXTENSION_NAME} show'] = """ + type: command + short-summary: Show details of a K8s-extension. +""" + +helps[f'{consts.EXTENSION_NAME} update'] = """ + type: command + short-summary: Update a K8s-extension. +""" diff --git a/src/k8s-extension/azext_k8s_extension/_params.py b/src/k8s-extension/azext_k8s_extension/_params.py new file mode 100644 index 00000000000..d96fe3c2ba7 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/_params.py @@ -0,0 +1,74 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.core.commands.parameters import ( + get_enum_type, + get_three_state_flag, + tags_type +) +from azure.cli.core.commands.validators import get_default_location_from_resource_group +import azext_k8s_extension._consts as consts + +from azext_k8s_extension.action import ( + AddConfigurationSettings, + AddConfigurationProtectedSettings +) + + +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', + options_list=['--name', '-n'], + help='Name of the extension instance') + c.argument('extension_type', + help='Name of the extension type.') + c.argument('cluster_name', + options_list=['--cluster-name', '-c'], + help='Name of the Kubernetes cluster') + c.argument('cluster_type', + arg_type=get_enum_type(['connectedClusters', 'managedClusters', 'appliances']), + help='Specify Arc clusters or AKS managed clusters or Arc appliances.') + c.argument('scope', + arg_type=get_enum_type(['cluster', 'namespace']), + help='Specify the extension scope.') + c.argument('auto_upgrade_minor_version', + arg_group="Version", + options_list=['--auto-upgrade-minor-version', '--auto-upgrade'], + arg_type=get_three_state_flag(), + help='Automatically upgrade minor version of the extension instance.') + c.argument('version', + arg_group="Version", + help='Specify the version to install for the extension instance if' + ' --auto-upgrade-minor-version is not enabled.') + c.argument('configuration_settings', + arg_group="Configuration", + options_list=['--configuration-settings', '--config'], + action=AddConfigurationSettings, + nargs='+', + help='Configuration Settings as key=value pair. Repeat parameter for each setting') + c.argument('configuration_protected_settings', + arg_group="Configuration", + options_list=['--configuration-protected-settings', '--config-protected'], + action=AddConfigurationProtectedSettings, + nargs='+', + help='Configuration Protected Settings as key=value pair. Repeat parameter for each setting') + c.argument('configuration_settings_file', + arg_group="Configuration", + options_list=['--configuration-settings-file', '--config-file'], + help='JSON file path for configuration-settings') + c.argument('configuration_protected_settings_file', + arg_group="Configuration", + options_list=['--configuration-protected-settings-file', '--config-protected-file'], + help='JSON file path for configuration-protected-settings') + c.argument('release_namespace', + help='Specify the namespace to install the extension release.') + c.argument('release_train', + help='Specify the release train for the extension type.') + c.argument('target_namespace', + help='Specify the target namespace to install to for the extension instance. This' + ' parameter is required if extension scope is set to \'namespace\'') diff --git a/src/k8s-extension/azext_k8s_extension/action.py b/src/k8s-extension/azext_k8s_extension/action.py new file mode 100644 index 00000000000..4afbbbcd611 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/action.py @@ -0,0 +1,37 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import argparse +from azure.cli.core.azclierror import ArgumentUsageError + + +# pylint: disable=protected-access, too-few-public-methods +class AddConfigurationSettings(argparse._AppendAction): + + def __call__(self, parser, namespace, values, option_string=None): + settings = {} + for item in values: + try: + key, value = item.split('=', 1) + settings[key] = value + except ValueError: + raise ArgumentUsageError('Usage error: {} configuration_setting_key=configuration_setting_value'. + format(option_string)) + super(AddConfigurationSettings, self).__call__(parser, namespace, settings, option_string) + + +# pylint: disable=protected-access, too-few-public-methods +class AddConfigurationProtectedSettings(argparse._AppendAction): + + def __call__(self, parser, namespace, values, option_string=None): + prot_settings = {} + for item in values: + try: + key, value = item.split('=', 1) + prot_settings[key] = value + except ValueError: + raise ArgumentUsageError('Usage error: {} configuration_protected_setting_key=' + 'configuration_protected_setting_value'.format(option_string)) + super(AddConfigurationProtectedSettings, self).__call__(parser, namespace, prot_settings, option_string) diff --git a/src/k8s-extension/azext_k8s_extension/azext_metadata.json b/src/k8s-extension/azext_k8s_extension/azext_metadata.json new file mode 100644 index 00000000000..cf7b8927a07 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/azext_metadata.json @@ -0,0 +1,4 @@ +{ + "azext.isPreview": true, + "azext.minCliCoreVersion": "2.15.0" +} diff --git a/src/k8s-extension/azext_k8s_extension/commands.py b/src/k8s-extension/azext_k8s_extension/commands.py new file mode 100644 index 00000000000..931662814c0 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/commands.py @@ -0,0 +1,26 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=line-too-long +from azure.cli.core.commands import CliCommandType +from azext_k8s_extension._client_factory import (cf_k8s_extension, cf_k8s_extension_operation) +from azext_k8s_extension._format import k8s_extension_list_table_format, k8s_extension_show_table_format +import azext_k8s_extension._consts as consts + + +def load_command_table(self, _): + + k8s_extension_sdk = CliCommandType( + operations_tmpl='azext_k8s_extension.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) \ + as g: + g.custom_command('create', 'create_k8s_extension') + g.custom_command('update', 'update_k8s_extension') + g.custom_command('delete', 'delete_k8s_extension', confirmation=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) diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py new file mode 100644 index 00000000000..ba9dbfce501 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -0,0 +1,279 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument,too-many-locals + +import json +from knack.log import get_logger + +from msrestazure.azure_exceptions import CloudError + +from azure.cli.core.azclierror import ResourceNotFoundError, MutuallyExclusiveArgumentError, \ + InvalidArgumentValueError, CommandNotFoundError, RequiredArgumentMissingError +from azure.cli.core.commands.client_factory import get_subscription_id +from azext_k8s_extension.vendored_sdks.models import ConfigurationIdentity +from azext_k8s_extension.vendored_sdks.models import ErrorResponseException +from azext_k8s_extension.vendored_sdks.models import Scope + +from azext_k8s_extension.partner_extensions.ContainerInsights import ContainerInsights +from azext_k8s_extension.partner_extensions.AzureDefender import AzureDefender +from azext_k8s_extension.partner_extensions.Cassandra import Cassandra +from azext_k8s_extension.partner_extensions.DefaultExtension import DefaultExtension +import azext_k8s_extension._consts as consts + +from ._client_factory import cf_resources + +logger = get_logger(__name__) + + +# A factory method to return the correct extension class based off of the extension name +def ExtensionFactory(extension_name): + extension_map = { + 'microsoft.azuremonitor.containers': ContainerInsights, + 'microsoft.azuredefender.kubernetes': AzureDefender, + 'cassandradatacentersoperator': Cassandra + } + + # Return the extension if we find it in the map, else return the default + return extension_map.get(extension_name, DefaultExtension)() + + +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) + + try: + extension = client.get(resource_group_name, + cluster_rp, cluster_type, cluster_name, name) + return extension + except ErrorResponseException as ex: + # Customize the error message for resources not found + if ex.response.status_code == 404: + # If Cluster not found + if ex.message.__contains__("(ResourceNotFound)"): + message = "{0} Verify that the cluster-type is correct and the resource exists.".format( + ex.message) + # If Configuration not found + elif ex.message.__contains__("Operation returned an invalid status code 'Not Found'"): + message = "(ExtensionNotFound) The Resource {0}/{1}/{2}/Microsoft.KubernetesConfiguration/" \ + "extensions/{3} could not be found!".format( + cluster_rp, cluster_type, cluster_name, name) + else: + message = ex.message + raise ResourceNotFoundError(message) + + +def create_k8s_extension(cmd, client, resource_group_name, cluster_name, name, cluster_type, + 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): + """Create a new Extension Instance. + + """ + extension_type_lower = extension_type.lower() + + # Determine ClusterRP + cluster_rp = __get_cluster_rp(cluster_type) + + # Configuration Settings & Configuration Protected Settings + if configuration_settings is not None and configuration_settings_file is not None: + raise MutuallyExclusiveArgumentError( + 'Error! Both configuration-settings and configuration-settings-file cannot be provided.' + ) + + if configuration_protected_settings is not None and configuration_protected_settings_file is not None: + raise MutuallyExclusiveArgumentError( + 'Error! Both configuration-protected-settings and configuration-protected-settings-file ' + 'cannot be provided.' + ) + + config_settings = {} + config_protected_settings = {} + # Get Configuration Settings from file + if configuration_settings_file is not None: + config_settings = __get_config_settings_from_file(configuration_settings_file) + + 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 = __get_config_settings_from_file(configuration_protected_settings_file) + + if configuration_protected_settings is not None: + for dicts in configuration_protected_settings: + for key, value in dicts.items(): + config_protected_settings[key] = value + + # Identity is not created by default. Extension type must specify if identity is required. + create_identity = False + extension_instance = None + + # Scope & Namespace validation - common to all extension-types + __validate_scope_and_namespace(scope, release_namespace, target_namespace) + + # Give Partners a chance to their extensionType specific validations and to set value over-rides. + + # Get the extension class based on the extension name + extension_class = ExtensionFactory(extension_type_lower) + extension_instance, name, create_identity = extension_class.Create( + cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type_lower, scope, + auto_upgrade_minor_version, release_train, version, target_namespace, release_namespace, config_settings, + config_protected_settings, configuration_settings_file, configuration_protected_settings_file) + + # Common validations + __validate_version_and_auto_upgrade(extension_instance.version, extension_instance.auto_upgrade_minor_version) + __validate_scope_after_customization(extension_instance.scope) + + # Create identity, if required + if create_identity: + extension_instance.identity, extension_instance.location = \ + __create_identity(cmd, resource_group_name, cluster_name, cluster_type, cluster_rp) + + # Try to create the resource + return client.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): + + """Patch an existing Extension Instance. + + """ + + # 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." + ) + + # # 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) + + # # Determine ClusterRP + # cluster_rp = __get_cluster_rp(cluster_type) + + # # Get the existing extensionInstance + # extension = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + + # extension_type_lower = extension.extension_type.lower() + + # # 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) + + # __validate_version_and_auto_upgrade(version, auto_upgrade_minor_version) + + # upd_extension = ExtensionInstanceUpdate(auto_upgrade_minor_version=auto_upgrade_minor_version, + # release_train=release_train, version=version) + + # return client.update(resource_group_name, cluster_rp, cluster_type, cluster_name, name, upd_extension) + + +def delete_k8s_extension(client, resource_group_name, cluster_name, name, cluster_type): + """Delete an existing Kubernetes Extension. + + """ + # Determine ClusterRP + cluster_rp = __get_cluster_rp(cluster_type) + return client.delete(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + + +def __create_identity(cmd, resource_group_name, cluster_name, cluster_type, cluster_rp): + subscription_id = get_subscription_id(cmd.cli_ctx) + resources = cf_resources(cmd.cli_ctx, subscription_id) + + cluster_resource_id = '/subscriptions/{0}/resourceGroups/{1}/providers/{2}/{3}/{4}'.format(subscription_id, + resource_group_name, + cluster_rp, + cluster_type, + cluster_name) + + if cluster_rp == 'Microsoft.Kubernetes': + parent_api_version = '2020-01-01-preview' + elif cluster_rp == 'Microsoft.ResourceConnector': + parent_api_version = '2020-09-15-privatepreview' + elif cluster_rp == 'Microsoft.ContainerService': + parent_api_version = '2017-07-01' + else: + raise InvalidArgumentValueError( + "Error! Cluster type '{}' is not supported for extension identity".format(cluster_type) + ) + + try: + resource = resources.get_by_id(cluster_resource_id, parent_api_version) + location = str(resource.location.lower()) + except CloudError as ex: + raise ex + identity_type = "SystemAssigned" + + return ConfigurationIdentity(type=identity_type), location + + +def __get_cluster_rp(cluster_type): + rp = "" + if cluster_type.lower() == 'connectedclusters': + rp = 'Microsoft.Kubernetes' + elif cluster_type.lower() == 'appliances': + rp = 'Microsoft.ResourceConnector' + elif cluster_type.lower() == '': + rp = 'Microsoft.ContainerService' + else: + raise InvalidArgumentValueError("Error! Cluster type '{}' is not supported".format(cluster_type)) + return rp + + +def __validate_scope_and_namespace(scope, release_namespace, target_namespace): + if scope == 'cluster': + if target_namespace is not None: + message = "When --scope is 'cluster', --target-namespace must not be given." + raise MutuallyExclusiveArgumentError(message) + else: + if release_namespace is not None: + message = "When --scope is 'namespace', --release-namespace must not be given." + raise MutuallyExclusiveArgumentError(message) + + +def __validate_scope_after_customization(scope_obj: Scope): + if scope_obj is not None and scope_obj.namespace is not None and scope_obj.namespace.target_namespace is None: + message = "When --scope is 'namespace', --target-namespace must be given." + raise RequiredArgumentMissingError(message) + + +def __validate_version_and_auto_upgrade(version, auto_upgrade_minor_version): + if version is not None: + if auto_upgrade_minor_version: + message = "To pin to specific version, auto-upgrade-minor-version must be set to 'false'." + raise MutuallyExclusiveArgumentError(message) + + auto_upgrade_minor_version = False + + +def __get_config_settings_from_file(file_path): + try: + config_file = open(file_path,) + settings = json.load(config_file) + except ValueError: + raise Exception("File {} is not a valid JSON file".format(file_path)) + + files = len(settings) + if files == 0: + raise Exception("File {} is empty".format(file_path)) + + return settings diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py new file mode 100644 index 00000000000..dcd2853affc --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py @@ -0,0 +1,71 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument + +from knack.log import get_logger + +from azext_k8s_extension.vendored_sdks.models import ExtensionInstance +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate +from azext_k8s_extension.vendored_sdks.models import ScopeCluster +from azext_k8s_extension.vendored_sdks.models import Scope + +from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel +from azext_k8s_extension.partner_extensions.ContainerInsights import _get_container_insights_settings + +logger = get_logger(__name__) + + +class AzureDefender(PartnerExtensionModel): + def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, + scope, auto_upgrade_minor_version, release_train, version, target_namespace, + release_namespace, configuration_settings, configuration_protected_settings, + configuration_settings_file, configuration_protected_settings_file): + + """ExtensionType 'microsoft.azuredefender.kubernetes' specific validations & defaults for Create + Must create and return a valid 'ExtensionInstance' object. + + """ + # NOTE-1: Replace default scope creation with your customization! + ext_scope = None + # Hardcoding name, release_namespace and scope since ci only supports one instance and cluster scope + # and platform doesnt have support yet extension specific constraints like this + name = extension_type.lower() + release_namespace = "azuredefender" + # Scope is always cluster + scope_cluster = ScopeCluster(release_namespace=release_namespace) + ext_scope = Scope(cluster=scope_cluster, namespace=None) + + is_ci_extension_type = False + + logger.warning('Ignoring name, release-namespace and scope parameters since %s ' + 'only supports cluster scope and single instance of this extension', extension_type) + + _get_container_insights_settings(cmd, resource_group_name, cluster_name, configuration_settings, + configuration_protected_settings, is_ci_extension_type) + + # NOTE-2: Return a valid ExtensionInstance object, Instance name and flag for Identity + create_identity = True + extension_instance = ExtensionInstance( + extension_type=extension_type, + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version, + scope=ext_scope, + configuration_settings=configuration_settings, + configuration_protected_settings=configuration_protected_settings + ) + return extension_instance, name, create_identity + + def Update(self, extension, auto_upgrade_minor_version, release_train, version): + """ExtensionType 'microsoft.azuredefender.kubernetes' specific validations & defaults for Update + Must create and return a valid 'ExtensionInstanceUpdate' object. + + """ + return ExtensionInstanceUpdate( + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version + ) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py new file mode 100644 index 00000000000..2a609ce125a --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py @@ -0,0 +1,57 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument + +from azext_k8s_extension.vendored_sdks.models import ExtensionInstance +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate +from azext_k8s_extension.vendored_sdks.models import ScopeCluster +from azext_k8s_extension.vendored_sdks.models import ScopeNamespace +from azext_k8s_extension.vendored_sdks.models import Scope + +from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel + + +class Cassandra(PartnerExtensionModel): + def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, + scope, auto_upgrade_minor_version, release_train, version, target_namespace, + release_namespace, configuration_settings, configuration_protected_settings, + configuration_settings_file, configuration_protected_settings_file): + + """Default validations & defaults for Create + Must create and return a valid 'ExtensionInstance' object. + + """ + ext_scope = None + if scope is not None: + if scope.lower() == 'cluster': + scope_cluster = ScopeCluster(release_namespace=release_namespace) + ext_scope = Scope(cluster=scope_cluster, namespace=None) + elif scope.lower() == 'namespace': + scope_namespace = ScopeNamespace(target_namespace=target_namespace) + ext_scope = Scope(namespace=scope_namespace, cluster=None) + + create_identity = True + extension_instance = ExtensionInstance( + extension_type=extension_type, + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version, + scope=ext_scope, + configuration_settings=configuration_settings, + configuration_protected_settings=configuration_protected_settings, + ) + return extension_instance, name, create_identity + + def Update(self, extension, auto_upgrade_minor_version, release_train, version): + """Default validations & defaults for Update + Must create and return a valid 'ExtensionInstanceUpdate' object. + + """ + return ExtensionInstanceUpdate( + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version + ) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py new file mode 100644 index 00000000000..8c678b34915 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py @@ -0,0 +1,458 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument + +import datetime +import json + +from knack.log import get_logger + +from azure.cli.core.azclierror import InvalidArgumentValueError +from azure.cli.core.commands import LongRunningOperation +from azure.cli.core.commands.client_factory import get_mgmt_service_client, get_subscription_id +from azure.cli.core.util import sdk_no_wait +from msrestazure.azure_exceptions import CloudError +from msrestazure.tools import parse_resource_id, is_valid_resource_id + +from azext_k8s_extension.vendored_sdks.models import ExtensionInstance +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate +from azext_k8s_extension.vendored_sdks.models import ScopeCluster +from azext_k8s_extension.vendored_sdks.models import Scope + +from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel + +from azext_k8s_extension._client_factory import ( + cf_resources, cf_resource_groups, cf_log_analytics) + +logger = get_logger(__name__) + + +class ContainerInsights(PartnerExtensionModel): + def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, + scope, auto_upgrade_minor_version, release_train, version, target_namespace, + release_namespace, configuration_settings, configuration_protected_settings, + configuration_settings_file, configuration_protected_settings_file): + + """ExtensionType 'microsoft.azuremonitor.containers' specific validations & defaults for Create + Must create and return a valid 'ExtensionInstance' object. + + """ + # NOTE-1: Replace default scope creation with your customization! + ext_scope = None + # Hardcoding name, release_namespace and scope since container-insights only supports one instance and cluster + # scope and platform doesnt have support yet extension specific constraints like this + name = 'azuremonitor-containers' + release_namespace = 'azuremonitor-containers' + # Scope is always cluster + scope_cluster = ScopeCluster(release_namespace=release_namespace) + ext_scope = Scope(cluster=scope_cluster, namespace=None) + + is_ci_extension_type = True + + logger.warning('Ignoring name, release-namespace and scope parameters since %s ' + 'only supports cluster scope and single instance of this extension', extension_type) + + _get_container_insights_settings(cmd, resource_group_name, cluster_name, configuration_settings, + configuration_protected_settings, is_ci_extension_type) + + # NOTE-2: Return a valid ExtensionInstance object, Instance name and flag for Identity + create_identity = True + extension_instance = ExtensionInstance( + extension_type=extension_type, + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version, + scope=ext_scope, + configuration_settings=configuration_settings, + configuration_protected_settings=configuration_protected_settings + ) + return extension_instance, name, create_identity + + def Update(self, extension, auto_upgrade_minor_version, release_train, version): + """ExtensionType 'microsoft.azuremonitor.containers' specific validations & defaults for Update + Must create and return a valid 'ExtensionInstanceUpdate' object. + + """ + return ExtensionInstanceUpdate( + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version + ) + + +# Custom Validation Logic for Container Insights + +def _invoke_deployment(cmd, resource_group_name, deployment_name, template, parameters, validate, no_wait, + subscription_id=None): + from azure.cli.core.profiles import ResourceType + deployment_properties = cmd.get_models('DeploymentProperties', resource_type=ResourceType.MGMT_RESOURCE_RESOURCES) + properties = deployment_properties(template=template, parameters=parameters, mode='incremental') + smc = get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES, + subscription_id=subscription_id).deployments + if validate: + logger.info('==== BEGIN TEMPLATE ====') + logger.info(json.dumps(template, indent=2)) + logger.info('==== END TEMPLATE ====') + + if cmd.supported_api_version(min_api='2019-10-01', resource_type=ResourceType.MGMT_RESOURCE_RESOURCES): + deployment_temp = cmd.get_models('Deployment', resource_type=ResourceType.MGMT_RESOURCE_RESOURCES) + deployment = deployment_temp(properties=properties) + + if validate: + validation_poller = smc.validate(resource_group_name, deployment_name, deployment) + return LongRunningOperation(cmd.cli_ctx)(validation_poller) + return sdk_no_wait(no_wait, smc.create_or_update, resource_group_name, deployment_name, deployment) + + if validate: + return smc.validate(resource_group_name, deployment_name, properties) + return sdk_no_wait(no_wait, smc.create_or_update, resource_group_name, deployment_name, properties) + + +def _ensure_default_log_analytics_workspace_for_monitoring(cmd, subscription_id, + cluster_resource_group_name, cluster_name): + # mapping for azure public cloud + # log analytics workspaces cannot be created in WCUS region due to capacity limits + # so mapped to EUS per discussion with log analytics team + # pylint: disable=too-many-locals,too-many-statements + + azurecloud_location_to_oms_region_code_map = { + "australiasoutheast": "ASE", + "australiaeast": "EAU", + "australiacentral": "CAU", + "canadacentral": "CCA", + "centralindia": "CIN", + "centralus": "CUS", + "eastasia": "EA", + "eastus": "EUS", + "eastus2": "EUS2", + "eastus2euap": "EAP", + "francecentral": "PAR", + "japaneast": "EJP", + "koreacentral": "SE", + "northeurope": "NEU", + "southcentralus": "SCUS", + "southeastasia": "SEA", + "uksouth": "SUK", + "usgovvirginia": "USGV", + "westcentralus": "EUS", + "westeurope": "WEU", + "westus": "WUS", + "westus2": "WUS2" + } + azurecloud_region_to_oms_region_map = { + "australiacentral": "australiacentral", + "australiacentral2": "australiacentral", + "australiaeast": "australiaeast", + "australiasoutheast": "australiasoutheast", + "brazilsouth": "southcentralus", + "canadacentral": "canadacentral", + "canadaeast": "canadacentral", + "centralus": "centralus", + "centralindia": "centralindia", + "eastasia": "eastasia", + "eastus": "eastus", + "eastus2": "eastus2", + "francecentral": "francecentral", + "francesouth": "francecentral", + "japaneast": "japaneast", + "japanwest": "japaneast", + "koreacentral": "koreacentral", + "koreasouth": "koreacentral", + "northcentralus": "eastus", + "northeurope": "northeurope", + "southafricanorth": "westeurope", + "southafricawest": "westeurope", + "southcentralus": "southcentralus", + "southeastasia": "southeastasia", + "southindia": "centralindia", + "uksouth": "uksouth", + "ukwest": "uksouth", + "westcentralus": "eastus", + "westeurope": "westeurope", + "westindia": "centralindia", + "westus": "westus", + "westus2": "westus2" + } + + # mapping for azure china cloud + # currently log analytics supported only China East 2 region + azurechina_location_to_oms_region_code_map = { + "chinaeast": "EAST2", + "chinaeast2": "EAST2", + "chinanorth": "EAST2", + "chinanorth2": "EAST2" + } + azurechina_region_to_oms_region_map = { + "chinaeast": "chinaeast2", + "chinaeast2": "chinaeast2", + "chinanorth": "chinaeast2", + "chinanorth2": "chinaeast2" + } + + # mapping for azure us governmner cloud + azurefairfax_location_to_oms_region_code_map = { + "usgovvirginia": "USGV" + } + azurefairfax_region_to_oms_region_map = { + "usgovvirginia": "usgovvirginia" + } + + cluster_location = '' + resources = cf_resources(cmd.cli_ctx, subscription_id) + + cluster_resource_id = '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Kubernetes' \ + '/connectedClusters/{2}'.format(subscription_id, cluster_resource_group_name, cluster_name) + try: + resource = resources.get_by_id(cluster_resource_id, '2020-01-01-preview') + cluster_location = resource.location.lower() + except CloudError as ex: + raise ex + + cloud_name = cmd.cli_ctx.cloud.name.lower() + workspace_region = "eastus" + workspace_region_code = "EUS" + + # sanity check that locations and clouds match. + if ((cloud_name == 'azurecloud' and azurechina_region_to_oms_region_map.get(cluster_location, False)) or + (cloud_name == 'azurecloud' and azurefairfax_region_to_oms_region_map.get(cluster_location, False))): + raise InvalidArgumentValueError( + 'Wrong cloud (azurecloud) setting for region {}, please use "az cloud set ..."' + .format(cluster_location) + ) + + if ((cloud_name == 'azurechinacloud' and azurecloud_region_to_oms_region_map.get(cluster_location, False)) or + (cloud_name == 'azurechinacloud' and azurefairfax_region_to_oms_region_map.get(cluster_location, False))): + raise InvalidArgumentValueError( + 'Wrong cloud (azurechinacloud) setting for region {}, please use "az cloud set ..."' + .format(cluster_location) + ) + + if ((cloud_name == 'azureusgovernment' and azurecloud_region_to_oms_region_map.get(cluster_location, False)) or + (cloud_name == 'azureusgovernment' and azurechina_region_to_oms_region_map.get(cluster_location, False))): + raise InvalidArgumentValueError( + 'Wrong cloud (azureusgovernment) setting for region {}, please use "az cloud set ..."' + .format(cluster_location) + ) + + if cloud_name == 'azurecloud': + workspace_region = azurecloud_region_to_oms_region_map.get(cluster_location, "eastus") + workspace_region_code = azurecloud_location_to_oms_region_code_map.get(workspace_region, "EUS") + elif cloud_name == 'azurechinacloud': + workspace_region = azurechina_region_to_oms_region_map.get(cluster_location, "chinaeast2") + workspace_region_code = azurechina_location_to_oms_region_code_map.get(workspace_region, "EAST2") + elif cloud_name == 'azureusgovernment': + workspace_region = azurefairfax_region_to_oms_region_map.get(cluster_location, "usgovvirginia") + workspace_region_code = azurefairfax_location_to_oms_region_code_map.get(workspace_region, "USGV") + else: + logger.error("AKS Monitoring addon not supported in cloud : %s", cloud_name) + + default_workspace_resource_group = 'DefaultResourceGroup-' + workspace_region_code + default_workspace_name = 'DefaultWorkspace-{0}-{1}'.format(subscription_id, workspace_region_code) + default_workspace_resource_id = '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.OperationalInsights' \ + '/workspaces/{2}'.format(subscription_id, default_workspace_resource_group, default_workspace_name) + resource_groups = cf_resource_groups(cmd.cli_ctx, subscription_id) + + # check if default RG exists + if resource_groups.check_existence(default_workspace_resource_group): + try: + resource = resources.get_by_id(default_workspace_resource_id, '2015-11-01-preview') + return resource.id + except CloudError as ex: + if ex.status_code != 404: + raise ex + else: + resource_groups.create_or_update(default_workspace_resource_group, { + 'location': workspace_region}) + + default_workspace_params = { + 'location': workspace_region, + 'properties': { + 'sku': { + 'name': 'standalone' + } + } + } + async_poller = resources.create_or_update_by_id(default_workspace_resource_id, '2015-11-01-preview', + default_workspace_params) + + ws_resource_id = '' + while True: + result = async_poller.result(15) + if async_poller.done(): + ws_resource_id = result.id + break + + return ws_resource_id + + +def _ensure_container_insights_for_monitoring(cmd, workspace_resource_id): + # extract subscription ID and resource group from workspace_resource_id URL + parsed = parse_resource_id(workspace_resource_id) + subscription_id, resource_group = parsed["subscription"], parsed["resource_group"] + + resources = cf_resources(cmd.cli_ctx, subscription_id) + try: + resource = resources.get_by_id(workspace_resource_id, '2015-11-01-preview') + location = resource.location + except CloudError as ex: + raise ex + + unix_time_in_millis = int( + (datetime.datetime.utcnow() - datetime.datetime.utcfromtimestamp(0)).total_seconds() * 1000.0) + + solution_deployment_name = 'ContainerInsights-{}'.format(unix_time_in_millis) + + # pylint: disable=line-too-long + template = { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Azure Monitor Log Analytics Resource ID" + } + }, + "workspaceRegion": { + "type": "string", + "metadata": { + "description": "Azure Monitor Log Analytics workspace region" + } + }, + "solutionDeploymentName": { + "type": "string", + "metadata": { + "description": "Name of the solution deployment" + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "name": "[parameters('solutionDeploymentName')]", + "apiVersion": "2017-05-10", + "subscriptionId": "[split(parameters('workspaceResourceId'),'/')[2]]", + "resourceGroup": "[split(parameters('workspaceResourceId'),'/')[4]]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "variables": {}, + "resources": [ + { + "apiVersion": "2015-11-01-preview", + "type": "Microsoft.OperationsManagement/solutions", + "location": "[parameters('workspaceRegion')]", + "name": "[Concat('ContainerInsights', '(', split(parameters('workspaceResourceId'),'/')" + "[8], ')')]", + "properties": { + "workspaceResourceId": "[parameters('workspaceResourceId')]" + }, + "plan": { + "name": "[Concat('ContainerInsights', '(', split(parameters('workspaceResourceId')," + "'/')[8], ')')]", + "product": "[Concat('OMSGallery/', 'ContainerInsights')]", + "promotionCode": "", + "publisher": "Microsoft" + } + } + ] + }, + "parameters": {} + } + } + ] + } + + params = { + "workspaceResourceId": { + "value": workspace_resource_id + }, + "workspaceRegion": { + "value": location + }, + "solutionDeploymentName": { + "value": solution_deployment_name + } + } + + deployment_name = 'arc-k8s-monitoring-{}'.format(unix_time_in_millis) + # publish the Container Insights solution to the Log Analytics workspace + return _invoke_deployment(cmd, resource_group, deployment_name, template, params, + validate=False, no_wait=False, subscription_id=subscription_id) + + +def _get_container_insights_settings(cmd, cluster_resource_group_name, cluster_name, configuration_settings, + configuration_protected_settings, is_ci_extension_type): + + subscription_id = get_subscription_id(cmd.cli_ctx) + workspace_resource_id = '' + + if configuration_settings is not None: + if 'loganalyticsworkspaceresourceid' in configuration_settings: + configuration_settings['logAnalyticsWorkspaceResourceID'] = \ + configuration_settings.pop('loganalyticsworkspaceresourceid') + + if 'logAnalyticsWorkspaceResourceID' in configuration_settings: + workspace_resource_id = configuration_settings['logAnalyticsWorkspaceResourceID'] + + workspace_resource_id = workspace_resource_id.strip() + + if configuration_protected_settings is not None: + if 'proxyEndpoint' in configuration_protected_settings: + # current supported format for proxy endpoint is http(s)://:@: + # do some basic validation since the ci agent does the complete validation + proxy = configuration_protected_settings['proxyEndpoint'].strip().lower() + proxy_parts = proxy.split('://') + if (not proxy) or (not proxy.startswith('http://') and not proxy.startswith('https://')) or \ + (len(proxy_parts) != 2): + raise InvalidArgumentValueError( + 'proxyEndpoint url should in this format http(s)://:@:' + ) + logger.info("successfully validated proxyEndpoint url hence passing proxy endpoint to extension") + configuration_protected_settings['omsagent.proxy'] = configuration_protected_settings['proxyEndpoint'] + + if not workspace_resource_id: + workspace_resource_id = _ensure_default_log_analytics_workspace_for_monitoring( + cmd, subscription_id, cluster_resource_group_name, cluster_name) + else: + if not is_valid_resource_id(workspace_resource_id): + raise InvalidArgumentValueError('{} is not a valid Azure resource ID.'.format(workspace_resource_id)) + + if is_ci_extension_type: + _ensure_container_insights_for_monitoring(cmd, workspace_resource_id).result() + + # extract subscription ID and resource group from workspace_resource_id URL + parsed = parse_resource_id(workspace_resource_id) + workspace_sub_id, workspace_rg_name, workspace_name = \ + parsed["subscription"], parsed["resource_group"], parsed["name"] + + log_analytics_client = cf_log_analytics(cmd.cli_ctx, workspace_sub_id) + log_analytics_workspace = log_analytics_client.workspaces.get(workspace_rg_name, workspace_name) + if not log_analytics_workspace: + raise InvalidArgumentValueError( + 'Fails to retrieve workspace by {}'.format(workspace_name)) + + shared_keys = log_analytics_client.shared_keys.get_shared_keys( + workspace_rg_name, workspace_name) + if not shared_keys: + raise InvalidArgumentValueError('Fails to retrieve shared key for workspace {}'.format( + log_analytics_workspace)) + configuration_protected_settings['omsagent.secret.wsid'] = log_analytics_workspace.customer_id + configuration_settings['logAnalyticsWorkspaceResourceID'] = workspace_resource_id + configuration_protected_settings['omsagent.secret.key'] = shared_keys.primary_shared_key + # set the domain for the ci agent for non azure public clouds + cloud_name = cmd.cli_ctx.cloud.name + if cloud_name.lower() == 'azurechinacloud': + configuration_settings['omsagent.domain'] = 'opinsights.azure.cn' + elif cloud_name.lower() == 'azureusgovernment': + configuration_settings['omsagent.domain'] = 'opinsights.azure.us' + elif cloud_name.lower() == 'usnat': + configuration_settings['omsagent.domain'] = 'opinsights.azure.eaglex.ic.gov' + elif cloud_name.lower() == 'ussec': + configuration_settings['omsagent.domain'] = 'opinsights.azure.microsoft.scloud' diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py new file mode 100644 index 00000000000..9a69199f838 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py @@ -0,0 +1,57 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument + +from azext_k8s_extension.vendored_sdks.models import ExtensionInstance +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate +from azext_k8s_extension.vendored_sdks.models import ScopeCluster +from azext_k8s_extension.vendored_sdks.models import ScopeNamespace +from azext_k8s_extension.vendored_sdks.models import Scope + +from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel + + +class DefaultExtension(PartnerExtensionModel): + def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, + scope, auto_upgrade_minor_version, release_train, version, target_namespace, + release_namespace, configuration_settings, configuration_protected_settings, + configuration_settings_file, configuration_protected_settings_file): + + """Default validations & defaults for Create + Must create and return a valid 'ExtensionInstance' object. + + """ + ext_scope = None + if scope is not None: + if scope.lower() == 'cluster': + scope_cluster = ScopeCluster(release_namespace=release_namespace) + ext_scope = Scope(cluster=scope_cluster, namespace=None) + elif scope.lower() == 'namespace': + scope_namespace = ScopeNamespace(target_namespace=target_namespace) + ext_scope = Scope(namespace=scope_namespace, cluster=None) + + create_identity = False + extension_instance = ExtensionInstance( + extension_type=extension_type, + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version, + scope=ext_scope, + configuration_settings=configuration_settings, + configuration_protected_settings=configuration_protected_settings + ) + return extension_instance, name, create_identity + + def Update(self, extension, auto_upgrade_minor_version, release_train, version): + """Default validations & defaults for Update + Must create and return a valid 'ExtensionInstanceUpdate' object. + + """ + return ExtensionInstanceUpdate( + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version + ) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py new file mode 100644 index 00000000000..96c489644e7 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py @@ -0,0 +1,23 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from abc import ABC, abstractmethod +from azext_k8s_extension.vendored_sdks.models import ExtensionInstance +from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate + + +class PartnerExtensionModel(ABC): + @abstractmethod + def Create(self, cmd, client, resource_group_name: str, cluster_name: str, name: str, cluster_type: str, + extension_type: str, scope: str, auto_upgrade_minor_version: bool, release_train: str, version: str, + target_namespace: str, release_namespace: str, configuration_settings: dict, + configuration_protected_settings: dict, configuration_settings_file: str, + configuration_protected_settings_file: str) -> ExtensionInstance: + pass + + @abstractmethod + def Update(self, extension: ExtensionInstance, auto_upgrade_minor_version: bool, + release_train: str, version: str) -> ExtensionInstanceUpdate: + pass diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py new file mode 100644 index 00000000000..9ccaff6c1b8 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/__init__.py @@ -0,0 +1,5 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ----------------------------------------------------------------------------- diff --git a/src/k8s-extension/azext_k8s_extension/tests/__init__.py b/src/k8s-extension/azext_k8s_extension/tests/__init__.py new file mode 100644 index 00000000000..99c0f28cd71 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/tests/__init__.py @@ -0,0 +1,5 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ----------------------------------------------------------------------------- diff --git a/src/k8s-extension/azext_k8s_extension/tests/latest/__init__.py b/src/k8s-extension/azext_k8s_extension/tests/latest/__init__.py new file mode 100644 index 00000000000..99c0f28cd71 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/tests/latest/__init__.py @@ -0,0 +1,5 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ----------------------------------------------------------------------------- diff --git a/src/k8s-extension/azext_k8s_extension/tests/latest/recordings/test_k8s_extension.yaml b/src/k8s-extension/azext_k8s_extension/tests/latest/recordings/test_k8s_extension.yaml new file mode 100644 index 00000000000..127b21ac873 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/tests/latest/recordings/test_k8s_extension.yaml @@ -0,0 +1,270 @@ +interactions: +- request: + body: '{"properties": {"extensionType": "microsoft.openservicemesh", "autoUpgradeMinorVersion": + false, "releaseTrain": "staging", "version": "0.1.0", "scope": {"cluster": {}}, + "configurationSettings": {}, "configurationProtectedSettings": {}}, "location": + ""}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-extension create + Connection: + - keep-alive + Content-Length: + - '252' + Content-Type: + - application/json; charset=utf-8 + ParameterSetName: + - -g -n -c --cluster-type --extension-type --release-train --version + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.1.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh?api-version=2020-07-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh","name":"openservice-mesh","type":"Microsoft.KubernetesConfiguration/extensions","properties":{"configurationSettings":{},"statuses":[],"extensionType":"microsoft.openservicemesh","autoUpgradeMinorVersion":false,"releaseTrain":"staging","version":"0.1.0","scope":{"cluster":{"releaseNamespace":"arc-osm-system"}},"installState":"Pending","lastStatusTime":null,"errorInfo":{},"creationTime":"2021-03-08T23:14:12.4010326+00:00","lastModifiedTime":"2021-03-08T23:14:12.4010327+00:00"}}' + headers: + api-supported-versions: + - 2020-07-01-Preview + cache-control: + - no-cache + content-length: + - '708' + content-type: + - application/json; charset=utf-8 + date: + - Mon, 08 Mar 2021 23:14:11 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding,Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-extension list + Connection: + - keep-alive + ParameterSetName: + - -c -g --cluster-type + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.1.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions?api-version=2020-07-01-preview + response: + body: + string: '{"value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh","name":"openservice-mesh","type":"Microsoft.KubernetesConfiguration/extensions","properties":{"extensionType":"microsoft.openservicemesh","autoUpgradeMinorVersion":false,"releaseTrain":"staging","version":"0.1.0","scope":{"cluster":{"releaseNamespace":"arc-osm-system"}},"installState":"Pending","lastStatusTime":null,"errorInfo":{},"creationTime":"2021-03-08T23:14:12.4010326+00:00","lastModifiedTime":"2021-03-08T23:14:12.4010327+00:00"}},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/hci22jan21","name":"hci22jan21","type":"Microsoft.KubernetesConfiguration/extensions","properties":{"extensionType":"microsoft.azstackhci.operator","autoUpgradeMinorVersion":true,"releaseTrain":"stable","version":"1.0.0","scope":{"cluster":{"releaseNamespace":null}},"installState":"Pending","lastStatusTime":null,"errorInfo":{},"creationTime":"2021-01-22T20:49:34.3336157+00:00","lastModifiedTime":"2021-01-22T20:49:34.3336249+00:00"}}],"nextLink":null}' + headers: + api-supported-versions: + - 2020-07-01-Preview + cache-control: + - no-cache + content-length: + - '1341' + content-type: + - application/json; charset=utf-8 + date: + - Mon, 08 Mar 2021 23:14:13 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding,Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-extension show + Connection: + - keep-alive + ParameterSetName: + - -c -g -n --cluster-type + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.1.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh?api-version=2020-07-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh","name":"openservice-mesh","type":"Microsoft.KubernetesConfiguration/extensions","properties":{"configurationSettings":{},"statuses":[],"extensionType":"microsoft.openservicemesh","autoUpgradeMinorVersion":false,"releaseTrain":"staging","version":"0.1.0","scope":{"cluster":{"releaseNamespace":"arc-osm-system"}},"installState":"Pending","lastStatusTime":null,"errorInfo":{},"creationTime":"2021-03-08T23:14:12.4010326+00:00","lastModifiedTime":"2021-03-08T23:14:12.4010327+00:00"}}' + headers: + api-supported-versions: + - 2020-07-01-Preview + cache-control: + - no-cache + content-length: + - '708' + content-type: + - application/json; charset=utf-8 + date: + - Mon, 08 Mar 2021 23:14:14 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding,Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-extension delete + Connection: + - keep-alive + Content-Length: + - '0' + ParameterSetName: + - -g -c -n --cluster-type -y + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.1.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/openservice-mesh?api-version=2020-07-01-preview + response: + body: + string: '{"content":null,"statusCode":200,"headers":[],"version":"1.1","reasonPhrase":"OK","trailingHeaders":[],"requestMessage":null,"isSuccessStatusCode":true}' + headers: + api-supported-versions: + - 2020-07-01-Preview + cache-control: + - no-cache + content-length: + - '152' + content-type: + - application/json; charset=utf-8 + date: + - Mon, 08 Mar 2021 23:14:14 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-deletes: + - '14999' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-extension list + Connection: + - keep-alive + ParameterSetName: + - -c -g --cluster-type + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.1.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions?api-version=2020-07-01-preview + response: + body: + string: '{"value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/extensions/hci22jan21","name":"hci22jan21","type":"Microsoft.KubernetesConfiguration/extensions","properties":{"extensionType":"microsoft.azstackhci.operator","autoUpgradeMinorVersion":true,"releaseTrain":"stable","version":"1.0.0","scope":{"cluster":{"releaseNamespace":null}},"installState":"Pending","lastStatusTime":null,"errorInfo":{},"creationTime":"2021-01-22T20:49:34.3336157+00:00","lastModifiedTime":"2021-01-22T20:49:34.3336249+00:00"}}],"nextLink":null}' + headers: + api-supported-versions: + - 2020-07-01-Preview + cache-control: + - no-cache + content-length: + - '673' + content-type: + - application/json; charset=utf-8 + date: + - Mon, 08 Mar 2021 23:14:16 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding,Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +version: 1 diff --git a/src/k8s-extension/azext_k8s_extension/tests/latest/test_k8s_extension_scenario.py b/src/k8s-extension/azext_k8s_extension/tests/latest/test_k8s_extension_scenario.py new file mode 100644 index 00000000000..0e53c9e6691 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/tests/latest/test_k8s_extension_scenario.py @@ -0,0 +1,67 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import os +import unittest + +from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer, record_only) + + +TEST_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '..')) + + +class K8sExtensionScenarioTest(ScenarioTest): + @record_only() + @ResourceGroupPreparer(name_prefix='cli_test_k8s_extension') + def test_k8s_extension(self): + resource_type = 'microsoft.openservicemesh' + self.kwargs.update({ + 'name': 'openservice-mesh', + 'rg': 'nanthirg0923', + 'cluster_name': 'nanthicluster0923', + 'cluster_type': 'connectedClusters', + 'extension_type': resource_type, + 'release_train': 'staging', + 'version': '0.1.0' + }) + + self.cmd('k8s-extension create -g {rg} -n {name} -c {cluster_name} --cluster-type {cluster_type} --extension-type {extension_type} --release-train {release_train} --version {version}', checks=[ + self.check('name', '{name}'), + self.check('releaseTrain', '{release_train}'), + self.check('version', '{version}'), + self.check('resourceGroup', '{rg}'), + self.check('extensionType', '{extension_type}') + ]) + + # Update is disabled for now + # self.cmd('k8s-extension update -g {rg} -n {name} --tags foo=boo', checks=[ + # self.check('tags.foo', 'boo') + # ]) + + installed_exts = self.cmd('k8s-extension list -c {cluster_name} -g {rg} --cluster-type {cluster_type}').get_output_in_json() + found_extension = False + for item in installed_exts: + if item['extensionType'] == resource_type: + found_extension = True + break + self.assertTrue(found_extension) + + self.cmd('k8s-extension show -c {cluster_name} -g {rg} -n {name} --cluster-type {cluster_type}', checks=[ + self.check('name', '{name}'), + self.check('releaseTrain', '{release_train}'), + self.check('version', '{version}'), + self.check('resourceGroup', '{rg}'), + self.check('extensionType', '{extension_type}') + ]) + + self.cmd('k8s-extension delete -g {rg} -c {cluster_name} -n {name} --cluster-type {cluster_type} -y') + + installed_exts = self.cmd('k8s-extension list -c {cluster_name} -g {rg} --cluster-type {cluster_type}').get_output_in_json() + found_extension = False + for item in installed_exts: + if item['extensionType'] == resource_type: + found_extension = True + break + self.assertFalse(found_extension) diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py new file mode 100644 index 00000000000..874177b4d34 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from ._configuration import SourceControlConfigurationClientConfiguration +from ._source_control_configuration_client import SourceControlConfigurationClient +__all__ = ['SourceControlConfigurationClient', 'SourceControlConfigurationClientConfiguration'] + +from .version import VERSION + +__version__ = VERSION + diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py new file mode 100644 index 00000000000..5043ed69594 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_configuration.py @@ -0,0 +1,49 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- +from msrestazure import AzureConfiguration + +from .version import VERSION + + +class SourceControlConfigurationClientConfiguration(AzureConfiguration): + """Configuration for SourceControlConfigurationClient + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credentials: Credentials needed for the client to connect to Azure. + :type credentials: :mod:`A msrestazure Credentials + object` + :param subscription_id: The Azure subscription ID. This is a + GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000) + :type subscription_id: str + :param str base_url: Service URL + """ + + def __init__( + self, credentials, subscription_id, base_url=None): + + if credentials is None: + raise ValueError("Parameter 'credentials' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + if not base_url: + base_url = 'https://management.azure.com' + + super(SourceControlConfigurationClientConfiguration, self).__init__(base_url) + + # Starting Autorest.Python 4.0.64, make connection pool activated by default + self.keep_alive = True + + self.add_user_agent('azure-mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self.add_user_agent('Azure-SDK-For-Python') + + self.credentials = credentials + self.subscription_id = subscription_id diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/_source_control_configuration_client.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_source_control_configuration_client.py new file mode 100644 index 00000000000..a77176d8cb1 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/_source_control_configuration_client.py @@ -0,0 +1,60 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.service_client import SDKClient +from msrest import Serializer, Deserializer + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from .operations import ExtensionsOperations +from . import models + + +class SourceControlConfigurationClient(SDKClient): + """KubernetesConfiguration Client + + :ivar config: Configuration for client. + :vartype config: SourceControlConfigurationClientConfiguration + + :ivar source_control_configurations: SourceControlConfigurations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.operations.Operations + :ivar extensions: Extensions operations + :vartype extensions: azure.mgmt.kubernetesconfiguration.operations.ExtensionsOperations + + :param credentials: Credentials needed for the client to connect to Azure. + :type credentials: :mod:`A msrestazure Credentials + object` + :param subscription_id: The Azure subscription ID. This is a + GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000) + :type subscription_id: str + :param str base_url: Service URL + """ + + def __init__( + self, credentials, subscription_id, base_url=None): + + self.config = SourceControlConfigurationClientConfiguration(credentials, subscription_id, base_url) + super(SourceControlConfigurationClient, self).__init__(self.config.credentials, self.config) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self.api_version = '2020-07-01-preview' + self._serialize = Serializer(client_models) + self._deserialize = Deserializer(client_models) + + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self.config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self.config, self._serialize, self._deserialize) + self.extensions = ExtensionsOperations( + self._client, self.config, self._serialize, self._deserialize) diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py new file mode 100644 index 00000000000..e74cb56832b --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/__init__.py @@ -0,0 +1,94 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +try: + from ._models_py3 import ComplianceStatus + from ._models_py3 import ConfigurationIdentity + from ._models_py3 import ErrorDefinition + from ._models_py3 import ErrorResponse, ErrorResponseException + from ._models_py3 import ExtensionInstance + from ._models_py3 import ExtensionInstanceUpdate + from ._models_py3 import ExtensionStatus + from ._models_py3 import HelmOperatorProperties + from ._models_py3 import ProxyResource + from ._models_py3 import Resource + from ._models_py3 import ResourceProviderOperation + from ._models_py3 import ResourceProviderOperationDisplay + from ._models_py3 import Result + from ._models_py3 import Scope + from ._models_py3 import ScopeCluster + from ._models_py3 import ScopeNamespace + from ._models_py3 import SourceControlConfiguration + from ._models_py3 import SystemData +except (SyntaxError, ImportError): + from ._models import ComplianceStatus + from ._models import ConfigurationIdentity + from ._models import ErrorDefinition + from ._models import ErrorResponse, ErrorResponseException + from ._models import ExtensionInstance + from ._models import ExtensionInstanceUpdate + from ._models import ExtensionStatus + from ._models import HelmOperatorProperties + from ._models import ProxyResource + from ._models import Resource + from ._models import ResourceProviderOperation + from ._models import ResourceProviderOperationDisplay + from ._models import Result + from ._models import Scope + from ._models import ScopeCluster + from ._models import ScopeNamespace + from ._models import SourceControlConfiguration + from ._models import SystemData +from ._paged_models import ExtensionInstancePaged +from ._paged_models import ResourceProviderOperationPaged +from ._paged_models import SourceControlConfigurationPaged +from ._source_control_configuration_client_enums import ( + ComplianceStateType, + MessageLevelType, + OperatorType, + OperatorScopeType, + ProvisioningStateType, + InstallStateType, + LevelType, + ResourceIdentityType, +) + +__all__ = [ + 'ComplianceStatus', + 'ConfigurationIdentity', + 'ErrorDefinition', + 'ErrorResponse', 'ErrorResponseException', + 'ExtensionInstance', + 'ExtensionInstanceUpdate', + 'ExtensionStatus', + 'HelmOperatorProperties', + 'ProxyResource', + 'Resource', + 'ResourceProviderOperation', + 'ResourceProviderOperationDisplay', + 'Result', + 'Scope', + 'ScopeCluster', + 'ScopeNamespace', + 'SourceControlConfiguration', + 'SystemData', + 'SourceControlConfigurationPaged', + 'ResourceProviderOperationPaged', + 'ExtensionInstancePaged', + 'ComplianceStateType', + 'MessageLevelType', + 'OperatorType', + 'OperatorScopeType', + 'ProvisioningStateType', + 'InstallStateType', + 'LevelType', + 'ResourceIdentityType', +] diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py new file mode 100644 index 00000000000..f74ea5d809e --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models.py @@ -0,0 +1,726 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.serialization import Model +from msrest.exceptions import HttpOperationError + + +class CloudError(Model): + """CloudError. + """ + + _attribute_map = { + } + + +class ComplianceStatus(Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar compliance_state: The compliance state of the configuration. + Possible values include: 'Pending', 'Compliant', 'Noncompliant', + 'Installed', 'Failed' + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: + 'Error', 'Warning', 'Information' + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = kwargs.get('last_config_applied', None) + self.message = kwargs.get('message', None) + self.message_level = kwargs.get('message_level', None) + + +class ConfigurationIdentity(Model): + """Identity for the managed cluster. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar principal_id: The principal id of the system assigned identity which + is used by the configuration. + :vartype principal_id: str + :ivar tenant_id: The tenant id of the system assigned identity which is + used by the configuration. + :vartype tenant_id: str + :param type: The type of identity used for the configuration. Type + 'SystemAssigned' will use an implicitly created identity. Type 'None' will + not use Managed Identity for the configuration. Possible values include: + 'SystemAssigned', 'None' + :type type: str or + ~azure.mgmt.kubernetesconfiguration.models.ResourceIdentityType + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'ResourceIdentityType'}, + } + + def __init__(self, **kwargs): + super(ConfigurationIdentity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = kwargs.get('type', None) + + +class ErrorDefinition(Model): + """Error definition. + + All required parameters must be populated in order to send to Azure. + + :param code: Required. Service specific error code which serves as the + substatus for the HTTP error code. + :type code: str + :param message: Required. Description of the error. + :type message: str + """ + + _validation = { + 'code': {'required': True}, + 'message': {'required': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ErrorDefinition, self).__init__(**kwargs) + self.code = kwargs.get('code', None) + self.message = kwargs.get('message', None) + + +class ErrorResponse(Model): + """Error response. + + :param error: Error definition. + :type error: ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDefinition'}, + } + + def __init__(self, **kwargs): + super(ErrorResponse, self).__init__(**kwargs) + self.error = kwargs.get('error', None) + + +class ErrorResponseException(HttpOperationError): + """Server responsed with exception of type: 'ErrorResponse'. + + :param deserialize: A deserializer + :param response: Server response to be deserialized. + """ + + def __init__(self, deserialize, response, *args): + + super(ErrorResponseException, self).__init__(deserialize, response, 'ErrorResponse', *args) + + +class Resource(Model): + """The Resource model definition. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__(self, **kwargs): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + self.system_data = kwargs.get('system_data', None) + + +class ProxyResource(Resource): + """ARM proxy resource. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__(self, **kwargs): + super(ProxyResource, self).__init__(**kwargs) + + +class ExtensionInstance(ProxyResource): + """The Extension Instance object. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param location: Location of resource type + :type location: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + :param extension_type: Type of the Extension, of which this resource is an + instance of. It must be one of the Extension Types registered with + Microsoft.KubernetesConfiguration by the Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this instance + participates in auto upgrade of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension instance, if + it is 'pinned' to a specific version. autoUpgradeMinorVersion must be + 'false'. + :type version: str + :param scope: Scope at which the extension instance is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs + for configuring this instance of the extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are + sensitive, as name-value pairs for configuring this instance of the + extension. + :type configuration_protected_settings: dict[str, str] + :param install_state: Status of installation of this instance of the + extension. Possible values include: 'Pending', 'Installed', 'Failed' + :type install_state: str or + ~azure.mgmt.kubernetesconfiguration.models.InstallStateType + :param statuses: Status from this instance of the extension. + :type statuses: + list[~azure.mgmt.kubernetesconfiguration.models.ExtensionStatus] + :ivar creation_time: DateLiteral (per ISO8601) noting the time the + resource was created by the client (user). + :vartype creation_time: str + :ivar last_modified_time: DateLiteral (per ISO8601) noting the time the + resource was modified by the client (user). + :vartype last_modified_time: str + :ivar last_status_time: DateLiteral (per ISO8601) noting the time of last + status from the agent. + :vartype last_status_time: str + :ivar error_info: Error information from the Agent - e.g. errors during + installation. + :vartype error_info: + ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + :param identity: The identity of the configuration. + :type identity: + ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'creation_time': {'readonly': True}, + 'last_modified_time': {'readonly': True}, + 'last_status_time': {'readonly': True}, + 'error_info': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'location': {'key': 'location', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'install_state': {'key': 'properties.installState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, + 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, + 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, + } + + def __init__(self, **kwargs): + super(ExtensionInstance, self).__init__(**kwargs) + self.location = kwargs.get('location', None) + self.extension_type = kwargs.get('extension_type', None) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', None) + self.release_train = kwargs.get('release_train', None) + self.version = kwargs.get('version', None) + self.scope = kwargs.get('scope', None) + self.configuration_settings = kwargs.get('configuration_settings', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.install_state = kwargs.get('install_state', None) + self.statuses = kwargs.get('statuses', None) + self.creation_time = None + self.last_modified_time = None + self.last_status_time = None + self.error_info = None + self.identity = kwargs.get('identity', None) + + +class ExtensionInstanceUpdate(Model): + """Update Extension Instance request object. + + :param auto_upgrade_minor_version: Flag to note if this instance + participates in Extension Lifecycle Management or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version number of extension, to 'pin' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + """ + + _attribute_map = { + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ExtensionInstanceUpdate, self).__init__(**kwargs) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', None) + self.release_train = kwargs.get('release_train', None) + self.version = kwargs.get('version', None) + + +class ExtensionStatus(Model): + """Status from this instance of the extension. + + :param code: Status code provided by the Extension + :type code: str + :param display_status: Short description of status of this instance of the + extension. + :type display_status: str + :param level: Level of the status. Possible values include: 'Error', + 'Warning', 'Information'. Default value: "Information" . + :type level: str or ~azure.mgmt.kubernetesconfiguration.models.LevelType + :param message: Detailed message of the status from the Extension + instance. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation + status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ExtensionStatus, self).__init__(**kwargs) + self.code = kwargs.get('code', None) + self.display_status = kwargs.get('display_status', None) + self.level = kwargs.get('level', "Information") + self.message = kwargs.get('message', None) + self.time = kwargs.get('time', None) + + +class HelmOperatorProperties(Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = kwargs.get('chart_version', None) + self.chart_values = kwargs.get('chart_values', None) + + +class ResourceProviderOperation(Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :param name: Operation name, in format of + {provider}/{resource}/{operation} + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation + applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__(self, **kwargs): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = kwargs.get('name', None) + self.display = kwargs.get('display', None) + self.is_data_action = None + + +class ResourceProviderOperationDisplay(Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = kwargs.get('provider', None) + self.resource = kwargs.get('resource', None) + self.operation = kwargs.get('operation', None) + self.description = kwargs.get('description', None) + + +class Result(Model): + """Sample result definition. + + :param sample_property: Sample property of type string + :type sample_property: str + """ + + _attribute_map = { + 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(Result, self).__init__(**kwargs) + self.sample_property = kwargs.get('sample_property', None) + + +class Scope(Model): + """Scope of the extensionInstance. It can be either Cluster or Namespace; but + not both. + + :param cluster: Specifies that the scope of the extensionInstance is + Cluster + :type cluster: ~azure.mgmt.kubernetesconfiguration.models.ScopeCluster + :param namespace: Specifies that the scope of the extensionInstance is + Namespace + :type namespace: ~azure.mgmt.kubernetesconfiguration.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__(self, **kwargs): + super(Scope, self).__init__(**kwargs) + self.cluster = kwargs.get('cluster', None) + self.namespace = kwargs.get('namespace', None) + + +class ScopeCluster(Model): + """Specifies that the scope of the extensionInstance is Cluster. + + :param release_namespace: Namespace where the extension Release must be + placed, for a Cluster scoped extensionInstance. If this namespace does + not exist, it will be created + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = kwargs.get('release_namespace', None) + + +class ScopeNamespace(Model): + """Specifies that the scope of the extensionInstance is Namespace. + + :param target_namespace: Namespace where the extensionInstance will be + created for an Namespace scoped extensionInstance. If this namespace does + not exist, it will be created + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = kwargs.get('target_namespace', None) + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is + installed to. Maximum of 253 lower case alphanumeric characters, hyphen + and period only. Default value: "default" . + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying + the specific configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: + 'Flux' + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string + format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected + configuration settings for the configuration + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. + Possible values include: 'cluster', 'namespace'. Default value: "cluster" + . + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl + configuration (either generated within the cluster or provided by the + user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents + containing public SSH keys required to access private Git instances + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git + configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. + Possible values include: 'Accepted', 'Deleting', 'Running', 'Succeeded', + 'Failed' + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__(self, **kwargs): + super(SourceControlConfiguration, self).__init__(**kwargs) + self.repository_url = kwargs.get('repository_url', None) + self.operator_namespace = kwargs.get('operator_namespace', "default") + self.operator_instance_name = kwargs.get('operator_instance_name', None) + self.operator_type = kwargs.get('operator_type', None) + self.operator_params = kwargs.get('operator_params', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.operator_scope = kwargs.get('operator_scope', "cluster") + self.repository_public_key = None + self.ssh_known_hosts_contents = kwargs.get('ssh_known_hosts_contents', None) + self.enable_helm_operator = kwargs.get('enable_helm_operator', None) + self.helm_operator_properties = kwargs.get('helm_operator_properties', None) + self.provisioning_state = None + self.compliance_status = None + + +class SystemData(Model): + """Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar created_by: A string identifier for the identity that created the + resource + :vartype created_by: str + :ivar created_by_type: The type of identity that created the resource: + user, application, managedIdentity, key + :vartype created_by_type: str + :ivar created_at: The timestamp of resource creation (UTC) + :vartype created_at: datetime + :ivar last_modified_by: A string identifier for the identity that last + modified the resource + :vartype last_modified_by: str + :ivar last_modified_by_type: The type of identity that last modified the + resource: user, application, managedIdentity, key + :vartype last_modified_by_type: str + :ivar last_modified_at: The timestamp of resource last modification (UTC) + :vartype last_modified_at: datetime + """ + + _validation = { + 'created_by': {'readonly': True}, + 'created_by_type': {'readonly': True}, + 'created_at': {'readonly': True}, + 'last_modified_by': {'readonly': True}, + 'last_modified_by_type': {'readonly': True}, + 'last_modified_at': {'readonly': True}, + } + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__(self, **kwargs): + super(SystemData, self).__init__(**kwargs) + self.created_by = None + self.created_by_type = None + self.created_at = None + self.last_modified_by = None + self.last_modified_by_type = None + self.last_modified_at = None diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py new file mode 100644 index 00000000000..57f42c85edd --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_models_py3.py @@ -0,0 +1,726 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.serialization import Model +from msrest.exceptions import HttpOperationError + + +class CloudError(Model): + """CloudError. + """ + + _attribute_map = { + } + + +class ComplianceStatus(Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar compliance_state: The compliance state of the configuration. + Possible values include: 'Pending', 'Compliant', 'Noncompliant', + 'Installed', 'Failed' + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: + 'Error', 'Warning', 'Information' + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__(self, *, last_config_applied=None, message: str=None, message_level=None, **kwargs) -> None: + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = last_config_applied + self.message = message + self.message_level = message_level + + +class ConfigurationIdentity(Model): + """Identity for the managed cluster. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar principal_id: The principal id of the system assigned identity which + is used by the configuration. + :vartype principal_id: str + :ivar tenant_id: The tenant id of the system assigned identity which is + used by the configuration. + :vartype tenant_id: str + :param type: The type of identity used for the configuration. Type + 'SystemAssigned' will use an implicitly created identity. Type 'None' will + not use Managed Identity for the configuration. Possible values include: + 'SystemAssigned', 'None' + :type type: str or + ~azure.mgmt.kubernetesconfiguration.models.ResourceIdentityType + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'ResourceIdentityType'}, + } + + def __init__(self, *, type=None, **kwargs) -> None: + super(ConfigurationIdentity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = type + + +class ErrorDefinition(Model): + """Error definition. + + All required parameters must be populated in order to send to Azure. + + :param code: Required. Service specific error code which serves as the + substatus for the HTTP error code. + :type code: str + :param message: Required. Description of the error. + :type message: str + """ + + _validation = { + 'code': {'required': True}, + 'message': {'required': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + } + + def __init__(self, *, code: str, message: str, **kwargs) -> None: + super(ErrorDefinition, self).__init__(**kwargs) + self.code = code + self.message = message + + +class ErrorResponse(Model): + """Error response. + + :param error: Error definition. + :type error: ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDefinition'}, + } + + def __init__(self, *, error=None, **kwargs) -> None: + super(ErrorResponse, self).__init__(**kwargs) + self.error = error + + +class ErrorResponseException(HttpOperationError): + """Server responsed with exception of type: 'ErrorResponse'. + + :param deserialize: A deserializer + :param response: Server response to be deserialized. + """ + + def __init__(self, deserialize, response, *args): + + super(ErrorResponseException, self).__init__(deserialize, response, 'ErrorResponse', *args) + + +class Resource(Model): + """The Resource model definition. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__(self, *, system_data=None, **kwargs) -> None: + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + self.system_data = system_data + + +class ProxyResource(Resource): + """ARM proxy resource. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__(self, *, system_data=None, **kwargs) -> None: + super(ProxyResource, self).__init__(system_data=system_data, **kwargs) + + +class ExtensionInstance(ProxyResource): + """The Extension Instance object. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param location: Location of resource type + :type location: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + :param extension_type: Type of the Extension, of which this resource is an + instance of. It must be one of the Extension Types registered with + Microsoft.KubernetesConfiguration by the Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this instance + participates in auto upgrade of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension instance, if + it is 'pinned' to a specific version. autoUpgradeMinorVersion must be + 'false'. + :type version: str + :param scope: Scope at which the extension instance is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs + for configuring this instance of the extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are + sensitive, as name-value pairs for configuring this instance of the + extension. + :type configuration_protected_settings: dict[str, str] + :param install_state: Status of installation of this instance of the + extension. Possible values include: 'Pending', 'Installed', 'Failed' + :type install_state: str or + ~azure.mgmt.kubernetesconfiguration.models.InstallStateType + :param statuses: Status from this instance of the extension. + :type statuses: + list[~azure.mgmt.kubernetesconfiguration.models.ExtensionStatus] + :ivar creation_time: DateLiteral (per ISO8601) noting the time the + resource was created by the client (user). + :vartype creation_time: str + :ivar last_modified_time: DateLiteral (per ISO8601) noting the time the + resource was modified by the client (user). + :vartype last_modified_time: str + :ivar last_status_time: DateLiteral (per ISO8601) noting the time of last + status from the agent. + :vartype last_status_time: str + :ivar error_info: Error information from the Agent - e.g. errors during + installation. + :vartype error_info: + ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + :param identity: The identity of the configuration. + :type identity: + ~azure.mgmt.kubernetesconfiguration.models.ConfigurationIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'creation_time': {'readonly': True}, + 'last_modified_time': {'readonly': True}, + 'last_status_time': {'readonly': True}, + 'error_info': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'location': {'key': 'location', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'identity': {'key': 'identity', 'type': 'ConfigurationIdentity'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'install_state': {'key': 'properties.installState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, + 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, + 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'} + } + + def __init__(self, *, system_data=None, location: str=None, extension_type: str=None, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, scope=None, configuration_settings=None, configuration_protected_settings=None, install_state=None, statuses=None, identity=None, **kwargs) -> None: + super(ExtensionInstance, self).__init__(system_data=system_data, **kwargs) + self.location = location + self.extension_type = extension_type + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + self.scope = scope + self.configuration_settings = configuration_settings + self.configuration_protected_settings = configuration_protected_settings + self.install_state = install_state + self.statuses = statuses + self.creation_time = None + self.last_modified_time = None + self.last_status_time = None + self.error_info = None + self.identity = identity + + +class ExtensionInstanceUpdate(Model): + """Update Extension Instance request object. + + :param auto_upgrade_minor_version: Flag to note if this instance + participates in Extension Lifecycle Management or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in + for auto-upgrade (e.g. Stable, Preview, etc.) - only if + autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version number of extension, to 'pin' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + """ + + _attribute_map = { + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + } + + def __init__(self, *, auto_upgrade_minor_version: bool=None, release_train: str=None, version: str=None, **kwargs) -> None: + super(ExtensionInstanceUpdate, self).__init__(**kwargs) + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + + +class ExtensionStatus(Model): + """Status from this instance of the extension. + + :param code: Status code provided by the Extension + :type code: str + :param display_status: Short description of status of this instance of the + extension. + :type display_status: str + :param level: Level of the status. Possible values include: 'Error', + 'Warning', 'Information'. Default value: "Information" . + :type level: str or ~azure.mgmt.kubernetesconfiguration.models.LevelType + :param message: Detailed message of the status from the Extension + instance. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation + status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__(self, *, code: str=None, display_status: str=None, level="Information", message: str=None, time: str=None, **kwargs) -> None: + super(ExtensionStatus, self).__init__(**kwargs) + self.code = code + self.display_status = display_status + self.level = level + self.message = message + self.time = time + + +class HelmOperatorProperties(Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__(self, *, chart_version: str=None, chart_values: str=None, **kwargs) -> None: + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = chart_version + self.chart_values = chart_values + + +class ResourceProviderOperation(Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :param name: Operation name, in format of + {provider}/{resource}/{operation} + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation + applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__(self, *, name: str=None, display=None, **kwargs) -> None: + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = name + self.display = display + self.is_data_action = None + + +class ResourceProviderOperationDisplay(Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__(self, *, provider: str=None, resource: str=None, operation: str=None, description: str=None, **kwargs) -> None: + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = provider + self.resource = resource + self.operation = operation + self.description = description + + +class Result(Model): + """Sample result definition. + + :param sample_property: Sample property of type string + :type sample_property: str + """ + + _attribute_map = { + 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, + } + + def __init__(self, *, sample_property: str=None, **kwargs) -> None: + super(Result, self).__init__(**kwargs) + self.sample_property = sample_property + + +class Scope(Model): + """Scope of the extensionInstance. It can be either Cluster or Namespace; but + not both. + + :param cluster: Specifies that the scope of the extensionInstance is + Cluster + :type cluster: ~azure.mgmt.kubernetesconfiguration.models.ScopeCluster + :param namespace: Specifies that the scope of the extensionInstance is + Namespace + :type namespace: ~azure.mgmt.kubernetesconfiguration.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__(self, *, cluster=None, namespace=None, **kwargs) -> None: + super(Scope, self).__init__(**kwargs) + self.cluster = cluster + self.namespace = namespace + + +class ScopeCluster(Model): + """Specifies that the scope of the extensionInstance is Cluster. + + :param release_namespace: Namespace where the extension Release must be + placed, for a Cluster scoped extensionInstance. If this namespace does + not exist, it will be created + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__(self, *, release_namespace: str=None, **kwargs) -> None: + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = release_namespace + + +class ScopeNamespace(Model): + """Specifies that the scope of the extensionInstance is Namespace. + + :param target_namespace: Namespace where the extensionInstance will be + created for an Namespace scoped extensionInstance. If this namespace does + not exist, it will be created + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__(self, *, target_namespace: str=None, **kwargs) -> None: + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = target_namespace + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Resource Id + :vartype id: str + :ivar name: Resource name + :vartype name: str + :ivar type: Resource type + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is + installed to. Maximum of 253 lower case alphanumeric characters, hyphen + and period only. Default value: "default" . + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying + the specific configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: + 'Flux' + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string + format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected + configuration settings for the configuration + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. + Possible values include: 'cluster', 'namespace'. Default value: "cluster" + . + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl + configuration (either generated within the cluster or provided by the + user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents + containing public SSH keys required to access private Git instances + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git + configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. + Possible values include: 'Accepted', 'Deleting', 'Running', 'Succeeded', + 'Failed' + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__(self, *, system_data=None, repository_url: str=None, operator_namespace: str="default", operator_instance_name: str=None, operator_type=None, operator_params: str=None, configuration_protected_settings=None, operator_scope="cluster", ssh_known_hosts_contents: str=None, enable_helm_operator: bool=None, helm_operator_properties=None, **kwargs) -> None: + super(SourceControlConfiguration, self).__init__(system_data=system_data, **kwargs) + self.repository_url = repository_url + self.operator_namespace = operator_namespace + self.operator_instance_name = operator_instance_name + self.operator_type = operator_type + self.operator_params = operator_params + self.configuration_protected_settings = configuration_protected_settings + self.operator_scope = operator_scope + self.repository_public_key = None + self.ssh_known_hosts_contents = ssh_known_hosts_contents + self.enable_helm_operator = enable_helm_operator + self.helm_operator_properties = helm_operator_properties + self.provisioning_state = None + self.compliance_status = None + + +class SystemData(Model): + """Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar created_by: A string identifier for the identity that created the + resource + :vartype created_by: str + :ivar created_by_type: The type of identity that created the resource: + user, application, managedIdentity, key + :vartype created_by_type: str + :ivar created_at: The timestamp of resource creation (UTC) + :vartype created_at: datetime + :ivar last_modified_by: A string identifier for the identity that last + modified the resource + :vartype last_modified_by: str + :ivar last_modified_by_type: The type of identity that last modified the + resource: user, application, managedIdentity, key + :vartype last_modified_by_type: str + :ivar last_modified_at: The timestamp of resource last modification (UTC) + :vartype last_modified_at: datetime + """ + + _validation = { + 'created_by': {'readonly': True}, + 'created_by_type': {'readonly': True}, + 'created_at': {'readonly': True}, + 'last_modified_by': {'readonly': True}, + 'last_modified_by_type': {'readonly': True}, + 'last_modified_at': {'readonly': True}, + } + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__(self, **kwargs) -> None: + super(SystemData, self).__init__(**kwargs) + self.created_by = None + self.created_by_type = None + self.created_at = None + self.last_modified_by = None + self.last_modified_by_type = None + self.last_modified_at = None diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py new file mode 100644 index 00000000000..c545286fe54 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_paged_models.py @@ -0,0 +1,53 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.paging import Paged + + +class SourceControlConfigurationPaged(Paged): + """ + A paging container for iterating over a list of :class:`SourceControlConfiguration ` object + """ + + _attribute_map = { + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'current_page': {'key': 'value', 'type': '[SourceControlConfiguration]'} + } + + def __init__(self, *args, **kwargs): + + super(SourceControlConfigurationPaged, self).__init__(*args, **kwargs) +class ResourceProviderOperationPaged(Paged): + """ + A paging container for iterating over a list of :class:`ResourceProviderOperation ` object + """ + + _attribute_map = { + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'current_page': {'key': 'value', 'type': '[ResourceProviderOperation]'} + } + + def __init__(self, *args, **kwargs): + + super(ResourceProviderOperationPaged, self).__init__(*args, **kwargs) +class ExtensionInstancePaged(Paged): + """ + A paging container for iterating over a list of :class:`ExtensionInstance ` object + """ + + _attribute_map = { + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'current_page': {'key': 'value', 'type': '[ExtensionInstance]'} + } + + def __init__(self, *args, **kwargs): + + super(ExtensionInstancePaged, self).__init__(*args, **kwargs) diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_source_control_configuration_client_enums.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_source_control_configuration_client_enums.py new file mode 100644 index 00000000000..7be14a4b085 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/models/_source_control_configuration_client_enums.py @@ -0,0 +1,68 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from enum import Enum + + +class ComplianceStateType(str, Enum): + + pending = "Pending" + compliant = "Compliant" + noncompliant = "Noncompliant" + installed = "Installed" + failed = "Failed" + + +class MessageLevelType(str, Enum): + + error = "Error" + warning = "Warning" + information = "Information" + + +class OperatorType(str, Enum): + + flux = "Flux" + + +class OperatorScopeType(str, Enum): + + cluster = "cluster" + namespace = "namespace" + + +class ProvisioningStateType(str, Enum): + + accepted = "Accepted" + deleting = "Deleting" + running = "Running" + succeeded = "Succeeded" + failed = "Failed" + + +class InstallStateType(str, Enum): + + pending = "Pending" + installed = "Installed" + failed = "Failed" + + +class LevelType(str, Enum): + + error = "Error" + warning = "Warning" + information = "Information" + + +class ResourceIdentityType(str, Enum): + + system_assigned = "SystemAssigned" + none = "None" diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py new file mode 100644 index 00000000000..6be16d2582d --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/__init__.py @@ -0,0 +1,20 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._operations import Operations +from ._extensions_operations import ExtensionsOperations + +__all__ = [ + 'SourceControlConfigurationsOperations', + 'Operations', + 'ExtensionsOperations', +] diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_extensions_operations.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_extensions_operations.py new file mode 100644 index 00000000000..e99f3328816 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_extensions_operations.py @@ -0,0 +1,431 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +import uuid +from msrest.pipeline import ClientRawResponse + +from .. import models + + +class ExtensionsOperations(object): + """ExtensionsOperations operations. + + You should not instantiate directly this class, but create a Client instance that will create it for you and attach it as attribute. + + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + :ivar api_version: The API version to be used with the HTTP request. Constant value: "2020-07-01-preview". + """ + + models = models + + def __init__(self, client, config, serializer, deserializer): + + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self.api_version = "2020-07-01-preview" + + self.config = config + + def create( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, extension_instance, custom_headers=None, raw=False, **operation_config): + """Create a new Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param extension_instance: Properties necessary to Create an Extension + Instance. + :type extension_instance: + ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstance + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: ExtensionInstance or ClientRawResponse if raw=true + :rtype: ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstance + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.create.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct body + body_content = self._serialize.body(extension_instance, 'ExtensionInstance') + + # Construct and send request + request = self._client.put(url, query_parameters, header_parameters, body_content) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('ExtensionInstance', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} + + def get( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, custom_headers=None, raw=False, **operation_config): + """Gets details of the Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: ExtensionInstance or ClientRawResponse if raw=true + :rtype: ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstance + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.get.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('ExtensionInstance', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} + + def update( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, extension_instance, custom_headers=None, raw=False, **operation_config): + """Update an existing Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param extension_instance: Properties to Update in the Extension + Instance. + :type extension_instance: + ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstanceUpdate + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: ExtensionInstance or ClientRawResponse if raw=true + :rtype: ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstance + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.update.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct body + body_content = self._serialize.body(extension_instance, 'ExtensionInstanceUpdate') + + # Construct and send request + request = self._client.patch(url, query_parameters, header_parameters, body_content) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('ExtensionInstance', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} + + def delete( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, extension_instance_name, custom_headers=None, raw=False, **operation_config): + """Delete a Kubernetes Cluster Extension Instance. This will cause the + Agent to Uninstall the extension instance from the cluster. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: None or ClientRawResponse if raw=true + :rtype: None or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.delete.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.delete(url, query_parameters, header_parameters) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200, 204]: + raise models.ErrorResponseException(self._deserialize, response) + + if raw: + client_raw_response = ClientRawResponse(None, response) + return client_raw_response + delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} + + def list( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, custom_headers=None, raw=False, **operation_config): + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: An iterator like instance of ExtensionInstance + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.ExtensionInstancePaged[~azure.mgmt.kubernetesconfiguration.models.ExtensionInstance] + :raises: + :class:`ErrorResponseException` + """ + def prepare_request(next_link=None): + if not next_link: + # Construct URL + url = self.list.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + else: + url = next_link + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + return request + + def internal_paging(next_link=None): + request = prepare_request(next_link) + + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + return response + + # Deserialize response + header_dict = None + if raw: + header_dict = {} + deserialized = models.ExtensionInstancePaged(internal_paging, self._deserialize.dependencies, header_dict) + + return deserialized + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions'} diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_operations.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_operations.py new file mode 100644 index 00000000000..245a93c8294 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_operations.py @@ -0,0 +1,101 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +import uuid +from msrest.pipeline import ClientRawResponse + +from .. import models + + +class Operations(object): + """Operations operations. + + You should not instantiate directly this class, but create a Client instance that will create it for you and attach it as attribute. + + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + :ivar api_version: The API version to be used with the HTTP request. Constant value: "2020-07-01-preview". + """ + + models = models + + def __init__(self, client, config, serializer, deserializer): + + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self.api_version = "2020-07-01-preview" + + self.config = config + + def list( + self, custom_headers=None, raw=False, **operation_config): + """List all the available operations the KubernetesConfiguration resource + provider supports. + + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: An iterator like instance of ResourceProviderOperation + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationPaged[~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperation] + :raises: + :class:`ErrorResponseException` + """ + def prepare_request(next_link=None): + if not next_link: + # Construct URL + url = self.list.metadata['url'] + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + else: + url = next_link + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + return request + + def internal_paging(next_link=None): + request = prepare_request(next_link) + + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + return response + + # Deserialize response + header_dict = None + if raw: + header_dict = {} + deserialized = models.ResourceProviderOperationPaged(internal_paging, self._deserialize.dependencies, header_dict) + + return deserialized + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_source_control_configurations_operations.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..83a49e32146 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/operations/_source_control_configurations_operations.py @@ -0,0 +1,386 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +import uuid +from msrest.pipeline import ClientRawResponse +from msrest.polling import LROPoller, NoPolling +from msrestazure.polling.arm_polling import ARMPolling + +from .. import models + + +class SourceControlConfigurationsOperations(object): + """SourceControlConfigurationsOperations operations. + + You should not instantiate directly this class, but create a Client instance that will create it for you and attach it as attribute. + + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + :ivar api_version: The API version to be used with the HTTP request. Constant value: "2020-07-01-preview". + """ + + models = models + + def __init__(self, client, config, serializer, deserializer): + + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self.api_version = "2020-07-01-preview" + + self.config = config + + def get( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, **operation_config): + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control + Configuration. + :type source_control_configuration_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: SourceControlConfiguration or ClientRawResponse if raw=true + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.get.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} + + def create_or_update( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, source_control_configuration, custom_headers=None, raw=False, **operation_config): + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control + Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create + KubernetesConfiguration. + :type source_control_configuration: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: SourceControlConfiguration or ClientRawResponse if raw=true + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.create_or_update.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct body + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + + # Construct and send request + request = self._client.put(url, query_parameters, header_parameters, body_content) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200, 201]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', response) + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} + + + def _delete_initial( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, **operation_config): + # Construct URL + url = self.delete.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.delete(url, query_parameters, header_parameters) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200, 204]: + raise models.ErrorResponseException(self._deserialize, response) + + if raw: + client_raw_response = ClientRawResponse(None, response) + return client_raw_response + + def delete( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, polling=True, **operation_config): + """This will delete the YAML file used to set up the Source control + configuration, thus stopping future sync from the source repo. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control + Configuration. + :type source_control_configuration_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: The poller return type is ClientRawResponse, the + direct response alongside the deserialized response + :param polling: True for ARMPolling, False for no polling, or a + polling object for personal polling strategy + :return: An instance of LROPoller that returns None or + ClientRawResponse if raw==True + :rtype: ~msrestazure.azure_operation.AzureOperationPoller[None] or + ~msrestazure.azure_operation.AzureOperationPoller[~msrest.pipeline.ClientRawResponse[None]] + :raises: + :class:`ErrorResponseException` + """ + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + custom_headers=custom_headers, + raw=True, + **operation_config + ) + + def get_long_running_output(response): + if raw: + client_raw_response = ClientRawResponse(None, response) + return client_raw_response + + lro_delay = operation_config.get( + 'long_running_operation_timeout', + self.config.long_running_operation_timeout) + if polling is True: polling_method = ARMPolling(lro_delay, **operation_config) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} + + def list( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, custom_headers=None, raw=False, **operation_config): + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: An iterator like instance of SourceControlConfiguration + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfigurationPaged[~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration] + :raises: + :class:`ErrorResponseException` + """ + def prepare_request(next_link=None): + if not next_link: + # Construct URL + url = self.list.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + else: + url = next_link + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + return request + + def internal_paging(next_link=None): + request = prepare_request(next_link) + + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + return response + + # Deserialize response + header_dict = None + if raw: + header_dict = {} + deserialized = models.SourceControlConfigurationPaged(internal_paging, self._deserialize.dependencies, header_dict) + + return deserialized + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} diff --git a/src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py b/src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py new file mode 100644 index 00000000000..3e682bbd5fb --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/vendored_sdks/version.py @@ -0,0 +1,13 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +VERSION = "0.3.0" + diff --git a/src/k8s-extension/setup.py b/src/k8s-extension/setup.py new file mode 100644 index 00000000000..d3d491fd48c --- /dev/null +++ b/src/k8s-extension/setup.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + + +from codecs import open +from setuptools import setup, find_packages +import azext_k8s_extension._consts as consts +try: + from azure_bdist_wheel import cmdclass +except ImportError: + from distutils import log as logger + logger.warn("Wheel is not available, disabling bdist_wheel hook") + +# The full list of classifiers is available at +# https://pypi.python.org/pypi?%3Aaction=list_classifiers +CLASSIFIERS = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'License :: OSI Approved :: MIT License', +] + +# TODO: Add any additional SDK dependencies here +DEPENDENCIES = [] + +with open('README.rst', 'r', encoding='utf-8') as f: + README = f.read() +with open('HISTORY.rst', 'r', encoding='utf-8') as f: + HISTORY = f.read() + +setup( + name=consts.EXTENSION_NAME, + version=consts.VERSION, + description='Microsoft Azure Command-Line Tools K8s-extension Extension', + # TODO: Update author and email, if applicable + author='Microsoft Corporation', + author_email='azpycli@microsoft.com', + # TODO: consider pointing directly to your source code instead of the generic repo + url='https://github.com/Azure/azure-cli-extensions', + long_description=README + '\n\n' + HISTORY, + license='MIT', + classifiers=CLASSIFIERS, + packages=find_packages(), + install_requires=DEPENDENCIES, + package_data={'azext_k8s_extension': ['azext_metadata.json']}, +) From 7f79cfb16fc8e4ec057d3b64f55b415894db2a45 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 17 Mar 2021 17:55:01 -0700 Subject: [PATCH 44/80] Remove custom pipelines file --- k8s-custom-pipelines.yml | 356 --------------------------------------- 1 file changed, 356 deletions(-) delete mode 100644 k8s-custom-pipelines.yml diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml deleted file mode 100644 index f4e2984ddf2..00000000000 --- a/k8s-custom-pipelines.yml +++ /dev/null @@ -1,356 +0,0 @@ -resources: - repositories: - - repository: K8sPartnerExtensionTest - type: git - endpoint: AzureReposConnection - name: One/compute-HybridMgmt-K8sPartnerExtensionTest - -trigger: - batch: true - branches: - include: - - k8s-extension/public - - k8s-extension/private -pr: - branches: - include: - - k8s-extension/public - - k8s-extension/private - -stages: -- stage: BuildTestPublishExtension - displayName: "Build, Test, and Publish Extension" - variables: - K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest - CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions - SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" - RESOURCE_GROUP: "K8sPartnerExtensionTest" - BASE_CLUSTER_NAME: "k8s-extension-cluster" - IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranch'], 'refs/heads/k8s-extension/private'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private'))] - - EXTENSION_NAME: "k8s-extension" - EXTENSION_FILE_NAME: "k8s_extension" - jobs: - - job: K8sExtensionTestSuite - displayName: "Run the Test Suite" - pool: - vmImage: 'ubuntu-16.04' - steps: - - checkout: self - - checkout: K8sPartnerExtensionTest - - bash: | - echo "Installing helm3" - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 - chmod 700 get_helm.sh - ./get_helm.sh - - echo "Installing kubectl" - curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x ./kubectl - sudo mv ./kubectl /usr/local/bin/kubectl - kubectl version --client - displayName: "Setup the VM with helm3 and kubectl" - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - echo "Building extension ${EXTENSION_NAME}..." - - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - - # clone azure-cli - pip install azdev - - ls $(CLI_REPO_PATH) - - azdev --version - azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build Extension with azdev" - - - bash: | - K8S_EXTENSION_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) - echo "##vso[task.setvariable variable=K8S_EXTENSION_VERSION]$K8S_EXTENSION_VERSION" - cp * $(K8S_EXTENSION_REPO_PATH)/bin - workingDirectory: $(CLI_REPO_PATH)/dist - displayName: "Copy the Built .whl to Extension Test Path" - - - bash: | - RAND_STR=$RANDOM - AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" - ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" - - JSON_STRING=$(jq -n \ - --arg SUB_ID "$SUBSCRIPTION_ID" \ - --arg RG "$RESOURCE_GROUP" \ - --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ - --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ - --arg K8S_EXTENSION_VERSION "$K8S_EXTENSION_VERSION" \ - '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-extension": $K8S_EXTENSION_VERSION, connectedk8s: "1.0.0"}}') - echo $JSON_STRING > settings.json - cat settings.json - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - displayName: "Generate a settings.json file" - - - bash : | - echo "Downloading the kind script" - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64 - chmod +x ./kind - ./kind create cluster - displayName: "Create and Start the Kind cluster" - - - task: AzureCLI@2 - displayName: Bootstrap - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Bootstrap.ps1 -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - - - task: AzureCLI@2 - displayName: Run the Test Suite Public Extensions Only - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Test.ps1 -CI -ExtensionType Public -OnlyPublicTests - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - continueOnError: true - condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'False')) - - - task: AzureCLI@2 - displayName: Run the Test Suite on Private + Public Extensions - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Test.ps1 -CI -ExtensionType Public - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - continueOnError: true - condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'True')) - - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'JUnit' - testResultsFiles: '**/TestResults.xml' - failTaskOnFailedTests: true - condition: succeededOrFailed() - - - task: AzureCLI@2 - displayName: Cleanup - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Cleanup.ps1 -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - condition: succeededOrFailed() - - - job: BuildPublishExtension - pool: - vmImage: 'ubuntu-16.04' - displayName: "Build and Publish the Extension Artifact" - variables: - CLI_REPO_PATH: $(Agent.BuildDirectory)/s - steps: - - bash: | - echo "Using the private preview of k8s-extension to build..." - - cp $(CLI_REPO_PATH)/src/k8s-extension $(CLI_REPO_PATH)/src/k8s-extension-private -r - cp $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts.py - - EXTENSION_NAME="k8s-extension-private" - EXTENSION_FILE_NAME="k8s_extension_private" - - echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" - echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" - condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'True')) - displayName: "Copy Files, Set Variables for k8s-extension-private" - - bash: | - echo "Using the public version of k8s-extension to build..." - - EXTENSION_NAME="k8s-extension" - EXTENSION_FILE_NAME="k8s_extension" - - echo "##vso[task.setvariable variable=EXTENSION_NAME]$EXTENSION_NAME" - echo "##vso[task.setvariable variable=EXTENSION_FILE_NAME]$EXTENSION_FILE_NAME" - condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'False')) - displayName: "Copy Files, Set Variables for k8s-extension" - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - echo "Building extension ${EXTENSION_NAME}..." - - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - - # clone azure-cli - pip install azdev - - ls $(CLI_REPO_PATH) - - azdev --version - azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build Extension with azdev" - - task: PublishBuildArtifacts@1 - inputs: - pathToPublish: $(CLI_REPO_PATH)/dist - -- stage: AzureCLIOfficial - displayName: "Azure Official CLI Code Checks" - dependsOn: [] - jobs: - - job: CheckLicenseHeader - displayName: "Check License" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - python -m venv env/ - - chmod +x ./env/bin/activate - source ./env/bin/activate - - # clone azure-cli - git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install -q azdev - - azdev setup -c ../azure-cli -r ./ - - azdev --version - az --version - - azdev verify license - - - job: StaticAnalysis - displayName: "Static Analysis" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests - displayName: 'Install wheel, pylint, flake8, requests' - - bash: python scripts/ci/source_code_static_analysis.py - displayName: "Static Analysis" - - - job: IndexVerify - displayName: "Verify Extensions Index" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: | - #!/usr/bin/env bash - set -ev - pip install wheel==0.30.0 requests packaging - export CI="ADO" - python ./scripts/ci/test_index.py -v - displayName: "Verify Extensions Index" - - - job: SourceTests - displayName: "Integration Tests, Build Tests" - pool: - vmImage: 'ubuntu-16.04' - strategy: - matrix: - Python36: - python.version: '3.6' - Python38: - python.version: '3.8' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python $(python.version)' - inputs: - versionSpec: '$(python.version)' - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - bash: ./scripts/ci/test_source.sh - displayName: 'Run integration test and build test' - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - - - job: LintModifiedExtensions - displayName: "CLI Linter on Modified Extensions" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - pip install virtualenv - python -m virtualenv venv/ - source ./venv/bin/activate - - # clone azure-cli - git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install azdev - - azdev --version - - azdev setup -c ../azure-cli -r ./ -e k8s-extension - - # overwrite the default AZURE_EXTENSION_DIR set by ADO - AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version - - AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-extension - displayName: "CLI Linter on Modified Extension" - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - - - job: IndexRefDocVerify - displayName: "Verify Ref Docs" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - task: Bash@3 - displayName: "Verify Extension Ref Docs" - inputs: - targetType: 'filePath' - filePath: scripts/ci/test_index_ref_doc.sh From 9f06b4919cb089ac6ee1afe3d30de053965f5701 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 24 Mar 2021 09:26:47 -0700 Subject: [PATCH 45/80] Update extension description, remove private const --- src/k8s-extension/README.rst | 54 +++++++++++++++++++ .../azext_k8s_extension/_consts_private.py | 8 --- .../azext_k8s_extension/_params.py | 5 +- 3 files changed, 57 insertions(+), 10 deletions(-) delete mode 100644 src/k8s-extension/azext_k8s_extension/_consts_private.py diff --git a/src/k8s-extension/README.rst b/src/k8s-extension/README.rst index e91e1b13229..5d4694e14cb 100644 --- a/src/k8s-extension/README.rst +++ b/src/k8s-extension/README.rst @@ -3,3 +3,57 @@ Microsoft Azure CLI 'k8s-extension' Extension This package is for the 'k8s-extension' extension. i.e. 'az k8s-extension' + +### How to use ### +Install this extension using the below CLI command +``` +az extension add --name k8s-extension +``` + +### Included Features +#### Kubernetes Extensions: +Kubernetes Extensions: [more info](https://docs.microsoft.com/en-us/azure/kubernetessconfiguration/)\ +*Examples:* + +##### Create a KubernetesExtension +``` +az k8s-extension create \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType \ + --name extensionName \ + --extension-type extensionType \ + --scope scopeType \ + --release-train releaseTrain \ + --version versionNumber \ + --auto-upgrade-minor-version autoUpgrade \ + --configuration-settings exampleSetting=exampleValue \ +``` + +##### Get a KubernetesExtension +``` +az k8s-extension show \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType \ + --name extensionName +``` + +##### Delete a KubernetesExtension +``` +az k8s-extension delete \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType \ + --name extensionName +``` + +##### List all KubernetesExtension of a cluster +``` +az k8s-extension list \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType +``` + +If you have issues, please give feedback by opening an issue at https://github.com/Azure/azure-cli-extensions/issues. \ No newline at end of file diff --git a/src/k8s-extension/azext_k8s_extension/_consts_private.py b/src/k8s-extension/azext_k8s_extension/_consts_private.py deleted file mode 100644 index bc4c8a2b694..00000000000 --- a/src/k8s-extension/azext_k8s_extension/_consts_private.py +++ /dev/null @@ -1,8 +0,0 @@ -# coding=utf-8 -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -EXTENSION_NAME = 'k8s-extension-private' -VERSION = "0.1PP.14" diff --git a/src/k8s-extension/azext_k8s_extension/_params.py b/src/k8s-extension/azext_k8s_extension/_params.py index d96fe3c2ba7..3bbc6056a2e 100644 --- a/src/k8s-extension/azext_k8s_extension/_params.py +++ b/src/k8s-extension/azext_k8s_extension/_params.py @@ -45,6 +45,9 @@ def load_arguments(self, _): arg_group="Version", help='Specify the version to install for the extension instance if' ' --auto-upgrade-minor-version is not enabled.') + c.argument('release_train', + arg_group="Version", + help='Specify the release train for the extension type.') c.argument('configuration_settings', arg_group="Configuration", options_list=['--configuration-settings', '--config'], @@ -67,8 +70,6 @@ def load_arguments(self, _): help='JSON file path for configuration-protected-settings') c.argument('release_namespace', help='Specify the namespace to install the extension release.') - c.argument('release_train', - help='Specify the release train for the extension type.') c.argument('target_namespace', help='Specify the target namespace to install to for the extension instance. This' ' parameter is required if extension scope is set to \'namespace\'') From eb4c58bb30928caef9fbff1778e68f326ef0d116 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 24 Mar 2021 13:06:14 -0700 Subject: [PATCH 46/80] Update pipeline file --- k8s-custom-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index f4e2984ddf2..a603608b138 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -26,7 +26,7 @@ stages: SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" RESOURCE_GROUP: "K8sPartnerExtensionTest" BASE_CLUSTER_NAME: "k8s-extension-cluster" - IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranch'], 'refs/heads/k8s-extension/private'), eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/k8s-extension/private'))] + IS_PRIVATE_BRANCH: $[or(eq(variables['Build.SourceBranch'], 'refs/heads/k8s-extension/private'), eq(variables['System.PullRequest.TargetBranch'], 'k8s-extension/private'))] EXTENSION_NAME: "k8s-extension" EXTENSION_FILE_NAME: "k8s_extension" From 7a07d526116c90951747ac243ff8166fd41fca29 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Fri, 2 Apr 2021 13:35:18 -0700 Subject: [PATCH 47/80] Disable check ref docs --- k8s-custom-pipelines.yml | 619 +++++++++++++++++++-------------------- 1 file changed, 301 insertions(+), 318 deletions(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 7b510de2852..6a840b390b9 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -1,318 +1,301 @@ -resources: - repositories: - - repository: K8sPartnerExtensionTest - type: git - endpoint: AzureReposConnection - name: One/compute-HybridMgmt-K8sPartnerExtensionTest - ref: joinnis/scc-testing - -trigger: - batch: true - branches: - include: - - k8s-configuration -pr: - branches: - include: - - k8s-configuration - -stages: -- stage: BuildTestPublishExtension - displayName: "Build, Test, and Publish Extension" - variables: - K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest - CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions - EXTENSION_NAME: "k8s-configuration" - EXTENSION_FILE_NAME: "k8s_configuration" - SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" - RESOURCE_GROUP: "K8sPartnerExtensionTest" - BASE_CLUSTER_NAME: "k8s-configuration-cluster" - jobs: - - job: K8sConfigurationTestSuite - displayName: "Run the Test Suite" - pool: - vmImage: 'ubuntu-16.04' - steps: - - checkout: self - - checkout: K8sPartnerExtensionTest - - - bash: | - echo "Installing helm3" - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 - chmod 700 get_helm.sh - ./get_helm.sh - - echo "Installing kubectl" - curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x ./kubectl - sudo mv ./kubectl /usr/local/bin/kubectl - kubectl version --client - displayName: "Setup the VM with helm3 and kubectl" - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - - # clone azure-cli - pip install azdev - - ls $(CLI_REPO_PATH) - - azdev --version - azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build $(EXTENSION_NAME) with azdev" - - - bash: | - K8S_CONFIG_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) - echo "##vso[task.setvariable variable=K8S_CONFIG_VERSION]$K8S_CONFIG_VERSION" - cp * $(K8S_EXTENSION_REPO_PATH)/extensions - workingDirectory: $(CLI_REPO_PATH)/dist - displayName: "Copy the Built .whl to Extension Test Path" - - - bash: | - RAND_STR=$RANDOM - AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" - ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" - - JSON_STRING=$(jq -n \ - --arg SUB_ID "$SUBSCRIPTION_ID" \ - --arg RG "$RESOURCE_GROUP" \ - --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ - --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ - --arg K8S_CONFIG_VERSION "$K8S_CONFIG_VERSION" \ - '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-configuration": $K8S_CONFIG_VERSION, connectedk8s: "1.0.0"}}') - echo $JSON_STRING > settings.json - cat settings.json - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - displayName: "Generate a settings.json file" - - - bash : | - echo "Downloading the kind script" - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64 - chmod +x ./kind - ./kind create cluster - displayName: "Create and Start the Kind cluster" - - - task: AzureCLI@2 - displayName: Bootstrap - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Bootstrap.ps1 -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - - - task: AzureCLI@2 - displayName: Run the Test Suite - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Test.ps1 -Type Configuration -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - continueOnError: true - - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'JUnit' - testResultsFiles: '**/TestResults.xml' - failTaskOnFailedTests: true - condition: succeededOrFailed() - - - task: AzureCLI@2 - displayName: Cleanup - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Cleanup.ps1 -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) - condition: succeededOrFailed() - - - job: BuildPublishExtension - pool: - vmImage: 'ubuntu-16.04' - displayName: "Build and Publish the Extension Artifact" - variables: - CLI_REPO_PATH: $(Agent.BuildDirectory)/s - EXTENSION_NAME: "k8s-configuration" - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - echo "Building extension ${EXTENSION_NAME}..." - - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - - # clone azure-cli - pip install azdev - - ls $(CLI_REPO_PATH) - - azdev --version - azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build Extension with azdev" - - task: PublishBuildArtifacts@1 - inputs: - pathToPublish: $(CLI_REPO_PATH)/dist - -- stage: AzureCLIOfficial - displayName: "Azure Official CLI Code Checks" - dependsOn: [] - jobs: - - job: CheckLicenseHeader - displayName: "Check License" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - python -m venv env/ - - chmod +x ./env/bin/activate - source ./env/bin/activate - - # clone azure-cli - git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install -q azdev - - azdev setup -c ../azure-cli -r ./ - - azdev --version - az --version - - azdev verify license - - - job: StaticAnalysis - displayName: "Static Analysis" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests - displayName: 'Install wheel, pylint, flake8, requests' - - bash: python scripts/ci/source_code_static_analysis.py - displayName: "Static Analysis" - - - job: IndexVerify - displayName: "Verify Extensions Index" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: | - #!/usr/bin/env bash - set -ev - pip install wheel==0.30.0 requests packaging - export CI="ADO" - python ./scripts/ci/test_index.py -v - displayName: "Verify Extensions Index" - - - job: SourceTests - displayName: "Integration Tests, Build Tests" - pool: - vmImage: 'ubuntu-16.04' - strategy: - matrix: - Python36: - python.version: '3.6' - Python38: - python.version: '3.8' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python $(python.version)' - inputs: - versionSpec: '$(python.version)' - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - bash: ./scripts/ci/test_source.sh - displayName: 'Run integration test and build test' - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - - - job: LintModifiedExtensions - displayName: "CLI Linter on Modified Extensions" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - pip install virtualenv - python -m virtualenv venv/ - source ./venv/bin/activate - - # clone azure-cli - git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install azdev - - azdev --version - - azdev setup -c ../azure-cli -r ./ -e k8s-configuration - - # overwrite the default AZURE_EXTENSION_DIR set by ADO - AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version - - AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-configuration - displayName: "CLI Linter on Modified Extension" - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - - - job: IndexRefDocVerify - displayName: "Verify Ref Docs" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - task: Bash@3 - displayName: "Verify Extension Ref Docs" - inputs: - targetType: 'filePath' - filePath: scripts/ci/test_index_ref_doc.sh +resources: + repositories: + - repository: K8sPartnerExtensionTest + type: git + endpoint: AzureReposConnection + name: One/compute-HybridMgmt-K8sPartnerExtensionTest + ref: joinnis/scc-testing + +trigger: + batch: true + branches: + include: + - k8s-configuration +pr: + branches: + include: + - k8s-configuration + +stages: +- stage: BuildTestPublishExtension + displayName: "Build, Test, and Publish Extension" + variables: + K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest + CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions + EXTENSION_NAME: "k8s-configuration" + EXTENSION_FILE_NAME: "k8s_configuration" + SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" + RESOURCE_GROUP: "K8sPartnerExtensionTest" + BASE_CLUSTER_NAME: "k8s-configuration-cluster" + jobs: + - job: K8sConfigurationTestSuite + displayName: "Run the Test Suite" + pool: + vmImage: 'ubuntu-16.04' + steps: + - checkout: self + - checkout: K8sPartnerExtensionTest + + - bash: | + echo "Installing helm3" + curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 + chmod 700 get_helm.sh + ./get_helm.sh + + echo "Installing kubectl" + curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin/kubectl + kubectl version --client + displayName: "Setup the VM with helm3 and kubectl" + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build $(EXTENSION_NAME) with azdev" + + - bash: | + K8S_CONFIG_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) + echo "##vso[task.setvariable variable=K8S_CONFIG_VERSION]$K8S_CONFIG_VERSION" + cp * $(K8S_EXTENSION_REPO_PATH)/extensions + workingDirectory: $(CLI_REPO_PATH)/dist + displayName: "Copy the Built .whl to Extension Test Path" + + - bash: | + RAND_STR=$RANDOM + AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" + ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" + + JSON_STRING=$(jq -n \ + --arg SUB_ID "$SUBSCRIPTION_ID" \ + --arg RG "$RESOURCE_GROUP" \ + --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ + --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ + --arg K8S_CONFIG_VERSION "$K8S_CONFIG_VERSION" \ + '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-configuration": $K8S_CONFIG_VERSION, connectedk8s: "1.0.0"}}') + echo $JSON_STRING > settings.json + cat settings.json + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + displayName: "Generate a settings.json file" + + - bash : | + echo "Downloading the kind script" + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64 + chmod +x ./kind + ./kind create cluster + displayName: "Create and Start the Kind cluster" + + - task: AzureCLI@2 + displayName: Bootstrap + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Bootstrap.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + + - task: AzureCLI@2 + displayName: Run the Test Suite + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Test.ps1 -Type Configuration -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + continueOnError: true + + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TestResults.xml' + failTaskOnFailedTests: true + condition: succeededOrFailed() + + - task: AzureCLI@2 + displayName: Cleanup + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Cleanup.ps1 -CI + workingDirectory: $(K8S_EXTENSION_REPO_PATH) + condition: succeededOrFailed() + + - job: BuildPublishExtension + pool: + vmImage: 'ubuntu-16.04' + displayName: "Build and Publish the Extension Artifact" + variables: + CLI_REPO_PATH: $(Agent.BuildDirectory)/s + EXTENSION_NAME: "k8s-configuration" + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + echo "Building extension ${EXTENSION_NAME}..." + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build Extension with azdev" + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: $(CLI_REPO_PATH)/dist + +- stage: AzureCLIOfficial + displayName: "Azure Official CLI Code Checks" + dependsOn: [] + jobs: + - job: CheckLicenseHeader + displayName: "Check License" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + python -m venv env/ + + chmod +x ./env/bin/activate + source ./env/bin/activate + + # clone azure-cli + git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install -q azdev + + azdev setup -c ../azure-cli -r ./ + + azdev --version + az --version + + azdev verify license + + - job: StaticAnalysis + displayName: "Static Analysis" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests + displayName: 'Install wheel, pylint, flake8, requests' + - bash: python scripts/ci/source_code_static_analysis.py + displayName: "Static Analysis" + + - job: IndexVerify + displayName: "Verify Extensions Index" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: | + #!/usr/bin/env bash + set -ev + pip install wheel==0.30.0 requests packaging + export CI="ADO" + python ./scripts/ci/test_index.py -v + displayName: "Verify Extensions Index" + + - job: SourceTests + displayName: "Integration Tests, Build Tests" + pool: + vmImage: 'ubuntu-16.04' + strategy: + matrix: + Python36: + python.version: '3.6' + Python38: + python.version: '3.8' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python $(python.version)' + inputs: + versionSpec: '$(python.version)' + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - bash: ./scripts/ci/test_source.sh + displayName: 'Run integration test and build test' + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: LintModifiedExtensions + displayName: "CLI Linter on Modified Extensions" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + pip install virtualenv + python -m virtualenv venv/ + source ./venv/bin/activate + + # clone azure-cli + git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install azdev + + azdev --version + + azdev setup -c ../azure-cli -r ./ -e k8s-configuration + + # overwrite the default AZURE_EXTENSION_DIR set by ADO + AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version + + AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-configuration + displayName: "CLI Linter on Modified Extension" + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) From 3290f6e32cdd61b370f475055eb07d77d09753fe Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Fri, 2 Apr 2021 13:35:49 -0700 Subject: [PATCH 48/80] Disable refs docs --- k8s-custom-pipelines.yml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index a603608b138..a3304668086 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -337,20 +337,3 @@ stages: env: ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - - - job: IndexRefDocVerify - displayName: "Verify Ref Docs" - pool: - vmImage: 'ubuntu-16.04' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - task: Bash@3 - displayName: "Verify Extension Ref Docs" - inputs: - targetType: 'filePath' - filePath: scripts/ci/test_index_ref_doc.sh From 22c8e9247ed5ae5fa3cb0f273e69dd9e2053fe34 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Fri, 2 Apr 2021 16:15:58 -0700 Subject: [PATCH 49/80] Update to include better create warning logs and remove update context (#20) * Update to include better create warning logs and remove update context * Remove help text for update * Fix spelling error * Update message --- src/k8s-extension/HISTORY.rst | 6 ++++++ src/k8s-extension/azext_k8s_extension/_consts.py | 2 +- src/k8s-extension/azext_k8s_extension/_help.py | 5 ----- src/k8s-extension/azext_k8s_extension/commands.py | 1 - .../azext_k8s_extension/partner_extensions/AzureDefender.py | 3 ++- .../partner_extensions/ContainerInsights.py | 3 ++- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/k8s-extension/HISTORY.rst b/src/k8s-extension/HISTORY.rst index 54c1e375f6f..d20160a2199 100644 --- a/src/k8s-extension/HISTORY.rst +++ b/src/k8s-extension/HISTORY.rst @@ -3,6 +3,12 @@ Release History =============== +0.2.1 +++++++++++++++++++ + +* Remove `k8s-extension update` until PATCH is supported +* Improved logging for overwriting extension name with default + 0.2.0 ++++++++++++++++++ diff --git a/src/k8s-extension/azext_k8s_extension/_consts.py b/src/k8s-extension/azext_k8s_extension/_consts.py index d0fdaf7775f..144e9450012 100644 --- a/src/k8s-extension/azext_k8s_extension/_consts.py +++ b/src/k8s-extension/azext_k8s_extension/_consts.py @@ -5,4 +5,4 @@ # -------------------------------------------------------------------------------------------- EXTENSION_NAME = 'k8s-extension' -VERSION = "0.2.0" +VERSION = "0.2.1" diff --git a/src/k8s-extension/azext_k8s_extension/_help.py b/src/k8s-extension/azext_k8s_extension/_help.py index 64e4be612ea..562f0af58aa 100644 --- a/src/k8s-extension/azext_k8s_extension/_help.py +++ b/src/k8s-extension/azext_k8s_extension/_help.py @@ -32,8 +32,3 @@ type: command short-summary: Show details of a K8s-extension. """ - -helps[f'{consts.EXTENSION_NAME} update'] = """ - type: command - short-summary: Update a K8s-extension. -""" diff --git a/src/k8s-extension/azext_k8s_extension/commands.py b/src/k8s-extension/azext_k8s_extension/commands.py index 931662814c0..3a823177d1c 100644 --- a/src/k8s-extension/azext_k8s_extension/commands.py +++ b/src/k8s-extension/azext_k8s_extension/commands.py @@ -20,7 +20,6 @@ def load_command_table(self, _): is_preview=True) \ as g: g.custom_command('create', 'create_k8s_extension') - g.custom_command('update', 'update_k8s_extension') g.custom_command('delete', 'delete_k8s_extension', confirmation=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) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py index dcd2853affc..3124faec4c1 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py @@ -41,7 +41,8 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t is_ci_extension_type = False logger.warning('Ignoring name, release-namespace and scope parameters since %s ' - 'only supports cluster scope and single instance of this extension', extension_type) + 'only supports cluster scope and single instance of this extension.', extension_type) + logger.warning("Defaulting to extension name '%s' and release-namespace '%s'", name, release_namespace) _get_container_insights_settings(cmd, resource_group_name, cluster_name, configuration_settings, configuration_protected_settings, is_ci_extension_type) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py index 8c678b34915..eade4256205 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py @@ -53,7 +53,8 @@ def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_t is_ci_extension_type = True logger.warning('Ignoring name, release-namespace and scope parameters since %s ' - 'only supports cluster scope and single instance of this extension', extension_type) + 'only supports cluster scope and single instance of this extension.', extension_type) + logger.warning("Defaulting to extension name '%s' and release-namespace '%s'", name, release_namespace) _get_container_insights_settings(cmd, resource_group_name, cluster_name, configuration_settings, configuration_protected_settings, is_ci_extension_type) From df82dd871408b5b131ab0e8e1714ead98ff20df6 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 14 Apr 2021 16:24:52 -0700 Subject: [PATCH 50/80] Fix k8s-extension conflict with private version --- k8s-custom-pipelines.yml | 4 +++- .../azext_k8s_extension/__init__.py | 11 ++++++----- .../azext_k8s_extension/_client_factory.py | 2 +- src/k8s-extension/azext_k8s_extension/_help.py | 2 +- .../azext_k8s_extension/_params.py | 4 ++-- .../azext_k8s_extension/commands.py | 8 ++++---- .../{_consts.py => consts.py} | 2 +- .../azext_k8s_extension/custom.py | 18 +++++++++--------- .../partner_extensions/AzureDefender.py | 12 ++++++------ .../partner_extensions/Cassandra.py | 12 ++++++------ .../partner_extensions/ContainerInsights.py | 12 ++++++------ .../partner_extensions/DefaultExtension.py | 12 ++++++------ .../PartnerExtensionModel.py | 4 ++-- src/k8s-extension/setup.py | 8 +++++--- 14 files changed, 58 insertions(+), 53 deletions(-) rename src/k8s-extension/azext_k8s_extension/{_consts.py => consts.py} (88%) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index a3304668086..451d1e08889 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -169,7 +169,9 @@ stages: echo "Using the private preview of k8s-extension to build..." cp $(CLI_REPO_PATH)/src/k8s-extension $(CLI_REPO_PATH)/src/k8s-extension-private -r - cp $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension/_consts.py + mv $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension_private + cp $(CLI_REPO_PATH)/src/k8s-extension-private/setup_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/setup.py + cp $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension_private/_consts_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension_private/_consts.py EXTENSION_NAME="k8s-extension-private" EXTENSION_FILE_NAME="k8s_extension_private" diff --git a/src/k8s-extension/azext_k8s_extension/__init__.py b/src/k8s-extension/azext_k8s_extension/__init__.py index e2301227d45..77d01d5f327 100644 --- a/src/k8s-extension/azext_k8s_extension/__init__.py +++ b/src/k8s-extension/azext_k8s_extension/__init__.py @@ -4,28 +4,29 @@ # -------------------------------------------------------------------------------------------- from azure.cli.core import AzCommandsLoader +from . import consts -from azext_k8s_extension._help import helps # pylint: disable=unused-import +from ._help import helps # pylint: disable=unused-import class K8sExtensionCommandsLoader(AzCommandsLoader): def __init__(self, cli_ctx=None): from azure.cli.core.commands import CliCommandType - from azext_k8s_extension._client_factory import cf_k8s_extension + from ._client_factory import cf_k8s_extension k8s_extension_custom = CliCommandType( - operations_tmpl='azext_k8s_extension.custom#{}', + operations_tmpl=consts.EXTENSION_PACKAGE_NAME+'.custom#{}', client_factory=cf_k8s_extension) super(K8sExtensionCommandsLoader, self).__init__(cli_ctx=cli_ctx, custom_command_type=k8s_extension_custom) def load_command_table(self, args): - from azext_k8s_extension.commands import load_command_table + from .commands import load_command_table load_command_table(self, args) return self.command_table def load_arguments(self, command): - from azext_k8s_extension._params import load_arguments + from ._params import load_arguments load_arguments(self, command) diff --git a/src/k8s-extension/azext_k8s_extension/_client_factory.py b/src/k8s-extension/azext_k8s_extension/_client_factory.py index 1a9a10c2615..6271246245e 100644 --- a/src/k8s-extension/azext_k8s_extension/_client_factory.py +++ b/src/k8s-extension/azext_k8s_extension/_client_factory.py @@ -8,7 +8,7 @@ def cf_k8s_extension(cli_ctx, *_): - from azext_k8s_extension.vendored_sdks import SourceControlConfigurationClient + from .vendored_sdks import SourceControlConfigurationClient return get_mgmt_service_client(cli_ctx, SourceControlConfigurationClient) diff --git a/src/k8s-extension/azext_k8s_extension/_help.py b/src/k8s-extension/azext_k8s_extension/_help.py index 562f0af58aa..862bf4572ac 100644 --- a/src/k8s-extension/azext_k8s_extension/_help.py +++ b/src/k8s-extension/azext_k8s_extension/_help.py @@ -5,7 +5,7 @@ # -------------------------------------------------------------------------------------------- from knack.help_files import helps # pylint: disable=unused-import -import azext_k8s_extension._consts as consts +from . import consts helps[f'{consts.EXTENSION_NAME}'] = """ diff --git a/src/k8s-extension/azext_k8s_extension/_params.py b/src/k8s-extension/azext_k8s_extension/_params.py index 3bbc6056a2e..52b680a69f7 100644 --- a/src/k8s-extension/azext_k8s_extension/_params.py +++ b/src/k8s-extension/azext_k8s_extension/_params.py @@ -9,9 +9,9 @@ tags_type ) from azure.cli.core.commands.validators import get_default_location_from_resource_group -import azext_k8s_extension._consts as consts +from . import consts -from azext_k8s_extension.action import ( +from .action import ( AddConfigurationSettings, AddConfigurationProtectedSettings ) diff --git a/src/k8s-extension/azext_k8s_extension/commands.py b/src/k8s-extension/azext_k8s_extension/commands.py index 3a823177d1c..d576ed4fb8e 100644 --- a/src/k8s-extension/azext_k8s_extension/commands.py +++ b/src/k8s-extension/azext_k8s_extension/commands.py @@ -5,15 +5,15 @@ # pylint: disable=line-too-long from azure.cli.core.commands import CliCommandType -from azext_k8s_extension._client_factory import (cf_k8s_extension, cf_k8s_extension_operation) -from azext_k8s_extension._format import k8s_extension_list_table_format, k8s_extension_show_table_format -import azext_k8s_extension._consts as consts +from ._client_factory import (cf_k8s_extension, cf_k8s_extension_operation) +from ._format import k8s_extension_list_table_format, k8s_extension_show_table_format +from . import consts def load_command_table(self, _): k8s_extension_sdk = CliCommandType( - operations_tmpl='azext_k8s_extension.vendored_sdks.operations#K8sExtensionsOperations.{}', + 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, diff --git a/src/k8s-extension/azext_k8s_extension/_consts.py b/src/k8s-extension/azext_k8s_extension/consts.py similarity index 88% rename from src/k8s-extension/azext_k8s_extension/_consts.py rename to src/k8s-extension/azext_k8s_extension/consts.py index 144e9450012..082fee5def8 100644 --- a/src/k8s-extension/azext_k8s_extension/_consts.py +++ b/src/k8s-extension/azext_k8s_extension/consts.py @@ -5,4 +5,4 @@ # -------------------------------------------------------------------------------------------- EXTENSION_NAME = 'k8s-extension' -VERSION = "0.2.1" +EXTENSION_PACKAGE_NAME = "azext_k8s_extension" \ No newline at end of file diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py index ba9dbfce501..5e314269aaf 100644 --- a/src/k8s-extension/azext_k8s_extension/custom.py +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -13,15 +13,15 @@ from azure.cli.core.azclierror import ResourceNotFoundError, MutuallyExclusiveArgumentError, \ InvalidArgumentValueError, CommandNotFoundError, RequiredArgumentMissingError from azure.cli.core.commands.client_factory import get_subscription_id -from azext_k8s_extension.vendored_sdks.models import ConfigurationIdentity -from azext_k8s_extension.vendored_sdks.models import ErrorResponseException -from azext_k8s_extension.vendored_sdks.models import Scope +from .vendored_sdks.models import ConfigurationIdentity +from .vendored_sdks.models import ErrorResponseException +from .vendored_sdks.models import Scope -from azext_k8s_extension.partner_extensions.ContainerInsights import ContainerInsights -from azext_k8s_extension.partner_extensions.AzureDefender import AzureDefender -from azext_k8s_extension.partner_extensions.Cassandra import Cassandra -from azext_k8s_extension.partner_extensions.DefaultExtension import DefaultExtension -import azext_k8s_extension._consts as consts +from .partner_extensions.ContainerInsights import ContainerInsights +from .partner_extensions.AzureDefender import AzureDefender +from .partner_extensions.Cassandra import Cassandra +from .partner_extensions.DefaultExtension import DefaultExtension +from . import consts from ._client_factory import cf_resources @@ -33,7 +33,7 @@ def ExtensionFactory(extension_name): extension_map = { 'microsoft.azuremonitor.containers': ContainerInsights, 'microsoft.azuredefender.kubernetes': AzureDefender, - 'cassandradatacentersoperator': Cassandra + 'cassandradatacentersoperator': Cassandra, } # Return the extension if we find it in the map, else return the default diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py index 3124faec4c1..a3e805006de 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureDefender.py @@ -7,13 +7,13 @@ from knack.log import get_logger -from azext_k8s_extension.vendored_sdks.models import ExtensionInstance -from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate -from azext_k8s_extension.vendored_sdks.models import ScopeCluster -from azext_k8s_extension.vendored_sdks.models import Scope +from ..vendored_sdks.models import ExtensionInstance +from ..vendored_sdks.models import ExtensionInstanceUpdate +from ..vendored_sdks.models import ScopeCluster +from ..vendored_sdks.models import Scope -from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel -from azext_k8s_extension.partner_extensions.ContainerInsights import _get_container_insights_settings +from .PartnerExtensionModel import PartnerExtensionModel +from .ContainerInsights import _get_container_insights_settings logger = get_logger(__name__) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py index 2a609ce125a..2357bf08af6 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/Cassandra.py @@ -5,13 +5,13 @@ # pylint: disable=unused-argument -from azext_k8s_extension.vendored_sdks.models import ExtensionInstance -from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate -from azext_k8s_extension.vendored_sdks.models import ScopeCluster -from azext_k8s_extension.vendored_sdks.models import ScopeNamespace -from azext_k8s_extension.vendored_sdks.models import Scope +from ..vendored_sdks.models import ExtensionInstance +from ..vendored_sdks.models import ExtensionInstanceUpdate +from ..vendored_sdks.models import ScopeCluster +from ..vendored_sdks.models import ScopeNamespace +from ..vendored_sdks.models import Scope -from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel +from .PartnerExtensionModel import PartnerExtensionModel class Cassandra(PartnerExtensionModel): diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py index eade4256205..00e82257e2d 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/ContainerInsights.py @@ -17,14 +17,14 @@ from msrestazure.azure_exceptions import CloudError from msrestazure.tools import parse_resource_id, is_valid_resource_id -from azext_k8s_extension.vendored_sdks.models import ExtensionInstance -from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate -from azext_k8s_extension.vendored_sdks.models import ScopeCluster -from azext_k8s_extension.vendored_sdks.models import Scope +from ..vendored_sdks.models import ExtensionInstance +from ..vendored_sdks.models import ExtensionInstanceUpdate +from ..vendored_sdks.models import ScopeCluster +from ..vendored_sdks.models import Scope -from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel +from .PartnerExtensionModel import PartnerExtensionModel -from azext_k8s_extension._client_factory import ( +from .._client_factory import ( cf_resources, cf_resource_groups, cf_log_analytics) logger = get_logger(__name__) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py index 9a69199f838..a72aef847fc 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/DefaultExtension.py @@ -5,13 +5,13 @@ # pylint: disable=unused-argument -from azext_k8s_extension.vendored_sdks.models import ExtensionInstance -from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate -from azext_k8s_extension.vendored_sdks.models import ScopeCluster -from azext_k8s_extension.vendored_sdks.models import ScopeNamespace -from azext_k8s_extension.vendored_sdks.models import Scope +from ..vendored_sdks.models import ExtensionInstance +from ..vendored_sdks.models import ExtensionInstanceUpdate +from ..vendored_sdks.models import ScopeCluster +from ..vendored_sdks.models import ScopeNamespace +from ..vendored_sdks.models import Scope -from azext_k8s_extension.partner_extensions.PartnerExtensionModel import PartnerExtensionModel +from .PartnerExtensionModel import PartnerExtensionModel class DefaultExtension(PartnerExtensionModel): diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py index 96c489644e7..b8cb01334d3 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/PartnerExtensionModel.py @@ -4,8 +4,8 @@ # -------------------------------------------------------------------------------------------- from abc import ABC, abstractmethod -from azext_k8s_extension.vendored_sdks.models import ExtensionInstance -from azext_k8s_extension.vendored_sdks.models import ExtensionInstanceUpdate +from ..vendored_sdks.models import ExtensionInstance +from ..vendored_sdks.models import ExtensionInstanceUpdate class PartnerExtensionModel(ABC): diff --git a/src/k8s-extension/setup.py b/src/k8s-extension/setup.py index d3d491fd48c..6b3c7556e93 100644 --- a/src/k8s-extension/setup.py +++ b/src/k8s-extension/setup.py @@ -8,7 +8,7 @@ from codecs import open from setuptools import setup, find_packages -import azext_k8s_extension._consts as consts + try: from azure_bdist_wheel import cmdclass except ImportError: @@ -32,14 +32,16 @@ # TODO: Add any additional SDK dependencies here DEPENDENCIES = [] +VERSION = "0.2.1" + with open('README.rst', 'r', encoding='utf-8') as f: README = f.read() with open('HISTORY.rst', 'r', encoding='utf-8') as f: HISTORY = f.read() setup( - name=consts.EXTENSION_NAME, - version=consts.VERSION, + name="k8s-extension", + version=VERSION, description='Microsoft Azure Command-Line Tools K8s-extension Extension', # TODO: Update author and email, if applicable author='Microsoft Corporation', From 0228851f933617e969a1b24befaff3e846c68712 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 14 Apr 2021 16:31:14 -0700 Subject: [PATCH 51/80] Fix style errors --- src/k8s-extension/azext_k8s_extension/__init__.py | 2 +- src/k8s-extension/azext_k8s_extension/commands.py | 2 +- src/k8s-extension/azext_k8s_extension/consts.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k8s-extension/azext_k8s_extension/__init__.py b/src/k8s-extension/azext_k8s_extension/__init__.py index 77d01d5f327..2da15ca787d 100644 --- a/src/k8s-extension/azext_k8s_extension/__init__.py +++ b/src/k8s-extension/azext_k8s_extension/__init__.py @@ -15,7 +15,7 @@ def __init__(self, cli_ctx=None): from azure.cli.core.commands import CliCommandType from ._client_factory import cf_k8s_extension k8s_extension_custom = CliCommandType( - operations_tmpl=consts.EXTENSION_PACKAGE_NAME+'.custom#{}', + operations_tmpl=consts.EXTENSION_PACKAGE_NAME + '.custom#{}', client_factory=cf_k8s_extension) super(K8sExtensionCommandsLoader, self).__init__(cli_ctx=cli_ctx, custom_command_type=k8s_extension_custom) diff --git a/src/k8s-extension/azext_k8s_extension/commands.py b/src/k8s-extension/azext_k8s_extension/commands.py index d576ed4fb8e..abe6f501b79 100644 --- a/src/k8s-extension/azext_k8s_extension/commands.py +++ b/src/k8s-extension/azext_k8s_extension/commands.py @@ -13,7 +13,7 @@ def load_command_table(self, _): k8s_extension_sdk = CliCommandType( - operations_tmpl=consts.EXTENSION_PACKAGE_NAME+'.vendored_sdks.operations#K8sExtensionsOperations.{}', + 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, diff --git a/src/k8s-extension/azext_k8s_extension/consts.py b/src/k8s-extension/azext_k8s_extension/consts.py index 082fee5def8..4d09158eacd 100644 --- a/src/k8s-extension/azext_k8s_extension/consts.py +++ b/src/k8s-extension/azext_k8s_extension/consts.py @@ -5,4 +5,4 @@ # -------------------------------------------------------------------------------------------- EXTENSION_NAME = 'k8s-extension' -EXTENSION_PACKAGE_NAME = "azext_k8s_extension" \ No newline at end of file +EXTENSION_PACKAGE_NAME = "azext_k8s_extension" From db4c5b2bf3ad51c48d55ea9f94972b12c2cf1da7 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 14 Apr 2021 16:38:21 -0700 Subject: [PATCH 52/80] Fix filename --- k8s-custom-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 451d1e08889..296e4b95614 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -171,7 +171,7 @@ stages: cp $(CLI_REPO_PATH)/src/k8s-extension $(CLI_REPO_PATH)/src/k8s-extension-private -r mv $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension_private cp $(CLI_REPO_PATH)/src/k8s-extension-private/setup_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/setup.py - cp $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension_private/_consts_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension_private/_consts.py + cp $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension_private/consts_private.py $(CLI_REPO_PATH)/src/k8s-extension-private/azext_k8s_extension_private/consts.py EXTENSION_NAME="k8s-extension-private" EXTENSION_FILE_NAME="k8s_extension_private" From 50771921db45669e0466ddf0566ac9a8f0f3e148 Mon Sep 17 00:00:00 2001 From: yuyue9284 <15863499+yuyue9284@users.noreply.github.com> Date: Sat, 24 Apr 2021 04:30:03 +0800 Subject: [PATCH 53/80] add customization for microsoft.azureml.kubernetes (#23) * add customization for microsoft.azureml.kubernetes * Update release history Co-authored-by: Yue Yu Co-authored-by: jonathan-innis --- src/k8s-extension/HISTORY.rst | 5 + .../azext_k8s_extension/custom.py | 2 + .../partner_extensions/AzureMLKubernetes.py | 402 ++++++++++++++++++ src/k8s-extension/setup.py | 2 +- 4 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py diff --git a/src/k8s-extension/HISTORY.rst b/src/k8s-extension/HISTORY.rst index d20160a2199..dbf39b332fe 100644 --- a/src/k8s-extension/HISTORY.rst +++ b/src/k8s-extension/HISTORY.rst @@ -3,6 +3,11 @@ Release History =============== +0.3.0 +++++++++++++++++++ + +* Release customization for microsoft.azureml.kubernetes + 0.2.1 ++++++++++++++++++ diff --git a/src/k8s-extension/azext_k8s_extension/custom.py b/src/k8s-extension/azext_k8s_extension/custom.py index 5e314269aaf..2441c69ed90 100644 --- a/src/k8s-extension/azext_k8s_extension/custom.py +++ b/src/k8s-extension/azext_k8s_extension/custom.py @@ -20,6 +20,7 @@ from .partner_extensions.ContainerInsights import ContainerInsights from .partner_extensions.AzureDefender import AzureDefender from .partner_extensions.Cassandra import Cassandra +from .partner_extensions.AzureMLKubernetes import AzureMLKubernetes from .partner_extensions.DefaultExtension import DefaultExtension from . import consts @@ -33,6 +34,7 @@ def ExtensionFactory(extension_name): extension_map = { 'microsoft.azuremonitor.containers': ContainerInsights, 'microsoft.azuredefender.kubernetes': AzureDefender, + 'microsoft.azureml.kubernetes': AzureMLKubernetes, 'cassandradatacentersoperator': Cassandra, } diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py new file mode 100644 index 00000000000..34aac58e017 --- /dev/null +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py @@ -0,0 +1,402 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument +import copy +from hashlib import md5 +from typing import Any, Dict, List, Tuple + +import azure.mgmt.relay +import azure.mgmt.relay.models +import azure.mgmt.resource.locks +import azure.mgmt.servicebus +import azure.mgmt.servicebus.models +import azure.mgmt.storage +import azure.mgmt.storage.models +import azure.mgmt.loganalytics +import azure.mgmt.loganalytics.models +from ..vendored_sdks.models import ( + ExtensionInstance, ExtensionInstanceUpdate, Scope, ScopeCluster) +from azure.cli.core.azclierror import InvalidArgumentValueError +from azure.cli.core.commands.client_factory import get_mgmt_service_client, get_subscription_id +from azure.mgmt.resource.locks.models import ManagementLockObject +from knack.log import get_logger +from msrestazure.azure_exceptions import CloudError + +from .._client_factory import cf_resources +from .PartnerExtensionModel import PartnerExtensionModel + +logger = get_logger(__name__) + +resource_tag = {'created_by': 'amlk8s-extension'} + + +class AzureMLKubernetes(PartnerExtensionModel): + def __init__(self): + # constants for configuration settings. + self.DEFAULT_RELEASE_NAMESPACE = 'azureml' + self.RELAY_CONNECTION_STRING_KEY = 'relayserver.relayConnectionString' + self.RELAY_CONNECTION_STRING_DEPRECATED_KEY = 'RelayConnectionString' # for 3rd party deployment, will be deprecated + self.HC_RESOURCE_ID_KEY = 'relayserver.hybridConnectionResourceID' + self.RELAY_HC_NAME_KEY = 'relayserver.hybridConnectionName' + self.SERVICE_BUS_CONNECTION_STRING_KEY = 'servicebus.connectionString' + self.SERVICE_BUS_RESOURCE_ID_KEY = 'servicebus.resourceID' + self.SERVICE_BUS_TOPIC_SUB_MAPPING_KEY = 'servicebus.topicSubMapping' + self.AZURE_LOG_ANALYTICS_ENABLED_KEY = 'azure_log_analytics.enabled' + self.AZURE_LOG_ANALYTICS_CUSTOMER_ID_KEY = 'azure_log_analytics.customer_id' + self.AZURE_LOG_ANALYTICS_CONNECTION_STRING = 'azure_log_analytics.connection_string' + self.JOB_SCHEDULER_LOCATION_KEY = 'jobSchedulerLocation' + self.CLUSTER_NAME_FRIENDLY_KEY = 'cluster_name_friendly' + + # component flag + self.ENABLE_TRAINING = 'enableTraining' + self.ENABLE_INFERENCE = 'enableInference' + + # constants for determine whether create underlying azure resource + self.RELAY_SERVER_CONNECTION_STRING = 'relayServerConnectionString' # create relay connection string if None + self.SERVICE_BUS_CONNECTION_STRING = 'serviceBusConnectionString' # create service bus if None + self.LOG_ANALYTICS_WS_ENABLED = 'logAnalyticsWS' # create log analytics workspace if true + + # constants for azure resources creation + self.RELAY_HC_AUTH_NAME = 'azureml_rw' + self.SERVICE_BUS_COMPUTE_STATE_TOPIC = 'computestate-updatedby-computeprovider' + self.SERVICE_BUS_COMPUTE_STATE_SUB = 'compute-scheduler-computestate' + self.SERVICE_BUS_JOB_STATE_TOPIC = 'jobstate-updatedby-computeprovider' + self.SERVICE_BUS_JOB_STATE_SUB = 'compute-scheduler-jobstate' + + # reference mapping + self.reference_mapping = { + self.RELAY_SERVER_CONNECTION_STRING: [self.RELAY_CONNECTION_STRING_KEY, self.RELAY_CONNECTION_STRING_DEPRECATED_KEY], + self.SERVICE_BUS_CONNECTION_STRING: [self.SERVICE_BUS_CONNECTION_STRING_KEY], + 'cluster_name': ['clusterId', 'prometheus.prometheusSpec.externalLabels.cluster_name'], + } + + def Create(self, cmd, client, resource_group_name, cluster_name, name, cluster_type, extension_type, + scope, auto_upgrade_minor_version, release_train, version, target_namespace, + release_namespace, configuration_settings, configuration_protected_settings, + configuration_settings_file, configuration_protected_settings_file): + if scope == 'namespace': + raise InvalidArgumentValueError("Invalid scope '{}'. This extension can be installed " + "only at 'cluster' scope.".format(scope)) + if not release_namespace: + release_namespace = self.DEFAULT_RELEASE_NAMESPACE + scope_cluster = ScopeCluster(release_namespace=release_namespace) + ext_scope = Scope(cluster=scope_cluster, namespace=None) + + # validate the config + self.__validate_config(configuration_settings, configuration_protected_settings) + + # get the arc's location + subscription_id = get_subscription_id(cmd.cli_ctx) + cluster_rp, parent_api_version = _get_cluster_rp_api_version(cluster_type) + cluster_resource_id = '/subscriptions/{0}/resourceGroups/{1}/providers/{2}' \ + '/{3}/{4}'.format(subscription_id, resource_group_name, cluster_rp, cluster_type, cluster_name) + cluster_location = '' + resources = cf_resources(cmd.cli_ctx, subscription_id) + try: + resource = resources.get_by_id( + cluster_resource_id, parent_api_version) + cluster_location = resource.location.lower() + except CloudError as ex: + raise ex + + # generate values for the extension if none is set. + configuration_settings['cluster_name'] = configuration_settings.get('cluster_name', cluster_resource_id) + configuration_settings['domain'] = configuration_settings.get( + 'doamin', '{}.cloudapp.azure.com'.format(cluster_location)) + configuration_settings['location'] = configuration_settings.get('location', cluster_location) + configuration_settings[self.JOB_SCHEDULER_LOCATION_KEY] = configuration_settings.get( + self.JOB_SCHEDULER_LOCATION_KEY, cluster_location) + configuration_settings[self.CLUSTER_NAME_FRIENDLY_KEY] = configuration_settings.get( + self.CLUSTER_NAME_FRIENDLY_KEY, cluster_name) + + # create Azure resources need by the extension based on the config. + self.__create_required_resource( + cmd, configuration_settings, configuration_protected_settings, subscription_id, resource_group_name, + cluster_name, cluster_location) + + # dereference + configuration_settings = _dereference(self.reference_mapping, configuration_settings) + configuration_protected_settings = _dereference(self.reference_mapping, configuration_protected_settings) + + # If release-train is not input, set it to 'stable' + if release_train is None: + release_train = 'stable' + + create_identity = True + extension_instance = ExtensionInstance( + extension_type=extension_type, + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version, + scope=ext_scope, + configuration_settings=configuration_settings, + configuration_protected_settings=configuration_protected_settings, + identity=None, + location="" + ) + return extension_instance, name, create_identity + + def Update(self, extension, auto_upgrade_minor_version, release_train, version): + return ExtensionInstanceUpdate( + auto_upgrade_minor_version=auto_upgrade_minor_version, + release_train=release_train, + version=version + ) + + def __validate_config(self, configuration_settings, configuration_protected_settings): + # perform basic validation of the input config + config_keys = configuration_settings.keys() + config_protected_keys = configuration_protected_settings.keys() + dup_keys = set(config_keys) & set(config_protected_keys) + if len(dup_keys) > 0: + for key in dup_keys: + logger.warn( + f'Duplicate keys found in both configuration settings and configuration protected setttings: {key}') + raise InvalidArgumentValueError("Duplicate keys found.") + + enable_training = _get_value_from_config_protected_config( + self.ENABLE_TRAINING, configuration_settings, configuration_protected_settings) + enable_training = str(enable_training).lower() == 'true' + + enable_inference = _get_value_from_config_protected_config( + self.ENABLE_INFERENCE, configuration_settings, configuration_protected_settings) + enable_inference = str(enable_inference).lower() == 'true' + + if not (enable_training or enable_inference): + raise InvalidArgumentValueError( + "Please create Microsoft.AzureML.Kubernetes extension instance either " + "for Machine Learning training or inference by specifying " + f"'--configuration-settings {self.ENABLE_TRAINING}=true' or '--configuration-settings {self.ENABLE_INFERENCE}=true'") + + configuration_settings[self.ENABLE_TRAINING] = configuration_settings.get(self.ENABLE_TRAINING, enable_training) + configuration_settings[self.ENABLE_INFERENCE] = configuration_settings.get( + self.ENABLE_INFERENCE, enable_inference) + configuration_protected_settings.pop(self.ENABLE_TRAINING, None) + configuration_protected_settings.pop(self.ENABLE_INFERENCE, None) + + def __create_required_resource( + self, cmd, configuration_settings, configuration_protected_settings, subscription_id, resource_group_name, + cluster_name, cluster_location): + if str(configuration_settings.get(self.LOG_ANALYTICS_WS_ENABLED, False)).lower() == 'true'\ + and not configuration_settings.get(self.AZURE_LOG_ANALYTICS_CONNECTION_STRING)\ + and not configuration_protected_settings.get(self.AZURE_LOG_ANALYTICS_CONNECTION_STRING): + logger.info('==== BEGIN LOG ANALYTICS WORKSPACE CREATION ====') + ws_costumer_id, shared_key = _get_log_analytics_ws_connection_string( + cmd, subscription_id, resource_group_name, cluster_name, cluster_location) + logger.info('==== END LOG ANALYTICS WORKSPACE CREATION ====') + configuration_settings[self.AZURE_LOG_ANALYTICS_ENABLED_KEY] = True + configuration_settings[self.AZURE_LOG_ANALYTICS_CUSTOMER_ID_KEY] = ws_costumer_id + configuration_protected_settings[self.AZURE_LOG_ANALYTICS_CONNECTION_STRING] = shared_key + + if not configuration_settings.get( + self.RELAY_SERVER_CONNECTION_STRING) and not configuration_protected_settings.get( + self.RELAY_SERVER_CONNECTION_STRING): + logger.info('==== BEGIN RELAY CREATION ====') + relay_connection_string, hc_resource_id, hc_name = _get_relay_connection_str( + cmd, subscription_id, resource_group_name, cluster_name, cluster_location, self.RELAY_HC_AUTH_NAME) + logger.info('==== END RELAY CREATION ====') + configuration_protected_settings[self.RELAY_SERVER_CONNECTION_STRING] = relay_connection_string + configuration_settings[self.HC_RESOURCE_ID_KEY] = hc_resource_id + configuration_settings[self.RELAY_HC_NAME_KEY] = hc_name + + if not configuration_settings.get( + self.SERVICE_BUS_CONNECTION_STRING) and not configuration_protected_settings.get( + self.SERVICE_BUS_CONNECTION_STRING): + logger.info('==== BEGIN SERVICE BUS CREATION ====') + topic_sub_mapping = { + self.SERVICE_BUS_COMPUTE_STATE_TOPIC: self.SERVICE_BUS_COMPUTE_STATE_SUB, + self.SERVICE_BUS_JOB_STATE_TOPIC: self.SERVICE_BUS_JOB_STATE_SUB + } + service_bus_connection_string, service_buse_resource_id = _get_service_bus_connection_string( + cmd, subscription_id, resource_group_name, cluster_name, cluster_location, topic_sub_mapping) + logger.info('==== END SERVICE BUS CREATION ====') + configuration_protected_settings[self.SERVICE_BUS_CONNECTION_STRING] = service_bus_connection_string + configuration_settings[self.SERVICE_BUS_RESOURCE_ID_KEY] = service_buse_resource_id + configuration_settings[f'{self.SERVICE_BUS_TOPIC_SUB_MAPPING_KEY}.{self.SERVICE_BUS_COMPUTE_STATE_TOPIC}'] = self.SERVICE_BUS_COMPUTE_STATE_SUB + configuration_settings[f'{self.SERVICE_BUS_TOPIC_SUB_MAPPING_KEY}.{self.SERVICE_BUS_JOB_STATE_TOPIC}'] = self.SERVICE_BUS_JOB_STATE_SUB + + +def _get_valid_name(input_name: str, suffix_len: int, max_len: int) -> str: + normalized_str = ''.join(filter(str.isalnum, input_name)) + assert len(normalized_str) > 0, "normalized name empty" + + if len(normalized_str) <= max_len: + return normalized_str + + if suffix_len > max_len: + logger.warning( + "suffix length is bigger than max length. Set suffix length to max length.") + suffix_len = max_len + + md5_suffix = md5(input_name.encode("utf8")).hexdigest()[:suffix_len] + new_name = normalized_str[:max_len - suffix_len] + md5_suffix + return new_name + + +def _lock_resource(cmd, lock_scope, lock_level='CanNotDelete'): + lock_client: azure.mgmt.resource.locks.ManagementLockClient = get_mgmt_service_client( + cmd.cli_ctx, azure.mgmt.resource.locks.ManagementLockClient) + # put lock on relay resource + lock_object = ManagementLockObject(level=lock_level, notes='locked by amlk8s.') + try: + lock_client.management_locks.create_or_update_by_scope( + scope=lock_scope, lock_name='amlk8s-resource-lock', parameters=lock_object) + except: + # try to lock the resource if user has the owner privilege + pass + + +def _get_relay_connection_str( + cmd, subscription_id, resource_group_name, cluster_name, cluster_location, auth_rule_name) -> Tuple[ + str, str, str]: + relay_client: azure.mgmt.relay.RelayManagementClient = get_mgmt_service_client( + cmd.cli_ctx, azure.mgmt.relay.RelayManagementClient) + + cluster_id = '{}-{}-{}-relay'.format(cluster_name, subscription_id, resource_group_name) + # create namespace + relay_namespace_name = _get_valid_name( + cluster_id, suffix_len=6, max_len=50) + relay_namespace_params = azure.mgmt.relay.models.RelayNamespace( + location=cluster_location, tags=resource_tag) + + async_poller = relay_client.namespaces.create_or_update( + resource_group_name, relay_namespace_name, relay_namespace_params) + while True: + async_poller.result(15) + if async_poller.done(): + break + + # create hybrid connection + hybrid_connection_name = cluster_name + hybrid_connection_object = relay_client.hybrid_connections.create_or_update( + resource_group_name, relay_namespace_name, hybrid_connection_name, requires_client_authorization=True) + + # relay_namespace_ojbect = relay_client.namespaces.get(resource_group_name, relay_namespace_name) + # relay_namespace_resource_id = relay_namespace_ojbect.id + # _lock_resource(cmd, lock_scope=relay_namespace_resource_id) + + # create authorization rule + auth_rule_rights = [azure.mgmt.relay.models.AccessRights.manage, + azure.mgmt.relay.models.AccessRights.send, azure.mgmt.relay.models.AccessRights.listen] + relay_client.hybrid_connections.create_or_update_authorization_rule( + resource_group_name, relay_namespace_name, hybrid_connection_name, auth_rule_name, rights=auth_rule_rights) + + # get connection string + key: azure.mgmt.relay.models.AccessKeys = relay_client.hybrid_connections.list_keys( + resource_group_name, relay_namespace_name, hybrid_connection_name, auth_rule_name) + return f'{key.primary_connection_string}', hybrid_connection_object.id, hybrid_connection_name + + +def _get_service_bus_connection_string(cmd, subscription_id, resource_group_name, cluster_name, cluster_location, + topic_sub_mapping: Dict[str, str]) -> Tuple[str, str]: + service_bus_client: azure.mgmt.servicebus.ServiceBusManagementClient = get_mgmt_service_client( + cmd.cli_ctx, azure.mgmt.servicebus.ServiceBusManagementClient) + cluster_id = '{}-{}-{}-service-bus'.format(cluster_name, + subscription_id, resource_group_name) + service_bus_namespace_name = _get_valid_name( + cluster_id, suffix_len=6, max_len=50) + + # create namespace + service_bus_sku = azure.mgmt.servicebus.models.SBSku( + name=azure.mgmt.servicebus.models.SkuName.standard.name) + service_bus_namespace = azure.mgmt.servicebus.models.SBNamespace( + location=cluster_location, + sku=service_bus_sku, + tags=resource_tag) + async_poller = service_bus_client.namespaces.create_or_update( + resource_group_name, service_bus_namespace_name, service_bus_namespace) + while True: + async_poller.result(15) + if async_poller.done(): + break + + for topic_name, service_bus_subscription_name in topic_sub_mapping.items(): + # create topic + topic = azure.mgmt.servicebus.models.SBTopic(max_size_in_megabytes=5120, default_message_time_to_live='P60D') + service_bus_client.topics.create_or_update( + resource_group_name, service_bus_namespace_name, topic_name, topic) + + # create subscription + sub = azure.mgmt.servicebus.models.SBSubscription( + max_delivery_count=1, default_message_time_to_live='P14D', lock_duration='PT30S') + service_bus_client.subscriptions.create_or_update( + resource_group_name, service_bus_namespace_name, topic_name, service_bus_subscription_name, sub) + + service_bus_object = service_bus_client.namespaces.get(resource_group_name, service_bus_namespace_name) + service_bus_resource_id = service_bus_object.id + # _lock_resource(cmd, service_bus_resource_id) + + # get connection string + auth_rules = service_bus_client.namespaces.list_authorization_rules( + resource_group_name, service_bus_namespace_name) + for rule in auth_rules: + key: azure.mgmt.servicebus.models.AccessKeys = service_bus_client.namespaces.list_keys( + resource_group_name, service_bus_namespace_name, rule.name) + return key.primary_connection_string, service_bus_resource_id + + +def _get_log_analytics_ws_connection_string( + cmd, subscription_id, resource_group_name, cluster_name, cluster_location) -> Tuple[ + str, str]: + log_analytics_ws_client: azure.mgmt.loganalytics.LogAnalyticsManagementClient = get_mgmt_service_client( + cmd.cli_ctx, azure.mgmt.loganalytics.LogAnalyticsManagementClient) + + # create workspace + cluster_id = '{}-{}-{}'.format(cluster_name, subscription_id, resource_group_name) + log_analytics_ws_name = _get_valid_name(cluster_id, suffix_len=6, max_len=63) + log_analytics_ws = azure.mgmt.loganalytics.models.Workspace(location=cluster_location, tags=resource_tag) + async_poller = log_analytics_ws_client.workspaces.begin_create_or_update( + resource_group_name, log_analytics_ws_name, log_analytics_ws) + customer_id = '' + # log_analytics_ws_resource_id = '' + while True: + log_analytics_ws_object = async_poller.result(15) + if async_poller.done(): + customer_id = log_analytics_ws_object.customer_id + # log_analytics_ws_resource_id = log_analytics_ws_object.id + break + + # _lock_resource(cmd, log_analytics_ws_resource_id) + + # get workspace shared keys + shared_key = log_analytics_ws_client.shared_keys.get_shared_keys( + resource_group_name, log_analytics_ws_name).primary_shared_key + return customer_id, shared_key + + +def _dereference(ref_mapping_dict: Dict[str, List], output_dict: Dict[str, Any]): + output_dict = copy.deepcopy(output_dict) + for ref_key, ref_list in ref_mapping_dict.items(): + if ref_key not in output_dict: + continue + ref_value = output_dict[ref_key] + for key in ref_list: + # if user has set the value, skip. + output_dict[key] = output_dict.get(key, ref_value) + return output_dict + + +def _get_value_from_config_protected_config(key, config, protected_config): + if key in config: + return config[key] + return protected_config.get(key) + + +def _get_cluster_rp_api_version(cluster_type) -> Tuple[str, str]: + rp = '' + parent_api_version = '' + if cluster_type.lower() == 'connectedclusters': + rp = 'Microsoft.Kubernetes' + parent_api_version = '2020-01-01-preview' + elif cluster_type.lower() == 'appliances': + rp = 'Microsoft.ResourceConnector' + parent_api_version = '2020-09-15-privatepreview' + elif cluster_type.lower() == '': + rp = 'Microsoft.ContainerService' + parent_api_version = '2017-07-01' + else: + raise InvalidArgumentValueError("Error! Cluster type '{}' is not supported".format(cluster_type)) + return rp, parent_api_version diff --git a/src/k8s-extension/setup.py b/src/k8s-extension/setup.py index 6b3c7556e93..3c9a1882a27 100644 --- a/src/k8s-extension/setup.py +++ b/src/k8s-extension/setup.py @@ -32,7 +32,7 @@ # TODO: Add any additional SDK dependencies here DEPENDENCIES = [] -VERSION = "0.2.1" +VERSION = "0.3.0" with open('README.rst', 'r', encoding='utf-8') as f: README = f.read() From 3d1515113695db539b87c75afe28fa30f90bad0e Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Mon, 26 Apr 2021 14:18:56 -0700 Subject: [PATCH 54/80] Add E2E Testing from Separate branch into internal code (#26) * Add internal e2e testing * Change to testing folder --- k8s-custom-pipelines.yml | 24 +-- testing/.gitignore | 8 + testing/Bootstrap.ps1 | 80 ++++++++++ testing/Cleanup.ps1 | 24 +++ testing/README.md | 116 ++++++++++++++ testing/Test.ps1 | 76 ++++++++++ .../bin/connectedk8s-1.0.0-py3-none-any.whl | Bin 0 -> 62802 bytes testing/bin/connectedk8s-values.yaml | 3 + .../bin/k8s_extension-0.2.0-py3-none-any.whl | Bin 0 -> 46987 bytes testing/docs/test_authoring.md | 142 ++++++++++++++++++ testing/owners.txt | 2 + testing/settings.template.json | 12 ++ .../private-preview/AzurePolicy.Tests.ps1 | 95 ++++++++++++ .../public/AzureMLKubernetes.Tests.ps1 | 94 ++++++++++++ .../extensions/public/AzureMonitor.Tests.ps1 | 95 ++++++++++++ testing/test/helper/Constants.ps1 | 7 + testing/test/helper/Helper.ps1 | 47 ++++++ 17 files changed, 809 insertions(+), 16 deletions(-) create mode 100644 testing/.gitignore create mode 100644 testing/Bootstrap.ps1 create mode 100644 testing/Cleanup.ps1 create mode 100644 testing/README.md create mode 100644 testing/Test.ps1 create mode 100644 testing/bin/connectedk8s-1.0.0-py3-none-any.whl create mode 100644 testing/bin/connectedk8s-values.yaml create mode 100644 testing/bin/k8s_extension-0.2.0-py3-none-any.whl create mode 100644 testing/docs/test_authoring.md create mode 100644 testing/owners.txt create mode 100644 testing/settings.template.json create mode 100644 testing/test/extensions/private-preview/AzurePolicy.Tests.ps1 create mode 100644 testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 create mode 100644 testing/test/extensions/public/AzureMonitor.Tests.ps1 create mode 100644 testing/test/helper/Constants.ps1 create mode 100644 testing/test/helper/Helper.ps1 diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 296e4b95614..00d87b68d13 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -1,10 +1,3 @@ -resources: - repositories: - - repository: K8sPartnerExtensionTest - type: git - endpoint: AzureReposConnection - name: One/compute-HybridMgmt-K8sPartnerExtensionTest - trigger: batch: true branches: @@ -21,8 +14,8 @@ stages: - stage: BuildTestPublishExtension displayName: "Build, Test, and Publish Extension" variables: - K8S_EXTENSION_REPO_PATH: $(Agent.BuildDirectory)/s/compute-HybridMgmt-K8sPartnerExtensionTest - CLI_REPO_PATH: $(Agent.BuildDirectory)/s/azure-cli-extensions + TEST_PATH: $(Agent.BuildDirectory)/s/testing + CLI_REPO_PATH: $(Agent.BuildDirectory)/s SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" RESOURCE_GROUP: "K8sPartnerExtensionTest" BASE_CLUSTER_NAME: "k8s-extension-cluster" @@ -37,7 +30,6 @@ stages: vmImage: 'ubuntu-16.04' steps: - checkout: self - - checkout: K8sPartnerExtensionTest - bash: | echo "Installing helm3" curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 @@ -78,7 +70,7 @@ stages: - bash: | K8S_EXTENSION_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) echo "##vso[task.setvariable variable=K8S_EXTENSION_VERSION]$K8S_EXTENSION_VERSION" - cp * $(K8S_EXTENSION_REPO_PATH)/bin + cp * $(TEST_PATH)/bin workingDirectory: $(CLI_REPO_PATH)/dist displayName: "Copy the Built .whl to Extension Test Path" @@ -96,7 +88,7 @@ stages: '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-extension": $K8S_EXTENSION_VERSION, connectedk8s: "1.0.0"}}') echo $JSON_STRING > settings.json cat settings.json - workingDirectory: $(K8S_EXTENSION_REPO_PATH) + workingDirectory: $(TEST_PATH) displayName: "Generate a settings.json file" - bash : | @@ -114,7 +106,7 @@ stages: scriptLocation: inlineScript inlineScript: | .\Bootstrap.ps1 -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) + workingDirectory: $(TEST_PATH) - task: AzureCLI@2 displayName: Run the Test Suite Public Extensions Only @@ -124,7 +116,7 @@ stages: scriptLocation: inlineScript inlineScript: | .\Test.ps1 -CI -ExtensionType Public -OnlyPublicTests - workingDirectory: $(K8S_EXTENSION_REPO_PATH) + workingDirectory: $(TEST_PATH) continueOnError: true condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'False')) @@ -136,7 +128,7 @@ stages: scriptLocation: inlineScript inlineScript: | .\Test.ps1 -CI -ExtensionType Public - workingDirectory: $(K8S_EXTENSION_REPO_PATH) + workingDirectory: $(TEST_PATH) continueOnError: true condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'True')) @@ -155,7 +147,7 @@ stages: scriptLocation: inlineScript inlineScript: | .\Cleanup.ps1 -CI - workingDirectory: $(K8S_EXTENSION_REPO_PATH) + workingDirectory: $(TEST_PATH) condition: succeededOrFailed() - job: BuildPublishExtension diff --git a/testing/.gitignore b/testing/.gitignore new file mode 100644 index 00000000000..7df7f6a7294 --- /dev/null +++ b/testing/.gitignore @@ -0,0 +1,8 @@ +settings.json +tmp/ +bin/* +!bin/connectedk8s-1.0.0-py3-none-any.whl +!bin/k8s_extension-0.2.0-py3-none-any.whl +!bin/k8s_extension_private-0.1.0-py3-none-any.whl +!bin/connectedk8s-values.yaml +*.xml \ No newline at end of file diff --git a/testing/Bootstrap.ps1 b/testing/Bootstrap.ps1 new file mode 100644 index 00000000000..c9123ba6d03 --- /dev/null +++ b/testing/Bootstrap.ps1 @@ -0,0 +1,80 @@ +param ( + [switch] $SkipInstall, + [switch] $CI +) + +# Disable confirm prompt for script +az config set core.disable_confirm_prompt=true + +# Configuring the environment +$ENVCONFIG = Get-Content -Path $PSScriptRoot/settings.json | ConvertFrom-Json + +az account set --subscription $ENVCONFIG.subscriptionId + +if (-not (Test-Path -Path $PSScriptRoot/tmp)) { + New-Item -ItemType Directory -Path $PSScriptRoot/tmp +} + +if (!$SkipInstall) { + Write-Host "Removing the old connnectedk8s extension..." + az extension remove -n connectedk8s + $connectedk8sVersion = $ENVCONFIG.extensionVersion.connectedk8s + if (!$connectedk8sVersion) { + Write-Host "connectedk8s extension version wasn't specified" -ForegroundColor Red + Exit 1 + } + Write-Host "Installing connectedk8s version $connectedk8sVersion..." + az extension add --source ./bin/connectedk8s-$connectedk8sVersion-py3-none-any.whl + if (!$?) { + Write-Host "Unable to find connectedk8s version $connectedk8sVersion, exiting..." + exit 1 + } +} + +Write-Host "Onboard cluster to Azure...starting!" + +az group show --name $envConfig.resourceGroup +if (!$?) { + Write-Host "Resource group does not exist, creating it now in region 'eastus2euap'" + az group create --name $envConfig.resourceGroup --location eastus2euap + + if (!$?) { + Write-Host "Failed to create Resource Group - exiting!" + Exit 1 + } +} + +# Skip creating the AKS Cluster if this is CI +if (!$CI) { + az aks show -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.aksClusterName + if (!$?) { + Write-Host "Cluster does not exist, creating it now" + az aks create -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.aksClusterName --generate-ssh-keys + } else { + Write-Host "Cluster already exists, no need to create it." + } + + Write-Host "Retrieving credentials for your AKS cluster..." + + az aks get-credentials -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.aksClusterName -f tmp/KUBECONFIG + if (!$?) + { + Write-Host "Cluster did not create successfully, exiting!" -ForegroundColor Red + Exit 1 + } + Write-Host "Successfully retrieved the AKS kubectl credentials" +} else { + Copy-Item $HOME/.kube/config -Destination $PSScriptRoot/tmp/KUBECONFIG +} + +az connectedk8s show -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.arcClusterName +if ($?) +{ + Write-Host "Cluster is already connected, no need to re-connect" + Exit 0 +} + +Write-Host "Connecting the cluster to Arc with connectedk8s..." +$Env:KUBECONFIG="$PSScriptRoot/tmp/KUBECONFIG" +$Env:HELMVALUESPATH="$PSScriptRoot/bin/connectedk8s-values.yaml" +az connectedk8s connect -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.arcClusterName diff --git a/testing/Cleanup.ps1 b/testing/Cleanup.ps1 new file mode 100644 index 00000000000..9957a044241 --- /dev/null +++ b/testing/Cleanup.ps1 @@ -0,0 +1,24 @@ +param ( + [switch] $CI +) + +# Disable confirm prompt for script +az config set core.disable_confirm_prompt=true + +$ENVCONFIG = Get-Content -Path $PSScriptRoot/settings.json | ConvertFrom-Json + +az account set --subscription $ENVCONFIG.subscriptionId + +$Env:KUBECONFIG="$PSScriptRoot/tmp/KUBECONFIG" +Write-Host "Removing the connectedk8s arc agents from the cluster..." +az connectedk8s delete -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.arcClusterName + +# Skip deleting the AKS Cluster if this is CI +if (!$CI) { + Write-Host "Deleting the AKS cluster from Azure..." + az aks delete -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.aksClusterName + if (Test-Path -Path $PSScriptRoot/tmp) { + Write-Host "Deleting the tmp directory from the test directory" + Remove-Item -Path $PSScriptRoot/tmp -Force -Confirm:$false + } +} \ No newline at end of file diff --git a/testing/README.md b/testing/README.md new file mode 100644 index 00000000000..2c2d48070bd --- /dev/null +++ b/testing/README.md @@ -0,0 +1,116 @@ +# K8s Partner Extension Test Suite + +This repository serves as the integration testing suite for the `k8s-extension` Azure CLI module. + +## Testing Requirements + +All partners who wish to merge their __Custom Private Preview Release__ (owner: _Partner_) into the __Official Private Preview Release__ are required to author additional integration tests for their extension to ensure that their extension will continue to function correctly as more extensions are added into the __Official Private Preview Release__. + +For more information on creating these tests, see [Authoring Tests](docs/test_authoring.md) + +## Pre-Requisites + +In order to properly test all regression tests within the test suite, you must onboard an AKS cluster which you will use to generate your Azure Arc resource to test the extensions. Ensure that you have a resource group where you can onboard this cluster. + +### Required Installations + +The following installations are required in your environment for the integration tests to run correctly: + +1. [Helm 3](https://helm.sh/docs/intro/install/) +2. [Kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) +3. [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) + +## Setup + +### Step 1: Install Pester + +This project contains [Pester](https://pester.dev/) test framework commands that are required for the integration tests to run. In an admin powershell terminal, run + +```powershell +Install-Module Pester -Force -SkipPublisherCheck +Import-Module Pester -PassThru +``` + +If you run into issues installing the framework, refer to the [Installation Guide](https://pester.dev/docs/introduction/installation) provided by the Pester docs. + +### Step 2: Get Test suite files + +You can either clone this repo (preferred option, since you will be adding your tests to this suite) or copy the files in this repo locally. Rest of the instructions here assume your working directory is k8spartner-extension-testing. + +### Step 3: Update the `k8s-extension`/`k8s-extension-private` .whl package + +This integration test suite references the .whl packages found in the `\bin` directory. After generating your `k8s-extension`/`k8s-extension-private` .whl package, copy your updated package into the `\bin` directory. + +### Step 4: Create a `settings.json` + +To onboard the AKS and Arc clusters correctly, you will need to create a `settings.json` configuration. Create a new `settings.json` file by copying the contents of the `settings.template.json` into this file. Update the subscription id, resource group, and AKS and Arc cluster name fields with your specific values. + +### Step 5: Update the extension version value in `settings.json` + +To ensure that the tests point to your `k8s-extension-private` `.whl` package, change the value of the `k8s-extension-private` to match your package versioning in the format (Major.Minor.Patch.Extension). For example, the `k8s_extension_private-0.1.0.openservicemesh_5-py3-none-any.whl` whl package would have extension versions set to +```json +{ + "k8s-extension": "0.1.0", + "k8s-extension-private": "0.1.0.openservicemesh_5", + "connectedk8s": "0.3.5" +} + +``` + +_Note: Updates to the `connectedk8s` version and `k8s-extension` version can also be made by adding a different version of the `connectedk8s` and `k8s-extension` whl packages and changing the `connectedk8s` and `k8s-extension` values to match the (Major.Minor.Patch) version format shown above_ + +### Step 6: Run the Bootstrap Command +To bootstrap the environment with AKS and Arc clusters, run +```powershell +.\Bootstrap.ps1 +``` +This script will provision the AKS and Arc clusters needed to run the integration test suite + +## Testing + +### Testing All Extension Suites +To test all extension test suites, you must call `.\Test.ps1` with the `-ExtensionType` parameter set to either `Public` or `Private`. Based on this flag, the test suite will install the extension type specified below + +| `-ExtensionType` | Installs `az extension` | +| ---------------- | --------------------- | +| `Public` | `k8s-extension` | +| `Private` | `k8s-extension-private` | + +For example, when calling +```bash +.\Test.ps1 -ExtensionType Public +``` +the script will install your `k8s-extension` whl package and run the full test suite of `*.Tests.ps1` files included in the `\test\extensions` directory + +### Testing Public Extensions Only +If you only want to run the test cases against public-preview or GA extension test cases, you can use the `-OnlyPublicTests` flag to specify this +```bash +.\Test.ps1 -ExtensionType Public -OnlyPublicTests +``` + +### Testing Specific Extension Suite + +If you only want to run the test script on your specific test file, you can do so by specifying path to your extension test suite in the execution call + +```powershell +.\Test.ps1 -Path +``` +For example to call the `AzureMonitor.Tests.ps1` test suite, we run +```powershell +.\Test.ps1 -ExtensionType Public -Path .\test\extensions\public\AzureMonitor.Tests.ps1 +``` + +### Skipping Extension Re-Install + +By default the `Test.ps1` script will uninstall any old versions of `k8s-extension`/'`k8s-extension-private` and re-install the version specified in `settings.json`. If you do not want this re-installation to occur, you can specify the `-SkipInstall` flag to skip this process. + +```powershell +.\Test.ps1 -ExtensionType Public -SkipInstall +``` + +## Cleanup +To cleanup the AKS and Arc clusters you have provisioned in testing, run +```powershell +.\Cleanup.ps1 +``` +This will remove the AKS and Arc clusters as well as the `\tmp` directory that were created by the bootstrapping script. \ No newline at end of file diff --git a/testing/Test.ps1 b/testing/Test.ps1 new file mode 100644 index 00000000000..6304c13dc28 --- /dev/null +++ b/testing/Test.ps1 @@ -0,0 +1,76 @@ +param ( + [string] $Path, + [switch] $SkipInstall, + [switch] $CI, + [switch] $OnlyPublicTests, + + [Parameter(Mandatory=$True)] + [ValidateSet('Public','Private')] + [string]$ExtensionType +) + +# Disable confirm prompt for script +az config set core.disable_confirm_prompt=true + +$ENVCONFIG = Get-Content -Path $PSScriptRoot/settings.json | ConvertFrom-Json + +az account set --subscription $ENVCONFIG.subscriptionId + +$Env:KUBECONFIG="$PSScriptRoot/tmp/KUBECONFIG" + +if ($ExtensionType -eq "Public") { + $k8sExtensionVersion = $ENVCONFIG.extensionVersion.'k8s-extension' + $Env:K8sExtensionName = "k8s-extension" + + if (!$SkipInstall) { + Write-Host "Removing the old k8s-extension extension..." + az extension remove -n k8s-extension + Write-Host "Installing k8s-extension version $k8sExtensionVersion..." + az extension add --source ./bin/k8s_extension-$k8sExtensionVersion-py3-none-any.whl + if (!$?) { + Write-Host "Unable to find k8s-extension version $k8sExtensionVersion, exiting..." + exit 1 + } + } +} else { + $k8sExtensionPrivateVersion = $ENVCONFIG.extensionVersion.'k8s-extension-private' + $Env:K8sExtensionName = "k8s-extension-private" + + if (!$SkipInstall) { + Write-Host "Removing the old k8s-extension-private extension..." + az extension remove -n k8s-extension-private + Write-Host "Installing k8s-extension-private version $k8sExtensionPrivateVersion..." + az extension add --source ./bin/k8s_extension_private-$k8sExtensionPrivateVersion-py3-none-any.whl + if (!$?) { + Write-Host "Unable to find k8s-extension-private version $k8sExtensionPrivateVersion, exiting..." + exit 1 + } + } +} + +if ($CI) { + if ($OnlyPublicTests) { + Write-Host "Invoking Pester to run tests from '$PSScriptRoot/test/extensions/public'" + $testResult = Invoke-Pester $PSScriptRoot/test/extensions/public -Passthru -Output Detailed + $testResult | Export-JUnitReport -Path TestResults.xml + } + else { + Write-Host "Invoking Pester to run tests from '$PSScriptRoot/test/extensions'" + $testResult = Invoke-Pester $PSScriptRoot/test/extensions -Passthru -Output Detailed + $testResult | Export-JUnitReport -Path TestResults.xml + } +} else { + if ($Path) { + Write-Host "Invoking Pester to run tests from '$PSScriptRoot/$Path'" + Invoke-Pester -Output Detailed $PSScriptRoot/$Path + } else { + if ($OnlyPublicTests) { + Write-Host "Invoking Pester to run tests from '$PSScriptRoot/test/extensions/public'" + Invoke-Pester -Output Detailed $PSScriptRoot/test/extensions/public + } + else { + Write-Host "Invoking Pester to run tests from '$PSScriptRoot/test/extensions'" + Invoke-Pester -Output Detailed $PSScriptRoot/test/extensions + } + } +} diff --git a/testing/bin/connectedk8s-1.0.0-py3-none-any.whl b/testing/bin/connectedk8s-1.0.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..08f34250036f455aad7e3e820c65d08d790e1201 GIT binary patch literal 62802 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

YVX(toUj*0P8con1X*tXmm22nWyt~gf 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

4OLf9N*^x0^yG1@+&DtXglO();gI7nFsJg6 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 literal 0 HcmV?d00001 diff --git a/testing/docs/test_authoring.md b/testing/docs/test_authoring.md new file mode 100644 index 00000000000..b41286ba66d --- /dev/null +++ b/testing/docs/test_authoring.md @@ -0,0 +1,142 @@ +# Test Authoring + +All partners are _required_ to author additional integration tests when merging their extension into the __Official Private Preview Release__. The information below outlines how to setup and author these additional tests. + +## Requirements + +All partners are required to cover standard CLI scenarios in your extensions testing suite. When adding these tests and preparing to merge your updated extension whl package, your tests along with the other tests in the test suite must pass at 100%. + +Standard CLI scenarios include: + +1. `az k8s-extension create` +2. `az k8s-extension show` +3. `az k8s-extension list` +4. `az k8s-extension update` +5. `az k8s-extension delete` + +In addition to these standard scenarios, if there are any rigorous parameter validation standards, these should also be included in this test suite. + +## Setup + +The setup process for test authoring is the same as setup for generic testing. See [Setup](../README.md#setup) for guidance. + +## Writing Tests + +This section outlines the common flow for creating and running additional extension integration tests for the `k8s-extension` package. + +The suite utilizes the [Pester](https://pester.dev/) framework. For more information on creating generic Pester tests, see the [Create a Pester Test](https://pester.dev/docs/quick-start#creating-a-pester-test) section in the Pester docs. + +### Step 1: Create Test File + +To create an integration test suite for your extension, create an extension test file in the format `.Tests.ps1` and place the file in one of the following directories +| Extension Type | Directory | +| ---------------------- | ----------------------------------- | +| General Availability | .\test\extensions\public | +| Public Preview | .\test\extensions\public | +| Private Preview | .\test\extensions\private-preview | + +For example, to create a test suite file for the Azure Monitor extension, I create the file `AzureMonitor.Tests.ps1` in the `\test\extensions\public` directory because Container Insights extension is in _Public Preview_. + +### Step 2: Setup Global Variables + +All test suite files must have the following structure for importing the environment config and declaring globals + +```powershell +Describe ' Testing' { + BeforeAll { + $extensionType = "" + $extensionName = "" + $extensionAgentName = "" + $extensionAgentNamespace = "" + + . $PSScriptRoot/../../helper/Constants.ps1 + . $PSScriptRoot/../../helper/Helper.ps1 + } +} +``` + +You can declare additional global variables for your tests by adding additional powershell variable to this `BeforeAll` block. + +_Note: Commonly used constants used by all extension test suites are stored in the `Constants.ps1` file_ + +### Step 3: Add Tests + +Adding tests to the test suite can now be performed by adding `It` blocks to the outer `Describe` block. For instance to test create on a extension in the case of AzureMonitor, I write the following test: + +```powershell +Describe 'Azure Monitor Testing' { + BeforeAll { + $extensionType = "microsoft.azuremonitor.containers" + $extensionName = "azuremonitor-containers" + $extensionAgentName = "omsagent" + $extensionAgentNamespace = "kube-system" + + . $PSScriptRoot/../../helper/Constants.ps1 + . $PSScriptRoot/../../helper/Helper.ps1 + } + + It 'Creates the extension and checks that it onboards correctly' { + $output = az k8s-extension create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType -n $extensionName + $? | Should -BeTrue + + $output = az k8s-extension show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeTrue + + $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion + $isAutoUpgradeMinorVersion.ToString() -eq "True" | Should -BeTrue + + # Loop and retry until the extension installs + $n = 0 + do + { + if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { + if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { + break + } + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } +} +``` + +The above test calls `az k8s-extension create` to create the `azuremonitor-containers` extension and retries checking that the extension resource was actually created on the Arc cluster and that the extension status successfully returns `$SUCCESS_MESSAGE` which is equivalent to `Successfully installed the extension`. + +## Tips/Notes + +### Accessing Extension Data + +`.\Test.ps1` assumes that the user has `kubectl` and `az` installed in their environment; therefore, tests are able to access information on the extension at the service and on the arc cluster. For instance, in the above test, we access the `extensionconfig` CRDs on the arc cluster by calling + +```powershell +kubectl get extensionconfigs -A -o json +``` + +If we want to access the extension data on the cluster with a specific `$extensionName`, we run + +```powershell +(kubectl get extensionconfigs -A -o json).items | Where-Object { $_.metadata.name -eq $extensionName } +``` + +Because some of these commands are so common, we provide the following helper commands in the `test\Helper.ps1` file + +| Command | Description | +| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | +| Get-ExtensionData | Retrieves the ExtensionConfig CRD in JSON format with `.meatadata.name` matching the `extensionName` | +| Get-ExtensionStatus | Retrieves the `.status.status` from the ExtensionConfig CRD with `.meatadata.name` matching the `extensionName` | +| Get-PodStatus -Namespace | Retrieves the `status.phase` from the first pod on the cluster with `.metadata.name` matching `extensionName` | + +### Stdout for Debugging + +To print out to the Console for debugging while writing your test cases use the `Write-Host` command. If you attempt to use the `Write-Output` command, it will not show because of the way that Pester is invoked + +```powershell +Write-Host "Some example output" +``` + +### Global Constants + +Looking at the above test, we can see that we are accessing the `ENVCONFIG` to retrieve the environment variables from the `settings.json`. All variables in the `settings.json` are accessible from the `ENVCONFIG`. The most useful ones for testing will be `ENVCONFIG.arcClusterName` and `ENVCONFIG.resourceGroup`. + diff --git a/testing/owners.txt b/testing/owners.txt new file mode 100644 index 00000000000..ead6f446410 --- /dev/null +++ b/testing/owners.txt @@ -0,0 +1,2 @@ +joinnis +nanthi \ No newline at end of file diff --git a/testing/settings.template.json b/testing/settings.template.json new file mode 100644 index 00000000000..5d459b44bee --- /dev/null +++ b/testing/settings.template.json @@ -0,0 +1,12 @@ +{ + "subscriptionId": "", + "resourceGroup": "", + "aksClusterName": "", + "arcClusterName": "", + + "extensionVersion": { + "k8s-extension": "0.2.0", + "k8s-extension-private": "0.1.0", + "connectedk8s": "0.3.5" + } +} \ No newline at end of file diff --git a/testing/test/extensions/private-preview/AzurePolicy.Tests.ps1 b/testing/test/extensions/private-preview/AzurePolicy.Tests.ps1 new file mode 100644 index 00000000000..ea8c3f46cb4 --- /dev/null +++ b/testing/test/extensions/private-preview/AzurePolicy.Tests.ps1 @@ -0,0 +1,95 @@ +Describe 'Azure Policy Testing' { + BeforeAll { + $extensionType = "microsoft.policyinsights" + $extensionName = "policy" + $extensionAgentName = "azure-policy" + $extensionAgentNamespace = "kube-system" + + . $PSScriptRoot/../../helper/Constants.ps1 + . $PSScriptRoot/../../helper/Helper.ps1 + } + + It 'Creates the extension and checks that it onboards correctly' { + $output = az $Env:K8sExtensionName create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType -n $extensionName + $? | Should -BeTrue + + $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeTrue + + $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion + $isAutoUpgradeMinorVersion.ToString() -eq "True" | Should -BeTrue + + # Loop and retry until the extension installs + $n = 0 + do + { + if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { + if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { + break + } + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Performs a show on the extension" { + $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeTrue + $output | Should -Not -BeNullOrEmpty + } + + It "Runs an update on the extension on the cluster" { + Set-ItResult -Skipped -Because "Update is not a valid scenario for now" + + # az $Env:K8sExtensionName update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName --auto-upgrade-minor-version false + # $? | Should -BeTrue + + # $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + # $? | Should -BeTrue + + # $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion + # $isAutoUpgradeMinorVersion.ToString() -eq "False" | Should -BeTrue + + # # Loop and retry until the extension config updates + # $n = 0 + # do + # { + # $isAutoUpgradeMinorVersion = (Get-ExtensionData $extensionName).spec.autoUpgradeMinorVersion + # if (!$isAutoUpgradeMinorVersion) { #autoUpgradeMinorVersion doesn't exist in ExtensionConfig CRD if false + # if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { + # if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { + # break + # } + # } + # } + # Start-Sleep -Seconds 10 + # $n += 1 + # } while ($n -le $MAX_RETRY_ATTEMPTS) + # $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Lists the extensions on the cluster" { + $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionType } + $extensionExists | Should -Not -BeNullOrEmpty + } + + It "Deletes the extension from the cluster" { + az $Env:K8sExtensionName delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeTrue + + # Extension should not be found on the cluster + az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeFalse + } + + It "Performs another list after the delete" { + $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionName } + $extensionExists | Should -BeNullOrEmpty + } +} diff --git a/testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 b/testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 new file mode 100644 index 00000000000..344e36a296c --- /dev/null +++ b/testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 @@ -0,0 +1,94 @@ +Describe 'AzureML Kubernetes Testing' { + BeforeAll { + $extensionType = "Microsoft.AzureML.Kubernetes" + $extensionName = "azureml-kubernetes-connector" + $extensionAgentNamespace = "azureml" + $relayResourceIDKey = "relayserver.hybridConnectionResourceID" + + . $PSScriptRoot/../../helper/Constants.ps1 + . $PSScriptRoot/../../helper/Helper.ps1 + } + + It 'Creates the extension and checks that it onboards correctly' { + $output = az k8s-extension create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType --name $extensionName --release-train preview --config enableTraining=true + $? | Should -BeTrue + + $output = az k8s-extension show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName + $? | Should -BeTrue + + $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion + $isAutoUpgradeMinorVersion.ToString() -eq "True" | Should -BeTrue + + # Loop and retry until the extension installs + $n = 0 + do + { + if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { + break + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + + # check if relay is populated + $relayResourceID = Get-ExtensionConfigurationSettings $extensionName $relayResourceIDKey + $relayResourceID | Should -Not -BeNullOrEmpty + } + + It "Performs a show on the extension" { + $output = az k8s-extension show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName + $? | Should -BeTrue + $output | Should -Not -BeNullOrEmpty + } + + It "Runs an update on the extension on the cluster" { + Set-ItResult -Skipped -Because "Update is not a valid scenario for now" + az k8s-extension update --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName --auto-upgrade-minor-version false + $? | Should -BeTrue + + $output = az k8s-extension show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName + $? | Should -BeTrue + + $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion + $isAutoUpgradeMinorVersion.ToString() -eq "False" | Should -BeTrue + + # Loop and retry until the extension config updates + $n = 0 + do + { + $isAutoUpgradeMinorVersion = (Get-ExtensionData $extensionName).spec.autoUpgradeMinorVersion + if (!$isAutoUpgradeMinorVersion) { #autoUpgradeMinorVersion doesn't exist in ExtensionConfig CRD if false + if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { + break + } + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Lists the extensions on the cluster" { + $output = az k8s-extension list --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionType } + $extensionExists | Should -Not -BeNullOrEmpty + } + + It "Deletes the extension from the cluster" { + az k8s-extension delete --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName + $? | Should -BeTrue + + # Extension should not be found on the cluster + az k8s-extension show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName + $? | Should -BeFalse + } + + It "Performs another list after the delete" { + $output = az k8s-extension list --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionName } + $extensionExists | Should -BeNullOrEmpty + } +} diff --git a/testing/test/extensions/public/AzureMonitor.Tests.ps1 b/testing/test/extensions/public/AzureMonitor.Tests.ps1 new file mode 100644 index 00000000000..c9baa2d0e48 --- /dev/null +++ b/testing/test/extensions/public/AzureMonitor.Tests.ps1 @@ -0,0 +1,95 @@ +Describe 'Azure Monitor Testing' { + BeforeAll { + $extensionType = "microsoft.azuremonitor.containers" + $extensionName = "azuremonitor-containers" + $extensionAgentName = "omsagent" + $extensionAgentNamespace = "kube-system" + + . $PSScriptRoot/../../helper/Constants.ps1 + . $PSScriptRoot/../../helper/Helper.ps1 + } + + It 'Creates the extension and checks that it onboards correctly' { + $output = az $Env:K8sExtensionName create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType -n $extensionName + $? | Should -BeTrue + + $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeTrue + + $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion + $isAutoUpgradeMinorVersion.ToString() -eq "True" | Should -BeTrue + + # Loop and retry until the extension installs + $n = 0 + do + { + if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { + if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { + break + } + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Performs a show on the extension" { + $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeTrue + $output | Should -Not -BeNullOrEmpty + } + + It "Runs an update on the extension on the cluster" { + Set-ItResult -Skipped -Because "Update is not a valid scenario for now" + + # az $Env:K8sExtensionName update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName --auto-upgrade-minor-version false + # $? | Should -BeTrue + + # $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + # $? | Should -BeTrue + + # $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion + # $isAutoUpgradeMinorVersion.ToString() -eq "False" | Should -BeTrue + + # # Loop and retry until the extension config updates + # $n = 0 + # do + # { + # $isAutoUpgradeMinorVersion = (Get-ExtensionData $extensionName).spec.autoUpgradeMinorVersion + # if (!$isAutoUpgradeMinorVersion) { #autoUpgradeMinorVersion doesn't exist in ExtensionConfig CRD if false + # if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { + # if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { + # break + # } + # } + # } + # Start-Sleep -Seconds 10 + # $n += 1 + # } while ($n -le $MAX_RETRY_ATTEMPTS) + # $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Lists the extensions on the cluster" { + $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionType } + $extensionExists | Should -Not -BeNullOrEmpty + } + + It "Deletes the extension from the cluster" { + az $Env:K8sExtensionName delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeTrue + + # Extension should not be found on the cluster + az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeFalse + } + + It "Performs another list after the delete" { + $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionName } + $extensionExists | Should -BeNullOrEmpty + } +} diff --git a/testing/test/helper/Constants.ps1 b/testing/test/helper/Constants.ps1 new file mode 100644 index 00000000000..3ecd3621bc5 --- /dev/null +++ b/testing/test/helper/Constants.ps1 @@ -0,0 +1,7 @@ +$ENVCONFIG = Get-Content -Path $PSScriptRoot/../../settings.json | ConvertFrom-Json +$SUCCESS_MESSAGE = "Successfully installed the extension" +$FAILED_MESSAGE = "Failed to install the extension" + +$POD_RUNNING = "Running" + +$MAX_RETRY_ATTEMPTS = 10 \ No newline at end of file diff --git a/testing/test/helper/Helper.ps1 b/testing/test/helper/Helper.ps1 new file mode 100644 index 00000000000..362a4eedf18 --- /dev/null +++ b/testing/test/helper/Helper.ps1 @@ -0,0 +1,47 @@ +function Get-ExtensionData { + param( + [string]$extensionName + ) + + $output = kubectl get extensionconfigs -A -o json | ConvertFrom-Json + return $output.items | Where-Object { $_.metadata.name -eq $extensionName } +} + +function Get-ExtensionStatus { + param( + [string]$extensionName + ) + + $extensionData = Get-ExtensionData $extensionName + if ($extensionData) { + return $extensionData.status.status + } + return $null +} + +function Get-PodStatus { + param( + [string]$podName, + [string]$Namespace + ) + + $allPodData = kubectl get pods -n $Namespace -o json | ConvertFrom-Json + $podData = $allPodData.items | Where-Object { $_.metadata.name -Match $podName } + if ($podData.Length -gt 1) { + return $podData[0].status.phase + } + return $podData.status.phase +} + +function Get-ExtensionConfigurationSettings { + param( + [string]$extensionName, + [string]$configKey + ) + + $extensionData = Get-ExtensionData $extensionName + if ($extensionData) { + return $extensionData.spec.parameter."$configKey" + } + return $null +} From 1ded4054cff3b90debca2ef41e2f15da99004ee0 Mon Sep 17 00:00:00 2001 From: Lia Kazakova <58274127+liakaz@users.noreply.github.com> Date: Mon, 26 Apr 2021 21:32:15 -0700 Subject: [PATCH 55/80] Inference CLI validation for Scoring FE (#24) * cli validation starter * added the call to the fe validation function * nodeport validation not required * test fix Co-authored-by: Jonathan Innis --- .../partner_extensions/AzureMLKubernetes.py | 30 +++++++++++++++++++ .../public/AzureMLKubernetes.Tests.ps1 | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py index 34aac58e017..1338765bab2 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py @@ -171,12 +171,42 @@ def __validate_config(self, configuration_settings, configuration_protected_sett "for Machine Learning training or inference by specifying " f"'--configuration-settings {self.ENABLE_TRAINING}=true' or '--configuration-settings {self.ENABLE_INFERENCE}=true'") + self.__validate_scoring_fe_settings(configuration_settings, configuration_protected_settings) + configuration_settings[self.ENABLE_TRAINING] = configuration_settings.get(self.ENABLE_TRAINING, enable_training) configuration_settings[self.ENABLE_INFERENCE] = configuration_settings.get( self.ENABLE_INFERENCE, enable_inference) configuration_protected_settings.pop(self.ENABLE_TRAINING, None) configuration_protected_settings.pop(self.ENABLE_INFERENCE, None) + def __validate_scoring_fe_settings(self, configuration_settings, configuration_protected_settings): + clusterPurpose = _get_value_from_config_protected_config( + 'clusterPurpose', configuration_settings, configuration_protected_settings) + if clusterPurpose and clusterPurpose not in ["DevTest", "FastProd"]: + raise InvalidArgumentValueError( + "Accepted values for '--configuration-settings clusterPurpose' " + "are 'DevTest' and 'FastProd'") + + feSslCert = _get_value_from_config_protected_config( + 'scoringFe.sslCert', configuration_settings, configuration_protected_settings) + sslKey = _get_value_from_config_protected_config( + 'scoringFe.sslKey', configuration_settings, configuration_protected_settings) + allowInsecureConnections = _get_value_from_config_protected_config( + 'allowInsecureConnections', configuration_settings, configuration_protected_settings) + allowInsecureConnections = str(allowInsecureConnections).lower() == 'true' + if (not feSslCert or not sslKey) and not allowInsecureConnections: + raise InvalidArgumentValueError( + "Provide ssl certificate and key. " + "Otherwise explicitly allow insecure connection by specifying " + "'--configuration-settings allowInsecureConnections=true'") + + feIsInternalLoadBalancer = _get_value_from_config_protected_config( + 'scoringFe.serviceType.internalLoadBalancer', configuration_settings, configuration_protected_settings) + feIsInternalLoadBalancer = str(feIsInternalLoadBalancer).lower() == 'true' + if feIsInternalLoadBalancer: + logger.warn( + 'Internal load balancer only supported on AKS and AKS Engine Clusters.') + def __create_required_resource( self, cmd, configuration_settings, configuration_protected_settings, subscription_id, resource_group_name, cluster_name, cluster_location): diff --git a/testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 b/testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 index 344e36a296c..a434544da12 100644 --- a/testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 +++ b/testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 @@ -10,7 +10,7 @@ Describe 'AzureML Kubernetes Testing' { } It 'Creates the extension and checks that it onboards correctly' { - $output = az k8s-extension create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType --name $extensionName --release-train preview --config enableTraining=true + $output = az k8s-extension create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType --name $extensionName --release-train preview --config enableTraining=true allowInsecureConnections=true $? | Should -BeTrue $output = az k8s-extension show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName From 53303d5e8772a9a85edd0a907ceea4d62e6cc002 Mon Sep 17 00:00:00 2001 From: Lia Kazakova <58274127+liakaz@users.noreply.github.com> Date: Tue, 27 Apr 2021 12:16:22 -0700 Subject: [PATCH 56/80] legal warning added (#27) --- .../partner_extensions/AzureMLKubernetes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py index 1338765bab2..efe261f6a5b 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py @@ -165,7 +165,9 @@ def __validate_config(self, configuration_settings, configuration_protected_sett self.ENABLE_INFERENCE, configuration_settings, configuration_protected_settings) enable_inference = str(enable_inference).lower() == 'true' - if not (enable_training or enable_inference): + if enable_inference: + logger.warn("The installed AzureML extension for AML inference is experimental and not covered by customer support. Please use with discretion.") + elif not (enable_training or enable_inference): raise InvalidArgumentValueError( "Please create Microsoft.AzureML.Kubernetes extension instance either " "for Machine Learning training or inference by specifying " From 3370264880fc0851d9cefa288400060e2c506ddb Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Tue, 27 Apr 2021 12:20:37 -0700 Subject: [PATCH 57/80] Remove deprecated method logger.warn --- .../partner_extensions/AzureMLKubernetes.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py index efe261f6a5b..34d71beb829 100644 --- a/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py +++ b/src/k8s-extension/azext_k8s_extension/partner_extensions/AzureMLKubernetes.py @@ -153,8 +153,8 @@ def __validate_config(self, configuration_settings, configuration_protected_sett dup_keys = set(config_keys) & set(config_protected_keys) if len(dup_keys) > 0: for key in dup_keys: - logger.warn( - f'Duplicate keys found in both configuration settings and configuration protected setttings: {key}') + logger.warning( + 'Duplicate keys found in both configuration settings and configuration protected setttings: %s', key) raise InvalidArgumentValueError("Duplicate keys found.") enable_training = _get_value_from_config_protected_config( @@ -166,7 +166,7 @@ def __validate_config(self, configuration_settings, configuration_protected_sett enable_inference = str(enable_inference).lower() == 'true' if enable_inference: - logger.warn("The installed AzureML extension for AML inference is experimental and not covered by customer support. Please use with discretion.") + logger.warning("The installed AzureML extension for AML inference is experimental and not covered by customer support. Please use with discretion.") elif not (enable_training or enable_inference): raise InvalidArgumentValueError( "Please create Microsoft.AzureML.Kubernetes extension instance either " @@ -206,7 +206,7 @@ def __validate_scoring_fe_settings(self, configuration_settings, configuration_p 'scoringFe.serviceType.internalLoadBalancer', configuration_settings, configuration_protected_settings) feIsInternalLoadBalancer = str(feIsInternalLoadBalancer).lower() == 'true' if feIsInternalLoadBalancer: - logger.warn( + logger.warning( 'Internal load balancer only supported on AKS and AKS Engine Clusters.') def __create_required_resource( From 4c66aeff079be3476da8d3b4673d27371b7a74d4 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Tue, 27 Apr 2021 13:09:31 -0700 Subject: [PATCH 58/80] Update k8s-custom-pipelines.yml for Azure Pipelines --- k8s-custom-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 00d87b68d13..7cc32e49d04 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -2,6 +2,7 @@ trigger: batch: true branches: include: + - release* - k8s-extension/public - k8s-extension/private pr: From e8651f2fa16365adc7d45826d59b6159882784e0 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Tue, 27 Apr 2021 13:10:00 -0700 Subject: [PATCH 59/80] Update k8s-custom-pipelines.yml for Azure Pipelines --- k8s-custom-pipelines.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 7cc32e49d04..00d87b68d13 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -2,7 +2,6 @@ trigger: batch: true branches: include: - - release* - k8s-extension/public - k8s-extension/private pr: From 9de1e4ef7d455c715e44721e863f7cb3ebd1f749 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Wed, 28 Apr 2021 13:03:33 -0700 Subject: [PATCH 60/80] Add Azure Defender to E2E testing (#28) * Add azure defender testing to e2e * Remove the debug flag --- testing/.gitignore | 2 +- .../bin/k8s_extension-0.2.0-py3-none-any.whl | Bin 46987 -> 0 bytes .../bin/k8s_extension-0.3.0-py3-none-any.whl | Bin 0 -> 52893 bytes testing/settings.template.json | 4 +- .../extensions/public/AzureDefender.Tests.ps1 | 93 ++++++++++++++++++ 5 files changed, 96 insertions(+), 3 deletions(-) delete mode 100644 testing/bin/k8s_extension-0.2.0-py3-none-any.whl create mode 100644 testing/bin/k8s_extension-0.3.0-py3-none-any.whl create mode 100644 testing/test/extensions/public/AzureDefender.Tests.ps1 diff --git a/testing/.gitignore b/testing/.gitignore index 7df7f6a7294..745d8708c4e 100644 --- a/testing/.gitignore +++ b/testing/.gitignore @@ -2,7 +2,7 @@ settings.json tmp/ bin/* !bin/connectedk8s-1.0.0-py3-none-any.whl -!bin/k8s_extension-0.2.0-py3-none-any.whl +!bin/k8s_extension-0.3.0-py3-none-any.whl !bin/k8s_extension_private-0.1.0-py3-none-any.whl !bin/connectedk8s-values.yaml *.xml \ No newline at end of file diff --git a/testing/bin/k8s_extension-0.2.0-py3-none-any.whl b/testing/bin/k8s_extension-0.2.0-py3-none-any.whl deleted file mode 100644 index bdb9dbafdcf64c2526a3baaafdc61ad5538a9c0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46987 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 diff --git a/testing/bin/k8s_extension-0.3.0-py3-none-any.whl b/testing/bin/k8s_extension-0.3.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..feb28b80b437c8af966b3b87a4fcad1a9b74d108 GIT binary patch literal 52893 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 b*Hx{YBsky%^Yh?A4x|a#NYixu{O$h(4U{Xp literal 0 HcmV?d00001 diff --git a/testing/settings.template.json b/testing/settings.template.json index 5d459b44bee..04eda8e4dfa 100644 --- a/testing/settings.template.json +++ b/testing/settings.template.json @@ -5,8 +5,8 @@ "arcClusterName": "", "extensionVersion": { - "k8s-extension": "0.2.0", + "k8s-extension": "0.3.0", "k8s-extension-private": "0.1.0", - "connectedk8s": "0.3.5" + "connectedk8s": "1.0.0" } } \ No newline at end of file diff --git a/testing/test/extensions/public/AzureDefender.Tests.ps1 b/testing/test/extensions/public/AzureDefender.Tests.ps1 new file mode 100644 index 00000000000..2d199e31638 --- /dev/null +++ b/testing/test/extensions/public/AzureDefender.Tests.ps1 @@ -0,0 +1,93 @@ +Describe 'Azure Defender Testing' { + BeforeAll { + $extensionType = "microsoft.azuredefender.kubernetes" + $extensionName = "microsoft.azuredefender.kubernetes" + $extensionAgentNamespace = "azuredefender" + + . $PSScriptRoot/../../helper/Constants.ps1 + . $PSScriptRoot/../../helper/Helper.ps1 + } + + It 'Creates the extension and checks that it onboards correctly' { + $output = az $Env:K8sExtensionName create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType -n $extensionName + $? | Should -BeTrue + + $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeTrue + + $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion + $isAutoUpgradeMinorVersion.ToString() -eq "True" | Should -BeTrue + + # Loop and retry until the extension installs + $n = 0 + do + { + # Only check the extension config, not the pod since this doesn't bring up pods + if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { + break + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Performs a show on the extension" { + $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeTrue + $output | Should -Not -BeNullOrEmpty + } + + It "Runs an update on the extension on the cluster" { + Set-ItResult -Skipped -Because "Update is not a valid scenario for now" + + # az $Env:K8sExtensionName update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName --auto-upgrade-minor-version false + # $? | Should -BeTrue + + # $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + # $? | Should -BeTrue + + # $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion + # $isAutoUpgradeMinorVersion.ToString() -eq "False" | Should -BeTrue + + # # Loop and retry until the extension config updates + # $n = 0 + # do + # { + # $isAutoUpgradeMinorVersion = (Get-ExtensionData $extensionName).spec.autoUpgradeMinorVersion + # if (!$isAutoUpgradeMinorVersion) { #autoUpgradeMinorVersion doesn't exist in ExtensionConfig CRD if false + # if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { + # if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { + # break + # } + # } + # } + # Start-Sleep -Seconds 10 + # $n += 1 + # } while ($n -le $MAX_RETRY_ATTEMPTS) + # $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Lists the extensions on the cluster" { + $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionType } + $extensionExists | Should -Not -BeNullOrEmpty + } + + It "Deletes the extension from the cluster" { + az $Env:K8sExtensionName delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeTrue + + # Extension should not be found on the cluster + az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName + $? | Should -BeFalse + } + + It "Performs another list after the delete" { + $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionName } + $extensionExists | Should -BeNullOrEmpty + } +} From 9c0317d7bf9ad42e4d890f3924735ecad4149aef Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 28 Apr 2021 16:25:30 -0700 Subject: [PATCH 61/80] Add configuration testing --- testing/Test.ps1 | 85 ++++++----- .../Configuration.HTTPS.Tests.ps1 | 54 +++++++ .../Configuration.HelmOperator.Tests.ps1 | 137 ++++++++++++++++++ .../Configuration.KnownHost.Tests.ps1 | 6 + .../Configuration.PrivateKey.Tests.ps1 | 86 +++++++++++ .../configurations/Configuration.Tests.ps1 | 80 ++++++++++ testing/test/configurations/Constants.ps1 | 8 + testing/test/configurations/Helper.ps1 | 45 ++++++ 8 files changed, 461 insertions(+), 40 deletions(-) create mode 100644 testing/test/configurations/Configuration.HTTPS.Tests.ps1 create mode 100644 testing/test/configurations/Configuration.HelmOperator.Tests.ps1 create mode 100644 testing/test/configurations/Configuration.KnownHost.Tests.ps1 create mode 100644 testing/test/configurations/Configuration.PrivateKey.Tests.ps1 create mode 100644 testing/test/configurations/Configuration.Tests.ps1 create mode 100644 testing/test/configurations/Constants.ps1 create mode 100644 testing/test/configurations/Helper.ps1 diff --git a/testing/Test.ps1 b/testing/Test.ps1 index 6304c13dc28..343f0eef2cc 100644 --- a/testing/Test.ps1 +++ b/testing/Test.ps1 @@ -18,59 +18,64 @@ az account set --subscription $ENVCONFIG.subscriptionId $Env:KUBECONFIG="$PSScriptRoot/tmp/KUBECONFIG" -if ($ExtensionType -eq "Public") { - $k8sExtensionVersion = $ENVCONFIG.extensionVersion.'k8s-extension' - $Env:K8sExtensionName = "k8s-extension" +if ($Type -eq 'Extension') { + if ($ExtensionType -eq "Public") { + $k8sExtensionVersion = $ENVCONFIG.extensionVersion.'k8s-extension' + $Env:K8sExtensionName = "k8s-extension" - if (!$SkipInstall) { - Write-Host "Removing the old k8s-extension extension..." - az extension remove -n k8s-extension - Write-Host "Installing k8s-extension version $k8sExtensionVersion..." - az extension add --source ./bin/k8s_extension-$k8sExtensionVersion-py3-none-any.whl - if (!$?) { - Write-Host "Unable to find k8s-extension version $k8sExtensionVersion, exiting..." - exit 1 + if (!$SkipInstall) { + Write-Host "Removing the old k8s-extension extension..." + az extension remove -n k8s-extension + Write-Host "Installing k8s-extension version $k8sExtensionVersion..." + az extension add --source ./bin/k8s_extension-$k8sExtensionVersion-py3-none-any.whl + if (!$?) { + Write-Host "Unable to find k8s-extension version $k8sExtensionVersion, exiting..." + exit 1 + } + } + } else { + $k8sExtensionPrivateVersion = $ENVCONFIG.extensionVersion.'k8s-extension-private' + $Env:K8sExtensionName = "k8s-extension-private" + + if (!$SkipInstall) { + Write-Host "Removing the old k8s-extension-private extension..." + az extension remove -n k8s-extension-private + Write-Host "Installing k8s-extension-private version $k8sExtensionPrivateVersion..." + az extension add --source ./bin/k8s_extension_private-$k8sExtensionPrivateVersion-py3-none-any.whl + if (!$?) { + Write-Host "Unable to find k8s-extension-private version $k8sExtensionPrivateVersion, exiting..." + exit 1 + } } } -} else { - $k8sExtensionPrivateVersion = $ENVCONFIG.extensionVersion.'k8s-extension-private' - $Env:K8sExtensionName = "k8s-extension-private" + if ($OnlyPublicTests) { + $testFilePath = "$PSScriptRoot/test/extensions/public" + } else { + $testFilePath = "$PSScriptRoot/test/extensions" + } +} +if ($Type -eq 'Configuration') { + $k8sConfigurationVersion = $ENVCONFIG.extensionVersion.'k8s-configuration' if (!$SkipInstall) { - Write-Host "Removing the old k8s-extension-private extension..." - az extension remove -n k8s-extension-private - Write-Host "Installing k8s-extension-private version $k8sExtensionPrivateVersion..." - az extension add --source ./bin/k8s_extension_private-$k8sExtensionPrivateVersion-py3-none-any.whl - if (!$?) { - Write-Host "Unable to find k8s-extension-private version $k8sExtensionPrivateVersion, exiting..." - exit 1 - } + Write-Host "Removing the old k8s-configuration extension..." + az extension remove -n k8s-configuration + Write-Host "Installing k8s-configuration version $k8sConfigurationVersion..." + az extension add --source ./extensions/k8s_configuration-$k8sConfigurationVersion-py3-none-any.whl } + $testFilePath = "$PSScriptRoot/test/configurations" } if ($CI) { - if ($OnlyPublicTests) { - Write-Host "Invoking Pester to run tests from '$PSScriptRoot/test/extensions/public'" - $testResult = Invoke-Pester $PSScriptRoot/test/extensions/public -Passthru -Output Detailed - $testResult | Export-JUnitReport -Path TestResults.xml - } - else { - Write-Host "Invoking Pester to run tests from '$PSScriptRoot/test/extensions'" - $testResult = Invoke-Pester $PSScriptRoot/test/extensions -Passthru -Output Detailed - $testResult | Export-JUnitReport -Path TestResults.xml - } + Write-Host "Invoking Pester to run tests from '$testFilePath'..." + $testResult = Invoke-Pester $testFilePath -Passthru -Output Detailed + $testResult | Export-JUnitReport -Path TestResults.xml } else { if ($Path) { Write-Host "Invoking Pester to run tests from '$PSScriptRoot/$Path'" Invoke-Pester -Output Detailed $PSScriptRoot/$Path } else { - if ($OnlyPublicTests) { - Write-Host "Invoking Pester to run tests from '$PSScriptRoot/test/extensions/public'" - Invoke-Pester -Output Detailed $PSScriptRoot/test/extensions/public - } - else { - Write-Host "Invoking Pester to run tests from '$PSScriptRoot/test/extensions'" - Invoke-Pester -Output Detailed $PSScriptRoot/test/extensions - } + Write-Host "Invoking Pester to run tests from '$testFilePath'..." + Invoke-Pester -Output Detailed $testFilePathc } } diff --git a/testing/test/configurations/Configuration.HTTPS.Tests.ps1 b/testing/test/configurations/Configuration.HTTPS.Tests.ps1 new file mode 100644 index 00000000000..a2dee2b348f --- /dev/null +++ b/testing/test/configurations/Configuration.HTTPS.Tests.ps1 @@ -0,0 +1,54 @@ +Describe 'Source Control Configuration (HTTPS) Testing' { + BeforeAll { + $configurationName = "https-config" + . $PSScriptRoot/Constants.ps1 + . $PSScriptRoot/Helper.ps1 + + $dummyValue = "dummyValue" + $secretName = "git-auth-$configurationName" + } + + It 'Creates a configuration with https user and https key on the cluster' { + $output = az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "https://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --https-user $dummyValue --https-key $dummyValue --operator-namespace $configurationName + $? | Should -BeTrue + + # Loop and retry until the configuration installs and helm pod comes up + $n = 0 + do + { + if (Get-ConfigStatus $configurationName -eq $SUCCESS_MESSAGE) { + if (Get-PodStatus $configurationName -Namespace $configurationName -eq $POD_RUNNING ) { + break + } + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + + Secret-Exists $secretName -Namespace $configurationName + } + + It "Lists the configurations on the cluster" { + $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + $configExists | Should -Not -BeNullOrEmpty + } + + It "Deletes the configuration from the cluster" { + az k8s-configuration delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeTrue + + # Configuration should be removed from the resource model + az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeFalse + } + + It "Performs another list after the delete" { + $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + $configExists | Should -BeNullOrEmpty + } +} \ No newline at end of file diff --git a/testing/test/configurations/Configuration.HelmOperator.Tests.ps1 b/testing/test/configurations/Configuration.HelmOperator.Tests.ps1 new file mode 100644 index 00000000000..8b89ba24c58 --- /dev/null +++ b/testing/test/configurations/Configuration.HelmOperator.Tests.ps1 @@ -0,0 +1,137 @@ +Describe 'Source Control Configuration (Helm Operator Properties) Testing' { + BeforeAll { + $configurationName = "helm-enabled-config" + . $PSScriptRoot/Constants.ps1 + . $PSScriptRoot/Helper.ps1 + + $customOperatorParams = "--set helm.versions=v3 --set mycustomhelmvalue=yay" + $customChartVersion = "0.6.0" + } + + It 'Creates a configuration with helm enabled on the cluster' { + $output = az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "https://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --enable-helm-operator --operator-namespace $configurationName --helm-operator-params "--set helm.versions=v3" + $? | Should -BeTrue + + # Loop and retry until the configuration installs and helm pod comes up + $n = 0 + do + { + if (Get-ConfigStatus $configurationName -eq $SUCCESS_MESSAGE) { + if (Get-PodStatus "$configurationName-helm" -Namespace $configurationName -eq $POD_RUNNING ) { + break + } + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Updates the helm operator params and performs a show" { + Set-ItResult -Skipped -Because "Update is not a valid scenario for now" + + az k8s-configuration update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -n $configurationName --helm-operator-params $customOperatorParams + $? | Should -BeTrue + + $output = az k8s-configuration show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeTrue + + $configData = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + ($configData.helmOperatorProperties.chartValues -eq $customOperatorParams) | Should -BeTrue + + # Loop and retry until the configuration updates + $n = 0 + do + { + $helmOperatorChartValues = (Get-ConfigData $configurationName).spec.helmOperatorProperties.chartValues + if ($helmOperatorChartValues -ne $null -And $helmOperatorChartValues.ToString() -eq $customOperatorParams) { + if (Get-ConfigStatus $configurationName -Match $SUCCESS_MESSAGE) { + break + } + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Updates the helm operator chart version and performs a show" { + Set-ItResult -Skipped -Because "Update is not a valid scenario for now" + + az k8s-configuration update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -n $configurationName --helm-operator-chart-version $customChartVersion + $? | Should -BeTrue + + $output = az k8s-configuration show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeTrue + + # Check that the helmOperatorProperties chartValues didn't change + $configData = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + ($configData.helmOperatorProperties.chartValues -eq $customOperatorParams) | Should -BeTrue + ($configData.helmOperatorProperties.chartVersion -eq $customChartVersion) | Should -BeTrue + + # Loop and retry until the configuration updates + $n = 0 + do + { + $helmOperatorChartVersion = (Get-ConfigData $configurationName).spec.helmOperatorProperties.chartVersion + if ($helmOperatorChartVersion -ne $null -And $helmOperatorChartVersion.ToString() -eq $customChartVersion) { + if (Get-ConfigStatus $configurationName -Match $SUCCESS_MESSAGE) { + break + } + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Disables the helm operator on the cluster" { + Set-ItResult -Skipped -Because "Update is not a valid scenario for now" + + az k8s-configuration update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -n $configurationName --enable-helm-operator=false + $? | Should -BeTrue + + $output = az k8s-configuration show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeTrue + + $helmOperatorEnabled = ($output | ConvertFrom-Json).enableHelmOperator + $helmOperatorEnabled.ToString() -eq "False" | Should -BeTrue + + # Loop and retry until the configuration updates + $n = 0 + do { + $helmOperatorEnabled = (Get-ConfigData $configurationName).spec.enableHelmOperator + if ($helmOperatorEnabled -ne $null -And $helmOperatorEnabled.ToString() -eq "False") { + if (Get-ConfigStatus $configurationName -Match $SUCCESS_MESSAGE) { + break + } + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Lists the configurations on the cluster" { + $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + $configExists | Should -Not -BeNullOrEmpty + } + + It "Deletes the configuration from the cluster" { + az k8s-configuration delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeTrue + + # Configuration should be removed from the resource model + az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeFalse + } + + It "Performs another list after the delete" { + $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + $configExists | Should -BeNullOrEmpty + } +} \ No newline at end of file diff --git a/testing/test/configurations/Configuration.KnownHost.Tests.ps1 b/testing/test/configurations/Configuration.KnownHost.Tests.ps1 new file mode 100644 index 00000000000..2cb2946bc3e --- /dev/null +++ b/testing/test/configurations/Configuration.KnownHost.Tests.ps1 @@ -0,0 +1,6 @@ +Describe 'Source Control Configuration (SSH Configs) Testing' { + BeforeAll { + . $PSScriptRoot/Constants.ps1 + . $PSScriptRoot/Helper.ps1 + } +} \ No newline at end of file diff --git a/testing/test/configurations/Configuration.PrivateKey.Tests.ps1 b/testing/test/configurations/Configuration.PrivateKey.Tests.ps1 new file mode 100644 index 00000000000..4bf86d52012 --- /dev/null +++ b/testing/test/configurations/Configuration.PrivateKey.Tests.ps1 @@ -0,0 +1,86 @@ +Describe 'Source Control Configuration (SSH Configs) Testing' { + BeforeAll { + . $PSScriptRoot/Constants.ps1 + . $PSScriptRoot/Helper.ps1 + + $RSA_KEYPATH = "$TMP_DIRECTORY\rsa.private" + $DSA_KEYPATH = "$TMP_DIRECTORY\dsa.private" + $ECDSA_KEYPATH = "$TMP_DIRECTORY\ecdsa.private" + $ED25519_KEYPATH = "$TMP_DIRECTORY\ed25519.private" + + $KEY_ARR = [System.Tuple]::Create("rsa", $RSA_KEYPATH), [System.Tuple]::Create("dsa", $DSA_KEYPATH), [System.Tuple]::Create("ecdsa", $ECDSA_KEYPATH), [System.Tuple]::Create("ed25519", $ED25519_KEYPATH) + foreach ($keyTuple in $KEY_ARR) { + # Automattically say yes to overwrite with ssh-keygen + Write-Output "y" | ssh-keygen -t $keyTuple.Item1 -f $keyTuple.Item2 -P """" + } + + $SSH_GIT_URL = "git://github.com/anubhav929/flux-get-started.git" + $HTTP_GIT_URL = "https://github.com/Azure/arc-k8s-demo" + + $configDataRSA = [System.Tuple]::Create("rsa-config", $RSA_KEYPATH) + $configDataDSA = [System.Tuple]::Create("dsa-config", $DSA_KEYPATH) + $configDataECDSA = [System.Tuple]::Create("ecdsa-config", $ECDSA_KEYPATH) + $configDataED25519 = [System.Tuple]::Create("ed25519-config", $ED25519_KEYPATH) + + $CONFIG_ARR = $configDataRSA, $configDataDSA, $configDataECDSA, $configDataED25519 + } + + It 'Creates a configuration with each type of ssh private key' { + foreach($configData in $CONFIG_ARR) { + az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u $SSH_GIT_URL -n $configData.Item1 --scope cluster --operator-namespace $configData.Item1 --ssh-private-key-file $configData.Item2 + $? | Should -BeTrue + } + + # Loop and retry until the configuration installs and helm pod comes up + $n = 0 + do + { + $readyConfigs = 0 + foreach($configData in $CONFIG_ARR) { + # TODO: Change this to checking the success message after we merge in the bugfix into the agent + if (Get-PodStatus $configData.Item1 -Namespace $configData.Item1 -eq $POD_RUNNING) { + $readyConfigs += 1 + } + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le 30 -And $readyConfigs -ne 4) + $n | Should -BeLessOrEqual 30 + } + + It 'Fails when trying to create a configuration with ssh url and https auth values' { + az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u $HTTP_GIT_URL -n "config-should-fail" --scope cluster --operator-namespace "config-should-fail" --ssh-private-key-file $RSA_KEYPATH + $? | Should -BeFalse + } + + It "Lists the configurations on the cluster" { + $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + foreach ($configData in $CONFIG_ARR) { + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configData.Item1 } + $configExists | Should -Not -BeNullOrEmpty + } + } + + It "Deletes the configuration from the cluster" { + foreach ($configData in $CONFIG_ARR) { + az k8s-configuration delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configData.Item1 + $? | Should -BeTrue + + # Configuration should be removed from the resource model + az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configData.Item1 + $? | Should -BeFalse + } + } + + It "Performs another list after the delete" { + $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + foreach ($configData in $CONFIG_ARR) { + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configData.Item1 } + $configExists | Should -BeNullOrEmpty + } + } +} \ No newline at end of file diff --git a/testing/test/configurations/Configuration.Tests.ps1 b/testing/test/configurations/Configuration.Tests.ps1 new file mode 100644 index 00000000000..a85df42ed2e --- /dev/null +++ b/testing/test/configurations/Configuration.Tests.ps1 @@ -0,0 +1,80 @@ +Describe 'Basic Source Control Configuration Testing' { + BeforeAll { + $configurationName = "basic-config" + . $PSScriptRoot/Constants.ps1 + . $PSScriptRoot/Helper.ps1 + } + + It 'Creates a configuration and checks that it onboards correctly' { + az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "https://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --enable-helm-operator=false --operator-namespace $configurationName + $? | Should -BeTrue + + # Loop and retry until the configuration installs + $n = 0 + do + { + if (Get-ConfigStatus $configurationName -Match $SUCCESS_MESSAGE) { + break + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Performs a show on the configuration" { + $output = az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -n $configurationName + $? | Should -BeTrue + $output | Should -Not -BeNullOrEmpty + } + + It "Runs an update on the configuration on the cluster" { + Set-ItResult -Skipped -Because "Update is not a valid scenario for now" + + az k8s-configuration update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName --enable-helm-operator + $? | Should -BeTrue + + $output = az k8s-configuration show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeTrue + + $helmOperatorEnabled = ($output | ConvertFrom-Json).enableHelmOperator + $helmOperatorEnabled.ToString() -eq "True" | Should -BeTrue + + # Loop and retry until the configuration updates + $n = 0 + do { + $helmOperatorEnabled = (Get-ConfigData $configurationName).spec.enableHelmOperator + if ($helmOperatorEnabled -And $helmOperatorEnabled.ToString() -eq "True") { + if (Get-ConfigStatus $configurationName -Match $SUCCESS_MESSAGE) { + break + } + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Lists the configurations on the cluster" { + $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + $configExists | Should -Not -BeNullOrEmpty + } + + It "Deletes the configuration from the cluster" { + az k8s-configuration delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeTrue + + # Configuration should be removed from the resource model + az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeFalse + } + + It "Performs another list after the delete" { + $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + $configExists | Should -BeNullOrEmpty + } +} \ No newline at end of file diff --git a/testing/test/configurations/Constants.ps1 b/testing/test/configurations/Constants.ps1 new file mode 100644 index 00000000000..f1e8c6ffdc3 --- /dev/null +++ b/testing/test/configurations/Constants.ps1 @@ -0,0 +1,8 @@ +$ENVCONFIG = Get-Content -Path $PSScriptRoot\..\..\settings.json | ConvertFrom-Json +$SUCCESS_MESSAGE = "Successfully installed the operator" +$FAILED_MESSAGE = "Failed the install of the operator" +$TMP_DIRECTORY = "$PSScriptRoot\..\..\tmp" + +$POD_RUNNING = "Running" + +$MAX_RETRY_ATTEMPTS = 18 \ No newline at end of file diff --git a/testing/test/configurations/Helper.ps1 b/testing/test/configurations/Helper.ps1 new file mode 100644 index 00000000000..842e2da84aa --- /dev/null +++ b/testing/test/configurations/Helper.ps1 @@ -0,0 +1,45 @@ +function Get-ConfigData { + param( + [string]$configName + ) + + $output = kubectl get gitconfigs -A -o json | ConvertFrom-Json + return $output.items | Where-Object { $_.metadata.name -eq $configurationName } +} + +function Get-ConfigStatus { + param( + [string]$configName + ) + + $configData = Get-ConfigData $configName + if ($configData -ne $null) { + return $configData.status.status + } + return $null +} + +function Get-PodStatus { + param( + [string]$podName, + [string]$Namespace + ) + + $allPodData = kubectl get pods -n $Namespace -o json | ConvertFrom-Json + $podData = $allPodData.items | Where-Object { $_.metadata.name -Match $podName } + return $podData.status.phase +} + +function Secret-Exists { + param( + [string]$secretName, + [string]$Namespace + ) + + $allSecretData = kubectl get secrets -n $Namespace -o json | ConvertFrom-Json + $secretData = $allSecretData.items | Where-Object { $_.metadata.name -Match $secretName } + if ($secretData.Length -ge 1) { + return $true + } + return $false +} \ No newline at end of file From 4c214821dbd3e40b8b6b00db4c6e8c14b25e1494 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 28 Apr 2021 16:37:40 -0700 Subject: [PATCH 62/80] Fix pipeline failures --- k8s-custom-pipelines.yml | 4 ++-- testing/.gitignore | 1 + testing/Test.ps1 | 10 +++++++--- .../k8s_configuration-1.0.0-py3-none-any.whl | Bin 0 -> 42351 bytes 4 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 testing/bin/k8s_configuration-1.0.0-py3-none-any.whl diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 00d87b68d13..99f0c95fcb6 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -115,7 +115,7 @@ stages: scriptType: pscore scriptLocation: inlineScript inlineScript: | - .\Test.ps1 -CI -ExtensionType Public -OnlyPublicTests + .\Test.ps1 -CI -ExtensionType Public -OnlyPublicTests -Type k8s-extension workingDirectory: $(TEST_PATH) continueOnError: true condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'False')) @@ -127,7 +127,7 @@ stages: scriptType: pscore scriptLocation: inlineScript inlineScript: | - .\Test.ps1 -CI -ExtensionType Public + .\Test.ps1 -CI -ExtensionType Public -Type k8s-extension workingDirectory: $(TEST_PATH) continueOnError: true condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'True')) diff --git a/testing/.gitignore b/testing/.gitignore index 745d8708c4e..083fdfb5c25 100644 --- a/testing/.gitignore +++ b/testing/.gitignore @@ -4,5 +4,6 @@ bin/* !bin/connectedk8s-1.0.0-py3-none-any.whl !bin/k8s_extension-0.3.0-py3-none-any.whl !bin/k8s_extension_private-0.1.0-py3-none-any.whl +!bin/k8s_configuration-1.0.0-py3-none-any.whl !bin/connectedk8s-values.yaml *.xml \ No newline at end of file diff --git a/testing/Test.ps1 b/testing/Test.ps1 index 343f0eef2cc..ba90e877654 100644 --- a/testing/Test.ps1 +++ b/testing/Test.ps1 @@ -6,7 +6,11 @@ param ( [Parameter(Mandatory=$True)] [ValidateSet('Public','Private')] - [string]$ExtensionType + [string]$ExtensionType, + + [Parameter(Mandatory=$True)] + [ValidateSet('k8s-extension','k8s-configuration')] + [string]$Type ) # Disable confirm prompt for script @@ -18,7 +22,7 @@ az account set --subscription $ENVCONFIG.subscriptionId $Env:KUBECONFIG="$PSScriptRoot/tmp/KUBECONFIG" -if ($Type -eq 'Extension') { +if ($Type -eq 'k8s-extension') { if ($ExtensionType -eq "Public") { $k8sExtensionVersion = $ENVCONFIG.extensionVersion.'k8s-extension' $Env:K8sExtensionName = "k8s-extension" @@ -55,7 +59,7 @@ if ($Type -eq 'Extension') { } } -if ($Type -eq 'Configuration') { +if ($Type -eq 'k8s-configuration') { $k8sConfigurationVersion = $ENVCONFIG.extensionVersion.'k8s-configuration' if (!$SkipInstall) { Write-Host "Removing the old k8s-configuration extension..." diff --git a/testing/bin/k8s_configuration-1.0.0-py3-none-any.whl b/testing/bin/k8s_configuration-1.0.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..cc8e8e0995f81da31f6f919f83d344cc164e9568 GIT binary patch literal 42351 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 Date: Wed, 28 Apr 2021 17:02:17 -0700 Subject: [PATCH 63/80] Make test script more intuitive --- k8s-custom-pipelines.yml | 4 +-- testing/Test.ps1 | 55 ++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 99f0c95fcb6..3c76c8f925b 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -115,7 +115,7 @@ stages: scriptType: pscore scriptLocation: inlineScript inlineScript: | - .\Test.ps1 -CI -ExtensionType Public -OnlyPublicTests -Type k8s-extension + .\Test.ps1 -CI -OnlyPublicTests -Type k8s-extension workingDirectory: $(TEST_PATH) continueOnError: true condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'False')) @@ -127,7 +127,7 @@ stages: scriptType: pscore scriptLocation: inlineScript inlineScript: | - .\Test.ps1 -CI -ExtensionType Public -Type k8s-extension + .\Test.ps1 -CI -Type k8s-extension workingDirectory: $(TEST_PATH) continueOnError: true condition: and(succeeded(), eq(variables['IS_PRIVATE_BRANCH'], 'True')) diff --git a/testing/Test.ps1 b/testing/Test.ps1 index ba90e877654..7429a121a21 100644 --- a/testing/Test.ps1 +++ b/testing/Test.ps1 @@ -9,7 +9,7 @@ param ( [string]$ExtensionType, [Parameter(Mandatory=$True)] - [ValidateSet('k8s-extension','k8s-configuration')] + [ValidateSet('k8s-extension','k8s-configuration', 'k8s-extension-private')] [string]$Type ) @@ -23,33 +23,36 @@ az account set --subscription $ENVCONFIG.subscriptionId $Env:KUBECONFIG="$PSScriptRoot/tmp/KUBECONFIG" if ($Type -eq 'k8s-extension') { - if ($ExtensionType -eq "Public") { - $k8sExtensionVersion = $ENVCONFIG.extensionVersion.'k8s-extension' - $Env:K8sExtensionName = "k8s-extension" + $k8sExtensionVersion = $ENVCONFIG.extensionVersion.'k8s-extension' + $Env:K8sExtensionName = "k8s-extension" - if (!$SkipInstall) { - Write-Host "Removing the old k8s-extension extension..." - az extension remove -n k8s-extension - Write-Host "Installing k8s-extension version $k8sExtensionVersion..." - az extension add --source ./bin/k8s_extension-$k8sExtensionVersion-py3-none-any.whl - if (!$?) { - Write-Host "Unable to find k8s-extension version $k8sExtensionVersion, exiting..." - exit 1 - } + if (!$SkipInstall) { + Write-Host "Removing the old k8s-extension extension..." + az extension remove -n k8s-extension + Write-Host "Installing k8s-extension version $k8sExtensionVersion..." + az extension add --source ./bin/k8s_extension-$k8sExtensionVersion-py3-none-any.whl + if (!$?) { + Write-Host "Unable to find k8s-extension version $k8sExtensionVersion, exiting..." + exit 1 } + } + if ($OnlyPublicTests) { + $testFilePath = "$PSScriptRoot/test/extensions/public" } else { - $k8sExtensionPrivateVersion = $ENVCONFIG.extensionVersion.'k8s-extension-private' - $Env:K8sExtensionName = "k8s-extension-private" + $testFilePath = "$PSScriptRoot/test/extensions" + } +} elseif ($Type -eq 'k8s-extension-private') { + $k8sExtensionPrivateVersion = $ENVCONFIG.extensionVersion.'k8s-extension-private' + $Env:K8sExtensionName = "k8s-extension-private" - if (!$SkipInstall) { - Write-Host "Removing the old k8s-extension-private extension..." - az extension remove -n k8s-extension-private - Write-Host "Installing k8s-extension-private version $k8sExtensionPrivateVersion..." - az extension add --source ./bin/k8s_extension_private-$k8sExtensionPrivateVersion-py3-none-any.whl - if (!$?) { - Write-Host "Unable to find k8s-extension-private version $k8sExtensionPrivateVersion, exiting..." - exit 1 - } + if (!$SkipInstall) { + Write-Host "Removing the old k8s-extension-private extension..." + az extension remove -n k8s-extension-private + Write-Host "Installing k8s-extension-private version $k8sExtensionPrivateVersion..." + az extension add --source ./bin/k8s_extension_private-$k8sExtensionPrivateVersion-py3-none-any.whl + if (!$?) { + Write-Host "Unable to find k8s-extension-private version $k8sExtensionPrivateVersion, exiting..." + exit 1 } } if ($OnlyPublicTests) { @@ -57,9 +60,7 @@ if ($Type -eq 'k8s-extension') { } else { $testFilePath = "$PSScriptRoot/test/extensions" } -} - -if ($Type -eq 'k8s-configuration') { +} elseif ($Type -eq 'k8s-configuration') { $k8sConfigurationVersion = $ENVCONFIG.extensionVersion.'k8s-configuration' if (!$SkipInstall) { Write-Host "Removing the old k8s-configuration extension..." From 4dca64d6cbf26deba4252764c6aa8718bfbb2f23 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Wed, 28 Apr 2021 17:14:22 -0700 Subject: [PATCH 64/80] Remove parameter from testing --- testing/Test.ps1 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/testing/Test.ps1 b/testing/Test.ps1 index 7429a121a21..e75354355ca 100644 --- a/testing/Test.ps1 +++ b/testing/Test.ps1 @@ -4,10 +4,6 @@ param ( [switch] $CI, [switch] $OnlyPublicTests, - [Parameter(Mandatory=$True)] - [ValidateSet('Public','Private')] - [string]$ExtensionType, - [Parameter(Mandatory=$True)] [ValidateSet('k8s-extension','k8s-configuration', 'k8s-extension-private')] [string]$Type From 8bc4b2fb889fa4f54fa646258bc8612774882072 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 29 Apr 2021 10:11:31 -0700 Subject: [PATCH 65/80] Add some debug --- k8s-custom-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index d1949fb306d..2f0914072d0 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -66,6 +66,7 @@ stages: K8S_CONFIG_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) echo "##vso[task.setvariable variable=K8S_CONFIG_VERSION]$K8S_CONFIG_VERSION" cp * $(TEST_PATH)/bin + echo $(ls -l) workingDirectory: $(CLI_REPO_PATH)/dist displayName: "Copy the Built .whl to Extension Test Path" From c93e9584ae4a3f1d4e5568bbeef873b7f774a717 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 29 Apr 2021 10:22:02 -0700 Subject: [PATCH 66/80] Fix wrong location for k8s config whl --- testing/Test.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/Test.ps1 b/testing/Test.ps1 index e75354355ca..06c089f6f52 100644 --- a/testing/Test.ps1 +++ b/testing/Test.ps1 @@ -62,7 +62,7 @@ if ($Type -eq 'k8s-extension') { Write-Host "Removing the old k8s-configuration extension..." az extension remove -n k8s-configuration Write-Host "Installing k8s-configuration version $k8sConfigurationVersion..." - az extension add --source ./extensions/k8s_configuration-$k8sConfigurationVersion-py3-none-any.whl + az extension add --source ./bin/k8s_configuration-$k8sConfigurationVersion-py3-none-any.whl } $testFilePath = "$PSScriptRoot/test/configurations" } From fa1e31ac2a087727ef809bd4f56a76016518bd15 Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 6 May 2021 16:52:37 -0700 Subject: [PATCH 67/80] Fix pip install upgrade issue --- k8s-custom-pipelines.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 2f0914072d0..940770361d9 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -51,6 +51,7 @@ stages: source env/bin/activate # clone azure-cli + pip install --upgrade pip pip install azdev ls $(CLI_REPO_PATH) @@ -155,6 +156,7 @@ stages: source env/bin/activate # clone azure-cli + pip install --upgrade pip pip install azdev ls $(CLI_REPO_PATH) @@ -193,6 +195,7 @@ stages: # clone azure-cli git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + pip install --upgrade pip pip install -q azdev azdev setup -c ../azure-cli -r ./ @@ -276,6 +279,7 @@ stages: # clone azure-cli git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + pip install --upgrade pip pip install azdev azdev --version From 201c63cd3308a36699acf99dbaff8882bfcd498e Mon Sep 17 00:00:00 2001 From: jonathan-innis Date: Thu, 6 May 2021 16:52:37 -0700 Subject: [PATCH 68/80] Fix pip install upgrade issue --- azure-pipelines.yml | 1 + k8s-custom-pipelines.yml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 393d779b986..83fc66610d0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -54,6 +54,7 @@ jobs: # clone azure-cli git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + pip install --upgrade pip pip install -q azdev==0.1.31 azdev setup -c ../azure-cli -r ./ diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 2f0914072d0..940770361d9 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -51,6 +51,7 @@ stages: source env/bin/activate # clone azure-cli + pip install --upgrade pip pip install azdev ls $(CLI_REPO_PATH) @@ -155,6 +156,7 @@ stages: source env/bin/activate # clone azure-cli + pip install --upgrade pip pip install azdev ls $(CLI_REPO_PATH) @@ -193,6 +195,7 @@ stages: # clone azure-cli git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + pip install --upgrade pip pip install -q azdev azdev setup -c ../azure-cli -r ./ @@ -276,6 +279,7 @@ stages: # clone azure-cli git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + pip install --upgrade pip pip install azdev azdev --version From c3f7628bbde4c5af6406794fc34ddafe087e209f Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Mon, 28 Jun 2021 15:53:37 -0700 Subject: [PATCH 69/80] Add Check for Provider Registration and Refactor (#19) * Add check for provider registration and refactor * Fix bug in checking registration * Add license header to utils * Update private key check and error messaging * Update based on refactoring * Fix failing tests * Add provider registration check * Create a test for uppercase url, address comments * Add blank line to fix style check --- src/k8s-configuration/HISTORY.rst | 4 + .../_client_factory.py | 9 +- .../azext_k8s_configuration/_consts.py | 7 + .../azext_k8s_configuration/_params.py | 8 +- .../azext_k8s_configuration/_utils.py | 61 ++++++ .../azext_k8s_configuration/_validators.py | 115 ++++++++++- .../azext_k8s_configuration/custom.py | 186 +++--------------- .../tests/latest/test_validators.py | 56 +++--- src/k8s-configuration/setup.py | 2 +- .../configurations/Configuration.Tests.ps1 | 5 + 10 files changed, 255 insertions(+), 198 deletions(-) create mode 100644 src/k8s-configuration/azext_k8s_configuration/_consts.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/_utils.py diff --git a/src/k8s-configuration/HISTORY.rst b/src/k8s-configuration/HISTORY.rst index 7de17458634..918019a6174 100644 --- a/src/k8s-configuration/HISTORY.rst +++ b/src/k8s-configuration/HISTORY.rst @@ -3,6 +3,10 @@ Release History =============== +1.0.1 +++++++++++++++++++ +* Add provider registration check + 1.0.0 ++++++++++++++++++ * Support api-version 2021-03-01 diff --git a/src/k8s-configuration/azext_k8s_configuration/_client_factory.py b/src/k8s-configuration/azext_k8s_configuration/_client_factory.py index d294b6fdfa4..86cbd33b7f4 100644 --- a/src/k8s-configuration/azext_k8s_configuration/_client_factory.py +++ b/src/k8s-configuration/azext_k8s_configuration/_client_factory.py @@ -3,13 +3,18 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- +from azure.cli.core.commands.client_factory import get_mgmt_service_client -def cf_k8s_configuration(cli_ctx, *_): - from azure.cli.core.commands.client_factory import get_mgmt_service_client +def cf_k8s_configuration(cli_ctx, *_): from azext_k8s_configuration.vendored_sdks import SourceControlConfigurationClient return get_mgmt_service_client(cli_ctx, SourceControlConfigurationClient) def cf_k8s_configuration_operation(cli_ctx, _): return cf_k8s_configuration(cli_ctx).source_control_configurations + + +def _resource_providers_client(cli_ctx): + from azure.mgmt.resource import ResourceManagementClient + return get_mgmt_service_client(cli_ctx, ResourceManagementClient).providers diff --git a/src/k8s-configuration/azext_k8s_configuration/_consts.py b/src/k8s-configuration/azext_k8s_configuration/_consts.py new file mode 100644 index 00000000000..e58470e7e78 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/_consts.py @@ -0,0 +1,7 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +PROVIDER_NAMESPACE = 'Microsoft.KubernetesConfiguration' +REGISTERED = "Registered" diff --git a/src/k8s-configuration/azext_k8s_configuration/_params.py b/src/k8s-configuration/azext_k8s_configuration/_params.py index 9198ef3882e..c9faab38cfb 100644 --- a/src/k8s-configuration/azext_k8s_configuration/_params.py +++ b/src/k8s-configuration/azext_k8s_configuration/_params.py @@ -13,7 +13,7 @@ ) from azure.cli.core.commands.validators import get_default_location_from_resource_group -from ._validators import validate_configuration_type, validate_operator_namespace, validate_operator_instance_name +from ._validators import _validate_configuration_type, _validate_operator_namespace, _validate_operator_instance_name def load_arguments(self, _): @@ -38,7 +38,7 @@ def load_arguments(self, _): arg_type=get_enum_type(['namespace', 'cluster']), help='''Specify scope of the operator to be 'namespace' or 'cluster' ''') c.argument('configuration_type', - validator=validate_configuration_type, + validator=_validate_configuration_type, arg_type=get_enum_type(['sourceControlConfiguration']), help='Type of the configuration') c.argument('enable_helm_operator', @@ -60,11 +60,11 @@ def load_arguments(self, _): c.argument('operator_instance_name', arg_group="Operator", help='Instance name of the Operator', - validator=validate_operator_instance_name) + validator=_validate_operator_instance_name) c.argument('operator_namespace', arg_group="Operator", help='Namespace in which to install the Operator', - validator=validate_operator_namespace) + validator=_validate_operator_namespace) c.argument('operator_type', arg_group="Operator", help='''Type of the operator. Valid value is 'flux' ''') diff --git a/src/k8s-configuration/azext_k8s_configuration/_utils.py b/src/k8s-configuration/azext_k8s_configuration/_utils.py new file mode 100644 index 00000000000..6ad8e600636 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/_utils.py @@ -0,0 +1,61 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import base64 +from azure.cli.core.azclierror import MutuallyExclusiveArgumentError, InvalidArgumentValueError + + +def _get_cluster_type(cluster_type): + if cluster_type.lower() == 'connectedclusters': + return 'Microsoft.Kubernetes' + # Since cluster_type is an enum of only two values, if not connectedClusters, it will be managedClusters. + return 'Microsoft.ContainerService' + + +def _fix_compliance_state(config): + # If we get Compliant/NonCompliant as compliance_sate, change them before returning + if config.compliance_status.compliance_state.lower() == 'noncompliant': + config.compliance_status.compliance_state = 'Failed' + elif config.compliance_status.compliance_state.lower() == 'compliant': + config.compliance_status.compliance_state = 'Installed' + + return config + + +def _get_data_from_key_or_file(key, filepath): + if key != '' and filepath != '': + raise MutuallyExclusiveArgumentError( + 'Error! Both textual key and key filepath cannot be provided', + 'Try providing the file parameter without providing the plaintext parameter') + data = '' + if filepath != '': + data = _read_key_file(filepath) + elif key != '': + data = key + return data + + +def _read_key_file(path): + try: + with open(path, "r") as myfile: # user passed in filename + data_list = myfile.readlines() # keeps newline characters intact + data_list_len = len(data_list) + if (data_list_len) <= 0: + raise Exception("File provided does not contain any data") + raw_data = ''.join(data_list) + return _to_base64(raw_data) + except Exception as ex: + raise InvalidArgumentValueError( + 'Error! Unable to read key file specified with: {0}'.format(ex), + 'Verify that the filepath specified exists and contains valid utf-8 data') from ex + + +def _from_base64(base64_str): + return base64.b64decode(base64_str) + + +def _to_base64(raw_data): + bytes_data = raw_data.encode('utf-8') + return base64.b64encode(bytes_data).decode('utf-8') diff --git a/src/k8s-configuration/azext_k8s_configuration/_validators.py b/src/k8s-configuration/azext_k8s_configuration/_validators.py index 0862de43205..47c6b97ca3a 100644 --- a/src/k8s-configuration/azext_k8s_configuration/_validators.py +++ b/src/k8s-configuration/azext_k8s_configuration/_validators.py @@ -4,34 +4,48 @@ # -------------------------------------------------------------------------------------------- import re -from azure.cli.core.azclierror import InvalidArgumentValueError +import io +from azure.cli.core.azclierror import InvalidArgumentValueError, MutuallyExclusiveArgumentError + +from knack.log import get_logger +from azext_k8s_configuration._client_factory import _resource_providers_client +from azext_k8s_configuration._utils import _from_base64 +import azext_k8s_configuration._consts as consts +from urllib.parse import urlparse +from paramiko.hostkeys import HostKeyEntry +from paramiko.ed25519key import Ed25519Key +from paramiko.ssh_exception import SSHException +from Crypto.PublicKey import RSA, ECC, DSA + + +logger = get_logger(__name__) # Parameter-Level Validation -def validate_configuration_type(configuration_type): +def _validate_configuration_type(configuration_type): if configuration_type.lower() != 'sourcecontrolconfiguration': raise InvalidArgumentValueError( 'Invalid configuration-type', 'Try specifying the valid value "sourceControlConfiguration"') -def validate_operator_namespace(namespace): +def _validate_operator_namespace(namespace): if namespace.operator_namespace: - __validate_k8s_name(namespace.operator_namespace, "--operator-namespace", 23) + _validate_k8s_name(namespace.operator_namespace, "--operator-namespace", 23) -def validate_operator_instance_name(namespace): +def _validate_operator_instance_name(namespace): if namespace.operator_instance_name: - __validate_k8s_name(namespace.operator_instance_name, "--operator-instance-name", 23) + _validate_k8s_name(namespace.operator_instance_name, "--operator-instance-name", 23) # Create Parameter Validation -def validate_configuration_name(configuration_name): - __validate_k8s_name(configuration_name, "--name", 63) +def _validate_configuration_name(configuration_name): + _validate_k8s_name(configuration_name, "--name", 63) # Helper -def __validate_k8s_name(param_value, param_name, max_len): +def _validate_k8s_name(param_value, param_name, max_len): if len(param_value) > max_len: raise InvalidArgumentValueError( 'Error! Invalid {0}'.format(param_name), @@ -44,3 +58,86 @@ def __validate_k8s_name(param_value, param_name, max_len): raise InvalidArgumentValueError( 'Error! Invalid {0}'.format(param_name), 'Parameter {0} can only contain lowercase alphanumeric characters and hyphens'.format(param_name)) + + +def _validate_url_with_params(repository_url, ssh_private_key_set, known_hosts_contents_set, https_auth_set): + scheme = urlparse(repository_url).scheme + + if scheme.lower() in ('http', 'https'): + if ssh_private_key_set: + raise MutuallyExclusiveArgumentError( + 'Error! An --ssh-private-key cannot be used with an http(s) url', + 'Verify the url provided is a valid ssh url and not an http(s) url') + if known_hosts_contents_set: + raise MutuallyExclusiveArgumentError( + 'Error! --ssh-known-hosts cannot be used with an http(s) url', + 'Verify the url provided is a valid ssh url and not an http(s) url') + if not https_auth_set and scheme == 'https': + logger.warning('Warning! https url is being used without https auth params, ensure the repository ' + 'url provided is not a private repo') + else: + if https_auth_set: + raise MutuallyExclusiveArgumentError( + 'Error! https auth (--https-user and --https-key) cannot be used with a non-http(s) url', + 'Verify the url provided is a valid http(s) url and not an ssh url') + + +def _validate_known_hosts(knownhost_data): + try: + knownhost_str = _from_base64(knownhost_data).decode('utf-8') + except Exception as ex: + raise InvalidArgumentValueError( + 'Error! ssh known_hosts is not a valid utf-8 base64 encoded string', + 'Verify that the string provided safely decodes into a valid utf-8 format') from ex + lines = knownhost_str.split('\n') + for line in lines: + line = line.strip(' ') + line_len = len(line) + if (line_len == 0) or (line[0] == "#"): + continue + try: + host_key = HostKeyEntry.from_line(line) + if not host_key: + raise Exception('not enough fields found in known_hosts line') + except Exception as ex: + raise InvalidArgumentValueError( + 'Error! ssh known_hosts provided in wrong format', + 'Verify that all lines in the known_hosts contents are provided in a valid sshd(8) format') from ex + + +def _validate_private_key(ssh_private_key_data): + try: + RSA.import_key(_from_base64(ssh_private_key_data)) + return + except ValueError: + try: + ECC.import_key(_from_base64(ssh_private_key_data)) + return + except ValueError: + try: + DSA.import_key(_from_base64(ssh_private_key_data)) + return + except ValueError: + try: + key_obj = io.StringIO(_from_base64(ssh_private_key_data).decode('utf-8')) + Ed25519Key(file_obj=key_obj) + return + except SSHException: + raise InvalidArgumentValueError( + 'Error! --ssh-private-key provided in invalid format', + 'Verify the key provided is a valid PEM-formatted key of type RSA, ECC, DSA, or Ed25519') + + +# pylint: disable=broad-except +def _validate_cc_registration(cmd): + try: + rp_client = _resource_providers_client(cmd.cli_ctx) + registration_state = rp_client.get(consts.PROVIDER_NAMESPACE).registration_state + + if registration_state.lower() != consts.REGISTERED.lower(): + logger.warning("'Source Control Configuration' cannot be used because '%s' provider has not been " + "registered. More details for registering this provider can be found here - " + "https://aka.ms/RegisterKubernetesConfigurationProvider", consts.PROVIDER_NAMESPACE) + except Exception: + logger.warning("Unable to fetch registration state of '%s' provider. " + "Failed to enable 'source control configuration' feature...", consts.PROVIDER_NAMESPACE) diff --git a/src/k8s-configuration/azext_k8s_configuration/custom.py b/src/k8s-configuration/azext_k8s_configuration/custom.py index de6f0dfc5ca..8882fd16cff 100644 --- a/src/k8s-configuration/azext_k8s_configuration/custom.py +++ b/src/k8s-configuration/azext_k8s_configuration/custom.py @@ -3,21 +3,17 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -import base64 -import io -from urllib.parse import urlparse -from azure.cli.core.azclierror import InvalidArgumentValueError, ResourceNotFoundError, \ - RequiredArgumentMissingError, MutuallyExclusiveArgumentError, CommandNotFoundError +from azure.cli.core.azclierror import ResourceNotFoundError, CommandNotFoundError, \ + RequiredArgumentMissingError from knack.log import get_logger -from paramiko.ed25519key import Ed25519Key -from paramiko.hostkeys import HostKeyEntry -from paramiko.ssh_exception import SSHException -from Crypto.PublicKey import RSA, ECC, DSA +from azext_k8s_configuration._utils import _get_cluster_type, \ + _fix_compliance_state, _get_data_from_key_or_file, _to_base64 +from azext_k8s_configuration._validators import _validate_known_hosts, _validate_url_with_params, \ + _validate_configuration_name, _validate_cc_registration, _validate_private_key from azext_k8s_configuration.vendored_sdks.models import SourceControlConfiguration from azext_k8s_configuration.vendored_sdks.models import HelmOperatorProperties from azext_k8s_configuration.vendored_sdks.models import ErrorResponseException -from ._validators import validate_configuration_name logger = get_logger(__name__) @@ -27,11 +23,11 @@ def show_k8s_configuration(client, resource_group_name, cluster_name, name, clus """ # Determine ClusterRP - cluster_rp = __get_cluster_type(cluster_type) + cluster_rp = _get_cluster_type(cluster_type) try: config = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) - return __fix_compliance_state(config) + return _fix_compliance_state(config) except ErrorResponseException as ex: # Customize the error message for resources not found if ex.response.status_code == 404: @@ -55,7 +51,7 @@ def show_k8s_configuration(client, resource_group_name, cluster_name, name, clus # pylint: disable=too-many-locals -def create_k8s_configuration(client, resource_group_name, cluster_name, name, repository_url, scope, cluster_type, +def create_k8s_configuration(cmd, client, resource_group_name, cluster_name, name, repository_url, scope, cluster_type, operator_instance_name=None, operator_namespace='default', helm_operator_chart_version='1.2.0', operator_type='flux', operator_params='', ssh_private_key='', ssh_private_key_file='', https_user='', https_key='', @@ -65,10 +61,10 @@ def create_k8s_configuration(client, resource_group_name, cluster_name, name, re """ # Validate configuration name - validate_configuration_name(name) + _validate_configuration_name(name) # Determine ClusterRP - cluster_rp = __get_cluster_type(cluster_type) + cluster_rp = _get_cluster_type(cluster_type) # Determine operatorInstanceName if operator_instance_name is None: @@ -81,22 +77,25 @@ def create_k8s_configuration(client, resource_group_name, cluster_name, name, re helm_operator_properties.chart_version = helm_operator_chart_version.strip() helm_operator_properties.chart_values = helm_operator_params.strip() - protected_settings = validate_and_get_protected_settings(ssh_private_key, - ssh_private_key_file, - https_user, - https_key) - knownhost_data = get_data_from_key_or_file(ssh_known_hosts, ssh_known_hosts_file) + protected_settings = _get_protected_settings(ssh_private_key, + ssh_private_key_file, + https_user, + https_key) + knownhost_data = _get_data_from_key_or_file(ssh_known_hosts, ssh_known_hosts_file) if knownhost_data: - validate_known_hosts(knownhost_data) + _validate_known_hosts(knownhost_data) # Flag which parameters have been set and validate these settings against the set repository url ssh_private_key_set = ssh_private_key != '' or ssh_private_key_file != '' known_hosts_contents_set = knownhost_data != '' https_auth_set = https_user != '' and https_key != '' - validate_url_with_params(repository_url, - ssh_private_key_set=ssh_private_key_set, - known_hosts_contents_set=known_hosts_contents_set, - https_auth_set=https_auth_set) + _validate_url_with_params(repository_url, + ssh_private_key_set=ssh_private_key_set, + known_hosts_contents_set=known_hosts_contents_set, + https_auth_set=https_auth_set) + + # Validate that the subscription is registered to Microsoft.KubernetesConfiguration + _validate_cc_registration(cmd) # Create sourceControlConfiguration object source_control_configuration = SourceControlConfiguration(repository_url=repository_url, @@ -114,7 +113,7 @@ def create_k8s_configuration(client, resource_group_name, cluster_name, name, re config = client.create_or_update(resource_group_name, cluster_rp, cluster_type, cluster_name, name, source_control_configuration) - return __fix_compliance_state(config) + return _fix_compliance_state(config) def update_k8s_configuration(client, resource_group_name, cluster_name, name, cluster_type, @@ -188,7 +187,7 @@ def update_k8s_configuration(client, resource_group_name, cluster_name, name, cl def list_k8s_configuration(client, resource_group_name, cluster_name, cluster_type): - cluster_rp = __get_cluster_type(cluster_type) + cluster_rp = _get_cluster_type(cluster_type) return client.list(resource_group_name, cluster_rp, cluster_type, cluster_name) @@ -197,49 +196,27 @@ def delete_k8s_configuration(client, resource_group_name, cluster_name, name, cl """ # Determine ClusterRP - cluster_rp = __get_cluster_type(cluster_type) + cluster_rp = _get_cluster_type(cluster_type) source_control_configuration_name = name return client.delete(resource_group_name, cluster_rp, cluster_type, cluster_name, source_control_configuration_name) -def validate_and_get_protected_settings(ssh_private_key, ssh_private_key_file, https_user, https_key): +def _get_protected_settings(ssh_private_key, ssh_private_key_file, https_user, https_key): protected_settings = {} - ssh_private_key_data = get_data_from_key_or_file(ssh_private_key, ssh_private_key_file) + ssh_private_key_data = _get_data_from_key_or_file(ssh_private_key, ssh_private_key_file) # Add gitops private key data to protected settings if exists # Dry-run all key types to determine if the private key is in a valid format - invalid_rsa_key, invalid_ecc_key, invalid_dsa_key, invalid_ed25519_key = (False, False, False, False) if ssh_private_key_data != '': - try: - RSA.import_key(from_base64(ssh_private_key_data)) - except ValueError: - invalid_rsa_key = True - try: - ECC.import_key(from_base64(ssh_private_key_data)) - except ValueError: - invalid_ecc_key = True - try: - DSA.import_key(from_base64(ssh_private_key_data)) - except ValueError: - invalid_dsa_key = True - try: - key_obj = io.StringIO(from_base64(ssh_private_key_data).decode('utf-8')) - Ed25519Key(file_obj=key_obj) - except SSHException: - invalid_ed25519_key = True - - if invalid_rsa_key and invalid_ecc_key and invalid_dsa_key and invalid_ed25519_key: - raise InvalidArgumentValueError( - 'Error! ssh private key provided in invalid format', - 'Verify the key provided is a valid PEM-formatted key of type RSA, ECC, DSA, or Ed25519') + _validate_private_key(ssh_private_key_data) protected_settings["sshPrivateKey"] = ssh_private_key_data # Check if both httpsUser and httpsKey exist, then add to protected settings if https_user != '' and https_key != '': - protected_settings['httpsUser'] = to_base64(https_user) - protected_settings['httpsKey'] = to_base64(https_key) + protected_settings['httpsUser'] = _to_base64(https_user) + protected_settings['httpsKey'] = _to_base64(https_key) elif https_user != '': raise RequiredArgumentMissingError( 'Error! --https-user used without --https-key', @@ -250,102 +227,3 @@ def validate_and_get_protected_settings(ssh_private_key, ssh_private_key_file, h 'Try providing both --https-user and --https-key together') return protected_settings - - -def __get_cluster_type(cluster_type): - if cluster_type.lower() == 'connectedclusters': - return 'Microsoft.Kubernetes' - # Since cluster_type is an enum of only two values, if not connectedClusters, it will be managedClusters. - return 'Microsoft.ContainerService' - - -def __fix_compliance_state(config): - # If we get Compliant/NonCompliant as compliance_sate, change them before returning - if config.compliance_status.compliance_state.lower() == 'noncompliant': - config.compliance_status.compliance_state = 'Failed' - elif config.compliance_status.compliance_state.lower() == 'compliant': - config.compliance_status.compliance_state = 'Installed' - - return config - - -def validate_url_with_params(repository_url, ssh_private_key_set, known_hosts_contents_set, https_auth_set): - scheme = urlparse(repository_url).scheme - - if scheme in ('http', 'https'): - if ssh_private_key_set: - raise MutuallyExclusiveArgumentError( - 'Error! An ssh private key cannot be used with an http(s) url', - 'Verify the url provided is a valid ssh url and not an http(s) url') - if known_hosts_contents_set: - raise MutuallyExclusiveArgumentError( - 'Error! ssh known_hosts cannot be used with an http(s) url', - 'Verify the url provided is a valid ssh url and not an http(s) url') - if not https_auth_set and scheme == 'https': - logger.warning('Warning! https url is being used without https auth params, ensure the repository ' - 'url provided is not a private repo') - else: - if https_auth_set: - raise MutuallyExclusiveArgumentError( - 'Error! https auth (--https-user and --https-key) cannot be used with a non-http(s) url', - 'Verify the url provided is a valid http(s) url and not an ssh url') - - -def validate_known_hosts(knownhost_data): - try: - knownhost_str = from_base64(knownhost_data).decode('utf-8') - except Exception as ex: - raise InvalidArgumentValueError( - 'Error! ssh known_hosts is not a valid utf-8 base64 encoded string', - 'Verify that the string provided safely decodes into a valid utf-8 format') from ex - lines = knownhost_str.split('\n') - for line in lines: - line = line.strip(' ') - line_len = len(line) - if (line_len == 0) or (line[0] == "#"): - continue - try: - host_key = HostKeyEntry.from_line(line) - if not host_key: - raise Exception('not enough fields found in known_hosts line') - except Exception as ex: - raise InvalidArgumentValueError( - 'Error! ssh known_hosts provided in wrong format', - 'Verify that all lines in the known_hosts contents are provided in a valid sshd(8) format') from ex - - -def get_data_from_key_or_file(key, filepath): - if key != '' and filepath != '': - raise MutuallyExclusiveArgumentError( - 'Error! Both textual key and key filepath cannot be provided', - 'Try providing the file parameter without providing the plaintext parameter') - data = '' - if filepath != '': - data = read_key_file(filepath) - elif key != '': - data = key - return data - - -def read_key_file(path): - try: - with open(path, "r") as myfile: # user passed in filename - data_list = myfile.readlines() # keeps newline characters intact - data_list_len = len(data_list) - if (data_list_len) <= 0: - raise Exception("File provided does not contain any data") - raw_data = ''.join(data_list) - return to_base64(raw_data) - except Exception as ex: - raise InvalidArgumentValueError( - 'Error! Unable to read key file specified with: {0}'.format(ex), - 'Verify that the filepath specified exists and contains valid utf-8 data') from ex - - -def from_base64(base64_str): - return base64.b64decode(base64_str) - - -def to_base64(raw_data): - bytes_data = raw_data.encode('utf-8') - return base64.b64encode(bytes_data).decode('utf-8') diff --git a/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py index ce3db8b84f4..29a796e05c5 100644 --- a/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py +++ b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py @@ -6,7 +6,7 @@ import unittest import base64 from azure.cli.core.azclierror import InvalidArgumentValueError, MutuallyExclusiveArgumentError -from azext_k8s_configuration.custom import validate_and_get_protected_settings, validate_url_with_params, validate_known_hosts +from azext_k8s_configuration.custom import _get_protected_settings import azext_k8s_configuration._validators as validators from Crypto.PublicKey import RSA, ECC, DSA from paramiko.ed25519key import Ed25519Key @@ -15,33 +15,33 @@ class TestValidateKeyTypes(unittest.TestCase): def test_bad_private_key(self): private_key_encoded = base64.b64encode("this is not a valid private key".encode('utf-8')).decode('utf-8') - err = "Error! ssh private key provided in invalid format" + err = "Error! --ssh-private-key provided in invalid format" with self.assertRaises(InvalidArgumentValueError) as cm: - validate_and_get_protected_settings(private_key_encoded, '', '', '') + _get_protected_settings(private_key_encoded, '', '', '') self.assertEqual(str(cm.exception), err) def test_rsa_private_key(self): rsa_key = "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUJsd0FBQUFkemMyZ3RjbgpOaEFBQUFBd0VBQVFBQUFZRUF1bVA5M09qRHdjdlEyZHZhRlJNNWYrMEhVSnFvOFJnbmdwaGN3NFZidnd1TVNoQTZFc2FyCjFsam1CNUNnT1NGNHJqNDIvcmdxMW1hWndoSUgvckdPSElNa0lIcjFrZmNKMnBrR3ZhK1NxVm4wWUhzMjBpUW02ay92ZXQKdXdVQ2J1QjlxSU5zL2h2b0ppQ21JMUVpVWZ4VGoxRFJCUG15OXR3Qm52bW5FS1kxZ2NhT2YrS2Y1aGhCc09pd00yZnBRTwp0aTlIcHVzM1JhNXpFeElWbjJzVitpRjVvV3ZZM1JQTTlKNXFPMXRObUtOWll6TjgzbDYxMlBzRmR1Vm1QM2NUUlJtK2pzCjdzZW5jY0U0RitzU0hQMlJpMk5DU0JvZ2RJOFR5VTlzeTM3Szl3bFJ5NGZkWWI1K1o3YUZjMjhTNDdDWlo5dTRFVXdWUEYKbjU4dTUzajU0empwdXNpei9ZWmx3MG5NeEQ5SXI0aHlJZ2s0NlUzVmdHR0NPUytZVTVZT2JURGhPRG5udk5VRkg2NVhCagpEM3l6WVJuRDA3b2swQ1JUR3RCOWMzTjBFNDBjUnlPeVpEQ0l5a0FPdHZXYnBUZzdnaXA2UDc4K2pLVlFnanFwRTVQdi9ICnl1dlB6cUJoUkpWcG5VR1dvWnFlcWJhd2N5RWZwdHFLaTNtWUdVMHBBQUFGa0U5cUs3SlBhaXV5QUFBQUIzTnphQzF5YzIKRUFBQUdCQUxwai9kem93OEhMME5uYjJoVVRPWC90QjFDYXFQRVlKNEtZWE1PRlc3OExqRW9RT2hMR3E5Wlk1Z2VRb0RraAplSzQrTnY2NEt0Wm1tY0lTQi82eGpoeURKQ0I2OVpIM0NkcVpCcjJ2a3FsWjlHQjdOdElrSnVwUDczcmJzRkFtN2dmYWlECmJQNGI2Q1lncGlOUklsSDhVNDlRMFFUNXN2YmNBWjc1cHhDbU5ZSEdqbi9pbitZWVFiRG9zRE5uNlVEcll2UjZick4wV3UKY3hNU0ZaOXJGZm9oZWFGcjJOMFR6UFNlYWp0YlRaaWpXV016Zk41ZXRkajdCWGJsWmo5M0UwVVp2bzdPN0hwM0hCT0JmcgpFaHo5a1l0alFrZ2FJSFNQRThsUGJNdCt5dmNKVWN1SDNXRytmbWUyaFhOdkV1T3dtV2ZidUJGTUZUeForZkx1ZDQrZU00CjZicklzLzJHWmNOSnpNUS9TSytJY2lJSk9PbE4xWUJoZ2prdm1GT1dEbTB3NFRnNTU3elZCUit1VndZdzk4czJFWnc5TzYKSk5Ba1V4clFmWE56ZEJPTkhFY2pzbVF3aU1wQURyYjFtNlU0TzRJcWVqKy9Qb3lsVUlJNnFST1Q3L3g4cnJ6ODZnWVVTVgphWjFCbHFHYW5xbTJzSE1oSDZiYWlvdDVtQmxOS1FBQUFBTUJBQUVBQUFHQkFMaElmSXFacUZKSFRXcllyN24rays4alR3ClFtcGJvWmc1YmZSWGdhdGljaEo4ZGlXOGlNblFFRVRBcFd0OU5FZ0tqbDRrSGRuSnoyUERkZzFIN0ExaHppbkNsdzZMTTAKYUkyMGxyR2NrWWpXNDRNd3ozYmRQNHlURTllSXRiM0pmN1pNSGpqek4rSy96bWN0eWdMeXFZSzVXYTljM1JnMXdIRWFNNAplakUvNDg4M25WUmJvSFJDcjFCVi8wQVVFTTZhNisrRHpVZW9WdWdWL3RsV3RVMlJuQlZ4eCtJS0FVSDZRTHJFU2JkUkRoCkVGUEFhRWtEb3crd3dDcFpqTXBhMHdRZXBDSkhwWkJLN1pBU25EU3R3Y2RKRE4yeHZzdVNOOGg0bkN0MlZWd0xRenJKeVAKU2VjcWM3M1hIc3E3VWx6ZU5veHlTVW9KZ2JjNTZoRzhWYS9ITlhsOUtkdkFlWUVzS1l1OW5NRUprVSt3VHo1KzUvM2wwVQpxSkErb0pTVTducjYydlVKQnljbXg0SFdBcjJ6QkR2QnFBUWMzRG9LWHczeVM1Z0c5Zkc0c25OUUkxOHVRSjdOSjdndHZHClpKRU56bTNJMmFTMzl5dndWZnFIMXpXVERxU2VNeWhYeWFnTkFEcGtCVEJIMVJQR2NtTFplclFmWWx1djVVUmFNTXdRQUEKQU1BdE9oNHFwUUhidm5tQ1RVakx4dXRrWnRaRlhNa0hmSTk5NS9Nd2RvWVY1eWRKV0pUVGsyKzB1QVBIcTZEejk2b3dWbQpjUkF2WDBDOVU5d3ZRMkpnR0Y1MDZzcmgzZkVpUzM2d1ArOFd0RjZ6ODd0enJwQnpQVHIxOGRONURCOEx5L3dXRk5BVTdqClBUbXM0dHlUY1VsRXR3eEt4TXJTNC9ROUZwMWozL3JNdnNZdGVaSVgycmN4YUhkWWJDVGJtTUpZS3lVTWVXTk56NXpub1EKcFcyd2NDSmpJc1MvS1F2WmR4cHZwNWd0RXE1WlEva3FvLzJVRWd1NHhwdDNWeUNma0FBQURCQVBOSHVEU1R0ZEpJWjdzcwpaQkVwcUE4TE54b1dMQ2RURnlpRERiUnpYOWVPTldkRFQ3NklaRE9HejczNXJhZUFSM2FiY0FhaUM0dDQwTFJTNGEyN29sCm9wK1dSak9wcjVNYUtOUnk4MCt6VWw3WUlSMjErKzVnMFVnNkRnQlBEdmFJSHFSTnRsZ2gyVXdTL0cva1lOaUlEY0JiS1EKOUcvdTI4ekRIRUtNL21YYS8wYnFtSm16ZUYvY1BLdHdScFE3clFoRnAwUkdFcnZtc0l4dDl6K0ZZZUdncjFBYUVTV0ZlTApmUmZsa0lnOVBWOEl0b09GN25qK2VtMkxkNTNCS1hSUUFBQU1FQXhDTFBueHFFVEsyMW5QOXFxQVYzMEZUUkhGNW9kRHg4ClpiYnZIbjgwdEgxQjYwZjRtTGJFRm56REZFR0NwS2Rwb3dyUXR6WUhnQzNBaGNJUE9BbXFXaDg0UEFPbisreHhFanNaQkwKRWhVWmNFUndkYTMzTnJDNTVEMzZxbDBMZEsrSGRuZUFzVGZhazh0bWVlOTJWb0RxdWovNGFSMjBmUTBJUFVzMU8rWHNRNQpGWVFYQzZndExHZGRzRVFoSDF6MTh6RGtWa1UwdEhlZkJaL2pFZXBiOEZScXoxR1hpT0hGK2xBZVE2b3crS0xlcWtCcXQ4CkZxMHhGdG90SlF4VnFWQUFBQUYycHZhVzV1YVhOQVJFVlRTMVJQVUMxUVRWVkdVRFpOQVFJRAotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K" - protected_settings = validate_and_get_protected_settings(rsa_key, '', '', '') + protected_settings = _get_protected_settings(rsa_key, '', '', '') self.assertEqual('sshPrivateKey' in protected_settings, True) self.assertEqual(protected_settings.get('sshPrivateKey'), rsa_key) def test_dsa_private_key(self): key = DSA.generate(2048) private_key_encoded = base64.b64encode(key.export_key()).decode('utf-8') - protected_settings = validate_and_get_protected_settings(private_key_encoded, '', '', '') + protected_settings = _get_protected_settings(private_key_encoded, '', '', '') self.assertEqual('sshPrivateKey' in protected_settings, True) self.assertEqual(protected_settings.get('sshPrivateKey'), private_key_encoded) def test_ecdsa_private_key(self): ecdsa_key = "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUFhQUFBQUJObFkyUnpZUwoxemFHRXlMVzVwYzNSd01qVTJBQUFBQ0c1cGMzUndNalUyQUFBQVFRUjBRc1BjWmJKeWZPaXE2a1M1d0VaeE5DbmR2YVJHCm1ETEUvVVBjakpDTDZQTVIyZmdPS2NnWlhzTEZkTUFzSnExS2d6TmNDN0ZXNGE0L0wrYTFWWUxDQUFBQXNIZ1RqTFY0RTQKeTFBQUFBRTJWalpITmhMWE5vWVRJdGJtbHpkSEF5TlRZQUFBQUlibWx6ZEhBeU5UWUFBQUJCQkhSQ3c5eGxzbko4NktycQpSTG5BUm5FMEtkMjlwRWFZTXNUOVE5eU1rSXZvOHhIWitBNHB5Qmxld3NWMHdDd21yVXFETTF3THNWYmhyajh2NXJWVmdzCklBQUFBZ0h1U3laU0NUZzJZbVNpOG9aY2c0cnVpODh0T1NUSm1aRVhkR09hdExySHNBQUFBWGFtOXBibTVwYzBCRVJWTkwKVkU5UUxWQk5WVVpRTmswQgotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K" - protected_settings = validate_and_get_protected_settings(ecdsa_key, '', '', '') + protected_settings = _get_protected_settings(ecdsa_key, '', '', '') self.assertEqual('sshPrivateKey' in protected_settings, True) self.assertEqual(protected_settings.get('sshPrivateKey'), ecdsa_key) def test_ed25519_private_key(self): ed25519_key = "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUFNd0FBQUF0emMyZ3RaVwpReU5UVXhPUUFBQUNCNjF0RzkrNGFmOTZsWGoyUStjWjJMT2JpV1liMlRtWVR6N3NSV0JDM1hVZ0FBQUtCRzFWRWZSdFZSCkh3QUFBQXR6YzJndFpXUXlOVFV4T1FBQUFDQjYxdEc5KzRhZjk2bFhqMlErY1oyTE9iaVdZYjJUbVlUejdzUldCQzNYVWcKQUFBRURRTStLcCtOSWpJVUhSUklqRFE5VDZ0U0V0SG9Ic0w1QjlwbHpCNlZ2MnluclcwYjM3aHAvM3FWZVBaRDV4bllzNQp1SlpodlpPWmhQUHV4RllFTGRkU0FBQUFGMnB2YVc1dWFYTkFSRVZUUzFSUFVDMVFUVlZHVURaTkFRSURCQVVHCi0tLS0tRU5EIE9QRU5TU0ggUFJJVkFURSBLRVktLS0tLQo=" - protected_settings = validate_and_get_protected_settings(ed25519_key, '', '', '') + protected_settings = _get_protected_settings(ed25519_key, '', '', '') self.assertEqual('sshPrivateKey' in protected_settings, True) self.assertEqual(protected_settings.get('sshPrivateKey'), ed25519_key) @@ -52,7 +52,7 @@ def test_long_operator_namespace(self): namespace = OperatorNamespace(operator_namespace) err = 'Error! Invalid --operator-namespace' with self.assertRaises(InvalidArgumentValueError) as cm: - validators.validate_operator_namespace(namespace) + validators._validate_operator_namespace(namespace) self.assertEqual(str(cm.exception), err) def test_long_operator_instance_name(self): @@ -60,7 +60,7 @@ def test_long_operator_instance_name(self): namespace = OperatorInstanceName(operator_instance_name) err = 'Error! Invalid --operator-instance-name' with self.assertRaises(InvalidArgumentValueError) as cm: - validators.validate_operator_instance_name(namespace) + validators._validate_operator_instance_name(namespace) self.assertEqual(str(cm.exception), err) def test_caps_operator_namespace(self): @@ -68,7 +68,7 @@ def test_caps_operator_namespace(self): namespace = OperatorNamespace(operator_namespace) err = 'Error! Invalid --operator-namespace' with self.assertRaises(InvalidArgumentValueError) as cm: - validators.validate_operator_namespace(namespace) + validators._validate_operator_namespace(namespace) self.assertEqual(str(cm.exception), err) def test_caps_operator_instance_name(self): @@ -76,68 +76,68 @@ def test_caps_operator_instance_name(self): namespace = OperatorInstanceName(operator_instance_name) err = 'Error! Invalid --operator-instance-name' with self.assertRaises(InvalidArgumentValueError) as cm: - validators.validate_operator_instance_name(namespace) + validators._validate_operator_instance_name(namespace) self.assertEqual(str(cm.exception), err) def test_long_config_name(self): config_name = "thisisaverylongnamethatistoolongtobeusedthisisaverylongnamethatistoolongtobeused" err = 'Error! Invalid --name' with self.assertRaises(InvalidArgumentValueError) as cm: - validators.validate_configuration_name(config_name) + validators._validate_configuration_name(config_name) self.assertEqual(str(cm.exception), err) def test_valid_config_name(self): config_name = "this-is-a-valid-config" - validators.validate_configuration_name(config_name) + validators._validate_configuration_name(config_name) def test_caps_config_name(self): config_name = "ThisIsaCapsConfigName" err = 'Error! Invalid --name' with self.assertRaises(InvalidArgumentValueError) as cm: - validators.validate_configuration_name(config_name) + validators._validate_configuration_name(config_name) self.assertEqual(str(cm.exception), err) def test_dot_config_name(self): config_name = "a234567890b234567890c234567890d234567890e234567890f234567890.23" err = 'Error! Invalid --name' with self.assertRaises(InvalidArgumentValueError) as cm: - validators.validate_configuration_name(config_name) + validators._validate_configuration_name(config_name) self.assertEqual(str(cm.exception), err) def test_end_hyphen_config_name(self): config_name = "a234567890b234567890c234567890d234567890e234567890f23456789023-" err = 'Error! Invalid --name' with self.assertRaises(InvalidArgumentValueError) as cm: - validators.validate_configuration_name(config_name) + validators._validate_configuration_name(config_name) self.assertEqual(str(cm.exception), err) class TestValidateURLWithParams(unittest.TestCase): def test_ssh_private_key_with_ssh_url(self): - validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', True, False, False) + validators._validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', True, False, False) def test_ssh_known_hosts_with_ssh_url(self): - validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', False, True, False) + validators._validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', False, True, False) def test_https_auth_with_https_url(self): - validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', False, False, True) + validators._validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', False, False, True) def test_ssh_private_key_with_https_url(self): - err = 'Error! An ssh private key cannot be used with an http(s) url' + err = 'Error! An --ssh-private-key cannot be used with an http(s) url' with self.assertRaises(MutuallyExclusiveArgumentError) as cm: - validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', True, False, False) + validators._validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', True, False, False) self.assertEqual(str(cm.exception), err) def test_ssh_known_hosts_with_https_url(self): - err = 'Error! ssh known_hosts cannot be used with an http(s) url' + err = 'Error! --ssh-known-hosts cannot be used with an http(s) url' with self.assertRaises(MutuallyExclusiveArgumentError) as cm: - validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', False, True, False) + validators._validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', False, True, False) self.assertEqual(str(cm.exception), err) def test_https_auth_with_ssh_url(self): err = 'Error! https auth (--https-user and --https-key) cannot be used with a non-http(s) url' with self.assertRaises(MutuallyExclusiveArgumentError) as cm: - validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', False, False, True) + validators._validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', False, False, True) self.assertEqual(str(cm.exception), err) @@ -145,24 +145,24 @@ class TestValidateKnownHosts(unittest.TestCase): def test_valid_known_hosts(self): known_hosts_raw = "ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H" known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') - validate_known_hosts(known_hosts_encoded) + validators._validate_known_hosts(known_hosts_encoded) def test_valid_known_hosts_with_comment(self): known_hosts_raw = "ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H ThisIsAValidComment" known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') - validate_known_hosts(known_hosts_encoded) + validators._validate_known_hosts(known_hosts_encoded) def test_valid_known_hosts_with_comment_own_line(self): known_hosts_raw = "#this is a comment on its own line\nssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H" known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') - validate_known_hosts(known_hosts_encoded) + validators._validate_known_hosts(known_hosts_encoded) def test_invalid_known_hosts(self): known_hosts_raw = "thisisabadknownhostsfilethatisaninvalidformat" known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') err = 'Error! ssh known_hosts provided in wrong format' with self.assertRaises(InvalidArgumentValueError) as cm: - validate_known_hosts(known_hosts_encoded) + validators._validate_known_hosts(known_hosts_encoded) self.assertEqual(str(cm.exception), err) diff --git a/src/k8s-configuration/setup.py b/src/k8s-configuration/setup.py index d6aa1b2377d..2701f5bee81 100644 --- a/src/k8s-configuration/setup.py +++ b/src/k8s-configuration/setup.py @@ -16,7 +16,7 @@ # TODO: Confirm this is the right version number you want and it matches your # HISTORY.rst entry. -VERSION = '1.0.0' +VERSION = '1.0.1' # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers diff --git a/testing/test/configurations/Configuration.Tests.ps1 b/testing/test/configurations/Configuration.Tests.ps1 index a85df42ed2e..23a8170fd44 100644 --- a/testing/test/configurations/Configuration.Tests.ps1 +++ b/testing/test/configurations/Configuration.Tests.ps1 @@ -55,6 +55,11 @@ Describe 'Basic Source Control Configuration Testing' { $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS } + It "Performs a re-PUT of the configuration on the cluster, with HTTPS in caps" { + az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "HTTPS://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --enable-helm-operator=false --operator-namespace $configurationName + $? | Should -BeTrue + } + It "Lists the configurations on the cluster" { $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters $? | Should -BeTrue From 1bc3aa46fe7e11ad519a28cf7f87b82ce07c4882 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Mon, 19 Jul 2021 13:33:44 -0700 Subject: [PATCH 70/80] Testing increase to ubuntu-latest --- k8s-custom-pipelines.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 940770361d9..5b78ede1b51 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -23,7 +23,7 @@ stages: - job: K8sConfigurationTestSuite displayName: "Run the Test Suite" pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-latest' steps: - checkout: self - bash: | @@ -136,7 +136,7 @@ stages: - job: BuildPublishExtension pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-latest' displayName: "Build and Publish the Extension Artifact" variables: CLI_REPO_PATH: $(Agent.BuildDirectory)/s @@ -177,7 +177,7 @@ stages: - job: CheckLicenseHeader displayName: "Check License" pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-latest' steps: - task: UsePythonVersion@0 displayName: 'Use Python 3.6' @@ -208,7 +208,7 @@ stages: - job: StaticAnalysis displayName: "Static Analysis" pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-latest' steps: - task: UsePythonVersion@0 displayName: 'Use Python 3.6' @@ -222,7 +222,7 @@ stages: - job: IndexVerify displayName: "Verify Extensions Index" pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-latest' steps: - task: UsePythonVersion@0 displayName: 'Use Python 3.7' @@ -239,7 +239,7 @@ stages: - job: SourceTests displayName: "Integration Tests, Build Tests" pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-latest' strategy: matrix: Python36: @@ -262,7 +262,7 @@ stages: - job: LintModifiedExtensions displayName: "CLI Linter on Modified Extensions" pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-latest' steps: - task: UsePythonVersion@0 displayName: 'Use Python 3.6' From fd973749c9451e0f9d5ef811a4ca79a5efaf0e72 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Tue, 20 Jul 2021 13:13:56 -0700 Subject: [PATCH 71/80] Update k8s-configuration Models to Track2 (#63) * Update models to track2 * Increase k8s-configuration version number * Update kind version * Change error to warning because of DSA failure --- k8s-custom-pipelines.yml | 2 +- src/k8s-configuration/HISTORY.rst | 4 + .../azext_k8s_configuration/custom.py | 6 +- .../tests/latest/test_validators.py | 4 +- .../vendored_sdks/__init__.py | 18 +- .../vendored_sdks/_configuration.py | 82 ++- .../_source_control_configuration_client.py | 95 +++- .../vendored_sdks/{version.py => _version.py} | 10 +- .../vendored_sdks/aio/__init__.py | 10 + .../vendored_sdks/aio/_configuration.py | 67 +++ .../_source_control_configuration_client.py | 87 +++ .../vendored_sdks/aio/operations/__init__.py | 15 + .../aio/operations/_operations.py | 105 ++++ ...ource_control_configurations_operations.py | 420 ++++++++++++++ .../vendored_sdks/models/__init__.py | 62 +- .../vendored_sdks/models/_models.py | 482 ++++++++-------- .../vendored_sdks/models/_models_py3.py | 519 ++++++++--------- .../vendored_sdks/models/_paged_models.py | 40 -- ...urce_control_configuration_client_enums.py | 95 ++-- .../vendored_sdks/operations/__init__.py | 7 +- .../vendored_sdks/operations/_operations.py | 127 +++-- ...ource_control_configurations_operations.py | 529 ++++++++++-------- src/k8s-configuration/setup.py | 4 +- .../Configuration.PrivateKey.Tests.ps1 | 9 +- 24 files changed, 1789 insertions(+), 1010 deletions(-) rename src/k8s-configuration/azext_k8s_configuration/vendored_sdks/{version.py => _version.py} (84%) create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_source_control_configuration_client.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_source_control_configurations_operations.py delete mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_paged_models.py diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 5b78ede1b51..75ad3a52f79 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -90,7 +90,7 @@ stages: - bash : | echo "Downloading the kind script" - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64 + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 chmod +x ./kind ./kind create cluster displayName: "Create and Start the Kind cluster" diff --git a/src/k8s-configuration/HISTORY.rst b/src/k8s-configuration/HISTORY.rst index 918019a6174..b8ef4668e03 100644 --- a/src/k8s-configuration/HISTORY.rst +++ b/src/k8s-configuration/HISTORY.rst @@ -3,6 +3,10 @@ Release History =============== +1.1.0 +++++++++++++++++++ +* Update sourceControlConfiguration resource models to Track2 + 1.0.1 ++++++++++++++++++ * Add provider registration check diff --git a/src/k8s-configuration/azext_k8s_configuration/custom.py b/src/k8s-configuration/azext_k8s_configuration/custom.py index 8882fd16cff..12a1bafe644 100644 --- a/src/k8s-configuration/azext_k8s_configuration/custom.py +++ b/src/k8s-configuration/azext_k8s_configuration/custom.py @@ -5,6 +5,7 @@ from azure.cli.core.azclierror import ResourceNotFoundError, CommandNotFoundError, \ RequiredArgumentMissingError +from azure.core.exceptions import HttpResponseError from knack.log import get_logger from azext_k8s_configuration._utils import _get_cluster_type, \ _fix_compliance_state, _get_data_from_key_or_file, _to_base64 @@ -13,7 +14,6 @@ from azext_k8s_configuration.vendored_sdks.models import SourceControlConfiguration from azext_k8s_configuration.vendored_sdks.models import HelmOperatorProperties -from azext_k8s_configuration.vendored_sdks.models import ErrorResponseException logger = get_logger(__name__) @@ -28,7 +28,7 @@ def show_k8s_configuration(client, resource_group_name, cluster_name, name, clus try: config = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) return _fix_compliance_state(config) - except ErrorResponseException as ex: + except HttpResponseError as ex: # Customize the error message for resources not found if ex.response.status_code == 404: # If Cluster not found @@ -200,7 +200,7 @@ def delete_k8s_configuration(client, resource_group_name, cluster_name, name, cl source_control_configuration_name = name - return client.delete(resource_group_name, cluster_rp, cluster_type, cluster_name, source_control_configuration_name) + return client.begin_delete(resource_group_name, cluster_rp, cluster_type, cluster_name, source_control_configuration_name) def _get_protected_settings(ssh_private_key, ssh_private_key_file, https_user, https_key): diff --git a/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py index 29a796e05c5..a83a5ae2071 100644 --- a/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py +++ b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py @@ -8,9 +8,7 @@ from azure.cli.core.azclierror import InvalidArgumentValueError, MutuallyExclusiveArgumentError from azext_k8s_configuration.custom import _get_protected_settings import azext_k8s_configuration._validators as validators -from Crypto.PublicKey import RSA, ECC, DSA -from paramiko.ed25519key import Ed25519Key - +from Crypto.PublicKey import DSA class TestValidateKeyTypes(unittest.TestCase): def test_bad_private_key(self): diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/__init__.py index 874177b4d34..f13062376d7 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/__init__.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/__init__.py @@ -1,19 +1,19 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from ._configuration import SourceControlConfigurationClientConfiguration from ._source_control_configuration_client import SourceControlConfigurationClient -__all__ = ['SourceControlConfigurationClient', 'SourceControlConfigurationClientConfiguration'] - -from .version import VERSION +from ._version import VERSION __version__ = VERSION +__all__ = ['SourceControlConfigurationClient'] +try: + from ._patch import patch_sdk # type: ignore + patch_sdk() +except ImportError: + pass diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_configuration.py index 5043ed69594..645328abb1f 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_configuration.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_configuration.py @@ -1,49 +1,71 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from msrestazure import AzureConfiguration -from .version import VERSION +from typing import TYPE_CHECKING +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from ._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + + from azure.core.credentials import TokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. -class SourceControlConfigurationClientConfiguration(AzureConfiguration): - """Configuration for SourceControlConfigurationClient Note that all parameters used to create this instance are saved as instance attributes. - :param credentials: Credentials needed for the client to connect to Azure. - :type credentials: :mod:`A msrestazure Credentials - object` - :param subscription_id: The Azure subscription ID. This is a - GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000) + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). :type subscription_id: str - :param str base_url: Service URL """ def __init__( - self, credentials, subscription_id, base_url=None): - - if credentials is None: - raise ValueError("Parameter 'credentials' must not be None.") + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") if subscription_id is None: raise ValueError("Parameter 'subscription_id' must not be None.") - if not base_url: - base_url = 'https://management.azure.com' - - super(SourceControlConfigurationClientConfiguration, self).__init__(base_url) - - # Starting Autorest.Python 4.0.64, make connection pool activated by default - self.keep_alive = True + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) - self.add_user_agent('azure-mgmt-kubernetesconfiguration/{}'.format(VERSION)) - self.add_user_agent('Azure-SDK-For-Python') - - self.credentials = credentials + self.credential = credential self.subscription_id = subscription_id + self.api_version = "2021-03-01" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs # type: Any + ): + # type: (...) -> None + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.BearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_source_control_configuration_client.py index b27243fc208..50b673797b5 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_source_control_configuration_client.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_source_control_configuration_client.py @@ -1,16 +1,22 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from msrest.service_client import SDKClient -from msrest import Serializer, Deserializer +from typing import TYPE_CHECKING + +from azure.mgmt.core import ARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Optional + + from azure.core.credentials import TokenCredential + from azure.core.pipeline.transport import HttpRequest, HttpResponse from ._configuration import SourceControlConfigurationClientConfiguration from .operations import SourceControlConfigurationsOperations @@ -18,38 +24,71 @@ from . import models -class SourceControlConfigurationClient(SDKClient): - """Use these APIs to create Source Control Configuration resources through ARM, for Kubernetes Clusters. +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. - :ivar config: Configuration for client. - :vartype config: SourceControlConfigurationClientConfiguration - - :ivar source_control_configurations: SourceControlConfigurations operations - :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.operations.SourceControlConfigurationsOperations + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2021_03_01.operations.SourceControlConfigurationsOperations :ivar operations: Operations operations - :vartype operations: azure.mgmt.kubernetesconfiguration.operations.Operations - - :param credentials: Credentials needed for the client to connect to Azure. - :type credentials: :mod:`A msrestazure Credentials - object` - :param subscription_id: The Azure subscription ID. This is a - GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000) + :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_03_01.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). :type subscription_id: str :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. """ def __init__( - self, credentials, subscription_id, base_url=None): - - self.config = SourceControlConfigurationClientConfiguration(credentials, subscription_id, base_url) - super(SourceControlConfigurationClient, self).__init__(self.config.credentials, self.config) + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + base_url=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> None + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = ARMPipelineClient(base_url=base_url, config=self._config, **kwargs) client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} - self.api_version = '2021-03-01' self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False self._deserialize = Deserializer(client_models) self.source_control_configurations = SourceControlConfigurationsOperations( - self._client, self.config, self._serialize, self._deserialize) + self._client, self._config, self._serialize, self._deserialize) self.operations = Operations( - self._client, self.config, self._serialize, self._deserialize) + self._client, self._config, self._serialize, self._deserialize) + + def _send_request(self, http_request, **kwargs): + # type: (HttpRequest, Any) -> HttpResponse + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.HttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + def close(self): + # type: () -> None + self._client.close() + + def __enter__(self): + # type: () -> SourceControlConfigurationClient + self._client.__enter__() + return self + + def __exit__(self, *exc_details): + # type: (Any) -> None + self._client.__exit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/version.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_version.py similarity index 84% rename from src/k8s-configuration/azext_k8s_configuration/vendored_sdks/version.py rename to src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_version.py index 9bd1dfac7ec..e5754a47ce6 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/version.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_version.py @@ -1,13 +1,9 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -VERSION = "0.2.0" - +VERSION = "1.0.0b1" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/__init__.py new file mode 100644 index 00000000000..ba52c91a7ba --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +__all__ = ['SourceControlConfigurationClient'] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_configuration.py new file mode 100644 index 00000000000..682d2762893 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_configuration.py @@ -0,0 +1,67 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from .._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + **kwargs: Any + ) -> None: + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2021-03-01" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs: Any + ) -> None: + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.AsyncBearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_source_control_configuration_client.py new file mode 100644 index 00000000000..2db9ca6cfeb --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_source_control_configuration_client.py @@ -0,0 +1,87 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Optional, TYPE_CHECKING + +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core import AsyncARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from .. import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2021_03_01.aio.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_03_01.aio.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + base_url: Optional[str] = None, + **kwargs: Any + ) -> None: + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = AsyncARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + + async def _send_request(self, http_request: HttpRequest, **kwargs: Any) -> AsyncHttpResponse: + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.AsyncHttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = await self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "SourceControlConfigurationClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details) -> None: + await self._client.__aexit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/__init__.py new file mode 100644 index 00000000000..07db19b318c --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/__init__.py @@ -0,0 +1,15 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._operations import Operations + +__all__ = [ + 'SourceControlConfigurationsOperations', + 'Operations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_operations.py new file mode 100644 index 00000000000..09d8376d112 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_operations.py @@ -0,0 +1,105 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class Operations: + """Operations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs: Any + ) -> AsyncIterable["_models.ResourceProviderOperationList"]: + """List all the available operations the KubernetesConfiguration resource provider supports. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..db8449803bd --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_source_control_configurations_operations.py @@ -0,0 +1,420 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class SourceControlConfigurationsOperations: + """SourceControlConfigurationsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def create_or_update( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + source_control_configuration: "_models.SourceControlConfiguration", + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create_or_update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def _delete_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> None: + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def begin_delete( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> AsyncLROPoller[None]: + """This will delete the YAML file used to set up the Source control configuration, thus stopping + future sync from the source repo. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.SourceControlConfigurationList"]: + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfigurationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('SourceControlConfigurationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/__init__.py index 86f85f9bcb5..95574a9920b 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/__init__.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/__init__.py @@ -1,73 +1,71 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- try: - from ._models_py3 import AzureEntityResource from ._models_py3 import ComplianceStatus from ._models_py3 import ErrorDefinition - from ._models_py3 import ErrorResponse, ErrorResponseException + from ._models_py3 import ErrorResponse from ._models_py3 import HelmOperatorProperties from ._models_py3 import ProxyResource from ._models_py3 import Resource from ._models_py3 import ResourceProviderOperation from ._models_py3 import ResourceProviderOperationDisplay + from ._models_py3 import ResourceProviderOperationList from ._models_py3 import Result from ._models_py3 import SourceControlConfiguration + from ._models_py3 import SourceControlConfigurationList from ._models_py3 import SystemData - from ._models_py3 import TrackedResource except (SyntaxError, ImportError): - from ._models import AzureEntityResource - from ._models import ComplianceStatus - from ._models import ErrorDefinition - from ._models import ErrorResponse, ErrorResponseException - from ._models import HelmOperatorProperties - from ._models import ProxyResource - from ._models import Resource - from ._models import ResourceProviderOperation - from ._models import ResourceProviderOperationDisplay - from ._models import Result - from ._models import SourceControlConfiguration - from ._models import SystemData - from ._models import TrackedResource -from ._paged_models import ResourceProviderOperationPaged -from ._paged_models import SourceControlConfigurationPaged + from ._models import ComplianceStatus # type: ignore + from ._models import ErrorDefinition # type: ignore + from ._models import ErrorResponse # type: ignore + from ._models import HelmOperatorProperties # type: ignore + from ._models import ProxyResource # type: ignore + from ._models import Resource # type: ignore + from ._models import ResourceProviderOperation # type: ignore + from ._models import ResourceProviderOperationDisplay # type: ignore + from ._models import ResourceProviderOperationList # type: ignore + from ._models import Result # type: ignore + from ._models import SourceControlConfiguration # type: ignore + from ._models import SourceControlConfigurationList # type: ignore + from ._models import SystemData # type: ignore + from ._source_control_configuration_client_enums import ( ComplianceStateType, + CreatedByType, + Enum0, + Enum1, MessageLevelType, - OperatorType, OperatorScopeType, + OperatorType, ProvisioningStateType, - CreatedByType, ) __all__ = [ - 'AzureEntityResource', 'ComplianceStatus', 'ErrorDefinition', - 'ErrorResponse', 'ErrorResponseException', + 'ErrorResponse', 'HelmOperatorProperties', 'ProxyResource', 'Resource', 'ResourceProviderOperation', 'ResourceProviderOperationDisplay', + 'ResourceProviderOperationList', 'Result', 'SourceControlConfiguration', + 'SourceControlConfigurationList', 'SystemData', - 'TrackedResource', - 'SourceControlConfigurationPaged', - 'ResourceProviderOperationPaged', 'ComplianceStateType', + 'CreatedByType', + 'Enum0', + 'Enum1', 'MessageLevelType', - 'OperatorType', 'OperatorScopeType', + 'OperatorType', 'ProvisioningStateType', - 'CreatedByType', ] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models.py index 676504953e7..00bd900ea10 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models.py @@ -1,123 +1,32 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from msrest.serialization import Model -from msrest.exceptions import HttpOperationError +from azure.core.exceptions import HttpResponseError +import msrest.serialization -class Resource(Model): - """Resource. - - Common fields that are returned in the response for all Azure Resource - Manager resources. - - Variables are only populated by the server, and will be ignored when - sending a request. - - :ivar id: Fully qualified resource ID for the resource. Ex - - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} - :vartype id: str - :ivar name: The name of the resource - :vartype name: str - :ivar type: The type of the resource. E.g. - "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" - :vartype type: str - """ - - _validation = { - 'id': {'readonly': True}, - 'name': {'readonly': True}, - 'type': {'readonly': True}, - } - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - } - - def __init__(self, **kwargs): - super(Resource, self).__init__(**kwargs) - self.id = None - self.name = None - self.type = None - - -class AzureEntityResource(Resource): - """Entity Resource. - - The resource model definition for an Azure Resource Manager resource with - an etag. - - Variables are only populated by the server, and will be ignored when - sending a request. - - :ivar id: Fully qualified resource ID for the resource. Ex - - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} - :vartype id: str - :ivar name: The name of the resource - :vartype name: str - :ivar type: The type of the resource. E.g. - "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" - :vartype type: str - :ivar etag: Resource Etag. - :vartype etag: str - """ - - _validation = { - 'id': {'readonly': True}, - 'name': {'readonly': True}, - 'type': {'readonly': True}, - 'etag': {'readonly': True}, - } - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - 'etag': {'key': 'etag', 'type': 'str'}, - } - - def __init__(self, **kwargs): - super(AzureEntityResource, self).__init__(**kwargs) - self.etag = None - - -class CloudError(Model): - """CloudError. - """ - - _attribute_map = { - } - - -class ComplianceStatus(Model): +class ComplianceStatus(msrest.serialization.Model): """Compliance Status details. - Variables are only populated by the server, and will be ignored when - sending a request. + Variables are only populated by the server, and will be ignored when sending a request. - :ivar compliance_state: The compliance state of the configuration. - Possible values include: 'Pending', 'Compliant', 'Noncompliant', - 'Installed', 'Failed' + :ivar compliance_state: The compliance state of the configuration. Possible values include: + "Pending", "Compliant", "Noncompliant", "Installed", "Failed". :vartype compliance_state: str or - ~azure.mgmt.kubernetesconfiguration.models.ComplianceStateType + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ComplianceStateType :param last_config_applied: Datetime the configuration was last applied. - :type last_config_applied: datetime + :type last_config_applied: ~datetime.datetime :param message: Message from when the configuration was applied. :type message: str - :param message_level: Level of the message. Possible values include: - 'Error', 'Warning', 'Information' + :param message_level: Level of the message. Possible values include: "Error", "Warning", + "Information". :type message_level: str or - ~azure.mgmt.kubernetesconfiguration.models.MessageLevelType + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.MessageLevelType """ _validation = { @@ -131,7 +40,10 @@ class ComplianceStatus(Model): 'message_level': {'key': 'messageLevel', 'type': 'str'}, } - def __init__(self, **kwargs): + def __init__( + self, + **kwargs + ): super(ComplianceStatus, self).__init__(**kwargs) self.compliance_state = None self.last_config_applied = kwargs.get('last_config_applied', None) @@ -139,13 +51,13 @@ def __init__(self, **kwargs): self.message_level = kwargs.get('message_level', None) -class ErrorDefinition(Model): +class ErrorDefinition(msrest.serialization.Model): """Error definition. All required parameters must be populated in order to send to Azure. - :param code: Required. Service specific error code which serves as the - substatus for the HTTP error code. + :param code: Required. Service specific error code which serves as the substatus for the HTTP + error code. :type code: str :param message: Required. Description of the error. :type message: str @@ -161,41 +73,41 @@ class ErrorDefinition(Model): 'message': {'key': 'message', 'type': 'str'}, } - def __init__(self, **kwargs): + def __init__( + self, + **kwargs + ): super(ErrorDefinition, self).__init__(**kwargs) - self.code = kwargs.get('code', None) - self.message = kwargs.get('message', None) + self.code = kwargs['code'] + self.message = kwargs['message'] -class ErrorResponse(Model): +class ErrorResponse(msrest.serialization.Model): """Error response. - :param error: Error definition. - :type error: ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar error: Error definition. + :vartype error: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ErrorDefinition """ + _validation = { + 'error': {'readonly': True}, + } + _attribute_map = { 'error': {'key': 'error', 'type': 'ErrorDefinition'}, } - def __init__(self, **kwargs): + def __init__( + self, + **kwargs + ): super(ErrorResponse, self).__init__(**kwargs) - self.error = kwargs.get('error', None) - - -class ErrorResponseException(HttpOperationError): - """Server responsed with exception of type: 'ErrorResponse'. - - :param deserialize: A deserializer - :param response: Server response to be deserialized. - """ + self.error = None - def __init__(self, deserialize, response, *args): - super(ErrorResponseException, self).__init__(deserialize, response, 'ErrorResponse', *args) - - -class HelmOperatorProperties(Model): +class HelmOperatorProperties(msrest.serialization.Model): """Properties for Helm operator. :param chart_version: Version of the operator Helm chart. @@ -209,28 +121,64 @@ class HelmOperatorProperties(Model): 'chart_values': {'key': 'chartValues', 'type': 'str'}, } - def __init__(self, **kwargs): + def __init__( + self, + **kwargs + ): super(HelmOperatorProperties, self).__init__(**kwargs) self.chart_version = kwargs.get('chart_version', None) self.chart_values = kwargs.get('chart_values', None) -class ProxyResource(Resource): - """Proxy Resource. +class Resource(msrest.serialization.Model): + """Common fields that are returned in the response for all Azure Resource Manager resources. - The resource model definition for a Azure Resource Manager proxy resource. - It will not have tags and a location. + Variables are only populated by the server, and will be ignored when sending a request. - Variables are only populated by the server, and will be ignored when - sending a request. + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class ProxyResource(Resource): + """The resource model definition for a Azure Resource Manager proxy resource. It will not have tags and a location. + + Variables are only populated by the server, and will be ignored when sending a request. :ivar id: Fully qualified resource ID for the resource. Ex - - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. :vartype id: str - :ivar name: The name of the resource + :ivar name: The name of the resource. :vartype name: str - :ivar type: The type of the resource. E.g. - "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". :vartype type: str """ @@ -246,24 +194,24 @@ class ProxyResource(Resource): 'type': {'key': 'type', 'type': 'str'}, } - def __init__(self, **kwargs): + def __init__( + self, + **kwargs + ): super(ProxyResource, self).__init__(**kwargs) -class ResourceProviderOperation(Model): +class ResourceProviderOperation(msrest.serialization.Model): """Supported operation of this resource provider. - Variables are only populated by the server, and will be ignored when - sending a request. + Variables are only populated by the server, and will be ignored when sending a request. - :param name: Operation name, in format of - {provider}/{resource}/{operation} + :param name: Operation name, in format of {provider}/{resource}/{operation}. :type name: str :param display: Display metadata associated with the operation. :type display: - ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationDisplay - :ivar is_data_action: The flag that indicates whether the operation - applies to data plane. + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. :vartype is_data_action: bool """ @@ -277,14 +225,17 @@ class ResourceProviderOperation(Model): 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, } - def __init__(self, **kwargs): + def __init__( + self, + **kwargs + ): super(ResourceProviderOperation, self).__init__(**kwargs) self.name = kwargs.get('name', None) self.display = kwargs.get('display', None) self.is_data_action = None -class ResourceProviderOperationDisplay(Model): +class ResourceProviderOperationDisplay(msrest.serialization.Model): """Display metadata associated with the operation. :param provider: Resource provider: Microsoft KubernetesConfiguration. @@ -304,7 +255,10 @@ class ResourceProviderOperationDisplay(Model): 'description': {'key': 'description', 'type': 'str'}, } - def __init__(self, **kwargs): + def __init__( + self, + **kwargs + ): super(ResourceProviderOperationDisplay, self).__init__(**kwargs) self.provider = kwargs.get('provider', None) self.resource = kwargs.get('resource', None) @@ -312,10 +266,40 @@ def __init__(self, **kwargs): self.description = kwargs.get('description', None) -class Result(Model): +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = kwargs.get('value', None) + self.next_link = None + + +class Result(msrest.serialization.Model): """Sample result definition. - :param sample_property: Sample property of type string + :param sample_property: Sample property of type string. :type sample_property: str """ @@ -323,7 +307,10 @@ class Result(Model): 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, } - def __init__(self, **kwargs): + def __init__( + self, + **kwargs + ): super(Result, self).__init__(**kwargs) self.sample_property = kwargs.get('sample_property', None) @@ -331,71 +318,63 @@ def __init__(self, **kwargs): class SourceControlConfiguration(ProxyResource): """The SourceControl Configuration object returned in Get & Put response. - Variables are only populated by the server, and will be ignored when - sending a request. + Variables are only populated by the server, and will be ignored when sending a request. :ivar id: Fully qualified resource ID for the resource. Ex - - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. :vartype id: str - :ivar name: The name of the resource + :ivar name: The name of the resource. :vartype name: str - :ivar type: The type of the resource. E.g. - "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". :vartype type: str + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SystemData :param repository_url: Url of the SourceControl Repository. :type repository_url: str - :param operator_namespace: The namespace to which this operator is - installed to. Maximum of 253 lower case alphanumeric characters, hyphen - and period only. Default value: "default" . + :param operator_namespace: The namespace to which this operator is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. :type operator_namespace: str - :param operator_instance_name: Instance name of the operator - identifying - the specific configuration. + :param operator_instance_name: Instance name of the operator - identifying the specific + configuration. :type operator_instance_name: str - :param operator_type: Type of the operator. Possible values include: - 'Flux' - :type operator_type: str or - ~azure.mgmt.kubernetesconfiguration.models.OperatorType - :param operator_params: Any Parameters for the Operator instance in string - format. + :param operator_type: Type of the operator. Possible values include: "Flux". + :type operator_type: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string format. :type operator_params: str - :param configuration_protected_settings: Name-value pairs of protected - configuration settings for the configuration + :param configuration_protected_settings: Name-value pairs of protected configuration settings + for the configuration. :type configuration_protected_settings: dict[str, str] - :param operator_scope: Scope at which the operator will be installed. - Possible values include: 'cluster', 'namespace'. Default value: "cluster" - . + :param operator_scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". :type operator_scope: str or - ~azure.mgmt.kubernetesconfiguration.models.OperatorScopeType - :ivar repository_public_key: Public Key associated with this SourceControl - configuration (either generated within the cluster or provided by the - user). + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl configuration + (either generated within the cluster or provided by the user). :vartype repository_public_key: str - :param ssh_known_hosts_contents: Base64-encoded known_hosts contents - containing public SSH keys required to access private Git instances + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents containing public SSH keys + required to access private Git instances. :type ssh_known_hosts_contents: str - :param enable_helm_operator: Option to enable Helm Operator for this git - configuration. + :param enable_helm_operator: Option to enable Helm Operator for this git configuration. :type enable_helm_operator: bool :param helm_operator_properties: Properties for Helm operator. :type helm_operator_properties: - ~azure.mgmt.kubernetesconfiguration.models.HelmOperatorProperties - :ivar provisioning_state: The provisioning state of the resource provider. - Possible values include: 'Accepted', 'Deleting', 'Running', 'Succeeded', - 'Failed' + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. Possible values + include: "Accepted", "Deleting", "Running", "Succeeded", "Failed". :vartype provisioning_state: str or - ~azure.mgmt.kubernetesconfiguration.models.ProvisioningStateType - :ivar compliance_status: Compliance Status of the Configuration + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration. :vartype compliance_status: - ~azure.mgmt.kubernetesconfiguration.models.ComplianceStatus - :param system_data: Top level metadata - https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources - :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ComplianceStatus """ _validation = { 'id': {'readonly': True}, 'name': {'readonly': True}, 'type': {'readonly': True}, + 'system_data': {'readonly': True}, 'repository_public_key': {'readonly': True}, 'provisioning_state': {'readonly': True}, 'compliance_status': {'readonly': True}, @@ -405,6 +384,7 @@ class SourceControlConfiguration(ProxyResource): 'id': {'key': 'id', 'type': 'str'}, 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, @@ -418,11 +398,14 @@ class SourceControlConfiguration(ProxyResource): 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, - 'system_data': {'key': 'systemData', 'type': 'SystemData'}, } - def __init__(self, **kwargs): + def __init__( + self, + **kwargs + ): super(SourceControlConfiguration, self).__init__(**kwargs) + self.system_data = None self.repository_url = kwargs.get('repository_url', None) self.operator_namespace = kwargs.get('operator_namespace', "default") self.operator_instance_name = kwargs.get('operator_instance_name', None) @@ -436,30 +419,58 @@ def __init__(self, **kwargs): self.helm_operator_properties = kwargs.get('helm_operator_properties', None) self.provisioning_state = None self.compliance_status = None - self.system_data = kwargs.get('system_data', None) -class SystemData(Model): +class SourceControlConfigurationList(msrest.serialization.Model): + """Result of the request to list Source Control Configurations. It contains a list of SourceControlConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Source Control Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SourceControlConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfigurationList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class SystemData(msrest.serialization.Model): """Metadata pertaining to creation and last modification of the resource. :param created_by: The identity that created the resource. :type created_by: str - :param created_by_type: The type of identity that created the resource. - Possible values include: 'User', 'Application', 'ManagedIdentity', 'Key' + :param created_by_type: The type of identity that created the resource. Possible values + include: "User", "Application", "ManagedIdentity", "Key". :type created_by_type: str or - ~azure.mgmt.kubernetesconfiguration.models.CreatedByType + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.CreatedByType :param created_at: The timestamp of resource creation (UTC). - :type created_at: datetime + :type created_at: ~datetime.datetime :param last_modified_by: The identity that last modified the resource. :type last_modified_by: str - :param last_modified_by_type: The type of identity that last modified the - resource. Possible values include: 'User', 'Application', - 'ManagedIdentity', 'Key' + :param last_modified_by_type: The type of identity that last modified the resource. Possible + values include: "User", "Application", "ManagedIdentity", "Key". :type last_modified_by_type: str or - ~azure.mgmt.kubernetesconfiguration.models.CreatedByType - :param last_modified_at: The type of identity that last modified the - resource. - :type last_modified_at: datetime + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.CreatedByType + :param last_modified_at: The timestamp of resource last modification (UTC). + :type last_modified_at: ~datetime.datetime """ _attribute_map = { @@ -471,7 +482,10 @@ class SystemData(Model): 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, } - def __init__(self, **kwargs): + def __init__( + self, + **kwargs + ): super(SystemData, self).__init__(**kwargs) self.created_by = kwargs.get('created_by', None) self.created_by_type = kwargs.get('created_by_type', None) @@ -479,49 +493,3 @@ def __init__(self, **kwargs): self.last_modified_by = kwargs.get('last_modified_by', None) self.last_modified_by_type = kwargs.get('last_modified_by_type', None) self.last_modified_at = kwargs.get('last_modified_at', None) - - -class TrackedResource(Resource): - """Tracked Resource. - - The resource model definition for an Azure Resource Manager tracked top - level resource which has 'tags' and a 'location'. - - Variables are only populated by the server, and will be ignored when - sending a request. - - All required parameters must be populated in order to send to Azure. - - :ivar id: Fully qualified resource ID for the resource. Ex - - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} - :vartype id: str - :ivar name: The name of the resource - :vartype name: str - :ivar type: The type of the resource. E.g. - "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" - :vartype type: str - :param tags: Resource tags. - :type tags: dict[str, str] - :param location: Required. The geo-location where the resource lives - :type location: str - """ - - _validation = { - 'id': {'readonly': True}, - 'name': {'readonly': True}, - 'type': {'readonly': True}, - 'location': {'required': True}, - } - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - 'tags': {'key': 'tags', 'type': '{str}'}, - 'location': {'key': 'location', 'type': 'str'}, - } - - def __init__(self, **kwargs): - super(TrackedResource, self).__init__(**kwargs) - self.tags = kwargs.get('tags', None) - self.location = kwargs.get('location', None) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models_py3.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models_py3.py index b77227e4d97..259854d16de 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models_py3.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models_py3.py @@ -1,123 +1,37 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from msrest.serialization import Model -from msrest.exceptions import HttpOperationError +import datetime +from typing import Dict, List, Optional, Union +from azure.core.exceptions import HttpResponseError +import msrest.serialization -class Resource(Model): - """Resource. +from ._source_control_configuration_client_enums import * - Common fields that are returned in the response for all Azure Resource - Manager resources. - Variables are only populated by the server, and will be ignored when - sending a request. - - :ivar id: Fully qualified resource ID for the resource. Ex - - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} - :vartype id: str - :ivar name: The name of the resource - :vartype name: str - :ivar type: The type of the resource. E.g. - "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" - :vartype type: str - """ - - _validation = { - 'id': {'readonly': True}, - 'name': {'readonly': True}, - 'type': {'readonly': True}, - } - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - } - - def __init__(self, **kwargs) -> None: - super(Resource, self).__init__(**kwargs) - self.id = None - self.name = None - self.type = None - - -class AzureEntityResource(Resource): - """Entity Resource. - - The resource model definition for an Azure Resource Manager resource with - an etag. - - Variables are only populated by the server, and will be ignored when - sending a request. - - :ivar id: Fully qualified resource ID for the resource. Ex - - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} - :vartype id: str - :ivar name: The name of the resource - :vartype name: str - :ivar type: The type of the resource. E.g. - "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" - :vartype type: str - :ivar etag: Resource Etag. - :vartype etag: str - """ - - _validation = { - 'id': {'readonly': True}, - 'name': {'readonly': True}, - 'type': {'readonly': True}, - 'etag': {'readonly': True}, - } - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - 'etag': {'key': 'etag', 'type': 'str'}, - } - - def __init__(self, **kwargs) -> None: - super(AzureEntityResource, self).__init__(**kwargs) - self.etag = None - - -class CloudError(Model): - """CloudError. - """ - - _attribute_map = { - } - - -class ComplianceStatus(Model): +class ComplianceStatus(msrest.serialization.Model): """Compliance Status details. - Variables are only populated by the server, and will be ignored when - sending a request. + Variables are only populated by the server, and will be ignored when sending a request. - :ivar compliance_state: The compliance state of the configuration. - Possible values include: 'Pending', 'Compliant', 'Noncompliant', - 'Installed', 'Failed' + :ivar compliance_state: The compliance state of the configuration. Possible values include: + "Pending", "Compliant", "Noncompliant", "Installed", "Failed". :vartype compliance_state: str or - ~azure.mgmt.kubernetesconfiguration.models.ComplianceStateType + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ComplianceStateType :param last_config_applied: Datetime the configuration was last applied. - :type last_config_applied: datetime + :type last_config_applied: ~datetime.datetime :param message: Message from when the configuration was applied. :type message: str - :param message_level: Level of the message. Possible values include: - 'Error', 'Warning', 'Information' + :param message_level: Level of the message. Possible values include: "Error", "Warning", + "Information". :type message_level: str or - ~azure.mgmt.kubernetesconfiguration.models.MessageLevelType + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.MessageLevelType """ _validation = { @@ -131,7 +45,14 @@ class ComplianceStatus(Model): 'message_level': {'key': 'messageLevel', 'type': 'str'}, } - def __init__(self, *, last_config_applied=None, message: str=None, message_level=None, **kwargs) -> None: + def __init__( + self, + *, + last_config_applied: Optional[datetime.datetime] = None, + message: Optional[str] = None, + message_level: Optional[Union[str, "MessageLevelType"]] = None, + **kwargs + ): super(ComplianceStatus, self).__init__(**kwargs) self.compliance_state = None self.last_config_applied = last_config_applied @@ -139,13 +60,13 @@ def __init__(self, *, last_config_applied=None, message: str=None, message_level self.message_level = message_level -class ErrorDefinition(Model): +class ErrorDefinition(msrest.serialization.Model): """Error definition. All required parameters must be populated in order to send to Azure. - :param code: Required. Service specific error code which serves as the - substatus for the HTTP error code. + :param code: Required. Service specific error code which serves as the substatus for the HTTP + error code. :type code: str :param message: Required. Description of the error. :type message: str @@ -161,41 +82,44 @@ class ErrorDefinition(Model): 'message': {'key': 'message', 'type': 'str'}, } - def __init__(self, *, code: str, message: str, **kwargs) -> None: + def __init__( + self, + *, + code: str, + message: str, + **kwargs + ): super(ErrorDefinition, self).__init__(**kwargs) self.code = code self.message = message -class ErrorResponse(Model): +class ErrorResponse(msrest.serialization.Model): """Error response. - :param error: Error definition. - :type error: ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar error: Error definition. + :vartype error: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ErrorDefinition """ + _validation = { + 'error': {'readonly': True}, + } + _attribute_map = { 'error': {'key': 'error', 'type': 'ErrorDefinition'}, } - def __init__(self, *, error=None, **kwargs) -> None: + def __init__( + self, + **kwargs + ): super(ErrorResponse, self).__init__(**kwargs) - self.error = error - - -class ErrorResponseException(HttpOperationError): - """Server responsed with exception of type: 'ErrorResponse'. - - :param deserialize: A deserializer - :param response: Server response to be deserialized. - """ - - def __init__(self, deserialize, response, *args): + self.error = None - super(ErrorResponseException, self).__init__(deserialize, response, 'ErrorResponse', *args) - -class HelmOperatorProperties(Model): +class HelmOperatorProperties(msrest.serialization.Model): """Properties for Helm operator. :param chart_version: Version of the operator Helm chart. @@ -209,28 +133,67 @@ class HelmOperatorProperties(Model): 'chart_values': {'key': 'chartValues', 'type': 'str'}, } - def __init__(self, *, chart_version: str=None, chart_values: str=None, **kwargs) -> None: + def __init__( + self, + *, + chart_version: Optional[str] = None, + chart_values: Optional[str] = None, + **kwargs + ): super(HelmOperatorProperties, self).__init__(**kwargs) self.chart_version = chart_version self.chart_values = chart_values -class ProxyResource(Resource): - """Proxy Resource. +class Resource(msrest.serialization.Model): + """Common fields that are returned in the response for all Azure Resource Manager resources. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ - The resource model definition for a Azure Resource Manager proxy resource. - It will not have tags and a location. + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class ProxyResource(Resource): + """The resource model definition for a Azure Resource Manager proxy resource. It will not have tags and a location. - Variables are only populated by the server, and will be ignored when - sending a request. + Variables are only populated by the server, and will be ignored when sending a request. :ivar id: Fully qualified resource ID for the resource. Ex - - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. :vartype id: str - :ivar name: The name of the resource + :ivar name: The name of the resource. :vartype name: str - :ivar type: The type of the resource. E.g. - "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". :vartype type: str """ @@ -246,24 +209,24 @@ class ProxyResource(Resource): 'type': {'key': 'type', 'type': 'str'}, } - def __init__(self, **kwargs) -> None: + def __init__( + self, + **kwargs + ): super(ProxyResource, self).__init__(**kwargs) -class ResourceProviderOperation(Model): +class ResourceProviderOperation(msrest.serialization.Model): """Supported operation of this resource provider. - Variables are only populated by the server, and will be ignored when - sending a request. + Variables are only populated by the server, and will be ignored when sending a request. - :param name: Operation name, in format of - {provider}/{resource}/{operation} + :param name: Operation name, in format of {provider}/{resource}/{operation}. :type name: str :param display: Display metadata associated with the operation. :type display: - ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationDisplay - :ivar is_data_action: The flag that indicates whether the operation - applies to data plane. + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. :vartype is_data_action: bool """ @@ -277,14 +240,20 @@ class ResourceProviderOperation(Model): 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, } - def __init__(self, *, name: str=None, display=None, **kwargs) -> None: + def __init__( + self, + *, + name: Optional[str] = None, + display: Optional["ResourceProviderOperationDisplay"] = None, + **kwargs + ): super(ResourceProviderOperation, self).__init__(**kwargs) self.name = name self.display = display self.is_data_action = None -class ResourceProviderOperationDisplay(Model): +class ResourceProviderOperationDisplay(msrest.serialization.Model): """Display metadata associated with the operation. :param provider: Resource provider: Microsoft KubernetesConfiguration. @@ -304,7 +273,15 @@ class ResourceProviderOperationDisplay(Model): 'description': {'key': 'description', 'type': 'str'}, } - def __init__(self, *, provider: str=None, resource: str=None, operation: str=None, description: str=None, **kwargs) -> None: + def __init__( + self, + *, + provider: Optional[str] = None, + resource: Optional[str] = None, + operation: Optional[str] = None, + description: Optional[str] = None, + **kwargs + ): super(ResourceProviderOperationDisplay, self).__init__(**kwargs) self.provider = provider self.resource = resource @@ -312,10 +289,42 @@ def __init__(self, *, provider: str=None, resource: str=None, operation: str=Non self.description = description -class Result(Model): +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + *, + value: Optional[List["ResourceProviderOperation"]] = None, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = value + self.next_link = None + + +class Result(msrest.serialization.Model): """Sample result definition. - :param sample_property: Sample property of type string + :param sample_property: Sample property of type string. :type sample_property: str """ @@ -323,7 +332,12 @@ class Result(Model): 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, } - def __init__(self, *, sample_property: str=None, **kwargs) -> None: + def __init__( + self, + *, + sample_property: Optional[str] = None, + **kwargs + ): super(Result, self).__init__(**kwargs) self.sample_property = sample_property @@ -331,71 +345,63 @@ def __init__(self, *, sample_property: str=None, **kwargs) -> None: class SourceControlConfiguration(ProxyResource): """The SourceControl Configuration object returned in Get & Put response. - Variables are only populated by the server, and will be ignored when - sending a request. + Variables are only populated by the server, and will be ignored when sending a request. :ivar id: Fully qualified resource ID for the resource. Ex - - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. :vartype id: str - :ivar name: The name of the resource + :ivar name: The name of the resource. :vartype name: str - :ivar type: The type of the resource. E.g. - "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". :vartype type: str + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SystemData :param repository_url: Url of the SourceControl Repository. :type repository_url: str - :param operator_namespace: The namespace to which this operator is - installed to. Maximum of 253 lower case alphanumeric characters, hyphen - and period only. Default value: "default" . + :param operator_namespace: The namespace to which this operator is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. :type operator_namespace: str - :param operator_instance_name: Instance name of the operator - identifying - the specific configuration. + :param operator_instance_name: Instance name of the operator - identifying the specific + configuration. :type operator_instance_name: str - :param operator_type: Type of the operator. Possible values include: - 'Flux' - :type operator_type: str or - ~azure.mgmt.kubernetesconfiguration.models.OperatorType - :param operator_params: Any Parameters for the Operator instance in string - format. + :param operator_type: Type of the operator. Possible values include: "Flux". + :type operator_type: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string format. :type operator_params: str - :param configuration_protected_settings: Name-value pairs of protected - configuration settings for the configuration + :param configuration_protected_settings: Name-value pairs of protected configuration settings + for the configuration. :type configuration_protected_settings: dict[str, str] - :param operator_scope: Scope at which the operator will be installed. - Possible values include: 'cluster', 'namespace'. Default value: "cluster" - . + :param operator_scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". :type operator_scope: str or - ~azure.mgmt.kubernetesconfiguration.models.OperatorScopeType - :ivar repository_public_key: Public Key associated with this SourceControl - configuration (either generated within the cluster or provided by the - user). + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl configuration + (either generated within the cluster or provided by the user). :vartype repository_public_key: str - :param ssh_known_hosts_contents: Base64-encoded known_hosts contents - containing public SSH keys required to access private Git instances + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents containing public SSH keys + required to access private Git instances. :type ssh_known_hosts_contents: str - :param enable_helm_operator: Option to enable Helm Operator for this git - configuration. + :param enable_helm_operator: Option to enable Helm Operator for this git configuration. :type enable_helm_operator: bool :param helm_operator_properties: Properties for Helm operator. :type helm_operator_properties: - ~azure.mgmt.kubernetesconfiguration.models.HelmOperatorProperties - :ivar provisioning_state: The provisioning state of the resource provider. - Possible values include: 'Accepted', 'Deleting', 'Running', 'Succeeded', - 'Failed' + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. Possible values + include: "Accepted", "Deleting", "Running", "Succeeded", "Failed". :vartype provisioning_state: str or - ~azure.mgmt.kubernetesconfiguration.models.ProvisioningStateType - :ivar compliance_status: Compliance Status of the Configuration + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration. :vartype compliance_status: - ~azure.mgmt.kubernetesconfiguration.models.ComplianceStatus - :param system_data: Top level metadata - https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources - :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ComplianceStatus """ _validation = { 'id': {'readonly': True}, 'name': {'readonly': True}, 'type': {'readonly': True}, + 'system_data': {'readonly': True}, 'repository_public_key': {'readonly': True}, 'provisioning_state': {'readonly': True}, 'compliance_status': {'readonly': True}, @@ -405,6 +411,7 @@ class SourceControlConfiguration(ProxyResource): 'id': {'key': 'id', 'type': 'str'}, 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, @@ -418,11 +425,25 @@ class SourceControlConfiguration(ProxyResource): 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, - 'system_data': {'key': 'systemData', 'type': 'SystemData'}, } - def __init__(self, *, repository_url: str=None, operator_namespace: str="default", operator_instance_name: str=None, operator_type=None, operator_params: str=None, configuration_protected_settings=None, operator_scope="cluster", ssh_known_hosts_contents: str=None, enable_helm_operator: bool=None, helm_operator_properties=None, system_data=None, **kwargs) -> None: + def __init__( + self, + *, + repository_url: Optional[str] = None, + operator_namespace: Optional[str] = "default", + operator_instance_name: Optional[str] = None, + operator_type: Optional[Union[str, "OperatorType"]] = None, + operator_params: Optional[str] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + operator_scope: Optional[Union[str, "OperatorScopeType"]] = "cluster", + ssh_known_hosts_contents: Optional[str] = None, + enable_helm_operator: Optional[bool] = None, + helm_operator_properties: Optional["HelmOperatorProperties"] = None, + **kwargs + ): super(SourceControlConfiguration, self).__init__(**kwargs) + self.system_data = None self.repository_url = repository_url self.operator_namespace = operator_namespace self.operator_instance_name = operator_instance_name @@ -436,30 +457,58 @@ def __init__(self, *, repository_url: str=None, operator_namespace: str="default self.helm_operator_properties = helm_operator_properties self.provisioning_state = None self.compliance_status = None - self.system_data = system_data -class SystemData(Model): +class SourceControlConfigurationList(msrest.serialization.Model): + """Result of the request to list Source Control Configurations. It contains a list of SourceControlConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Source Control Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SourceControlConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfigurationList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class SystemData(msrest.serialization.Model): """Metadata pertaining to creation and last modification of the resource. :param created_by: The identity that created the resource. :type created_by: str - :param created_by_type: The type of identity that created the resource. - Possible values include: 'User', 'Application', 'ManagedIdentity', 'Key' + :param created_by_type: The type of identity that created the resource. Possible values + include: "User", "Application", "ManagedIdentity", "Key". :type created_by_type: str or - ~azure.mgmt.kubernetesconfiguration.models.CreatedByType + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.CreatedByType :param created_at: The timestamp of resource creation (UTC). - :type created_at: datetime + :type created_at: ~datetime.datetime :param last_modified_by: The identity that last modified the resource. :type last_modified_by: str - :param last_modified_by_type: The type of identity that last modified the - resource. Possible values include: 'User', 'Application', - 'ManagedIdentity', 'Key' + :param last_modified_by_type: The type of identity that last modified the resource. Possible + values include: "User", "Application", "ManagedIdentity", "Key". :type last_modified_by_type: str or - ~azure.mgmt.kubernetesconfiguration.models.CreatedByType - :param last_modified_at: The type of identity that last modified the - resource. - :type last_modified_at: datetime + ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.CreatedByType + :param last_modified_at: The timestamp of resource last modification (UTC). + :type last_modified_at: ~datetime.datetime """ _attribute_map = { @@ -471,7 +520,17 @@ class SystemData(Model): 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, } - def __init__(self, *, created_by: str=None, created_by_type=None, created_at=None, last_modified_by: str=None, last_modified_by_type=None, last_modified_at=None, **kwargs) -> None: + def __init__( + self, + *, + created_by: Optional[str] = None, + created_by_type: Optional[Union[str, "CreatedByType"]] = None, + created_at: Optional[datetime.datetime] = None, + last_modified_by: Optional[str] = None, + last_modified_by_type: Optional[Union[str, "CreatedByType"]] = None, + last_modified_at: Optional[datetime.datetime] = None, + **kwargs + ): super(SystemData, self).__init__(**kwargs) self.created_by = created_by self.created_by_type = created_by_type @@ -479,49 +538,3 @@ def __init__(self, *, created_by: str=None, created_by_type=None, created_at=Non self.last_modified_by = last_modified_by self.last_modified_by_type = last_modified_by_type self.last_modified_at = last_modified_at - - -class TrackedResource(Resource): - """Tracked Resource. - - The resource model definition for an Azure Resource Manager tracked top - level resource which has 'tags' and a 'location'. - - Variables are only populated by the server, and will be ignored when - sending a request. - - All required parameters must be populated in order to send to Azure. - - :ivar id: Fully qualified resource ID for the resource. Ex - - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} - :vartype id: str - :ivar name: The name of the resource - :vartype name: str - :ivar type: The type of the resource. E.g. - "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" - :vartype type: str - :param tags: Resource tags. - :type tags: dict[str, str] - :param location: Required. The geo-location where the resource lives - :type location: str - """ - - _validation = { - 'id': {'readonly': True}, - 'name': {'readonly': True}, - 'type': {'readonly': True}, - 'location': {'required': True}, - } - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - 'tags': {'key': 'tags', 'type': '{str}'}, - 'location': {'key': 'location', 'type': 'str'}, - } - - def __init__(self, *, location: str, tags=None, **kwargs) -> None: - super(TrackedResource, self).__init__(**kwargs) - self.tags = tags - self.location = location diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_paged_models.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_paged_models.py deleted file mode 100644 index da03391d8d6..00000000000 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_paged_models.py +++ /dev/null @@ -1,40 +0,0 @@ -# coding=utf-8 -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. -# -------------------------------------------------------------------------- - -from msrest.paging import Paged - - -class SourceControlConfigurationPaged(Paged): - """ - A paging container for iterating over a list of :class:`SourceControlConfiguration ` object - """ - - _attribute_map = { - 'next_link': {'key': 'nextLink', 'type': 'str'}, - 'current_page': {'key': 'value', 'type': '[SourceControlConfiguration]'} - } - - def __init__(self, *args, **kwargs): - - super(SourceControlConfigurationPaged, self).__init__(*args, **kwargs) -class ResourceProviderOperationPaged(Paged): - """ - A paging container for iterating over a list of :class:`ResourceProviderOperation ` object - """ - - _attribute_map = { - 'next_link': {'key': 'nextLink', 'type': 'str'}, - 'current_page': {'key': 'value', 'type': '[ResourceProviderOperation]'} - } - - def __init__(self, *args, **kwargs): - - super(ResourceProviderOperationPaged, self).__init__(*args, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_source_control_configuration_client_enums.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_source_control_configuration_client_enums.py index 6708ac68cde..be122639f51 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_source_control_configuration_client_enums.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_source_control_configuration_client_enums.py @@ -1,56 +1,87 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from enum import Enum +from enum import Enum, EnumMeta +from six import with_metaclass +class _CaseInsensitiveEnumMeta(EnumMeta): + def __getitem__(self, name): + return super().__getitem__(name.upper()) -class ComplianceStateType(str, Enum): + def __getattr__(cls, name): + """Return the enum member matching `name` + We use __getattr__ instead of descriptors or inserting into the enum + class' __dict__ in order to support `name` and `value` being both + properties for enum members (which live in the class' __dict__) and + enum members themselves. + """ + try: + return cls._member_map_[name.upper()] + except KeyError: + raise AttributeError(name) - pending = "Pending" - compliant = "Compliant" - noncompliant = "Noncompliant" - installed = "Installed" - failed = "Failed" +class ComplianceStateType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The compliance state of the configuration. + """ -class MessageLevelType(str, Enum): + PENDING = "Pending" + COMPLIANT = "Compliant" + NONCOMPLIANT = "Noncompliant" + INSTALLED = "Installed" + FAILED = "Failed" - error = "Error" - warning = "Warning" - information = "Information" +class CreatedByType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The type of identity that created the resource. + """ + USER = "User" + APPLICATION = "Application" + MANAGED_IDENTITY = "ManagedIdentity" + KEY = "Key" -class OperatorType(str, Enum): +class Enum0(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): - flux = "Flux" + MICROSOFT_CONTAINER_SERVICE = "Microsoft.ContainerService" + MICROSOFT_KUBERNETES = "Microsoft.Kubernetes" +class Enum1(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): -class OperatorScopeType(str, Enum): + MANAGED_CLUSTERS = "managedClusters" + CONNECTED_CLUSTERS = "connectedClusters" - cluster = "cluster" - namespace = "namespace" +class MessageLevelType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Level of the message. + """ + ERROR = "Error" + WARNING = "Warning" + INFORMATION = "Information" -class ProvisioningStateType(str, Enum): +class OperatorScopeType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Scope at which the operator will be installed. + """ - accepted = "Accepted" - deleting = "Deleting" - running = "Running" - succeeded = "Succeeded" - failed = "Failed" + CLUSTER = "cluster" + NAMESPACE = "namespace" +class OperatorType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Type of the operator + """ -class CreatedByType(str, Enum): + FLUX = "Flux" - user = "User" - application = "Application" - managed_identity = "ManagedIdentity" - key = "Key" +class ProvisioningStateType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The provisioning state of the resource provider. + """ + + ACCEPTED = "Accepted" + DELETING = "Deleting" + RUNNING = "Running" + SUCCEEDED = "Succeeded" + FAILED = "Failed" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/__init__.py index b6c0858d9a7..07db19b318c 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/__init__.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/__init__.py @@ -1,12 +1,9 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- from ._source_control_configurations_operations import SourceControlConfigurationsOperations diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_operations.py index 5308b8f8270..4f46b393205 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_operations.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_operations.py @@ -1,101 +1,110 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings -import uuid -from msrest.pipeline import ClientRawResponse +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat -from .. import models +from .. import models as _models +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] class Operations(object): """Operations operations. - You should not instantiate directly this class, but create a Client instance that will create it for you and attach it as attribute. + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models :param client: Client for service requests. :param config: Configuration of service client. :param serializer: An object model serializer. :param deserializer: An object model deserializer. - :ivar api_version: The API version to be used with the HTTP request. Constant value: "2021-03-01". """ - models = models + models = _models def __init__(self, client, config, serializer, deserializer): - self._client = client self._serialize = serializer self._deserialize = deserializer - self.api_version = "2021-03-01" - - self.config = config + self._config = config def list( - self, custom_headers=None, raw=False, **operation_config): - """List all the available operations the KubernetesConfiguration resource - provider supports. - - :param dict custom_headers: headers that will be added to the request - :param bool raw: returns the direct response alongside the - deserialized response - :param operation_config: :ref:`Operation configuration - overrides`. - :return: An iterator like instance of ResourceProviderOperation - :rtype: - ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationPaged[~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperation] - :raises: - :class:`ErrorResponseException` + self, + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ResourceProviderOperationList"] + """List all the available operations the KubernetesConfiguration resource provider supports. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + if not next_link: # Construct URL - url = self.list.metadata['url'] - + url = self.list.metadata['url'] # type: ignore # Construct parameters - query_parameters = {} - query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + request = self._client.get(url, query_parameters, header_parameters) else: url = next_link - query_parameters = {} - - # Construct headers - header_parameters = {} - header_parameters['Accept'] = 'application/json' - if self.config.generate_client_request_id: - header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) - if custom_headers: - header_parameters.update(custom_headers) - if self.config.accept_language is not None: - header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') - - # Construct and send request - request = self._client.get(url, query_parameters, header_parameters) + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) return request - def internal_paging(next_link=None): + def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): request = prepare_request(next_link) - response = self._client.send(request, stream=False, **operation_config) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response if response.status_code not in [200]: - raise models.ErrorResponseException(self._deserialize, response) - - return response + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) - # Deserialize response - header_dict = None - if raw: - header_dict = {} - deserialized = models.ResourceProviderOperationPaged(internal_paging, self._deserialize.dependencies, header_dict) + return pipeline_response - return deserialized - list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_source_control_configurations_operations.py index 4b4a8599262..7808e3e5917 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_source_control_configurations_operations.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_source_control_configurations_operations.py @@ -1,386 +1,429 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# +# Licensed under the MIT License. See License.txt in the project root for license information. # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings -import uuid -from msrest.pipeline import ClientRawResponse -from msrest.polling import LROPoller, NoPolling -from msrestazure.polling.arm_polling import ARMPolling +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.core.polling import LROPoller, NoPolling, PollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.arm_polling import ARMPolling -from .. import models +from .. import models as _models +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] class SourceControlConfigurationsOperations(object): """SourceControlConfigurationsOperations operations. - You should not instantiate directly this class, but create a Client instance that will create it for you and attach it as attribute. + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models :param client: Client for service requests. :param config: Configuration of service client. :param serializer: An object model serializer. :param deserializer: An object model deserializer. - :ivar api_version: The API version to be used with the HTTP request. Constant value: "2021-03-01". """ - models = models + models = _models def __init__(self, client, config, serializer, deserializer): - self._client = client self._serialize = serializer self._deserialize = deserializer - self.api_version = "2021-03-01" - - self.config = config + self._config = config def get( - self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, **operation_config): + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.SourceControlConfiguration" """Gets details of the Source Control Configuration. :param resource_group_name: The name of the resource group. :type resource_group_name: str - :param cluster_rp: The Kubernetes cluster RP - either - Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes - (for OnPrem K8S clusters). Possible values include: - 'Microsoft.ContainerService', 'Microsoft.Kubernetes' - :type cluster_rp: str - :param cluster_resource_name: The Kubernetes cluster resource name - - either managedClusters (for AKS clusters) or connectedClusters (for - OnPrem K8S clusters). Possible values include: 'managedClusters', - 'connectedClusters' - :type cluster_resource_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str - :param source_control_configuration_name: Name of the Source Control - Configuration. + :param source_control_configuration_name: Name of the Source Control Configuration. :type source_control_configuration_name: str - :param dict custom_headers: headers that will be added to the request - :param bool raw: returns the direct response alongside the - deserialized response - :param operation_config: :ref:`Operation configuration - overrides`. - :return: SourceControlConfiguration or ClientRawResponse if raw=true - :rtype: - ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration - or ~msrest.pipeline.ClientRawResponse - :raises: - :class:`ErrorResponseException` + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + # Construct URL - url = self.get.metadata['url'] + url = self.get.metadata['url'] # type: ignore path_format_arguments = { - 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), - 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), } url = self._client.format_url(url, **path_format_arguments) # Construct parameters - query_parameters = {} - query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') # Construct headers - header_parameters = {} - header_parameters['Accept'] = 'application/json' - if self.config.generate_client_request_id: - header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) - if custom_headers: - header_parameters.update(custom_headers) - if self.config.accept_language is not None: - header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') - - # Construct and send request + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + request = self._client.get(url, query_parameters, header_parameters) - response = self._client.send(request, stream=False, **operation_config) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response if response.status_code not in [200]: - raise models.ErrorResponseException(self._deserialize, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) - deserialized = None - if response.status_code == 200: - deserialized = self._deserialize('SourceControlConfiguration', response) + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) - if raw: - client_raw_response = ClientRawResponse(deserialized, response) - return client_raw_response + if cls: + return cls(pipeline_response, deserialized, {}) return deserialized - get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore def create_or_update( - self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, source_control_configuration, custom_headers=None, raw=False, **operation_config): + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + source_control_configuration, # type: "_models.SourceControlConfiguration" + **kwargs # type: Any + ): + # type: (...) -> "_models.SourceControlConfiguration" """Create a new Kubernetes Source Control Configuration. :param resource_group_name: The name of the resource group. :type resource_group_name: str - :param cluster_rp: The Kubernetes cluster RP - either - Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes - (for OnPrem K8S clusters). Possible values include: - 'Microsoft.ContainerService', 'Microsoft.Kubernetes' - :type cluster_rp: str - :param cluster_resource_name: The Kubernetes cluster resource name - - either managedClusters (for AKS clusters) or connectedClusters (for - OnPrem K8S clusters). Possible values include: 'managedClusters', - 'connectedClusters' - :type cluster_resource_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str - :param source_control_configuration_name: Name of the Source Control - Configuration. + :param source_control_configuration_name: Name of the Source Control Configuration. :type source_control_configuration_name: str - :param source_control_configuration: Properties necessary to Create - KubernetesConfiguration. - :type source_control_configuration: - ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration - :param dict custom_headers: headers that will be added to the request - :param bool raw: returns the direct response alongside the - deserialized response - :param operation_config: :ref:`Operation configuration - overrides`. - :return: SourceControlConfiguration or ClientRawResponse if raw=true - :rtype: - ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration - or ~msrest.pipeline.ClientRawResponse - :raises: - :class:`ErrorResponseException` + :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + # Construct URL - url = self.create_or_update.metadata['url'] + url = self.create_or_update.metadata['url'] # type: ignore path_format_arguments = { - 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), - 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), } url = self._client.format_url(url, **path_format_arguments) # Construct parameters - query_parameters = {} - query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') # Construct headers - header_parameters = {} - header_parameters['Accept'] = 'application/json' - header_parameters['Content-Type'] = 'application/json; charset=utf-8' - if self.config.generate_client_request_id: - header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) - if custom_headers: - header_parameters.update(custom_headers) - if self.config.accept_language is not None: - header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') - - # Construct body - body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') - # Construct and send request - request = self._client.put(url, query_parameters, header_parameters, body_content) - response = self._client.send(request, stream=False, **operation_config) + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response if response.status_code not in [200, 201]: - raise models.ErrorResponseException(self._deserialize, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) - deserialized = None if response.status_code == 200: - deserialized = self._deserialize('SourceControlConfiguration', response) + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + if response.status_code == 201: - deserialized = self._deserialize('SourceControlConfiguration', response) + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) - if raw: - client_raw_response = ClientRawResponse(deserialized, response) - return client_raw_response + if cls: + return cls(pipeline_response, deserialized, {}) return deserialized - create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} - + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore def _delete_initial( - self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, **operation_config): + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + # Construct URL - url = self.delete.metadata['url'] + url = self._delete_initial.metadata['url'] # type: ignore path_format_arguments = { - 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), - 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), } url = self._client.format_url(url, **path_format_arguments) # Construct parameters - query_parameters = {} - query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') # Construct headers - header_parameters = {} - if self.config.generate_client_request_id: - header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) - if custom_headers: - header_parameters.update(custom_headers) - if self.config.accept_language is not None: - header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') - - # Construct and send request + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + request = self._client.delete(url, query_parameters, header_parameters) - response = self._client.send(request, stream=False, **operation_config) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response if response.status_code not in [200, 204]: - raise models.ErrorResponseException(self._deserialize, response) - - if raw: - client_raw_response = ClientRawResponse(None, response) - return client_raw_response - - def delete( - self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, polling=True, **operation_config): - """This will delete the YAML file used to set up the Source control - configuration, thus stopping future sync from the source repo. + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def begin_delete( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> LROPoller[None] + """This will delete the YAML file used to set up the Source control configuration, thus stopping + future sync from the source repo. :param resource_group_name: The name of the resource group. :type resource_group_name: str - :param cluster_rp: The Kubernetes cluster RP - either - Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes - (for OnPrem K8S clusters). Possible values include: - 'Microsoft.ContainerService', 'Microsoft.Kubernetes' - :type cluster_rp: str - :param cluster_resource_name: The Kubernetes cluster resource name - - either managedClusters (for AKS clusters) or connectedClusters (for - OnPrem K8S clusters). Possible values include: 'managedClusters', - 'connectedClusters' - :type cluster_resource_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str - :param source_control_configuration_name: Name of the Source Control - Configuration. + :param source_control_configuration_name: Name of the Source Control Configuration. :type source_control_configuration_name: str - :param dict custom_headers: headers that will be added to the request - :param bool raw: The poller return type is ClientRawResponse, the - direct response alongside the deserialized response - :param polling: True for ARMPolling, False for no polling, or a - polling object for personal polling strategy - :return: An instance of LROPoller that returns None or - ClientRawResponse if raw==True - :rtype: ~msrestazure.azure_operation.AzureOperationPoller[None] or - ~msrestazure.azure_operation.AzureOperationPoller[~msrest.pipeline.ClientRawResponse[None]] - :raises: - :class:`ErrorResponseException` + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: """ - raw_result = self._delete_initial( - resource_group_name=resource_group_name, - cluster_rp=cluster_rp, - cluster_resource_name=cluster_resource_name, - cluster_name=cluster_name, - source_control_configuration_name=source_control_configuration_name, - custom_headers=custom_headers, - raw=True, - **operation_config + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) - def get_long_running_output(response): - if raw: - client_raw_response = ClientRawResponse(None, response) - return client_raw_response + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } - lro_delay = operation_config.get( - 'long_running_operation_timeout', - self.config.long_running_operation_timeout) - if polling is True: polling_method = ARMPolling(lro_delay, **operation_config) + if polling is True: polling_method = ARMPolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) elif polling is False: polling_method = NoPolling() else: polling_method = polling - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) - delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore def list( - self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, custom_headers=None, raw=False, **operation_config): + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.SourceControlConfigurationList"] """List all Source Control Configurations. :param resource_group_name: The name of the resource group. :type resource_group_name: str - :param cluster_rp: The Kubernetes cluster RP - either - Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes - (for OnPrem K8S clusters). Possible values include: - 'Microsoft.ContainerService', 'Microsoft.Kubernetes' - :type cluster_rp: str - :param cluster_resource_name: The Kubernetes cluster resource name - - either managedClusters (for AKS clusters) or connectedClusters (for - OnPrem K8S clusters). Possible values include: 'managedClusters', - 'connectedClusters' - :type cluster_resource_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str - :param dict custom_headers: headers that will be added to the request - :param bool raw: returns the direct response alongside the - deserialized response - :param operation_config: :ref:`Operation configuration - overrides`. - :return: An iterator like instance of SourceControlConfiguration - :rtype: - ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfigurationPaged[~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration] - :raises: - :class:`ErrorResponseException` + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfigurationList] + :raises: ~azure.core.exceptions.HttpResponseError """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + if not next_link: # Construct URL - url = self.list.metadata['url'] + url = self.list.metadata['url'] # type: ignore path_format_arguments = { - 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), - 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str') + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), } url = self._client.format_url(url, **path_format_arguments) - # Construct parameters - query_parameters = {} - query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + request = self._client.get(url, query_parameters, header_parameters) else: url = next_link - query_parameters = {} - - # Construct headers - header_parameters = {} - header_parameters['Accept'] = 'application/json' - if self.config.generate_client_request_id: - header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) - if custom_headers: - header_parameters.update(custom_headers) - if self.config.accept_language is not None: - header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') - - # Construct and send request - request = self._client.get(url, query_parameters, header_parameters) + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) return request - def internal_paging(next_link=None): + def extract_data(pipeline_response): + deserialized = self._deserialize('SourceControlConfigurationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): request = prepare_request(next_link) - response = self._client.send(request, stream=False, **operation_config) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response if response.status_code not in [200]: - raise models.ErrorResponseException(self._deserialize, response) - - return response + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) - # Deserialize response - header_dict = None - if raw: - header_dict = {} - deserialized = models.SourceControlConfigurationPaged(internal_paging, self._deserialize.dependencies, header_dict) + return pipeline_response - return deserialized - list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} # type: ignore diff --git a/src/k8s-configuration/setup.py b/src/k8s-configuration/setup.py index 2701f5bee81..9579d8ebbe3 100644 --- a/src/k8s-configuration/setup.py +++ b/src/k8s-configuration/setup.py @@ -14,9 +14,7 @@ from distutils import log as logger logger.warn("Wheel is not available, disabling bdist_wheel hook") -# TODO: Confirm this is the right version number you want and it matches your -# HISTORY.rst entry. -VERSION = '1.0.1' +VERSION = '1.1.0' # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers diff --git a/testing/test/configurations/Configuration.PrivateKey.Tests.ps1 b/testing/test/configurations/Configuration.PrivateKey.Tests.ps1 index 4bf86d52012..0ee9ee2b54c 100644 --- a/testing/test/configurations/Configuration.PrivateKey.Tests.ps1 +++ b/testing/test/configurations/Configuration.PrivateKey.Tests.ps1 @@ -4,11 +4,10 @@ Describe 'Source Control Configuration (SSH Configs) Testing' { . $PSScriptRoot/Helper.ps1 $RSA_KEYPATH = "$TMP_DIRECTORY\rsa.private" - $DSA_KEYPATH = "$TMP_DIRECTORY\dsa.private" $ECDSA_KEYPATH = "$TMP_DIRECTORY\ecdsa.private" $ED25519_KEYPATH = "$TMP_DIRECTORY\ed25519.private" - $KEY_ARR = [System.Tuple]::Create("rsa", $RSA_KEYPATH), [System.Tuple]::Create("dsa", $DSA_KEYPATH), [System.Tuple]::Create("ecdsa", $ECDSA_KEYPATH), [System.Tuple]::Create("ed25519", $ED25519_KEYPATH) + $KEY_ARR = [System.Tuple]::Create("rsa", $RSA_KEYPATH), [System.Tuple]::Create("ecdsa", $ECDSA_KEYPATH), [System.Tuple]::Create("ed25519", $ED25519_KEYPATH) foreach ($keyTuple in $KEY_ARR) { # Automattically say yes to overwrite with ssh-keygen Write-Output "y" | ssh-keygen -t $keyTuple.Item1 -f $keyTuple.Item2 -P """" @@ -18,15 +17,15 @@ Describe 'Source Control Configuration (SSH Configs) Testing' { $HTTP_GIT_URL = "https://github.com/Azure/arc-k8s-demo" $configDataRSA = [System.Tuple]::Create("rsa-config", $RSA_KEYPATH) - $configDataDSA = [System.Tuple]::Create("dsa-config", $DSA_KEYPATH) $configDataECDSA = [System.Tuple]::Create("ecdsa-config", $ECDSA_KEYPATH) $configDataED25519 = [System.Tuple]::Create("ed25519-config", $ED25519_KEYPATH) - $CONFIG_ARR = $configDataRSA, $configDataDSA, $configDataECDSA, $configDataED25519 + $CONFIG_ARR = $configDataRSA, $configDataECDSA, $configDataED25519 } It 'Creates a configuration with each type of ssh private key' { foreach($configData in $CONFIG_ARR) { + Write-Host "Creating a configuration of type $($configData.Item1)" az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u $SSH_GIT_URL -n $configData.Item1 --scope cluster --operator-namespace $configData.Item1 --ssh-private-key-file $configData.Item2 $? | Should -BeTrue } @@ -44,7 +43,7 @@ Describe 'Source Control Configuration (SSH Configs) Testing' { } Start-Sleep -Seconds 10 $n += 1 - } while ($n -le 30 -And $readyConfigs -ne 4) + } while ($n -le 30 -And $readyConfigs -ne 3) $n | Should -BeLessOrEqual 30 } From 3b5c2ebafe7bd9d5f0d64185fbe4f79c6a0222d8 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Tue, 31 Aug 2021 14:21:28 -0700 Subject: [PATCH 72/80] Upgrade helm operator chart version (#75) --- src/k8s-configuration/azext_k8s_configuration/_help.py | 4 ++-- src/k8s-configuration/azext_k8s_configuration/custom.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k8s-configuration/azext_k8s_configuration/_help.py b/src/k8s-configuration/azext_k8s_configuration/_help.py index 3fa338c7b28..a01183b8f5f 100644 --- a/src/k8s-configuration/azext_k8s_configuration/_help.py +++ b/src/k8s-configuration/azext_k8s_configuration/_help.py @@ -22,7 +22,7 @@ --cluster-type connectedClusters --name MyGitConfig --operator-instance-name OperatorInst01 \\ --operator-namespace OperatorNamespace01 --operator-type flux --operator-params "'--git-readonly'" \\ --repository-url git://github.com/fluxHowTo/flux-get-started --enable-helm-operator \\ - --helm-operator-chart-version 1.2.0 --scope namespace --helm-operator-params '--set helm.versions=v3' \\ + --helm-operator-chart-version 1.4.0 --scope namespace --helm-operator-params '--set helm.versions=v3' \\ --ssh-private-key '' --ssh-private-key-file '' --https-user '' --https-key '' \\ --ssh-known-hosts '' --ssh-known-hosts-file '' """ @@ -66,5 +66,5 @@ az k8s-configuration update --resource-group MyResourceGroup --cluster-name MyClusterName \\ --cluster-type connectedClusters --name MyConfigurationName --enable-helm-operator \\ --repository-url git://github.com/fluxHowTo/flux-get-started --operator-params "'--git-readonly'" \\ - --helm-operator-chart-version 1.2.0 --helm-operator-params '--set helm.versions=v3' + --helm-operator-chart-version 1.4.0 --helm-operator-params '--set helm.versions=v3' """ diff --git a/src/k8s-configuration/azext_k8s_configuration/custom.py b/src/k8s-configuration/azext_k8s_configuration/custom.py index 12a1bafe644..ea84523c764 100644 --- a/src/k8s-configuration/azext_k8s_configuration/custom.py +++ b/src/k8s-configuration/azext_k8s_configuration/custom.py @@ -53,7 +53,7 @@ def show_k8s_configuration(client, resource_group_name, cluster_name, name, clus # pylint: disable=too-many-locals def create_k8s_configuration(cmd, client, resource_group_name, cluster_name, name, repository_url, scope, cluster_type, operator_instance_name=None, operator_namespace='default', - helm_operator_chart_version='1.2.0', operator_type='flux', operator_params='', + helm_operator_chart_version='1.4.0', operator_type='flux', operator_params='', ssh_private_key='', ssh_private_key_file='', https_user='', https_key='', ssh_known_hosts='', ssh_known_hosts_file='', enable_helm_operator=None, helm_operator_params=''): From e542474477e6ca6fcb1c3af0bf202d13b4483f44 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Mon, 20 Sep 2021 15:24:34 -0700 Subject: [PATCH 73/80] Pin helm version --- k8s-custom-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s-custom-pipelines.yml b/k8s-custom-pipelines.yml index 75ad3a52f79..79c14d07635 100644 --- a/k8s-custom-pipelines.yml +++ b/k8s-custom-pipelines.yml @@ -30,7 +30,7 @@ stages: echo "Installing helm3" curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 chmod 700 get_helm.sh - ./get_helm.sh + ./get_helm.sh --version v3.6.3 echo "Installing kubectl" curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" From 65d955496ab300513f5859f9a008aded98c6e588 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Tue, 12 Oct 2021 14:12:08 -0700 Subject: [PATCH 74/80] Bump version --- src/k8s-configuration/HISTORY.rst | 4 ++++ src/k8s-configuration/setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/k8s-configuration/HISTORY.rst b/src/k8s-configuration/HISTORY.rst index b8ef4668e03..237b49c08e2 100644 --- a/src/k8s-configuration/HISTORY.rst +++ b/src/k8s-configuration/HISTORY.rst @@ -3,6 +3,10 @@ Release History =============== +1.1.1 +++++++++++++++++++ +* Enable helm-operator chart version 1.4.0 + 1.1.0 ++++++++++++++++++ * Update sourceControlConfiguration resource models to Track2 diff --git a/src/k8s-configuration/setup.py b/src/k8s-configuration/setup.py index 9579d8ebbe3..6b597acaa7f 100644 --- a/src/k8s-configuration/setup.py +++ b/src/k8s-configuration/setup.py @@ -14,7 +14,7 @@ from distutils import log as logger logger.warn("Wheel is not available, disabling bdist_wheel hook") -VERSION = '1.1.0' +VERSION = '1.1.1' # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers From 8f622c67649126877948f87c7dfe791edfa11901 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Tue, 9 Nov 2021 14:18:29 -0800 Subject: [PATCH 75/80] Migrate pipeline (#90) --- .../pipeline/k8s-custom-pipelines.yml | 592 +++++++++--------- 1 file changed, 296 insertions(+), 296 deletions(-) rename k8s-custom-pipelines.yml => testing/pipeline/k8s-custom-pipelines.yml (96%) diff --git a/k8s-custom-pipelines.yml b/testing/pipeline/k8s-custom-pipelines.yml similarity index 96% rename from k8s-custom-pipelines.yml rename to testing/pipeline/k8s-custom-pipelines.yml index 79c14d07635..5db2f6d7047 100644 --- a/k8s-custom-pipelines.yml +++ b/testing/pipeline/k8s-custom-pipelines.yml @@ -1,296 +1,296 @@ -trigger: - batch: true - branches: - include: - - k8s-configuration -pr: - branches: - include: - - k8s-configuration - -stages: -- stage: BuildTestPublishExtension - displayName: "Build, Test, and Publish Extension" - variables: - TEST_PATH: $(Agent.BuildDirectory)/s/testing - CLI_REPO_PATH: $(Agent.BuildDirectory)/s - EXTENSION_NAME: "k8s-configuration" - EXTENSION_FILE_NAME: "k8s_configuration" - SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" - RESOURCE_GROUP: "K8sPartnerExtensionTest" - BASE_CLUSTER_NAME: "k8s-configuration-cluster" - jobs: - - job: K8sConfigurationTestSuite - displayName: "Run the Test Suite" - pool: - vmImage: 'ubuntu-latest' - steps: - - checkout: self - - bash: | - echo "Installing helm3" - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 - chmod 700 get_helm.sh - ./get_helm.sh --version v3.6.3 - - echo "Installing kubectl" - curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x ./kubectl - sudo mv ./kubectl /usr/local/bin/kubectl - kubectl version --client - displayName: "Setup the VM with helm3 and kubectl" - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - - # clone azure-cli - pip install --upgrade pip - pip install azdev - - ls $(CLI_REPO_PATH) - - azdev --version - azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build $(EXTENSION_NAME) with azdev" - - - bash: | - K8S_CONFIG_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) - echo "##vso[task.setvariable variable=K8S_CONFIG_VERSION]$K8S_CONFIG_VERSION" - cp * $(TEST_PATH)/bin - echo $(ls -l) - workingDirectory: $(CLI_REPO_PATH)/dist - displayName: "Copy the Built .whl to Extension Test Path" - - - bash: | - RAND_STR=$RANDOM - AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" - ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" - - JSON_STRING=$(jq -n \ - --arg SUB_ID "$SUBSCRIPTION_ID" \ - --arg RG "$RESOURCE_GROUP" \ - --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ - --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ - --arg K8S_CONFIG_VERSION "$K8S_CONFIG_VERSION" \ - '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-configuration": $K8S_CONFIG_VERSION, connectedk8s: "1.0.0"}}') - echo $JSON_STRING > settings.json - cat settings.json - workingDirectory: $(TEST_PATH) - displayName: "Generate a settings.json file" - - - bash : | - echo "Downloading the kind script" - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 - chmod +x ./kind - ./kind create cluster - displayName: "Create and Start the Kind cluster" - - - task: AzureCLI@2 - displayName: Bootstrap - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Bootstrap.ps1 -CI - workingDirectory: $(TEST_PATH) - - - task: AzureCLI@2 - displayName: Run the Test Suite - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Test.ps1 -Type k8s-configuration -CI - workingDirectory: $(TEST_PATH) - continueOnError: true - - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'JUnit' - testResultsFiles: '**/TestResults.xml' - failTaskOnFailedTests: true - condition: succeededOrFailed() - - - task: AzureCLI@2 - displayName: Cleanup - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Cleanup.ps1 -CI - workingDirectory: $(TEST_PATH) - condition: succeededOrFailed() - - - job: BuildPublishExtension - pool: - vmImage: 'ubuntu-latest' - displayName: "Build and Publish the Extension Artifact" - variables: - CLI_REPO_PATH: $(Agent.BuildDirectory)/s - EXTENSION_NAME: "k8s-configuration" - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - echo "Building extension ${EXTENSION_NAME}..." - - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - - # clone azure-cli - pip install --upgrade pip - pip install azdev - - ls $(CLI_REPO_PATH) - - azdev --version - azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build Extension with azdev" - - task: PublishBuildArtifacts@1 - inputs: - pathToPublish: $(CLI_REPO_PATH)/dist - -- stage: AzureCLIOfficial - displayName: "Azure Official CLI Code Checks" - dependsOn: [] - jobs: - - job: CheckLicenseHeader - displayName: "Check License" - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - python -m venv env/ - - chmod +x ./env/bin/activate - source ./env/bin/activate - - # clone azure-cli - git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install --upgrade pip - pip install -q azdev - - azdev setup -c ../azure-cli -r ./ - - azdev --version - az --version - - azdev verify license - - - job: StaticAnalysis - displayName: "Static Analysis" - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests - displayName: 'Install wheel, pylint, flake8, requests' - - bash: python scripts/ci/source_code_static_analysis.py - displayName: "Static Analysis" - - - job: IndexVerify - displayName: "Verify Extensions Index" - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: | - #!/usr/bin/env bash - set -ev - pip install wheel==0.30.0 requests packaging - export CI="ADO" - python ./scripts/ci/test_index.py -v - displayName: "Verify Extensions Index" - - - job: SourceTests - displayName: "Integration Tests, Build Tests" - pool: - vmImage: 'ubuntu-latest' - strategy: - matrix: - Python36: - python.version: '3.6' - Python38: - python.version: '3.8' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python $(python.version)' - inputs: - versionSpec: '$(python.version)' - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - bash: ./scripts/ci/test_source.sh - displayName: 'Run integration test and build test' - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - - - job: LintModifiedExtensions - displayName: "CLI Linter on Modified Extensions" - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - pip install virtualenv - python -m virtualenv venv/ - source ./venv/bin/activate - - # clone azure-cli - git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install --upgrade pip - pip install azdev - - azdev --version - - azdev setup -c ../azure-cli -r ./ -e k8s-configuration - - # overwrite the default AZURE_EXTENSION_DIR set by ADO - AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version - - AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-configuration - displayName: "CLI Linter on Modified Extension" - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) +trigger: + batch: true + branches: + include: + - k8s-configuration +pr: + branches: + include: + - k8s-configuration + +stages: +- stage: BuildTestPublishExtension + displayName: "Build, Test, and Publish Extension" + variables: + TEST_PATH: $(Agent.BuildDirectory)/s/testing + CLI_REPO_PATH: $(Agent.BuildDirectory)/s + EXTENSION_NAME: "k8s-configuration" + EXTENSION_FILE_NAME: "k8s_configuration" + SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" + RESOURCE_GROUP: "K8sPartnerExtensionTest" + BASE_CLUSTER_NAME: "k8s-configuration-cluster" + jobs: + - job: K8sConfigurationTestSuite + displayName: "Run the Test Suite" + pool: + vmImage: 'ubuntu-latest' + steps: + - checkout: self + - bash: | + echo "Installing helm3" + curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 + chmod 700 get_helm.sh + ./get_helm.sh --version v3.6.3 + + echo "Installing kubectl" + curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin/kubectl + kubectl version --client + displayName: "Setup the VM with helm3 and kubectl" + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install --upgrade pip + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build $(EXTENSION_NAME) with azdev" + + - bash: | + K8S_CONFIG_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) + echo "##vso[task.setvariable variable=K8S_CONFIG_VERSION]$K8S_CONFIG_VERSION" + cp * $(TEST_PATH)/bin + echo $(ls -l) + workingDirectory: $(CLI_REPO_PATH)/dist + displayName: "Copy the Built .whl to Extension Test Path" + + - bash: | + RAND_STR=$RANDOM + AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" + ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" + + JSON_STRING=$(jq -n \ + --arg SUB_ID "$SUBSCRIPTION_ID" \ + --arg RG "$RESOURCE_GROUP" \ + --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ + --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ + --arg K8S_CONFIG_VERSION "$K8S_CONFIG_VERSION" \ + '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-configuration": $K8S_CONFIG_VERSION, connectedk8s: "1.0.0"}}') + echo $JSON_STRING > settings.json + cat settings.json + workingDirectory: $(TEST_PATH) + displayName: "Generate a settings.json file" + + - bash : | + echo "Downloading the kind script" + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 + chmod +x ./kind + ./kind create cluster + displayName: "Create and Start the Kind cluster" + + - task: AzureCLI@2 + displayName: Bootstrap + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Bootstrap.ps1 -CI + workingDirectory: $(TEST_PATH) + + - task: AzureCLI@2 + displayName: Run the Test Suite + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Test.ps1 -Type k8s-configuration -CI + workingDirectory: $(TEST_PATH) + continueOnError: true + + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TestResults.xml' + failTaskOnFailedTests: true + condition: succeededOrFailed() + + - task: AzureCLI@2 + displayName: Cleanup + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Cleanup.ps1 -CI + workingDirectory: $(TEST_PATH) + condition: succeededOrFailed() + + - job: BuildPublishExtension + pool: + vmImage: 'ubuntu-latest' + displayName: "Build and Publish the Extension Artifact" + variables: + CLI_REPO_PATH: $(Agent.BuildDirectory)/s + EXTENSION_NAME: "k8s-configuration" + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + echo "Building extension ${EXTENSION_NAME}..." + + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + + # clone azure-cli + pip install --upgrade pip + pip install azdev + + ls $(CLI_REPO_PATH) + + azdev --version + azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build Extension with azdev" + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: $(CLI_REPO_PATH)/dist + +- stage: AzureCLIOfficial + displayName: "Azure Official CLI Code Checks" + dependsOn: [] + jobs: + - job: CheckLicenseHeader + displayName: "Check License" + pool: + vmImage: 'ubuntu-latest' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + python -m venv env/ + + chmod +x ./env/bin/activate + source ./env/bin/activate + + # clone azure-cli + git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install --upgrade pip + pip install -q azdev + + azdev setup -c ../azure-cli -r ./ + + azdev --version + az --version + + azdev verify license + + - job: StaticAnalysis + displayName: "Static Analysis" + pool: + vmImage: 'ubuntu-latest' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests + displayName: 'Install wheel, pylint, flake8, requests' + - bash: python scripts/ci/source_code_static_analysis.py + displayName: "Static Analysis" + + - job: IndexVerify + displayName: "Verify Extensions Index" + pool: + vmImage: 'ubuntu-latest' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: 3.7 + - bash: | + #!/usr/bin/env bash + set -ev + pip install wheel==0.30.0 requests packaging + export CI="ADO" + python ./scripts/ci/test_index.py -v + displayName: "Verify Extensions Index" + + - job: SourceTests + displayName: "Integration Tests, Build Tests" + pool: + vmImage: 'ubuntu-latest' + strategy: + matrix: + Python36: + python.version: '3.6' + Python38: + python.version: '3.8' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python $(python.version)' + inputs: + versionSpec: '$(python.version)' + - bash: pip install wheel==0.30.0 + displayName: 'Install wheel==0.30.0' + - bash: ./scripts/ci/test_source.sh + displayName: 'Run integration test and build test' + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) + + - job: LintModifiedExtensions + displayName: "CLI Linter on Modified Extensions" + pool: + vmImage: 'ubuntu-latest' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + + # prepare and activate virtualenv + pip install virtualenv + python -m virtualenv venv/ + source ./venv/bin/activate + + # clone azure-cli + git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + + pip install --upgrade pip + pip install azdev + + azdev --version + + azdev setup -c ../azure-cli -r ./ -e k8s-configuration + + # overwrite the default AZURE_EXTENSION_DIR set by ADO + AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version + + AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-configuration + displayName: "CLI Linter on Modified Extension" + env: + ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) + ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) From d0117629a3f310a973b25e55b7c9cd84703a8e41 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Tue, 9 Nov 2021 17:13:00 -0800 Subject: [PATCH 76/80] Disable updates on configuration tests (#89) --- .../Configuration.HelmOperator.Tests.ps1 | 85 ------------------- .../configurations/Configuration.Tests.ps1 | 27 ------ 2 files changed, 112 deletions(-) diff --git a/testing/test/configurations/Configuration.HelmOperator.Tests.ps1 b/testing/test/configurations/Configuration.HelmOperator.Tests.ps1 index 8b89ba24c58..2d7bbf173ea 100644 --- a/testing/test/configurations/Configuration.HelmOperator.Tests.ps1 +++ b/testing/test/configurations/Configuration.HelmOperator.Tests.ps1 @@ -27,91 +27,6 @@ Describe 'Source Control Configuration (Helm Operator Properties) Testing' { $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS } - It "Updates the helm operator params and performs a show" { - Set-ItResult -Skipped -Because "Update is not a valid scenario for now" - - az k8s-configuration update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -n $configurationName --helm-operator-params $customOperatorParams - $? | Should -BeTrue - - $output = az k8s-configuration show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeTrue - - $configData = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - ($configData.helmOperatorProperties.chartValues -eq $customOperatorParams) | Should -BeTrue - - # Loop and retry until the configuration updates - $n = 0 - do - { - $helmOperatorChartValues = (Get-ConfigData $configurationName).spec.helmOperatorProperties.chartValues - if ($helmOperatorChartValues -ne $null -And $helmOperatorChartValues.ToString() -eq $customOperatorParams) { - if (Get-ConfigStatus $configurationName -Match $SUCCESS_MESSAGE) { - break - } - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Updates the helm operator chart version and performs a show" { - Set-ItResult -Skipped -Because "Update is not a valid scenario for now" - - az k8s-configuration update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -n $configurationName --helm-operator-chart-version $customChartVersion - $? | Should -BeTrue - - $output = az k8s-configuration show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeTrue - - # Check that the helmOperatorProperties chartValues didn't change - $configData = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - ($configData.helmOperatorProperties.chartValues -eq $customOperatorParams) | Should -BeTrue - ($configData.helmOperatorProperties.chartVersion -eq $customChartVersion) | Should -BeTrue - - # Loop and retry until the configuration updates - $n = 0 - do - { - $helmOperatorChartVersion = (Get-ConfigData $configurationName).spec.helmOperatorProperties.chartVersion - if ($helmOperatorChartVersion -ne $null -And $helmOperatorChartVersion.ToString() -eq $customChartVersion) { - if (Get-ConfigStatus $configurationName -Match $SUCCESS_MESSAGE) { - break - } - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Disables the helm operator on the cluster" { - Set-ItResult -Skipped -Because "Update is not a valid scenario for now" - - az k8s-configuration update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -n $configurationName --enable-helm-operator=false - $? | Should -BeTrue - - $output = az k8s-configuration show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeTrue - - $helmOperatorEnabled = ($output | ConvertFrom-Json).enableHelmOperator - $helmOperatorEnabled.ToString() -eq "False" | Should -BeTrue - - # Loop and retry until the configuration updates - $n = 0 - do { - $helmOperatorEnabled = (Get-ConfigData $configurationName).spec.enableHelmOperator - if ($helmOperatorEnabled -ne $null -And $helmOperatorEnabled.ToString() -eq "False") { - if (Get-ConfigStatus $configurationName -Match $SUCCESS_MESSAGE) { - break - } - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - It "Lists the configurations on the cluster" { $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters $? | Should -BeTrue diff --git a/testing/test/configurations/Configuration.Tests.ps1 b/testing/test/configurations/Configuration.Tests.ps1 index 23a8170fd44..3ab06b06b1d 100644 --- a/testing/test/configurations/Configuration.Tests.ps1 +++ b/testing/test/configurations/Configuration.Tests.ps1 @@ -28,33 +28,6 @@ Describe 'Basic Source Control Configuration Testing' { $output | Should -Not -BeNullOrEmpty } - It "Runs an update on the configuration on the cluster" { - Set-ItResult -Skipped -Because "Update is not a valid scenario for now" - - az k8s-configuration update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName --enable-helm-operator - $? | Should -BeTrue - - $output = az k8s-configuration show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeTrue - - $helmOperatorEnabled = ($output | ConvertFrom-Json).enableHelmOperator - $helmOperatorEnabled.ToString() -eq "True" | Should -BeTrue - - # Loop and retry until the configuration updates - $n = 0 - do { - $helmOperatorEnabled = (Get-ConfigData $configurationName).spec.enableHelmOperator - if ($helmOperatorEnabled -And $helmOperatorEnabled.ToString() -eq "True") { - if (Get-ConfigStatus $configurationName -Match $SUCCESS_MESSAGE) { - break - } - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - It "Performs a re-PUT of the configuration on the cluster, with HTTPS in caps" { az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "HTTPS://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --enable-helm-operator=false --operator-namespace $configurationName $? | Should -BeTrue From 5482780ad42e52f5d39dcc9073aed2e358f0437a Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Thu, 11 Nov 2021 16:31:46 -0800 Subject: [PATCH 77/80] Release k8s-configuration v1.2.0 for Flux v2 Public Preview (#86) * Scaffold out the k8s-config package * Base implementation of CLI commands * Add create scenario and cleanup in consts * Add help text to commands, params * Add other clients to client factory * Automatically installing the flux extension * Move flux and extension into modules * Updated the versioned sdks * Push working command for testing * Update to multi api versioned sdk * Support other extension methods * Fix nullity check * Add source control provider * Add scc commands * Add defer logic for create with cache * Use default extension with identity * Fix identity creation * Add kustomization caching * Add formatters * Add scc provider * Add help text for k8s-config fluxv1 * Add help text for extension * Allow force delete of extension and fluxconfiguration * Add location to the extension model * Update with latest from k8s-extension * Add k8s-config testing * Add license header * Fix all style issues * Update codeowners file * Validate data before checking cluster compliance * No kustomizations warning * Fix identity issue in 2020-07-01 * Fix k8s regex * Fix configuration name regex validation * Fix name length validation * Adding some validation warnings * Add protected settings to request * Exclude private test path * Add suspend functionality * Add correct values to build Kustomization * Add no_wait * Fix style issues * Use base64 encoded httpsUser * Fix formatting error and base64 encoding error * Fix style issues * Fix force * Updated help text * Style fixes * Increase namespace maximum len * Add managed cluster support to k8s-config * Custom confirmation when prune is enabled * Add flux commands to existing k8s-configuration * Remove extension provider from CLI * Fix style issues * Override extension variables * Strip newlines from known_hosts file * Update help text and validators * Strip newlines from known hosts * Add provisioning state check for flux extension * Pin helm version * Remove validation from create command * Add patch support with new SDK * Add implementation for CRUD of source and kustomization * Fix errors on patch * Fix some bugs in patching properties * Add fixes for patch in k8s-configuraiton * Change duration formatting in table output * Add validation and conversion for durations * Bump verison and fix typo * Fix bug with dependencies * Fix linter and style issues * Fix delete prune check * Add flux testing * Create separate jobs for scenarios * Update error text --- .github/pull.yml | 8 - .../azext_dataprotection/manual/version.py | 22 +- src/k8s-configuration/HISTORY.rst | 5 + src/k8s-configuration/README.rst | 60 +- .../azext_k8s_configuration/__init__.py | 8 +- .../_client_factory.py | 38 +- .../azext_k8s_configuration/_format.py | 25 - .../azext_k8s_configuration/_help.py | 140 +- .../azext_k8s_configuration/_params.py | 154 +- .../azext_k8s_configuration/_utils.py | 61 - .../azext_k8s_configuration/_validators.py | 143 -- .../azext_k8s_configuration/action.py | 68 + .../azext_k8s_configuration/commands.py | 48 +- .../azext_k8s_configuration/confirm.py | 12 + .../azext_k8s_configuration/consts.py | 152 ++ .../azext_k8s_configuration/custom.py | 336 ++-- .../azext_k8s_configuration/format.py | 70 + .../providers/FluxConfigurationProvider.py | 508 +++++ .../SourceControlConfigurationProvider.py | 139 ++ .../providers/__init__.py | 0 .../test_k8s_configuration_success.yaml | 964 +++++---- .../test_kubernetesconfiguration_scenario.py | 20 +- .../tests/latest/test_validators.py | 77 +- .../azext_k8s_configuration/utils.py | 145 ++ .../azext_k8s_configuration/validators.py | 276 +++ .../vendored_sdks/__init__.py | 3 - .../vendored_sdks/_configuration.py | 14 +- .../_source_control_configuration_client.py | 310 ++- .../vendored_sdks/_version.py | 2 +- .../vendored_sdks/aio/_configuration.py | 16 +- .../_source_control_configuration_client.py | 309 ++- .../aio/operations/_operations.py | 11 +- ...ource_control_configurations_operations.py | 56 +- .../vendored_sdks/models.py | 8 + .../v2020_07_01_preview/__init__.py | 19 + .../v2020_07_01_preview/_configuration.py | 71 + .../_source_control_configuration_client.py | 99 + .../v2020_07_01_preview/_version.py} | 16 +- .../v2020_07_01_preview/aio/__init__.py | 10 + .../v2020_07_01_preview/aio/_configuration.py | 67 + .../_source_control_configuration_client.py | 92 + .../aio/operations/__init__.py | 17 + .../aio/operations/_extensions_operations.py | 433 ++++ .../aio/operations/_operations.py | 105 + ...ource_control_configurations_operations.py | 420 ++++ .../v2020_07_01_preview/models/__init__.py | 99 + .../v2020_07_01_preview/models/_models.py | 817 ++++++++ .../v2020_07_01_preview/models/_models_py3.py | 890 ++++++++ ...urce_control_configuration_client_enums.py | 102 + .../operations/__init__.py | 17 + .../operations/_extensions_operations.py | 442 ++++ .../operations/_operations.py | 110 + ...ource_control_configurations_operations.py | 429 ++++ .../v2020_10_01_preview/__init__.py | 19 + .../v2020_10_01_preview/_configuration.py | 71 + .../_source_control_configuration_client.py | 94 + .../v2020_10_01_preview/_version.py | 9 + .../v2020_10_01_preview/aio/__init__.py | 10 + .../v2020_10_01_preview/aio/_configuration.py | 67 + .../_source_control_configuration_client.py | 87 + .../aio}/operations/__init__.py | 0 .../aio/operations/_operations.py | 105 + ...ource_control_configurations_operations.py | 420 ++++ .../v2020_10_01_preview/models/__init__.py | 69 + .../v2020_10_01_preview/models/_models.py | 506 +++++ .../v2020_10_01_preview/models/_models_py3.py | 549 +++++ ...urce_control_configuration_client_enums.py | 78 + .../operations/__init__.py | 15 + .../operations/_operations.py | 110 + ...ource_control_configurations_operations.py | 429 ++++ .../vendored_sdks/v2021_03_01/__init__.py | 19 + .../v2021_03_01/_configuration.py | 71 + .../_source_control_configuration_client.py | 94 + .../vendored_sdks/v2021_03_01/_version.py | 9 + .../vendored_sdks/v2021_03_01/aio/__init__.py | 10 + .../v2021_03_01/aio/_configuration.py | 67 + .../_source_control_configuration_client.py | 87 + .../v2021_03_01/aio/operations/__init__.py | 15 + .../v2021_03_01/aio/operations/_operations.py | 105 + ...ource_control_configurations_operations.py | 420 ++++ .../{ => v2021_03_01}/models/__init__.py | 0 .../{ => v2021_03_01}/models/_models.py | 0 .../{ => v2021_03_01}/models/_models_py3.py | 0 ...urce_control_configuration_client_enums.py | 0 .../v2021_03_01/operations/__init__.py | 15 + .../operations/_operations.py | 0 ...ource_control_configurations_operations.py | 0 .../v2021_05_01_preview/__init__.py | 19 + .../v2021_05_01_preview/_configuration.py | 71 + .../_source_control_configuration_client.py | 124 ++ .../v2021_05_01_preview/_version.py | 9 + .../v2021_05_01_preview/aio/__init__.py | 10 + .../v2021_05_01_preview/aio/_configuration.py | 67 + .../_source_control_configuration_client.py | 117 ++ .../aio/operations/__init__.py | 27 + .../_cluster_extension_type_operations.py | 114 ++ .../_cluster_extension_types_operations.py | 122 ++ .../_extension_type_versions_operations.py | 117 ++ .../aio/operations/_extensions_operations.py | 495 +++++ .../_location_extension_types_operations.py | 113 ++ .../_operation_status_operations.py | 204 ++ .../aio/operations/_operations.py | 105 + ...ource_control_configurations_operations.py | 420 ++++ .../v2021_05_01_preview/models/__init__.py | 124 ++ .../v2021_05_01_preview/models/_models.py | 1056 ++++++++++ .../v2021_05_01_preview/models/_models_py3.py | 1144 +++++++++++ ...urce_control_configuration_client_enums.py | 118 ++ .../operations/__init__.py | 27 + .../_cluster_extension_type_operations.py | 119 ++ .../_cluster_extension_types_operations.py | 127 ++ .../_extension_type_versions_operations.py | 122 ++ .../operations/_extensions_operations.py | 505 +++++ .../_location_extension_types_operations.py | 118 ++ .../_operation_status_operations.py | 210 ++ .../operations/_operations.py | 110 + ...ource_control_configurations_operations.py | 429 ++++ .../vendored_sdks/v2021_09_01/__init__.py | 19 + .../v2021_09_01/_configuration.py | 71 + .../_source_control_configuration_client.py | 99 + .../vendored_sdks/v2021_09_01/_version.py | 9 + .../vendored_sdks/v2021_09_01/aio/__init__.py | 10 + .../v2021_09_01/aio/_configuration.py | 67 + .../_source_control_configuration_client.py | 92 + .../v2021_09_01/aio/operations/__init__.py | 17 + .../aio/operations/_extensions_operations.py | 645 ++++++ .../_operation_status_operations.py | 204 ++ .../v2021_09_01/aio/operations/_operations.py | 106 + .../v2021_09_01/models/__init__.py | 86 + .../v2021_09_01/models/_models.py | 739 +++++++ .../v2021_09_01/models/_models_py3.py | 804 ++++++++ ...urce_control_configuration_client_enums.py | 65 + .../v2021_09_01/operations/__init__.py | 17 + .../operations/_extensions_operations.py | 657 ++++++ .../_operation_status_operations.py | 210 ++ .../v2021_09_01/operations/_operations.py | 111 + .../v2021_11_01_preview/__init__.py | 19 + .../v2021_11_01_preview/_configuration.py | 71 + .../_source_control_configuration_client.py | 134 ++ .../v2021_11_01_preview/_version.py | 9 + .../v2021_11_01_preview/aio/__init__.py | 10 + .../v2021_11_01_preview/aio/_configuration.py | 67 + .../_source_control_configuration_client.py | 127 ++ .../aio/operations/__init__.py | 31 + .../_cluster_extension_type_operations.py | 114 ++ .../_cluster_extension_types_operations.py | 127 ++ .../_extension_type_versions_operations.py | 117 ++ .../aio/operations/_extensions_operations.py | 645 ++++++ ...flux_config_operation_status_operations.py | 118 ++ .../_flux_configurations_operations.py | 647 ++++++ .../_location_extension_types_operations.py | 113 ++ .../_operation_status_operations.py | 204 ++ .../aio/operations/_operations.py | 105 + ...ource_control_configurations_operations.py | 420 ++++ .../v2021_11_01_preview/models/__init__.py | 169 ++ .../v2021_11_01_preview/models/_models.py | 1637 +++++++++++++++ .../v2021_11_01_preview/models/_models_py3.py | 1789 +++++++++++++++++ ...urce_control_configuration_client_enums.py | 145 ++ .../operations/__init__.py | 31 + .../_cluster_extension_type_operations.py | 119 ++ .../_cluster_extension_types_operations.py | 132 ++ .../_extension_type_versions_operations.py | 122 ++ .../operations/_extensions_operations.py | 657 ++++++ ...flux_config_operation_status_operations.py | 123 ++ .../_flux_configurations_operations.py | 659 ++++++ .../_location_extension_types_operations.py | 118 ++ .../_operation_status_operations.py | 210 ++ .../operations/_operations.py | 110 + ...ource_control_configurations_operations.py | 429 ++++ src/k8s-configuration/setup.py | 3 +- testing/Test.ps1 | 61 +- testing/pipeline/k8s-custom-pipelines.yml | 122 +- testing/pipeline/templates/run-test.yml | 112 ++ testing/test/configurations/Constants.ps1 | 3 +- .../test/configurations/Flux.HTTPS.Tests.ps1 | 55 + .../configurations/Flux.PrivateKey.Tests.ps1 | 88 + testing/test/configurations/Flux.Tests.ps1 | 61 + testing/test/configurations/Helper.ps1 | 21 + 177 files changed, 31154 insertions(+), 1284 deletions(-) delete mode 100644 .github/pull.yml delete mode 100644 src/k8s-configuration/azext_k8s_configuration/_format.py delete mode 100644 src/k8s-configuration/azext_k8s_configuration/_utils.py delete mode 100644 src/k8s-configuration/azext_k8s_configuration/_validators.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/action.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/confirm.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/consts.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/format.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/providers/FluxConfigurationProvider.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/providers/SourceControlConfigurationProvider.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/providers/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/utils.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/validators.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/_source_control_configuration_client.py rename src/k8s-configuration/azext_k8s_configuration/{_consts.py => vendored_sdks/v2020_07_01_preview/_version.py} (58%) create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/_source_control_configuration_client.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_extensions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_source_control_configurations_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_models.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_models_py3.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_source_control_configuration_client_enums.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_extensions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_source_control_configurations_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_source_control_configuration_client.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_version.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/_source_control_configuration_client.py rename src/k8s-configuration/azext_k8s_configuration/vendored_sdks/{ => v2020_10_01_preview/aio}/operations/__init__.py (100%) create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/operations/_source_control_configurations_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_models.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_models_py3.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_source_control_configuration_client_enums.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/_source_control_configurations_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_source_control_configuration_client.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_version.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/_source_control_configuration_client.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/_source_control_configurations_operations.py rename src/k8s-configuration/azext_k8s_configuration/vendored_sdks/{ => v2021_03_01}/models/__init__.py (100%) rename src/k8s-configuration/azext_k8s_configuration/vendored_sdks/{ => v2021_03_01}/models/_models.py (100%) rename src/k8s-configuration/azext_k8s_configuration/vendored_sdks/{ => v2021_03_01}/models/_models_py3.py (100%) rename src/k8s-configuration/azext_k8s_configuration/vendored_sdks/{ => v2021_03_01}/models/_source_control_configuration_client_enums.py (100%) create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/operations/__init__.py rename src/k8s-configuration/azext_k8s_configuration/vendored_sdks/{ => v2021_03_01}/operations/_operations.py (100%) rename src/k8s-configuration/azext_k8s_configuration/vendored_sdks/{ => v2021_03_01}/operations/_source_control_configurations_operations.py (100%) create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_source_control_configuration_client.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_version.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/_source_control_configuration_client.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_cluster_extension_type_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_cluster_extension_types_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_extension_type_versions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_extensions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_location_extension_types_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_operation_status_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_source_control_configurations_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_models.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_models_py3.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_source_control_configuration_client_enums.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_cluster_extension_type_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_cluster_extension_types_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_extension_type_versions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_extensions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_location_extension_types_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_operation_status_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_source_control_configurations_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_source_control_configuration_client.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_version.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/_source_control_configuration_client.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_extensions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_operation_status_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_models.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_models_py3.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_source_control_configuration_client_enums.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_extensions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_operation_status_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_source_control_configuration_client.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_version.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/_configuration.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/_source_control_configuration_client.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_cluster_extension_type_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_cluster_extension_types_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_extension_type_versions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_extensions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_flux_config_operation_status_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_flux_configurations_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_location_extension_types_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_operation_status_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_source_control_configurations_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_models.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_models_py3.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_source_control_configuration_client_enums.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/__init__.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_cluster_extension_type_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_cluster_extension_types_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_extension_type_versions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_extensions_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_flux_config_operation_status_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_flux_configurations_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_location_extension_types_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_operation_status_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_operations.py create mode 100644 src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_source_control_configurations_operations.py create mode 100644 testing/pipeline/templates/run-test.yml create mode 100644 testing/test/configurations/Flux.HTTPS.Tests.ps1 create mode 100644 testing/test/configurations/Flux.PrivateKey.Tests.ps1 create mode 100644 testing/test/configurations/Flux.Tests.ps1 diff --git a/.github/pull.yml b/.github/pull.yml deleted file mode 100644 index 71e1e286c72..00000000000 --- a/.github/pull.yml +++ /dev/null @@ -1,8 +0,0 @@ -version: 1 -rules: - - base: master - upstream: Azure:master - mergeMethod: hardreset - - base: release - upstream: Azure:master - mergeMethod: hardreset diff --git a/src/dataprotection/azext_dataprotection/manual/version.py b/src/dataprotection/azext_dataprotection/manual/version.py index 7d80efbfc5b..c8d62cb0608 100644 --- a/src/dataprotection/azext_dataprotection/manual/version.py +++ b/src/dataprotection/azext_dataprotection/manual/version.py @@ -1,11 +1,11 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. -# -------------------------------------------------------------------------- - -VERSION = "0.2.0" +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +VERSION = "0.2.0" diff --git a/src/k8s-configuration/HISTORY.rst b/src/k8s-configuration/HISTORY.rst index 237b49c08e2..830db4ca2e2 100644 --- a/src/k8s-configuration/HISTORY.rst +++ b/src/k8s-configuration/HISTORY.rst @@ -3,6 +3,11 @@ Release History =============== +1.2.0 +++++++++++++++++++ +* Add Flux v2 support with command subgroups +* Add update support to Flux v2 resources + 1.1.1 ++++++++++++++++++ * Enable helm-operator chart version 1.4.0 diff --git a/src/k8s-configuration/README.rst b/src/k8s-configuration/README.rst index 09ddc9d9bbb..78c42245fd3 100644 --- a/src/k8s-configuration/README.rst +++ b/src/k8s-configuration/README.rst @@ -11,11 +11,57 @@ az extension add --name k8s-configuration ``` ### Included Features -#### Kubernetes Configuration: -Kubernetes SourceControl Configuration: [more info](https://docs.microsoft.com/en-us/azure/kubernetessconfiguration/)\ + +#### Flux Configuration (Flux v2): +Flux Configuration (Flux v1) Configuration: [more info](https://docs.microsoft.com/en-us/azure/kubernetessconfiguration/)\ +*Examples:* + +##### Create a Flux Configuration (Flux v2) +``` +az k8s-configuration create flux \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType \ + --name configurationName \ + --namespace configurationNamespace \ + --scope cluster + --kind git \ + --url https://github.com/Azure/arc-k8s-demo \ + --branch main \ + --kustomization name=my-kustomization +``` + +##### Get a Flux Configuration (Flux v2) +``` +az k8s-configuration flux show \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType \ + --name configurationName +``` + +##### Delete a Flux Configuration (Flux v2) +``` +az k8s-configuration flux delete \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType \ + --name configurationName +``` + +##### List all Flux Configuration (Flux v2) on a cluster +``` +az k8s-configuration flux list \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType +``` + +#### Source Control Configuration (Flux v1): +Source Control Configuration (Flux v1) Configuration: [more info](https://docs.microsoft.com/en-us/azure/kubernetessconfiguration/)\ *Examples:* -##### Create a KubernetesConfiguration +##### Create a Source Control Configuration (Flux v1) ``` az k8s-configuration create \ --resource-group groupName \ @@ -31,7 +77,7 @@ az k8s-configuration create \ --helm-operator-params chartParameters ``` -##### Get a KubernetesConfiguration +##### Get a Source Control Configuration (Flux v1) ``` az k8s-configuration show \ --resource-group groupName \ @@ -40,7 +86,7 @@ az k8s-configuration show \ --name configurationName ``` -##### Delete a KubernetesConfiguration +##### Delete a Source Control Configuration (Flux v1) ``` az k8s-configuration delete \ --resource-group groupName \ @@ -49,7 +95,7 @@ az k8s-configuration delete \ --name configurationName ``` -##### Update a KubernetesConfiguration +##### Update a Source Control Configuration (Flux v1) ``` az k8s-configuration create \ --resource-group groupName \ @@ -63,7 +109,7 @@ az k8s-configuration create \ --helm-operator-params chartParameters ``` -##### List all KubernetesConfigurations of a cluster +##### List all Source Control Configuration (Flux v1) on a cluster ``` az k8s-configuration list \ --resource-group groupName \ diff --git a/src/k8s-configuration/azext_k8s_configuration/__init__.py b/src/k8s-configuration/azext_k8s_configuration/__init__.py index db560042e65..ea33c66418f 100644 --- a/src/k8s-configuration/azext_k8s_configuration/__init__.py +++ b/src/k8s-configuration/azext_k8s_configuration/__init__.py @@ -12,12 +12,12 @@ class K8sConfigurationCommandsLoader(AzCommandsLoader): def __init__(self, cli_ctx=None): from azure.cli.core.commands import CliCommandType - from azext_k8s_configuration._client_factory import cf_k8s_configuration + from azext_k8s_configuration._client_factory import k8s_configuration_client k8s_configuration_custom = CliCommandType( operations_tmpl='azext_k8s_configuration.custom#{}', - client_factory=cf_k8s_configuration) - super(K8sConfigurationCommandsLoader, self).__init__(cli_ctx=cli_ctx, - custom_command_type=k8s_configuration_custom) + client_factory=k8s_configuration_client) + super().__init__(cli_ctx=cli_ctx, + custom_command_type=k8s_configuration_custom) def load_command_table(self, args): from azext_k8s_configuration.commands import load_command_table diff --git a/src/k8s-configuration/azext_k8s_configuration/_client_factory.py b/src/k8s-configuration/azext_k8s_configuration/_client_factory.py index 86cbd33b7f4..372adc3f1fd 100644 --- a/src/k8s-configuration/azext_k8s_configuration/_client_factory.py +++ b/src/k8s-configuration/azext_k8s_configuration/_client_factory.py @@ -4,17 +4,45 @@ # -------------------------------------------------------------------------------------------- from azure.cli.core.commands.client_factory import get_mgmt_service_client +from azure.cli.core.profiles import ResourceType +from . import consts -def cf_k8s_configuration(cli_ctx, *_): +def k8s_configuration_client(cli_ctx, **kwargs): from azext_k8s_configuration.vendored_sdks import SourceControlConfigurationClient - return get_mgmt_service_client(cli_ctx, SourceControlConfigurationClient) + return get_mgmt_service_client(cli_ctx, SourceControlConfigurationClient, **kwargs) -def cf_k8s_configuration_operation(cli_ctx, _): - return cf_k8s_configuration(cli_ctx).source_control_configurations +def k8s_configuration_fluxconfig_client(cli_ctx, *_): + return k8s_configuration_client(cli_ctx, api_version=consts.FLUXCONFIG_API_VERSION).flux_configurations -def _resource_providers_client(cli_ctx): +def k8s_configuration_sourcecontrol_client(cli_ctx, *_): + return k8s_configuration_client( + cli_ctx, + api_version=consts.SOURCE_CONTROL_API_VERSION + ).source_control_configurations + + +def k8s_configuration_extension_client(cli_ctx, *_): + return k8s_configuration_client(cli_ctx, api_version=consts.EXTENSION_API_VERSION).extensions + + +def resource_providers_client(cli_ctx): from azure.mgmt.resource import ResourceManagementClient return get_mgmt_service_client(cli_ctx, ResourceManagementClient).providers + + +def cf_resource_groups(cli_ctx, subscription_id=None): + return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES, + subscription_id=subscription_id).resource_groups + + +def cf_resources(cli_ctx, subscription_id=None): + return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES, + subscription_id=subscription_id).resources + + +def cf_log_analytics(cli_ctx, subscription_id=None): + from azure.mgmt.loganalytics import LogAnalyticsManagementClient # pylint: disable=no-name-in-module + return get_mgmt_service_client(cli_ctx, LogAnalyticsManagementClient, subscription_id=subscription_id) diff --git a/src/k8s-configuration/azext_k8s_configuration/_format.py b/src/k8s-configuration/azext_k8s_configuration/_format.py deleted file mode 100644 index a1ea04822d8..00000000000 --- a/src/k8s-configuration/azext_k8s_configuration/_format.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -from collections import OrderedDict - - -def k8s_configuration_list_table_format(results): - return [__get_table_row(result) for result in results] - - -def k8s_configuration_show_table_format(result): - return __get_table_row(result) - - -def __get_table_row(result): - return OrderedDict([ - ('name', result['name']), - ('repositoryUrl', result['repositoryUrl']), - ('operatorName', result['operatorInstanceName']), - ('operatorNamespace', result['operatorNamespace']), - ('scope', result['operatorScope']), - ('provisioningState', result['provisioningState']) - ]) diff --git a/src/k8s-configuration/azext_k8s_configuration/_help.py b/src/k8s-configuration/azext_k8s_configuration/_help.py index a01183b8f5f..91c50291288 100644 --- a/src/k8s-configuration/azext_k8s_configuration/_help.py +++ b/src/k8s-configuration/azext_k8s_configuration/_help.py @@ -6,17 +6,16 @@ from knack.help_files import helps # pylint: disable=unused-import - helps['k8s-configuration'] = """ type: group - short-summary: Commands to manage Kubernetes configuration. + short-summary: Commands to manage resources from Microsoft.KubernetesConfiguration. """ helps['k8s-configuration create'] = """ type: command - short-summary: Create a Kubernetes configuration. + short-summary: Create a Flux v1 Kubernetes configuration (This command is for Flux v1, to use the newer Flux v2, run "az k8s-configuration flux create"). examples: - - name: Create a Kubernetes configuration + - name: Create a Flux v1 Kubernetes configuration text: |- az k8s-configuration create --resource-group MyResourceGroup --cluster-name MyClusterName \\ --cluster-type connectedClusters --name MyGitConfig --operator-instance-name OperatorInst01 \\ @@ -29,9 +28,9 @@ helps['k8s-configuration list'] = """ type: command - short-summary: List Kubernetes configurations. + short-summary: List Flux v1 Kubernetes configurations (This command is for Flux v1, to use the newer Flux v2, run "az k8s-configuration flux list"). examples: - - name: List all Kubernetes configurations of a cluster + - name: List Flux v1 Kubernetes configuration text: |- az k8s-configuration list --resource-group MyResourceGroup --cluster-name MyClusterName \\ --cluster-type connectedClusters @@ -39,9 +38,9 @@ helps['k8s-configuration delete'] = """ type: command - short-summary: Delete a Kubernetes configuration. + short-summary: Delete a Flux v1 Kubernetes configuration (This command is for Flux v1, to use the newer Flux v2, run "az k8s-configuration flux delete"). examples: - - name: Delete a Kubernetes configuration + - name: Delete a Flux v1 Kubernetes configuration text: |- az k8s-configuration delete --resource-group MyResourceGroup --cluster-name MyClusterName \\ --cluster-type connectedClusters --name MyConfigurationName @@ -49,22 +48,129 @@ helps['k8s-configuration show'] = """ type: command - short-summary: Show details of a Kubernetes configuration. + short-summary: Show details of a Flux v1 Kubernetes configuration (This command is for Flux v1, to use the newer Flux v2, run "az k8s-configuration flux show"). examples: - - name: Show a Kubernetes configuration + - name: Show details of a Flux v1 Kubernetes configuration text: |- az k8s-configuration show --resource-group MyResourceGroup --cluster-name MyClusterName \\ --cluster-type connectedClusters --name MyConfigurationName """ -helps['k8s-configuration update'] = """ +helps['k8s-configuration flux'] = """ + type: group + short-summary: Commands to manage Flux v2 Kubernetes configurations. +""" + +helps['k8s-configuration flux create'] = """ + type: command + short-summary: Create a Kubernetes Flux v2 Configuration. + examples: + - name: Create a Kubernetes v2 Flux Configuration + text: |- + az k8s-configuration flux create --resource-group my-resource-group \\ + --cluster-name mycluster --cluster-type connectedClusters \\ + --name myconfig --scope cluster --namespace my-namespace \\ + --kind git --url https://github.com/Azure/arc-k8s-demo \\ + --branch main --kustomization name=my-kustomization +""" + +helps['k8s-configuration flux update'] = """ + type: command + short-summary: Update a Kubernetes Flux v2 Configuration. + examples: + - name: Update a Kubernetes v2 Flux Configuration + text: |- + az k8s-configuration flux update --resource-group my-resource-group \\ + --cluster-name mycluster --cluster-type connectedClusters --name myconfig \\ + --url https://github.com/Azure/arc-k8s-demo --branch main \\ + --kustomization name=my-kustomization path=./my/new-path +""" + +helps['k8s-configuration flux list'] = """ + type: command + short-summary: List Kubernetes Flux v2 Configurations. + examples: + - name: List all Kubernetes Flux v2 Configurations on a cluster + text: |- + az k8s-configuration flux list --resource-group my-resource-group \\ + --cluster-name mycluster --cluster-type connectedClusters +""" + +helps['k8s-configuration flux show'] = """ + type: command + short-summary: Show a Kubernetes Flux v2 Configuration. + examples: + - name: Show details of a Kubernetes Flux v2 Configuration + text: |- + az k8s-configuration flux show --resource-group my-resource-group \\ + --cluster-name mycluster --cluster-type connectedClusters --name myconfig +""" + +helps['k8s-configuration flux delete'] = """ + type: command + short-summary: Delete a Kubernetes Flux v2 Configuration. + examples: + - name: Delete an existing Kubernetes Flux v2 Configuration + text: |- + az k8s-configuration flux delete --resource-group my-resource-group \\ + --cluster-name mycluster --cluster-type connectedClusters --name myconfig +""" + +helps['k8s-configuration flux kustomization'] = """ + type: group + short-summary: Commands to manage Kustomizations associated with Flux v2 Kubernetes configurations. +""" + +helps['k8s-configuration flux kustomization create'] = """ + type: command + short-summary: Create a Kustomization associated with a Kubernetes Flux v2 Configuration. + examples: + - name: Create a Kustomization associated wiht a Kubernetes v2 Flux Configuration + text: |- + az k8s-configuration flux kustomization create --resource-group my-resource-group \\ + --cluster-name mycluster --cluster-type connectedClusters --name myconfig \\ + --kustomization-name my-kustomization-2 --path ./my/path --prune --force +""" + +helps['k8s-configuration flux kustomization update'] = """ + type: command + short-summary: Update a Kustomization associated with a Kubernetes Flux v2 Configuration. + examples: + - name: Update a Kustomization associated with a Kubernetes v2 Flux Configuration + text: |- + az k8s-configuration flux kustomization update --resource-group my-resource-group \\ + --cluster-name mycluster --cluster-type connectedClusters --name myconfig \\ + --kustomization-name my-kustomization --path ./my/new-path --prune --force +""" + +helps['k8s-configuration flux kustomization list'] = """ + type: command + short-summary: List Kustomizations associated with a Kubernetes Flux v2 Configuration. + examples: + - name: List all Kustomizations associated with a Kubernetes Flux v2 Configuration on a cluster + text: |- + az k8s-configuration flux kustomization list --resource-group my-resource-group \\ + --cluster-name mycluster --name myconfig --cluster-type connectedClusters +""" + +helps['k8s-configuration flux kustomization show'] = """ + type: command + short-summary: Show a Kustomization associated with a Flux v2 Configuration. + examples: + - name: Show details of a Kustomization associated with a Kubernetes Flux v2 Configuration + text: |- + az k8s-configuration flux kustomization show --resource-group my-resource-group \\ + --cluster-name mycluster --cluster-type connectedClusters --name myconfig \\ + --kustomization-name my-kustomization +""" + +helps['k8s-configuration flux kustomization delete'] = """ type: command - short-summary: Update a Kubernetes configuration. + short-summary: Delete a Kustomization associated with a Kubernetes Flux v2 Configuration. examples: - - name: Update an existing Kubernetes configuration + - name: Delete an existing Kustomization associated with a Kubernetes Flux v2 Configuration text: |- - az k8s-configuration update --resource-group MyResourceGroup --cluster-name MyClusterName \\ - --cluster-type connectedClusters --name MyConfigurationName --enable-helm-operator \\ - --repository-url git://github.com/fluxHowTo/flux-get-started --operator-params "'--git-readonly'" \\ - --helm-operator-chart-version 1.4.0 --helm-operator-params '--set helm.versions=v3' + az k8s-configuration flux kustomization delete --resource-group my-resource-group \\ + --cluster-name mycluster --cluster-type connectedClusters --name myconfig \\ + --kustomization-name my-kustomization """ diff --git a/src/k8s-configuration/azext_k8s_configuration/_params.py b/src/k8s-configuration/azext_k8s_configuration/_params.py index c9faab38cfb..bcb72dd2d54 100644 --- a/src/k8s-configuration/azext_k8s_configuration/_params.py +++ b/src/k8s-configuration/azext_k8s_configuration/_params.py @@ -3,44 +3,134 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- # pylint: disable=line-too-long +# pylint: disable=too-many-statements -from knack.arguments import CLIArgumentType - +from azure.cli.core.commands.validators import get_default_location_from_resource_group from azure.cli.core.commands.parameters import ( - get_three_state_flag, get_enum_type, + get_three_state_flag, tags_type ) +from .validators import ( + validate_configuration_name, + validate_fluxconfig_name, + validate_namespace, + validate_operator_instance_name, + validate_operator_namespace +) -from azure.cli.core.commands.validators import get_default_location_from_resource_group -from ._validators import _validate_configuration_type, _validate_operator_namespace, _validate_operator_instance_name +from .action import ( + KustomizationAddAction, +) +from . import consts def load_arguments(self, _): - sourcecontrolconfiguration_type = CLIArgumentType(help='Name of the Kubernetes Configuration') - with self.argument_context('k8s-configuration') as c: c.argument('tags', tags_type) - c.argument('location', - validator=get_default_location_from_resource_group) - c.argument('name', sourcecontrolconfiguration_type, - options_list=['--name', '-n']) + c.argument('location', validator=get_default_location_from_resource_group) c.argument('cluster_name', options_list=['--cluster-name', '-c'], help='Name of the Kubernetes cluster') c.argument('cluster_type', + options_list=['--cluster-type', '-t'], arg_type=get_enum_type(['connectedClusters', 'managedClusters']), - help='Specify Arc clusters or AKS managed clusters.') + help='Specify Arc connected clusters or AKS managed clusters.') + + with self.argument_context('k8s-configuration flux') as c: + c.argument('name', + options_list=['--name', '-n'], + help='Name of the flux configuration', + validator=validate_fluxconfig_name) + c.argument('scope', + options_list=['--scope', '-s'], + arg_type=get_enum_type(['namespace', 'cluster']), + help="Specify scope of the operator to be 'namespace' or 'cluster'") + c.argument('namespace', + help='Namespace to deploy the configuration', + options_list=['--namespace', '--ns'], + validator=validate_namespace) + c.argument('kind', + arg_type=get_enum_type([consts.GIT]), + help='Source kind to reconcile') + c.argument('url', + options_list=['--url', '-u'], + help='URL of the git repo source to reconcile') + c.argument('timeout', + help='Maximum time to reconcile the source before timing out') + c.argument('sync_interval', + options_list=['--interval', '--sync-interval'], + help='Time between reconciliations of the source on the cluster') + c.argument('branch', + arg_group="Git Repo Ref", + help='Branch within the git source to reconcile with the cluster') + c.argument('tag', + arg_group="Git Repo Ref", + help='Tag within the git source to reconcile with the cluster') + c.argument('semver', + arg_group="Git Repo Ref", + help='Semver range within the git source to reconcile with the cluster') + c.argument('commit', + arg_group="Git Repo Ref", + help='Commit within the git source to reconcile with the cluster') + c.argument('ssh_private_key', + arg_group="Auth", + help='Base64-encoded private ssh key for private repository sync') + c.argument('ssh_private_key_file', + arg_group="Auth", + help='Filepath to private ssh key for private repository sync') + c.argument('https_user', + arg_group="Auth", + help='HTTPS username for private repository sync') + c.argument('https_key', + arg_group="Auth", + help='HTTPS token/password for private repository sync') + c.argument('https_ca_cert', + arg_group="Auth", + help='Base64-encoded HTTPS CA certificate for TLS communication with private repository sync') + c.argument('https_ca_cert_file', + arg_group="Auth", + help='Filepath to HTTPS CA certificate file for TLS communication with private repository sync') + c.argument('known_hosts', + arg_group="Auth", + help='Base64-encoded known_hosts data containing public SSH keys required to access private Git instances') + c.argument('known_hosts_file', + arg_group="Auth", + help='Filepath to known_hosts contents containing public SSH keys required to access private Git instances') + c.argument('local_auth_ref', + options_list=['--local-auth-ref', '--local-ref'], + arg_group="Auth", + help='Local reference to a kubernetes secret in the configuration namespace to use for communication to the source') + c.argument('suspend', + arg_type=get_three_state_flag(), + help='Suspend the reconciliation of the source and kustomizations associated with this configuration') + c.argument('kustomization', + action=KustomizationAddAction, + options_list=['--kustomization', '-k'], + help="Define kustomizations to sync sources with parameters ['name', 'path', 'depends_on', 'timeout', 'sync_interval', 'retry_interval', 'prune', 'force']", + nargs='+') + + with self.argument_context('k8s-configuration flux delete') as c: + c.argument('force', + arg_type=get_three_state_flag(), + help='Force delete the flux configuration from the cluster.') + c.argument('yes', + options_list=['--yes', '-y'], + help='Do not prompt for confirmation') + + with self.argument_context('k8s-configuration') as c: + c.argument('name', + options_list=['--name', '-n'], + help='Name of the configuration', + validator=validate_configuration_name) + + with self.argument_context('k8s-configuration create') as c: c.argument('repository_url', options_list=['--repository-url', '-u'], help='Url of the source control repository') c.argument('scope', arg_type=get_enum_type(['namespace', 'cluster']), help='''Specify scope of the operator to be 'namespace' or 'cluster' ''') - c.argument('configuration_type', - validator=_validate_configuration_type, - arg_type=get_enum_type(['sourceControlConfiguration']), - help='Type of the configuration') c.argument('enable_helm_operator', arg_group="Helm Operator", arg_type=get_three_state_flag(), @@ -60,11 +150,11 @@ def load_arguments(self, _): c.argument('operator_instance_name', arg_group="Operator", help='Instance name of the Operator', - validator=_validate_operator_instance_name) + validator=validate_operator_instance_name) c.argument('operator_namespace', arg_group="Operator", help='Namespace in which to install the Operator', - validator=_validate_operator_namespace) + validator=validate_operator_namespace) c.argument('operator_type', arg_group="Operator", help='''Type of the operator. Valid value is 'flux' ''') @@ -86,3 +176,31 @@ def load_arguments(self, _): c.argument('ssh_known_hosts_file', arg_group="Auth", help='Specify filepath to known_hosts contents containing public SSH keys required to access private Git instances') + + with self.argument_context('k8s-configuration flux kustomization') as c: + c.argument('kustomization_name', + options_list=['--kustomization-name', '-k'], + help='Specify the name of the kustomization to target') + c.argument('path', + help='Specify the path in the source that the kustomization should apply') + c.argument('dependencies', + options_list=['--depends', '--dependencies', "--depends-on"], + help='Comma-separated list of kustomization dependencies') + c.argument('timeout', + help='Maximum time to reconcile the kustomization before timing out') + c.argument('sync_interval', + options_list=['--interval', '--sync-interval'], + help='Time between reconciliations of the kustomization on the cluster') + c.argument('retry_interval', + help='Time between reconciliations of the kustomization on the cluster on failures, defaults to --sync-interval') + c.argument('prune', + arg_type=get_three_state_flag(), + help='Garbage collect resources deployed by the kustomization on the cluster') + c.argument('force', + arg_type=get_three_state_flag(), + help='Re-create resources that cannot be updated on the cluster (i.e. jobs)') + + with self.argument_context('k8s-configuration flux kustomization delete') as c: + c.argument('yes', + options_list=['--yes', '-y'], + help='Do not prompt for confirmation') diff --git a/src/k8s-configuration/azext_k8s_configuration/_utils.py b/src/k8s-configuration/azext_k8s_configuration/_utils.py deleted file mode 100644 index 6ad8e600636..00000000000 --- a/src/k8s-configuration/azext_k8s_configuration/_utils.py +++ /dev/null @@ -1,61 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -import base64 -from azure.cli.core.azclierror import MutuallyExclusiveArgumentError, InvalidArgumentValueError - - -def _get_cluster_type(cluster_type): - if cluster_type.lower() == 'connectedclusters': - return 'Microsoft.Kubernetes' - # Since cluster_type is an enum of only two values, if not connectedClusters, it will be managedClusters. - return 'Microsoft.ContainerService' - - -def _fix_compliance_state(config): - # If we get Compliant/NonCompliant as compliance_sate, change them before returning - if config.compliance_status.compliance_state.lower() == 'noncompliant': - config.compliance_status.compliance_state = 'Failed' - elif config.compliance_status.compliance_state.lower() == 'compliant': - config.compliance_status.compliance_state = 'Installed' - - return config - - -def _get_data_from_key_or_file(key, filepath): - if key != '' and filepath != '': - raise MutuallyExclusiveArgumentError( - 'Error! Both textual key and key filepath cannot be provided', - 'Try providing the file parameter without providing the plaintext parameter') - data = '' - if filepath != '': - data = _read_key_file(filepath) - elif key != '': - data = key - return data - - -def _read_key_file(path): - try: - with open(path, "r") as myfile: # user passed in filename - data_list = myfile.readlines() # keeps newline characters intact - data_list_len = len(data_list) - if (data_list_len) <= 0: - raise Exception("File provided does not contain any data") - raw_data = ''.join(data_list) - return _to_base64(raw_data) - except Exception as ex: - raise InvalidArgumentValueError( - 'Error! Unable to read key file specified with: {0}'.format(ex), - 'Verify that the filepath specified exists and contains valid utf-8 data') from ex - - -def _from_base64(base64_str): - return base64.b64decode(base64_str) - - -def _to_base64(raw_data): - bytes_data = raw_data.encode('utf-8') - return base64.b64encode(bytes_data).decode('utf-8') diff --git a/src/k8s-configuration/azext_k8s_configuration/_validators.py b/src/k8s-configuration/azext_k8s_configuration/_validators.py deleted file mode 100644 index 47c6b97ca3a..00000000000 --- a/src/k8s-configuration/azext_k8s_configuration/_validators.py +++ /dev/null @@ -1,143 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -import re -import io -from azure.cli.core.azclierror import InvalidArgumentValueError, MutuallyExclusiveArgumentError - -from knack.log import get_logger -from azext_k8s_configuration._client_factory import _resource_providers_client -from azext_k8s_configuration._utils import _from_base64 -import azext_k8s_configuration._consts as consts -from urllib.parse import urlparse -from paramiko.hostkeys import HostKeyEntry -from paramiko.ed25519key import Ed25519Key -from paramiko.ssh_exception import SSHException -from Crypto.PublicKey import RSA, ECC, DSA - - -logger = get_logger(__name__) - - -# Parameter-Level Validation -def _validate_configuration_type(configuration_type): - if configuration_type.lower() != 'sourcecontrolconfiguration': - raise InvalidArgumentValueError( - 'Invalid configuration-type', - 'Try specifying the valid value "sourceControlConfiguration"') - - -def _validate_operator_namespace(namespace): - if namespace.operator_namespace: - _validate_k8s_name(namespace.operator_namespace, "--operator-namespace", 23) - - -def _validate_operator_instance_name(namespace): - if namespace.operator_instance_name: - _validate_k8s_name(namespace.operator_instance_name, "--operator-instance-name", 23) - - -# Create Parameter Validation -def _validate_configuration_name(configuration_name): - _validate_k8s_name(configuration_name, "--name", 63) - - -# Helper -def _validate_k8s_name(param_value, param_name, max_len): - if len(param_value) > max_len: - raise InvalidArgumentValueError( - 'Error! Invalid {0}'.format(param_name), - 'Parameter {0} can be a maximum of {1} characters'.format(param_name, max_len)) - if not re.match(r'^[a-z0-9]([-a-z0-9]*[a-z0-9])?$', param_value): - if param_value[0] == "-" or param_value[-1] == "-": - raise InvalidArgumentValueError( - 'Error! Invalid {0}'.format(param_name), - 'Parameter {0} cannot begin or end with a hyphen'.format(param_name)) - raise InvalidArgumentValueError( - 'Error! Invalid {0}'.format(param_name), - 'Parameter {0} can only contain lowercase alphanumeric characters and hyphens'.format(param_name)) - - -def _validate_url_with_params(repository_url, ssh_private_key_set, known_hosts_contents_set, https_auth_set): - scheme = urlparse(repository_url).scheme - - if scheme.lower() in ('http', 'https'): - if ssh_private_key_set: - raise MutuallyExclusiveArgumentError( - 'Error! An --ssh-private-key cannot be used with an http(s) url', - 'Verify the url provided is a valid ssh url and not an http(s) url') - if known_hosts_contents_set: - raise MutuallyExclusiveArgumentError( - 'Error! --ssh-known-hosts cannot be used with an http(s) url', - 'Verify the url provided is a valid ssh url and not an http(s) url') - if not https_auth_set and scheme == 'https': - logger.warning('Warning! https url is being used without https auth params, ensure the repository ' - 'url provided is not a private repo') - else: - if https_auth_set: - raise MutuallyExclusiveArgumentError( - 'Error! https auth (--https-user and --https-key) cannot be used with a non-http(s) url', - 'Verify the url provided is a valid http(s) url and not an ssh url') - - -def _validate_known_hosts(knownhost_data): - try: - knownhost_str = _from_base64(knownhost_data).decode('utf-8') - except Exception as ex: - raise InvalidArgumentValueError( - 'Error! ssh known_hosts is not a valid utf-8 base64 encoded string', - 'Verify that the string provided safely decodes into a valid utf-8 format') from ex - lines = knownhost_str.split('\n') - for line in lines: - line = line.strip(' ') - line_len = len(line) - if (line_len == 0) or (line[0] == "#"): - continue - try: - host_key = HostKeyEntry.from_line(line) - if not host_key: - raise Exception('not enough fields found in known_hosts line') - except Exception as ex: - raise InvalidArgumentValueError( - 'Error! ssh known_hosts provided in wrong format', - 'Verify that all lines in the known_hosts contents are provided in a valid sshd(8) format') from ex - - -def _validate_private_key(ssh_private_key_data): - try: - RSA.import_key(_from_base64(ssh_private_key_data)) - return - except ValueError: - try: - ECC.import_key(_from_base64(ssh_private_key_data)) - return - except ValueError: - try: - DSA.import_key(_from_base64(ssh_private_key_data)) - return - except ValueError: - try: - key_obj = io.StringIO(_from_base64(ssh_private_key_data).decode('utf-8')) - Ed25519Key(file_obj=key_obj) - return - except SSHException: - raise InvalidArgumentValueError( - 'Error! --ssh-private-key provided in invalid format', - 'Verify the key provided is a valid PEM-formatted key of type RSA, ECC, DSA, or Ed25519') - - -# pylint: disable=broad-except -def _validate_cc_registration(cmd): - try: - rp_client = _resource_providers_client(cmd.cli_ctx) - registration_state = rp_client.get(consts.PROVIDER_NAMESPACE).registration_state - - if registration_state.lower() != consts.REGISTERED.lower(): - logger.warning("'Source Control Configuration' cannot be used because '%s' provider has not been " - "registered. More details for registering this provider can be found here - " - "https://aka.ms/RegisterKubernetesConfigurationProvider", consts.PROVIDER_NAMESPACE) - except Exception: - logger.warning("Unable to fetch registration state of '%s' provider. " - "Failed to enable 'source control configuration' feature...", consts.PROVIDER_NAMESPACE) diff --git a/src/k8s-configuration/azext_k8s_configuration/action.py b/src/k8s-configuration/azext_k8s_configuration/action.py new file mode 100644 index 00000000000..5ad965b6114 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/action.py @@ -0,0 +1,68 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- +# pylint: disable=protected-access + +import argparse +from azure.cli.core.azclierror import InvalidArgumentValueError +from .vendored_sdks.v2021_11_01_preview.models import KustomizationDefinition, DependsOnDefinition +from .validators import validate_kustomization +from . import consts +from .utils import parse_dependencies, parse_duration + + +class InternalKustomizationDefinition(KustomizationDefinition): + def __init__(self, **kwargs): + self.name = kwargs.get('name', "") + super().__init__(**kwargs) + + def to_KustomizationDefinition(self): + k_dict = dict(self.__dict__) + del k_dict['name'] + del k_dict['additional_properties'] + return KustomizationDefinition(**k_dict) + + +class KustomizationAddAction(argparse._AppendAction): + def __call__(self, parser, namespace, values, option_string=None): + validate_kustomization(values) + model_dependency = [] + sync_interval = None + retry_interval = None + timeout = None + kwargs = {} + for item in values: + try: + key, value = item.split('=', 1) + if key in consts.DEPENDENCY_KEYS: + dependencies = parse_dependencies(value) + for dep in dependencies: + model_dependency.append( + DependsOnDefinition( + kustomization_name=dep + ) + ) + elif key in consts.SYNC_INTERVAL_KEYS: + sync_interval = value + elif key in consts.RETRY_INTERVAL_KEYS: + retry_interval = value + elif key in consts.TIMEOUT_KEYS: + timeout = value + else: + kwargs[key] = value + except ValueError as ex: + raise InvalidArgumentValueError('usage error: {} KEY=VALUE [KEY=VALUE ...]' + .format(option_string)) from ex + super().__call__( + parser, + namespace, + InternalKustomizationDefinition( + depends_on=model_dependency, + sync_interval_in_seconds=parse_duration(sync_interval), + retry_interval_in_seconds=parse_duration(retry_interval), + timeout_in_seconds=parse_duration(timeout), + **kwargs + ), + option_string + ) diff --git a/src/k8s-configuration/azext_k8s_configuration/commands.py b/src/k8s-configuration/azext_k8s_configuration/commands.py index 541dfe3943b..ad471c24069 100644 --- a/src/k8s-configuration/azext_k8s_configuration/commands.py +++ b/src/k8s-configuration/azext_k8s_configuration/commands.py @@ -5,19 +5,47 @@ # pylint: disable=line-too-long from azure.cli.core.commands import CliCommandType -from azext_k8s_configuration._client_factory import (cf_k8s_configuration, cf_k8s_configuration_operation) -from ._format import k8s_configuration_show_table_format, k8s_configuration_list_table_format +from azext_k8s_configuration._client_factory import ( + k8s_configuration_fluxconfig_client, + k8s_configuration_sourcecontrol_client +) +from .format import ( + fluxconfig_list_table_format, + fluxconfig_show_table_format, + fluxconfig_kustomization_list_table_format, + fluxconfig_kustomization_show_table_format, + sourcecontrol_list_table_format, + sourcecontrol_show_table_format +) def load_command_table(self, _): + k8s_configuration_fluxconfig_sdk = CliCommandType( + operations_tmpl='azext_k8s_configuration.vendored_sdks.operations#FluxConfigurationsOperations.{}', + client_factory=k8s_configuration_fluxconfig_client + ) - k8s_configuration_sdk = CliCommandType( + k8s_configuration_sourcecontrol_sdk = CliCommandType( operations_tmpl='azext_k8s_configuration.vendored_sdks.operations#SourceControlConfigurationsOperations.{}', - client_factory=cf_k8s_configuration) + client_factory=k8s_configuration_sourcecontrol_client + ) - with self.command_group('k8s-configuration', k8s_configuration_sdk, client_factory=cf_k8s_configuration_operation) as g: - g.custom_command('create', 'create_k8s_configuration') - g.custom_command('update', 'update_k8s_configuration') - g.custom_command('delete', 'delete_k8s_configuration', confirmation=True) - g.custom_command('list', 'list_k8s_configuration', table_transformer=k8s_configuration_list_table_format) - g.custom_show_command('show', 'show_k8s_configuration', table_transformer=k8s_configuration_show_table_format) + with self.command_group('k8s-configuration flux', k8s_configuration_fluxconfig_sdk, client_factory=k8s_configuration_fluxconfig_client, is_preview=True) as g: + g.custom_command('create', 'flux_config_create', supports_no_wait=True) + g.custom_command('update', 'flux_config_update', supports_no_wait=True) + g.custom_command('list', "flux_config_list", table_transformer=fluxconfig_list_table_format) + g.custom_show_command('show', 'flux_config_show', table_transformer=fluxconfig_show_table_format) + g.custom_command('delete', 'flux_config_delete', supports_no_wait=True) + + with self.command_group('k8s-configuration flux kustomization', k8s_configuration_fluxconfig_sdk, client_factory=k8s_configuration_fluxconfig_client, is_preview=True) as g: + g.custom_command('create', 'flux_config_create_kustomization', supports_no_wait=True) + g.custom_command('update', 'flux_config_update_kustomization', supports_no_wait=True) + g.custom_command('delete', 'flux_config_delete_kustomization', supports_no_wait=True) + g.custom_command('list', 'flux_config_list_kustomization', table_transformer=fluxconfig_kustomization_list_table_format) + g.custom_show_command('show', 'flux_config_show_kustomization', table_transformer=fluxconfig_kustomization_show_table_format) + + with self.command_group('k8s-configuration', k8s_configuration_sourcecontrol_sdk, client_factory=k8s_configuration_sourcecontrol_client) as g: + g.custom_command('create', 'sourcecontrol_create', deprecate_info=self.deprecate(redirect='k8s-configuration flux create')) + g.custom_command('list', 'sourcecontrol_list', table_transformer=sourcecontrol_list_table_format, deprecate_info=self.deprecate(redirect='k8s-configuration flux list')) + g.custom_show_command('show', 'sourcecontrol_show', table_transformer=sourcecontrol_show_table_format, deprecate_info=self.deprecate(redirect='k8s-configuration flux show')) + g.custom_command('delete', 'sourcecontrol_delete', confirmation=True, deprecate_info=self.deprecate(redirect='k8s-configuration flux delete')) diff --git a/src/k8s-configuration/azext_k8s_configuration/confirm.py b/src/k8s-configuration/azext_k8s_configuration/confirm.py new file mode 100644 index 00000000000..2f8d3a6bdd6 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/confirm.py @@ -0,0 +1,12 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.core.util import user_confirmation + + +def user_confirmation_factory(cmd, yes, message="Are you sure you want to perform this operation?"): + if cmd.cli_ctx.config.getboolean('core', 'disable_confirm_prompt', fallback=False): + return + user_confirmation(message, yes=yes) diff --git a/src/k8s-configuration/azext_k8s_configuration/consts.py b/src/k8s-configuration/azext_k8s_configuration/consts.py new file mode 100644 index 00000000000..f008ba2e21c --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/consts.py @@ -0,0 +1,152 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=line-too-long + +# API VERSIONS ----------------------------------------- + +SOURCE_CONTROL_API_VERSION = '2021-03-01' +FLUXCONFIG_API_VERSION = '2021-11-01-preview' +EXTENSION_API_VERSION = "2021-09-01" + +# ERROR/HELP TEXT DEFINITIONS ----------------------------------------- + +KUSTOMIZATION_REQUIRED_VALUES_MISSING_ERROR = "Error! Kustomization definition is invalid, required values {} not found" +KUSTOMIZATION_REQUIRED_VALUES_MISSING_HELP = "Add the required values to the Kustomization object and try again" + +REPOSITORY_REF_REQUIRED_VALUES_MISSING_ERROR = "Error! Repository reference is invalid" +REPOSITORY_REF_REQUIRED_VALUES_MISSING_HELP = "Specifying one of [--branch, --tag, --semver, --commit] is required" + +REPOSITORY_REF_TOO_MANY_VALUES_ERROR = "Error! Repository reference is invalid" +REPOSITORY_REF_TOO_MANY_VALUES_HELP = "Specifying more than one repository ref argument is invalid" + +GIT_REPOSITORY_REQUIRED_VALUES_MISSING_ERROR = "Error! Required property '{}' was not specified for kind 'GitRepository'" +GIT_REPOSITORY_REQUIRED_VALUES_MISSING_HELP = "Add missing required property and try again" + +INVALID_DURATION_ERROR = "Error! Invalid {0}." +INVALID_DURATION_HELP = "Specify a valid ISO8601 duration and try again" + +INVALID_URL_ERROR = "Error! Invalid --url." +INVALID_URL_HELP = "Url must beginwith one of ['http://', 'https://', 'git@', 'ssh://']" + +INVALID_KUBERNETES_NAME_LENGTH_ERROR = "Error! Invalid {0}" +INVALID_KUBERNETES_NAME_LENGTH_HELP = "Parameter {0} can be a maximum of {1} characters. Specify a shorter name and try again." + +INVALID_KUBERNETES_NAME_HYPHEN_ERROR = "Error! Invalid {0}" +INVALID_KUBERNETES_NAME_HYPHEN_HELP = "Parameter {0} cannot begin or end with a hyphen." + +INVALID_KUBERNETES_NAME_PERIOD_ERROR = "Error! Invalid {0}" +INVALID_KUBERNETES_NAME_PERIOD_HELP = "Parameter {0} cannot begin or end with a period." + +INVALID_KUBERNETES_DNS_NAME_ERROR = "Error! Invalid {0}" +INVALID_KUBERNETES_DNS_NAME_HELP = "Parameter {0} can only contain lowercase alphanumeric characters and hyphens" + +INVALID_KUBERNETES_DNS_SUBDOMAIN_NAME_ERROR = "Error! Invalid {0}" +INVALID_KUBERNETES_DNS_SUBDOMAIN_NAME_HELP = "Parameter {0} can only contain lowercase alphanumeric characters, hyphens, and periods" + +DUPLICATE_KUSTOMIZATION_NAME_ERROR = "Error! Invalid kustomization list. Kustomization name '{0}' duplicated in multiple Kustomization objects" +DUPLICATE_KUSTOMIZATION_NAME_HELP = "Ensure that all Kustomization names are unique and try again" + +KUSTOMIZATION_NAME_TOO_LONG_ERROR = "Error! Invalid Kustomization list. Flux configuration name '{0}' combined with kustomization name '{1}' cannot be greater than 62 characters" +KUSTOMIZATION_NAME_TOO_LONG_HELP = "Shorten the flux configuration or the kustomization name and try again" + +CREATE_KUSTOMIZATION_EXIST_ERROR = "Error! Cannot create a kustomization that already exists. Kustomization name '{0}' already exists on configuration '{1}'" +CREATE_KUSTOMIZATION_EXIST_HELP = "You can update an already created kustomization with 'az k8s-configuration flux kustomization update'" + +UPDATE_KUSTOMIZATION_NO_EXIST_ERROR = "Error! Cannot update a kustomization that doesn't exist. Kustomization name '{0}' does not exist on configuration '{1}'" +UPDATE_KUSTOMIZATION_NO_EXIST_HELP = "You can add the kustomization to the configuration with 'az k8s-configuration flux kustomization create'" + +DELETE_KUSTOMIZATION_NO_EXIST_ERROR = "Error! Cannot delete a kustomization that doesn't exist." +DELETE_KUSTOMIZATION_NO_EXIST_HELP = "You can view all kustomizations on a configuration with 'az k8s-configuration flux kustomization list'" + +SHOW_KUSTOMIZATION_NO_EXIST_ERROR = "Error! Kustomization with name '{0}' does not exist on configuration '{1}'." +SHOW_KUSTOMIZATION_NO_EXIST_HELP = "You can view all kustomizations on a configuration with 'az k8s-configuration flux kustomization list'" + +SSH_PRIVATE_KEY_WITH_HTTP_URL_ERROR = "Error! An --ssh-private-key cannot be used with an http(s) url" +SSH_PRIVATE_KEY_WITH_HTTP_URL_HELP = "Verify the url provided is a valid ssh url and not an http(s) url" + +KNOWN_HOSTS_WITH_HTTP_URL_ERROR = "Error! --ssh-known-hosts cannot be used with an http(s) url" +KNOWN_HOSTS_WITH_HTTP_URL_HELP = "Verify the url provided is a valid ssh url and not an http(s) url" + +HTTPS_AUTH_WITH_SSH_URL_ERROR = "Error! https auth (--https-user and --https-key) cannot be used with a non-http(s) url" +HTTPS_AUTH_WITH_SSH_URL_HELP = "Verify the url provided is a valid http(s) url and not an ssh url" + +KNOWN_HOSTS_BASE64_ENCODING_ERROR = "Error! ssh known_hosts is not a valid utf-8 base64 encoded string" +KNOWN_HOSTS_BASE64_ENCODING_HELP = "Verify that the string provided safely decodes into a valid utf-8 format" + +KNOWN_HOSTS_FORMAT_ERROR = "Error! ssh known_hosts provided in wrong format" +KNOWN_HOSTS_FORMAT_HELP = "Verify that all lines in the known_hosts contents are provided in a valid sshd(8) format" + +SSH_PRIVATE_KEY_ERROR = "Error! --ssh-private-key provided in invalid format" +SSH_PRIVATE_KEY_HELP = "Verify the key provided is a valid PEM-formatted key of type RSA, ECC, DSA, or Ed25519" + +HTTPS_USER_KEY_MATCH_ERROR = "Error! --https-user and --https-key cannot be used separately" +HTTPS_USER_KEY_MATCH_HELP = "Try providing both --https-user and --https-key together" + +KEY_FILE_READ_ERROR = "Error! Unable to read key file specified with: {0}" +KEY_FILE_READ_HELP = "Verify that the filepath specified exists and contains valid utf-8 data" + +KEY_AND_FILE_TOGETHER_ERROR = "Error! Both textual key and key filepath cannot be provided" +KEY_AND_FILE_TOGETHER_HELP = "Try providing the file parameter without providing the plaintext parameter" + +SCC_EXISTS_ON_CLUSTER_ERROR = "Error! Flux v1 configurations already exist on the cluster" +SCC_EXISTS_ON_CLUSTER_HELP = "Try removing all Flux v1 configurations from the cluster before attempting to add Flux v2 configurations" + +FLUX_EXTENSION_NOT_SUCCEEDED_OR_CREATING_ERROR = "Error! 'Microsoft.Flux' extension is installed but not in a succeeded state on the cluster. Unable to proceed with Flux v2 configuration install." +FLUX_EXTENSION_NOT_SUCCEEDED_OR_CREATING_HELP = "Try resolving the extension error on the cluster or removing and re-installing the extension." + +FLUX_EXTENSION_CREATING_ERROR = "Error! 'Microsoft.Flux' extension is currently installing on the cluster. Unable to proceed with Flux v2 configuration install." +FLUX_EXTENSION_CREATING_HELP = "Try again in a few minutes when the 'Microsoft.Flux' extension installation has completed." + +HTTP_URL_NO_AUTH_WARNING = "Warning! https url is being used without https auth params, ensure the repository url provided is not a private repo" + +NO_KUSTOMIZATIONS_WARNING = "Warning! No kustomizations were specified for this configuration. A kustomization will be generated with the default name 'kustomization-1'." +DEFAULT_KUSTOMIZATION_NAME = "kustomization-1" + +# PROVIDER REGISTRATION ----------------------------------------- + +CC_REGISTRATION_WARNING = "'Flux Configuration' cannot be used because '%s' provider has not been registered. More details for registering this provider can be found here - %s" +CC_REGISTRATION_LINK = "https://aka.ms/RegisterKubernetesConfigurationProvider" +CC_REGISTRATION_ERROR = "Unable to fetch registration state of '{0}' provider. Failed to enable 'flux configuration' feature..." +CC_PROVIDER_NAMESPACE = 'Microsoft.KubernetesConfiguration' +REGISTERED = "Registered" +CREATING = "Creating" +SUCCEEDED = "Succeeded" + +FLUX_EXTENSION_TYPE = "microsoft.flux" + +SSH_PRIVATE_KEY_KEY = "sshPrivateKey" +HTTPS_USER_KEY = "httpsUser" +HTTPS_KEY_KEY = "httpsKey" + +DEPENDENCY_KEYS = ["dependencies", "depends_on", "dependsOn", "depends"] +SYNC_INTERVAL_KEYS = ["interval", "sync_interval", "syncInterval"] +RETRY_INTERVAL_KEYS = ["retryInterval", "retry_interval"] +TIMEOUT_KEYS = ["timeout"] +REQUIRED_KUSTOMIZATION_KEYS = {"name"} + +VALID_DURATION_REGEX = r"((?P\d+?)h)?((?P\d+?)m)?((?P\d+?)s)?" +VALID_URL_REGEX = r"^(((http|https|ssh)://)|(git@))" + +VALID_KUBERNETES_DNS_SUBDOMAIN_NAME_REGEX = r"^[a-z0-9]([\.\-a-z0-9]*[a-z0-9])?$" +VALID_KUBERNETES_DNS_NAME_REGEX = r"^[a-z0-9]([\-a-z0-9]*[a-z0-9])?$" + +GIT = "git" +GIT_REPOSITORY = "GitRepository" + +CONNECTED_CLUSTERS = "connectedclusters" +MANAGED_CLUSTERS = "managedclusters" +APPLIANCES = "appliances" + +MANAGED_RP_NAMESPACE = "Microsoft.ContainerService" +CONNECTED_RP_NAMESPACE = "Microsoft.Kubernetes" +APPLIANCE_RP_NAMESPACE = "Microsoft.ResourceConnector" + +KUBERNETES_MAX_NAME_SIZE = 63 + +DF_RM_ENDPOINT = 'https://api-dogfood.resources.windows-int.net/' + +FLUX_EXTENSION_RELEASETRAIN = "FLUX_EXTENSION_RELEASETRAIN" +FLUX_EXTENSION_VERSION = "FLUX_EXTENSION_VERSION" diff --git a/src/k8s-configuration/azext_k8s_configuration/custom.py b/src/k8s-configuration/azext_k8s_configuration/custom.py index ea84523c764..91145605887 100644 --- a/src/k8s-configuration/azext_k8s_configuration/custom.py +++ b/src/k8s-configuration/azext_k8s_configuration/custom.py @@ -3,227 +3,125 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -from azure.cli.core.azclierror import ResourceNotFoundError, CommandNotFoundError, \ - RequiredArgumentMissingError -from azure.core.exceptions import HttpResponseError -from knack.log import get_logger -from azext_k8s_configuration._utils import _get_cluster_type, \ - _fix_compliance_state, _get_data_from_key_or_file, _to_base64 -from azext_k8s_configuration._validators import _validate_known_hosts, _validate_url_with_params, \ - _validate_configuration_name, _validate_cc_registration, _validate_private_key - -from azext_k8s_configuration.vendored_sdks.models import SourceControlConfiguration -from azext_k8s_configuration.vendored_sdks.models import HelmOperatorProperties - -logger = get_logger(__name__) - - -def show_k8s_configuration(client, resource_group_name, cluster_name, name, cluster_type): - """Get an existing Kubernetes Source Control Configuration. - - """ - # Determine ClusterRP - cluster_rp = _get_cluster_type(cluster_type) - - try: - config = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) - return _fix_compliance_state(config) - except HttpResponseError as ex: - # Customize the error message for resources not found - if ex.response.status_code == 404: - # If Cluster not found - if ex.message.__contains__("(ResourceNotFound)"): - message = ex.message - recommendation = 'Verify that the --cluster-type is correct and the Resource ' \ - '{0}/{1}/{2} exists'.format(cluster_rp, cluster_type, cluster_name) - # If Configuration not found - elif ex.message.__contains__("Operation returned an invalid status code 'Not Found'"): - message = '(ConfigurationNotFound) The Resource {0}/{1}/{2}/Microsoft.KubernetesConfiguration/' \ - 'sourcecontrolConfigurations/{3} could not be found!'.format(cluster_rp, cluster_type, - cluster_name, name) - recommendation = 'Verify that the Resource {0}/{1}/{2}/Microsoft.KubernetesConfiguration' \ - '/sourcecontrolConfigurations/{3} exists'.format(cluster_rp, cluster_type, - cluster_name, name) - else: - message = ex.message - recommendation = '' - raise ResourceNotFoundError(message, recommendation) from ex +# pylint: disable=unused-argument + +from .providers.FluxConfigurationProvider import FluxConfigurationProvider +from .providers.SourceControlConfigurationProvider import SourceControlConfigurationProvider +from . import consts + + +# Source Control Configuration Methods + +def sourcecontrol_create(cmd, client, resource_group_name, cluster_name, name, repository_url, scope, cluster_type, + operator_instance_name=None, operator_namespace='default', + helm_operator_chart_version='1.4.0', operator_type='flux', operator_params='', + ssh_private_key='', ssh_private_key_file='', https_user='', https_key='', + ssh_known_hosts='', ssh_known_hosts_file='', enable_helm_operator=None, + helm_operator_params=''): + provider = SourceControlConfigurationProvider(cmd) + return provider.create(resource_group_name, cluster_name, name, repository_url, scope, cluster_type, + operator_instance_name, operator_namespace, helm_operator_chart_version, operator_type, + operator_params, ssh_private_key, ssh_private_key_file, https_user, https_key, + ssh_known_hosts, ssh_known_hosts_file, enable_helm_operator, helm_operator_params) + + +def sourcecontrol_show(cmd, client, resource_group_name, cluster_type, cluster_name, name): + provider = SourceControlConfigurationProvider(cmd) + return provider.show(resource_group_name, cluster_type, cluster_name, name) + + +def sourcecontrol_list(cmd, client, resource_group_name, cluster_type, cluster_name): + provider = SourceControlConfigurationProvider(cmd) + return provider.list(resource_group_name, cluster_type, cluster_name) + + +def sourcecontrol_delete(cmd, client, resource_group_name, cluster_type, cluster_name, name): + provider = SourceControlConfigurationProvider(cmd) + return provider.delete(resource_group_name, cluster_type, cluster_name, name) + + +# Flux Configuration Methods +def flux_config_show(cmd, client, resource_group_name, cluster_type, cluster_name, name): + provider = FluxConfigurationProvider(cmd) + return provider.show(resource_group_name, cluster_type, cluster_name, name) + + +def flux_config_list(cmd, client, resource_group_name, cluster_type, cluster_name): + provider = FluxConfigurationProvider(cmd) + return provider.list(resource_group_name, cluster_type, cluster_name) + + +# pylint: disable=too-many-locals +def flux_config_create(cmd, client, resource_group_name, cluster_type, cluster_name, name, url=None, + scope='cluster', namespace='default', kind=consts.GIT, timeout=None, sync_interval=None, + branch=None, tag=None, semver=None, commit=None, local_auth_ref=None, ssh_private_key=None, + ssh_private_key_file=None, https_user=None, https_key=None, https_ca_cert=None, + https_ca_cert_file=None, known_hosts=None, known_hosts_file=None, suspend=False, + kustomization=None, no_wait=False): + + provider = FluxConfigurationProvider(cmd) + return provider.create(resource_group_name, cluster_type, cluster_name, name, url, scope, namespace, kind, + timeout, sync_interval, branch, tag, semver, commit, local_auth_ref, ssh_private_key, + ssh_private_key_file, https_user, https_key, https_ca_cert, https_ca_cert_file, known_hosts, + known_hosts_file, suspend, kustomization, no_wait) # pylint: disable=too-many-locals -def create_k8s_configuration(cmd, client, resource_group_name, cluster_name, name, repository_url, scope, cluster_type, - operator_instance_name=None, operator_namespace='default', - helm_operator_chart_version='1.4.0', operator_type='flux', operator_params='', - ssh_private_key='', ssh_private_key_file='', https_user='', https_key='', - ssh_known_hosts='', ssh_known_hosts_file='', enable_helm_operator=None, - helm_operator_params=''): - """Create a new Kubernetes Source Control Configuration. - - """ - # Validate configuration name - _validate_configuration_name(name) - - # Determine ClusterRP - cluster_rp = _get_cluster_type(cluster_type) - - # Determine operatorInstanceName - if operator_instance_name is None: - operator_instance_name = name - - # Create helmOperatorProperties object - helm_operator_properties = None - if enable_helm_operator: - helm_operator_properties = HelmOperatorProperties() - helm_operator_properties.chart_version = helm_operator_chart_version.strip() - helm_operator_properties.chart_values = helm_operator_params.strip() - - protected_settings = _get_protected_settings(ssh_private_key, - ssh_private_key_file, - https_user, - https_key) - knownhost_data = _get_data_from_key_or_file(ssh_known_hosts, ssh_known_hosts_file) - if knownhost_data: - _validate_known_hosts(knownhost_data) - - # Flag which parameters have been set and validate these settings against the set repository url - ssh_private_key_set = ssh_private_key != '' or ssh_private_key_file != '' - known_hosts_contents_set = knownhost_data != '' - https_auth_set = https_user != '' and https_key != '' - _validate_url_with_params(repository_url, - ssh_private_key_set=ssh_private_key_set, - known_hosts_contents_set=known_hosts_contents_set, - https_auth_set=https_auth_set) - - # Validate that the subscription is registered to Microsoft.KubernetesConfiguration - _validate_cc_registration(cmd) - - # Create sourceControlConfiguration object - source_control_configuration = SourceControlConfiguration(repository_url=repository_url, - operator_namespace=operator_namespace, - operator_instance_name=operator_instance_name, - operator_type=operator_type, - operator_params=operator_params, - configuration_protected_settings=protected_settings, - operator_scope=scope, - ssh_known_hosts_contents=knownhost_data, - enable_helm_operator=enable_helm_operator, - helm_operator_properties=helm_operator_properties) - - # Try to create the resource - config = client.create_or_update(resource_group_name, cluster_rp, cluster_type, cluster_name, - name, source_control_configuration) - - return _fix_compliance_state(config) - - -def update_k8s_configuration(client, resource_group_name, cluster_name, name, cluster_type, - repository_url=None, operator_params=None, ssh_known_hosts='', - ssh_known_hosts_file='', enable_helm_operator=None, helm_operator_chart_version=None, - helm_operator_params=None): - """Update an existing Kubernetes Source Control Configuration. - - """ - - # TODO: Remove this after we eventually get PATCH implemented for update and uncomment - raise CommandNotFoundError( - "\"k8s-configuration update\" currently is not available. " - "Use \"k8s-configuration create\" to update a previously created configuration." - ) - - # # Determine ClusterRP - # cluster_rp = __get_cluster_type(cluster_type) - - # source_control_configuration_name = name.strip() - - # config = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, - # source_control_configuration_name) - # update_yes = False - - # # Set input values, if they are supplied - # if repository_url is not None: - # config.repository_url = repository_url - # update_yes = True - - # if operator_params is not None: - # config.operator_params = operator_params - # update_yes = True - - # knownhost_data = get_data_from_key_or_file(ssh_known_hosts, ssh_known_hosts_file) - # if knownhost_data: - # validate_known_hosts(knownhost_data) - # config.ssh_known_hosts_contents = knownhost_data - # update_yes = True - - # if enable_helm_operator is not None: - # config.enable_helm_operator = enable_helm_operator - # update_yes = True - - # # Get the helm operator properties from the config and set them - # if config.helm_operator_properties is None: - # config.helm_operator_properties = HelmOperatorProperties() - # if helm_operator_chart_version is not None: - # config.helm_operator_properties.chart_version = helm_operator_chart_version.strip() - # update_yes = True - # if helm_operator_params is not None: - # config.helm_operator_properties.chart_values = helm_operator_params.strip() - # update_yes = True - - # if update_yes is False: - # raise RequiredArgumentMissingError( - # 'Invalid update. No values to update!', - # 'Verify that at least one changed parameter is provided in the update command') - - # # Flag which parameters have been set and validate these settings against the set repository url - # known_hosts_contents_set = config.ssh_known_hosts_contents != "" - # validate_url_with_params(config.repository_url, - # ssh_private_key_set=False, - # known_hosts_contents_set=known_hosts_contents_set, - # https_auth_set=False) - - # config = client.create_or_update(resource_group_name, cluster_rp, cluster_type, cluster_name, - # source_control_configuration_name, config) - - # return __fix_compliance_state(config) - - -def list_k8s_configuration(client, resource_group_name, cluster_name, cluster_type): - cluster_rp = _get_cluster_type(cluster_type) - return client.list(resource_group_name, cluster_rp, cluster_type, cluster_name) - - -def delete_k8s_configuration(client, resource_group_name, cluster_name, name, cluster_type): - """Delete an existing Kubernetes Source Control Configuration. - - """ - # Determine ClusterRP - cluster_rp = _get_cluster_type(cluster_type) - - source_control_configuration_name = name - - return client.begin_delete(resource_group_name, cluster_rp, cluster_type, cluster_name, source_control_configuration_name) - - -def _get_protected_settings(ssh_private_key, ssh_private_key_file, https_user, https_key): - protected_settings = {} - ssh_private_key_data = _get_data_from_key_or_file(ssh_private_key, ssh_private_key_file) +def flux_config_update(cmd, client, resource_group_name, cluster_type, cluster_name, name, url=None, + timeout=None, sync_interval=None, branch=None, tag=None, semver=None, commit=None, + local_auth_ref=None, ssh_private_key=None, ssh_private_key_file=None, https_user=None, + https_key=None, https_ca_cert=None, https_ca_cert_file=None, known_hosts=None, + known_hosts_file=None, suspend=None, kustomization=None, no_wait=False): + + provider = FluxConfigurationProvider(cmd) + return provider.update(resource_group_name, cluster_type, cluster_name, name, url, timeout, sync_interval, + branch, tag, semver, commit, local_auth_ref, ssh_private_key, ssh_private_key_file, + https_user, https_key, https_ca_cert, https_ca_cert_file, known_hosts, + known_hosts_file, suspend, kustomization, no_wait) + + +def flux_config_create_kustomization(cmd, client, resource_group_name, cluster_type, cluster_name, name, + kustomization_name, dependencies=None, timeout=None, sync_interval=None, + retry_interval=None, path='', prune=None, force=None, no_wait=False): + + provider = FluxConfigurationProvider(cmd) + return provider.create_kustomization(resource_group_name, cluster_type, cluster_name, name, kustomization_name, + dependencies, timeout, sync_interval, retry_interval, path, prune, + force, no_wait) + + +def flux_config_update_kustomization(cmd, client, resource_group_name, cluster_type, cluster_name, name, + kustomization_name, dependencies=None, timeout=None, sync_interval=None, + retry_interval=None, path=None, prune=None, force=None, no_wait=False): + + provider = FluxConfigurationProvider(cmd) + return provider.update_kustomization(resource_group_name, cluster_type, cluster_name, name, kustomization_name, + dependencies, timeout, sync_interval, retry_interval, path, prune, + force, no_wait) + + +def flux_config_delete_kustomization(cmd, client, resource_group_name, cluster_type, cluster_name, name, + kustomization_name, no_wait=False, yes=False): + + provider = FluxConfigurationProvider(cmd) + return provider.delete_kustomization(resource_group_name, cluster_type, cluster_name, + name, kustomization_name, no_wait, yes) + + +def flux_config_list_kustomization(cmd, client, resource_group_name, cluster_type, cluster_name, name): + + provider = FluxConfigurationProvider(cmd) + return provider.list_kustomization(resource_group_name, cluster_type, cluster_name, name) + + +def flux_config_show_kustomization(cmd, client, resource_group_name, cluster_type, cluster_name, name, + kustomization_name): + + provider = FluxConfigurationProvider(cmd) + return provider.show_kustomization(resource_group_name, cluster_type, cluster_name, name, kustomization_name) - # Add gitops private key data to protected settings if exists - # Dry-run all key types to determine if the private key is in a valid format - if ssh_private_key_data != '': - _validate_private_key(ssh_private_key_data) - protected_settings["sshPrivateKey"] = ssh_private_key_data - # Check if both httpsUser and httpsKey exist, then add to protected settings - if https_user != '' and https_key != '': - protected_settings['httpsUser'] = _to_base64(https_user) - protected_settings['httpsKey'] = _to_base64(https_key) - elif https_user != '': - raise RequiredArgumentMissingError( - 'Error! --https-user used without --https-key', - 'Try providing both --https-user and --https-key together') - elif https_key != '': - raise RequiredArgumentMissingError( - 'Error! --http-key used without --http-user', - 'Try providing both --https-user and --https-key together') - - return protected_settings +def flux_config_delete(cmd, client, resource_group_name, cluster_type, + cluster_name, name, force=False, no_wait=False, yes=False): + provider = FluxConfigurationProvider(cmd) + return provider.delete(resource_group_name, cluster_type, cluster_name, name, force, no_wait, yes) diff --git a/src/k8s-configuration/azext_k8s_configuration/format.py b/src/k8s-configuration/azext_k8s_configuration/format.py new file mode 100644 index 00000000000..2fd2b60bdb2 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/format.py @@ -0,0 +1,70 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from collections import OrderedDict +from .utils import format_duration + + +def sourcecontrol_list_table_format(results): + return [__get_sourcecontrolconfig_table_row(result) for result in results] + + +def sourcecontrol_show_table_format(result): + return __get_sourcecontrolconfig_table_row(result) + + +def __get_sourcecontrolconfig_table_row(result): + return OrderedDict([ + ('name', result['name']), + ('repositoryUrl', result['repositoryUrl']), + ('operatorName', result['operatorInstanceName']), + ('operatorNamespace', result['operatorNamespace']), + ('scope', result['operatorScope']), + ('provisioningState', result['provisioningState']) + ]) + + +def fluxconfig_list_table_format(results): + return [__get_fluxconfig_table_row(result) for result in results] + + +def fluxconfig_show_table_format(result): + return __get_fluxconfig_table_row(result) + + +def __get_fluxconfig_table_row(result): + return OrderedDict([ + ('name', result['name']), + ('namespace', result['namespace']), + ('scope', result['scope']), + ('provisioningState', result['provisioningState']), + ('complianceState', result['complianceState']), + ('lastSourceSyncedAt', result['lastSourceSyncedAt']), + ]) + + +def fluxconfig_kustomization_list_table_format(results): + return [__get_fluxconfig_kustomization_table_row(k, v) for k, v in results.items()] + + +def fluxconfig_kustomization_show_table_format(results): + return [__get_fluxconfig_kustomization_table_row(k, v) for k, v in results.items()] + + +def __get_fluxconfig_kustomization_table_row(key, value): + deps = [] + for dep in value.get('dependsOn') or []: + if dep.get('kustomizationName'): + deps.append(dep['kustomizationName']) + + return OrderedDict([ + ('name', key), + ('path', value['path']), + ('dependsOn', ','.join(deps)), + ('syncInterval', format_duration(value['syncIntervalInSeconds'])), + ('timeout', format_duration(value['timeoutInSeconds'])), + ('prune', value['prune']), + ('force', value['force']) + ]) diff --git a/src/k8s-configuration/azext_k8s_configuration/providers/FluxConfigurationProvider.py b/src/k8s-configuration/azext_k8s_configuration/providers/FluxConfigurationProvider.py new file mode 100644 index 00000000000..5275679545b --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/providers/FluxConfigurationProvider.py @@ -0,0 +1,508 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=unused-argument + +import os + +from azure.cli.core.azclierror import DeploymentError, ResourceNotFoundError, ValidationError +from azure.cli.core.util import sdk_no_wait +from azure.cli.core.commands.client_factory import get_subscription_id + +from azure.core.exceptions import HttpResponseError +from knack.log import get_logger + +from ..confirm import user_confirmation_factory +from .._client_factory import ( + cf_resources, + k8s_configuration_fluxconfig_client, + k8s_configuration_extension_client +) +from ..utils import ( + get_parent_api_version, + get_cluster_rp, + get_data_from_key_or_file, + parse_dependencies, + parse_duration, + has_prune_enabled, + to_base64, + is_dogfood_cluster +) +from ..validators import ( + validate_cc_registration, + validate_known_hosts, + validate_repository_ref, + validate_duration, + validate_git_repository, + validate_private_key, + validate_url_with_params +) +from .. import consts +from ..vendored_sdks.v2021_11_01_preview.models import ( + FluxConfiguration, + FluxConfigurationPatch, + GitRepositoryDefinition, + RepositoryRefDefinition, + KustomizationDefinition, + DependsOnDefinition +) +from ..vendored_sdks.v2021_05_01_preview.models import ( + Extension, + Identity +) +from .SourceControlConfigurationProvider import SourceControlConfigurationProvider + +logger = get_logger(__name__) + + +class FluxConfigurationProvider: + def __init__(self, cmd): + self.extension_client = k8s_configuration_extension_client(cmd.cli_ctx) + self.source_control_configuration_provider = SourceControlConfigurationProvider(cmd) + self.cmd = cmd + self.client = k8s_configuration_fluxconfig_client(cmd.cli_ctx) + + def show(self, resource_group_name, cluster_type, cluster_name, name): + """Get an existing Kubernetes Source Control Configuration. + + """ + # Determine ClusterRP + cluster_rp = get_cluster_rp(cluster_type) + try: + config = self.client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + return config + except HttpResponseError as ex: + # Customize the error message for resources not found + if ex.response.status_code == 404: + # If Cluster not found + if ex.message.__contains__("(ResourceNotFound)"): + message = ex.message + recommendation = 'Verify that the --cluster-type is correct and the Resource ' \ + '{0}/{1}/{2} exists'.format(cluster_rp, cluster_type, cluster_name) + # If Configuration not found + elif ex.message.__contains__("Operation returned an invalid status code 'Not Found'"): + message = '(FluxConfigurationNotFound) The Resource {0}/{1}/{2}/' \ + 'Microsoft.KubernetesConfiguration/fluxConfigurations/{3} ' \ + 'could not be found!' \ + .format(cluster_rp, cluster_type, cluster_name, name) + recommendation = 'Verify that the Resource {0}/{1}/{2}/Microsoft.KubernetesConfiguration' \ + '/fluxConfigurations/{3} exists'.format(cluster_rp, cluster_type, + cluster_name, name) + else: + message = ex.message + recommendation = '' + raise ResourceNotFoundError(message, recommendation) from ex + raise ex + + def list(self, resource_group_name, cluster_type, cluster_name): + cluster_rp = get_cluster_rp(cluster_type) + return self.client.list(resource_group_name, cluster_rp, cluster_type, cluster_name) + + # pylint: disable=too-many-locals + def create(self, resource_group_name, cluster_type, cluster_name, name, url=None, scope='cluster', + namespace='default', kind=consts.GIT, timeout=None, sync_interval=None, branch=None, + tag=None, semver=None, commit=None, local_auth_ref=None, ssh_private_key=None, + ssh_private_key_file=None, https_user=None, https_key=None, https_ca_cert=None, + https_ca_cert_file=None, known_hosts=None, known_hosts_file=None, suspend=False, + kustomization=None, no_wait=False): + + # Determine the cluster RP + cluster_rp = get_cluster_rp(cluster_type) + dp_source_kind = "" + git_repository = None + + # Validate and Create the Data before checking the cluster compataibility + if kind == consts.GIT: + dp_source_kind = consts.GIT_REPOSITORY + git_repository = self._validate_and_get_gitrepository(url, branch, tag, semver, commit, timeout, + sync_interval, ssh_private_key, + ssh_private_key_file, https_user, + https_key, https_ca_cert, https_ca_cert_file, + known_hosts, known_hosts_file, local_auth_ref, True) + + if kustomization: + # Convert the Internal List Representation of Kustomization to Dictionary + kustomization = {k.name: k.to_KustomizationDefinition() for k in kustomization} + else: + logger.warning(consts.NO_KUSTOMIZATIONS_WARNING) + kustomization = { + consts.DEFAULT_KUSTOMIZATION_NAME: KustomizationDefinition() + } + + # Get the protected settings and validate the private key value + protected_settings = get_protected_settings( + ssh_private_key, ssh_private_key_file, https_user, https_key + ) + if protected_settings and consts.SSH_PRIVATE_KEY_KEY in protected_settings: + validate_private_key(protected_settings['sshPrivateKey']) + + flux_configuration = FluxConfiguration( + scope=scope, + namespace=namespace, + source_kind=dp_source_kind, + git_repository=git_repository, + suspend=suspend, + kustomizations=kustomization, + configuration_protected_settings=protected_settings, + ) + + self._validate_source_control_config_not_installed(resource_group_name, cluster_type, cluster_name) + self._validate_extension_install(resource_group_name, cluster_rp, cluster_type, cluster_name, no_wait) + + logger.warning("Creating the flux configuration '%s' in the cluster. This may take a few minutes...", name) + + return sdk_no_wait(no_wait, self.client.begin_create_or_update, resource_group_name, cluster_rp, + cluster_type, cluster_name, name, flux_configuration) + + def update(self, resource_group_name, cluster_type, cluster_name, name, url=None, + timeout=None, sync_interval=None, branch=None, tag=None, semver=None, + commit=None, local_auth_ref=None, ssh_private_key=None, ssh_private_key_file=None, + https_user=None, https_key=None, https_ca_cert=None, https_ca_cert_file=None, known_hosts=None, + known_hosts_file=None, suspend=None, kustomization=None, no_wait=False): + # Determine the cluster RP + cluster_rp = get_cluster_rp(cluster_type) + + git_repository = None + if any([url, branch, tag, semver, commit, + timeout, sync_interval, + ssh_private_key, ssh_private_key_file, + https_user, https_key, https_ca_cert, + https_ca_cert_file, known_hosts, + known_hosts_file, local_auth_ref]): + git_repository = self._validate_and_get_gitrepository(url, branch, tag, semver, commit, + timeout, sync_interval, + ssh_private_key, ssh_private_key_file, + https_user, https_key, https_ca_cert, + https_ca_cert_file, known_hosts, + known_hosts_file, local_auth_ref, False) + + if kustomization: + # Convert the Internal List Representation of Kustomization to Dictionary + kustomization = {k.name: k.to_KustomizationDefinition() for k in kustomization} + + # Get the protected settings and validate the private key value + protected_settings = get_protected_settings( + ssh_private_key, ssh_private_key_file, https_user, https_key + ) + if protected_settings and consts.SSH_PRIVATE_KEY_KEY in protected_settings: + validate_private_key(protected_settings['sshPrivateKey']) + + flux_configuration = FluxConfigurationPatch( + git_repository=git_repository, + suspend=suspend, + kustomizations=kustomization, + configuration_protected_settings=protected_settings, + ) + + return sdk_no_wait(no_wait, self.client.begin_update, resource_group_name, cluster_rp, + cluster_type, cluster_name, name, flux_configuration) + + def create_kustomization(self, resource_group_name, cluster_type, cluster_name, name, + kustomization_name, dependencies=None, timeout=None, sync_interval=None, + retry_interval=None, path='', prune=False, force=False, no_wait=False): + # Pre-Validation + validate_duration("--timeout", timeout) + validate_duration("--sync-interval", sync_interval) + validate_duration("--retry-interval", retry_interval) + + # Determine ClusterRP + cluster_rp = get_cluster_rp(cluster_type) + current_config = self.client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + if kustomization_name in current_config.kustomizations: + raise ValidationError( + consts.CREATE_KUSTOMIZATION_EXIST_ERROR.format(kustomization_name, name), + consts.CREATE_KUSTOMIZATION_EXIST_HELP + ) + + # Add the dependencies in their model to the kustomization + model_dependencies = None + if dependencies: + model_dependencies = [] + for dep in parse_dependencies(dependencies): + model_dependencies.append( + DependsOnDefinition( + kustomization_name=dep + ) + ) + + kustomization = { + kustomization_name: KustomizationDefinition( + path=path, + depends_on=model_dependencies, + timeout_in_seconds=parse_duration(timeout), + sync_interval_in_seconds=parse_duration(sync_interval), + retry_interval_in_seconds=parse_duration(retry_interval), + prune=prune, + force=force + ) + } + flux_configuration_patch = FluxConfigurationPatch( + kustomizations=kustomization + ) + return sdk_no_wait(no_wait, self.client.begin_update, resource_group_name, cluster_rp, + cluster_type, cluster_name, name, flux_configuration_patch) + + def update_kustomization(self, resource_group_name, cluster_type, cluster_name, name, + kustomization_name, dependencies=None, timeout=None, sync_interval=None, + retry_interval=None, path=None, prune=False, force=False, no_wait=False): + # Pre-Validation + validate_duration("--timeout", timeout) + validate_duration("--sync-interval", sync_interval) + validate_duration("--retry-interval", retry_interval) + + # Determine ClusterRP + cluster_rp = get_cluster_rp(cluster_type) + current_config = self.client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + if kustomization_name not in current_config.kustomizations: + raise ValidationError( + consts.UPDATE_KUSTOMIZATION_NO_EXIST_ERROR.format(kustomization_name, name), + consts.UPDATE_KUSTOMIZATION_NO_EXIST_HELP + ) + + # Add the dependencies in their model to the kustomization + model_dependencies = None + if dependencies: + model_dependencies = [] + for dep in parse_dependencies(dependencies): + model_dependencies.append( + DependsOnDefinition( + kustomization_name=dep + ) + ) + + kustomization = { + kustomization_name: KustomizationDefinition( + path=path, + depends_on=model_dependencies, + timeout_in_seconds=parse_duration(timeout), + sync_interval_in_seconds=parse_duration(sync_interval), + retry_interval_in_seconds=parse_duration(retry_interval), + prune=prune, + force=force + ) + } + flux_configuration_patch = FluxConfigurationPatch( + kustomizations=kustomization + ) + return sdk_no_wait(no_wait, self.client.begin_update, resource_group_name, cluster_rp, + cluster_type, cluster_name, name, flux_configuration_patch) + + def delete_kustomization(self, resource_group_name, cluster_type, cluster_name, name, + kustomization_name, no_wait=False, yes=False): + # Confirmation message for deletes + user_confirmation_factory(self.cmd, yes) + + # Determine ClusterRP + cluster_rp = get_cluster_rp(cluster_type) + + current_config = self.client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + if kustomization_name not in current_config.kustomizations: + raise ValidationError( + consts.DELETE_KUSTOMIZATION_NO_EXIST_ERROR.format(kustomization_name, name), + consts.DELETE_KUSTOMIZATION_NO_EXIST_HELP + ) + + if current_config.kustomizations[kustomization_name].prune: + logger.warning("Prune is enabled on this kustomization. Deleting a kustomization " + "with prune enabled will also delete the Kubernetes objects " + "deployed by the kustomization.") + user_confirmation_factory(self.cmd, yes, "Do you want to continue?") + + kustomization = { + kustomization_name: None + } + flux_configuration_patch = FluxConfigurationPatch( + kustomizations=kustomization + ) + return sdk_no_wait(no_wait, self.client.begin_update, resource_group_name, cluster_rp, + cluster_type, cluster_name, name, flux_configuration_patch) + + def list_kustomization(self, resource_group_name, cluster_type, cluster_name, name): + # Determine ClusterRP + cluster_rp = get_cluster_rp(cluster_type) + current_config = self.client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + return current_config.kustomizations + + def show_kustomization(self, resource_group_name, cluster_type, cluster_name, name, kustomization_name): + # Determine ClusterRP + cluster_rp = get_cluster_rp(cluster_type) + current_config = self.client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + if kustomization_name not in current_config.kustomizations: + raise ValidationError( + consts.SHOW_KUSTOMIZATION_NO_EXIST_ERROR.format(kustomization_name, name), + consts.SHOW_KUSTOMIZATION_NO_EXIST_HELP + ) + return {kustomization_name: current_config.kustomizations[kustomization_name]} + + def delete(self, resource_group_name, cluster_type, cluster_name, name, force, no_wait, yes): + # Confirmation message for deletes + user_confirmation_factory(self.cmd, yes) + + # Determine ClusterRP + cluster_rp = get_cluster_rp(cluster_type) + + config = None + try: + config = self.client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + except HttpResponseError: + logger.warning("No flux configuration with name '%s' found on cluster '%s', so nothing to delete", + name, cluster_name) + return None + + if has_prune_enabled(config): + logger.warning("Prune is enabled on one or more of your kustomizations. Deleting a Flux " + "configuration with prune enabled will also delete the Kubernetes objects " + "deployed by the kustomization(s).") + user_confirmation_factory(self.cmd, yes, "Do you want to continue?") + + if not force: + logger.info("Deleting the flux configuration from the cluster. This may take a few minutes...") + return sdk_no_wait(no_wait, self.client.begin_delete, resource_group_name, cluster_rp, cluster_type, + cluster_name, name, force_delete=force) + + def _is_deferred(self): + if '--defer' in self.cmd.cli_ctx.data.get('safe_params'): + return True + return False + + def _validate_source_control_config_not_installed(self, resource_group_name, cluster_type, cluster_name): + # Validate if we are able to install the flux configuration + configs = self.source_control_configuration_provider.list(resource_group_name, cluster_type, cluster_name) + # configs is an iterable, no len() so we have to iterate to check for configs + for _ in configs: + raise DeploymentError( + consts.SCC_EXISTS_ON_CLUSTER_ERROR, + consts.SCC_EXISTS_ON_CLUSTER_HELP) + + def _validate_extension_install(self, resource_group_name, cluster_rp, cluster_type, cluster_name, no_wait): + # Validate if the extension is installed, if not, install it + extensions = self.extension_client.list(resource_group_name, cluster_rp, cluster_type, cluster_name) + flux_extension = None + for extension in extensions: + if extension.extension_type.lower() == consts.FLUX_EXTENSION_TYPE: + flux_extension = extension + break + if not flux_extension: + logger.warning("'Microsoft.Flux' extension not found on the cluster, installing it now." + " This may take a few minutes...") + + extension = Extension( + extension_type="microsoft.flux", + auto_upgrade_minor_version=True, + release_train=os.getenv(consts.FLUX_EXTENSION_RELEASETRAIN), + version=os.getenv(consts.FLUX_EXTENSION_VERSION) + ) + if not is_dogfood_cluster(self.cmd): + extension = self.__add_identity(extension, + resource_group_name, + cluster_rp, + cluster_type, + cluster_name) + + logger.info("Starting extension creation on the cluster. This might take a few minutes...") + sdk_no_wait(no_wait, self.extension_client.begin_create, resource_group_name, cluster_rp, cluster_type, + cluster_name, "flux", extension).result() + # Only show that we have received a success when we have --no-wait + if not no_wait: + logger.warning("'Microsoft.Flux' extension was successfully installed on the cluster") + elif flux_extension.provisioning_state == consts.CREATING: + raise DeploymentError( + consts.FLUX_EXTENSION_CREATING_ERROR, + consts.FLUX_EXTENSION_CREATING_HELP + ) + elif flux_extension.provisioning_state != consts.SUCCEEDED: + raise DeploymentError( + consts.FLUX_EXTENSION_NOT_SUCCEEDED_OR_CREATING_ERROR, + consts.FLUX_EXTENSION_NOT_SUCCEEDED_OR_CREATING_HELP + ) + + def _validate_and_get_gitrepository(self, url, branch, tag, semver, commit, timeout, sync_interval, + ssh_private_key, ssh_private_key_file, https_user, https_key, + https_ca_cert, https_ca_cert_file, known_hosts, known_hosts_file, + local_auth_ref, is_create): + # Pre-Validation + validate_duration("--timeout", timeout) + validate_duration("--sync-interval", sync_interval) + + # Get the known hosts data and validate it + knownhost_data = get_data_from_key_or_file(known_hosts, known_hosts_file, strip_newline=True) + if knownhost_data: + validate_known_hosts(knownhost_data) + + https_ca_data = get_data_from_key_or_file(https_ca_cert, https_ca_cert_file, strip_newline=True) + + # Validate registration with the RP endpoint + validate_cc_registration(self.cmd) + + if is_create: + validate_git_repository(url) + validate_url_with_params(url, ssh_private_key, ssh_private_key_file, + known_hosts, known_hosts_file, https_user, https_key) + validate_repository_ref(branch, tag, semver, commit) + + repository_ref = None + if any([branch, tag, semver, commit]): + repository_ref = RepositoryRefDefinition( + branch=branch, + tag=tag, + semver=semver, + commit=commit + ) + + # Encode the https username to base64 + if https_user: + https_user = to_base64(https_user) + + return GitRepositoryDefinition( + url=url, + timeout_in_seconds=parse_duration(timeout), + sync_interval_in_seconds=parse_duration(sync_interval), + repository_ref=repository_ref, + ssh_known_hosts=knownhost_data, + https_user=https_user, + local_auth_ref=local_auth_ref, + https_ca_file=https_ca_data + ) + + def __add_identity(self, extension_instance, resource_group_name, cluster_rp, cluster_type, cluster_name): + subscription_id = get_subscription_id(self.cmd.cli_ctx) + resources = cf_resources(self.cmd.cli_ctx, subscription_id) + + cluster_resource_id = '/subscriptions/{0}/resourceGroups/{1}/providers/{2}/{3}/{4}'.format(subscription_id, + resource_group_name, + cluster_rp, + cluster_type, + cluster_name) + + if cluster_rp == consts.MANAGED_RP_NAMESPACE: + return extension_instance + parent_api_version = get_parent_api_version(cluster_rp) + try: + resource = resources.get_by_id(cluster_resource_id, parent_api_version) + location = str(resource.location.lower()) + except HttpResponseError as ex: + raise ex + identity_type = "SystemAssigned" + + extension_instance.identity = Identity(type=identity_type) + extension_instance.location = location + return extension_instance + + +def get_protected_settings(ssh_private_key, ssh_private_key_file, https_user, https_key): + protected_settings = {} + ssh_private_key_data = get_data_from_key_or_file(ssh_private_key, ssh_private_key_file) + + # Add gitops private key data to protected settings if exists + # Dry-run all key types to determine if the private key is in a valid format + if ssh_private_key_data: + protected_settings[consts.SSH_PRIVATE_KEY_KEY] = ssh_private_key_data + + # Check if both httpsUser and httpsKey exist, then add to protected settings + if https_user and https_key: + protected_settings[consts.HTTPS_KEY_KEY] = to_base64(https_key) + + # Return the protected settings dict if there are any values there + return protected_settings if len(protected_settings) > 0 else None diff --git a/src/k8s-configuration/azext_k8s_configuration/providers/SourceControlConfigurationProvider.py b/src/k8s-configuration/azext_k8s_configuration/providers/SourceControlConfigurationProvider.py new file mode 100644 index 00000000000..d5d497ac514 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/providers/SourceControlConfigurationProvider.py @@ -0,0 +1,139 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.core.azclierror import ResourceNotFoundError +from azure.core.exceptions import HttpResponseError +from knack.log import get_logger + +from .._client_factory import k8s_configuration_sourcecontrol_client +from ..utils import fix_compliance_state, get_cluster_rp, get_data_from_key_or_file, to_base64 +from ..validators import validate_cc_registration, validate_known_hosts, validate_url_with_params +from .. import consts + +from ..vendored_sdks.v2021_03_01.models import ( + HelmOperatorProperties, + SourceControlConfiguration +) + +logger = get_logger(__name__) + + +class SourceControlConfigurationProvider: + def __init__(self, cmd): + self.cmd = cmd + self.client = k8s_configuration_sourcecontrol_client(cmd.cli_ctx) + + def show(self, resource_group_name, cluster_type, cluster_name, name): + # Determine ClusterRP + cluster_rp = get_cluster_rp(cluster_type) + try: + extension = self.client.get(resource_group_name, + cluster_rp, cluster_type, + cluster_name, name) + return extension + except HttpResponseError as ex: + # Customize the error message for resources not found + if ex.response.status_code == 404: + # If Cluster not found + if ex.message.__contains__("(ResourceNotFound)"): + message = "{0} Verify that the cluster-type is correct and the resource exists.".format( + ex.message) + # If Configuration not found + elif ex.message.__contains__("Operation returned an invalid status code 'Not Found'"): + message = "(SourceControlConfigurationNotFound) The Resource {0}/{1}/{2}/" \ + "Microsoft.KubernetesConfiguration/sourceControlConfigurations/{3}" \ + "could not be found!".format(cluster_rp, cluster_type, + cluster_name, name) + else: + message = ex.message + raise ResourceNotFoundError(message) from ex + raise ex + + def list(self, resource_group_name, cluster_type, cluster_name): + cluster_rp = get_cluster_rp(cluster_type) + return self.client.list(resource_group_name, cluster_rp, cluster_type, cluster_name) + + def delete(self, resource_group_name, cluster_type, cluster_name, name): + cluster_rp = get_cluster_rp(cluster_type) + return self.client.begin_delete(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + + # pylint: disable=too-many-locals + def create(self, resource_group_name, cluster_name, name, repository_url, scope, cluster_type, + operator_instance_name, operator_namespace, helm_operator_chart_version, operator_type, + operator_params, ssh_private_key, ssh_private_key_file, https_user, https_key, + ssh_known_hosts, ssh_known_hosts_file, enable_helm_operator, helm_operator_params): + + """Create a new Kubernetes Source Control Configuration. + + """ + # Determine ClusterRP + cluster_rp = get_cluster_rp(cluster_type) + + # Determine operatorInstanceName + if operator_instance_name is None: + operator_instance_name = name + + # Create helmOperatorProperties object + helm_operator_properties = None + if enable_helm_operator: + helm_operator_properties = HelmOperatorProperties() + helm_operator_properties.chart_version = helm_operator_chart_version.strip() + helm_operator_properties.chart_values = helm_operator_params.strip() + + validate_url_with_params(repository_url, + ssh_private_key, + ssh_private_key_file, + ssh_known_hosts, + ssh_known_hosts_file, + https_user, + https_key) + + protected_settings = get_protected_settings(ssh_private_key, + ssh_private_key_file, + https_user, + https_key) + knownhost_data = get_data_from_key_or_file(ssh_known_hosts, ssh_known_hosts_file) + if knownhost_data: + validate_known_hosts(knownhost_data) + + # Validate that the subscription is registered to Microsoft.KubernetesConfiguration + validate_cc_registration(self.cmd) + + # Create sourceControlConfiguration object + source_control_configuration = SourceControlConfiguration( + repository_url=repository_url, + operator_namespace=operator_namespace, + operator_instance_name=operator_instance_name, + operator_type=operator_type, + operator_params=operator_params, + configuration_protected_settings=protected_settings, + operator_scope=scope, + ssh_known_hosts_contents=knownhost_data, + enable_helm_operator=enable_helm_operator, + helm_operator_properties=helm_operator_properties + ) + + # Try to create the resource + config = self.client.create_or_update(resource_group_name, cluster_rp, cluster_type, cluster_name, + name, source_control_configuration) + + return fix_compliance_state(config) + + +def get_protected_settings(ssh_private_key, ssh_private_key_file, https_user, https_key): + protected_settings = {} + ssh_private_key_data = get_data_from_key_or_file(ssh_private_key, ssh_private_key_file) + + # Add gitops private key data to protected settings if exists + # Dry-run all key types to determine if the private key is in a valid format + if ssh_private_key_data: + protected_settings[consts.SSH_PRIVATE_KEY_KEY] = ssh_private_key_data + + # Check if both httpsUser and httpsKey exist, then add to protected settings + if https_user and https_key: + protected_settings[consts.HTTPS_USER_KEY] = to_base64(https_user) + protected_settings[consts.HTTPS_KEY_KEY] = to_base64(https_key) + + return protected_settings diff --git a/src/k8s-configuration/azext_k8s_configuration/providers/__init__.py b/src/k8s-configuration/azext_k8s_configuration/providers/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/k8s-configuration/azext_k8s_configuration/tests/latest/recordings/test_k8s_configuration_success.yaml b/src/k8s-configuration/azext_k8s_configuration/tests/latest/recordings/test_k8s_configuration_success.yaml index df066387443..41ea5533cf5 100644 --- a/src/k8s-configuration/azext_k8s_configuration/tests/latest/recordings/test_k8s_configuration_success.yaml +++ b/src/k8s-configuration/azext_k8s_configuration/tests/latest/recordings/test_k8s_configuration_success.yaml @@ -1,441 +1,523 @@ -interactions: -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - CommandName: - - k8s-configuration show - Connection: - - keep-alive - ParameterSetName: - - -g -c -n --cluster-type - User-Agent: - - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 - azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 - accept-language: - - en-US - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10?api-version=2021-03-01 - response: - body: - string: '{"error":{"code":"ResourceNotFound","message":"SourceControlConfiguration - with name ''cli-test-config10'' not found."}}' - headers: - api-supported-versions: - - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 - cache-control: - - no-cache - content-length: - - '117' - content-type: - - application/json; charset=utf-8 - date: - - Wed, 10 Feb 2021 22:59:01 GMT - expires: - - '-1' - pragma: - - no-cache - server: - - openresty/1.15.8.2 - strict-transport-security: - - max-age=31536000; includeSubDomains - x-content-type-options: - - nosniff - status: - code: 404 - message: Not Found -- request: - body: '{"properties": {"repositoryUrl": "git://github.com/anubhav929/flux-get-started", - "operatorNamespace": "cli-test-config10-opns", "operatorInstanceName": "cli-test-config10-opin", - "operatorType": "flux", "operatorParams": "--git-readonly ", "configurationProtectedSettings": - {"sshPrivateKey": "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUJsd0FBQUFkemMyZ3RjbgpOaEFBQUFBd0VBQVFBQUFZRUFxZlBtNlc3YkVLTmVvN3VCQzhTMXYydUpPS1NZWGNmanlpVEk2djNkZUhRSjJtMGFRajB0CmtwM05qMUZkRUsrMkVXTy9xNGFkWUpaS0ZZSjluWTZyREZOSXBZdmVWaVNUQjhITzI5VVdySTRLVGZMRGhiVmVCV0pjQVcKMkFpZ0ZnTU5qdTZXa0JVL1NWK1FCVHJiRVl6RFhpOTVNR1ZveTVKV3drdkdtakRaOHFSaEFxbU0rdUF4S1I4Z1lyRllPZgpRbC9zM2I5ajJKQ1VtVFlwYkxqMkJPd0JNQ1J3NlFQY0lVcVlaaUl3MUNNaXZKZ2tVQTdwUlRCZHVsYXlXNWQ2MTl4RFNsCmZ6N1JuU0tKM3RwanEwZThBTmtkU1h4SjQrMXhpNm5IM0lVY1ZBM1NzcVhWam80ak5sNU5EWkJlTDNpQ0xXSVZYUkpDemsKNGg3a2pXVkQ3UnNDNGJDOTF6MzlZMDlnK3ZIdjErZFplUmNYZWIvNkFzbTBEeHVhRGo2cVVCVm9JOWkwbzFKbndiMnA0MQpGV2prazljc054a2dnajMzU3ozTWJRTVN0bTFLaWU2bHNRamlMUXdGT3Qwd3lFTnova2RUR25idkVMUTN3aWdUdVFrelFOCnlMR2dmK3FXZnhqL1l1MWt5b0xrQVpqT3JxdEttalVILzk3Y3lncWhBQUFGa08zNi9uWHQrdjUxQUFBQUIzTnphQzF5YzIKRUFBQUdCQUtuejV1bHUyeENqWHFPN2dRdkV0YjlyaVRpa21GM0g0OG9reU9yOTNYaDBDZHB0R2tJOUxaS2R6WTlSWFJDdgp0aEZqdjZ1R25XQ1dTaFdDZloyT3F3eFRTS1dMM2xZa2t3ZkJ6dHZWRnF5T0NrM3l3NFcxWGdWaVhBRnRnSW9CWUREWTd1CmxwQVZQMGxma0FVNjJ4R013MTR2ZVRCbGFNdVNWc0pMeHBvdzJmS2tZUUtwalByZ01Ta2ZJR0t4V0RuMEpmN04yL1k5aVEKbEprMktXeTQ5Z1RzQVRBa2NPa0QzQ0ZLbUdZaU1OUWpJcnlZSkZBTzZVVXdYYnBXc2x1WGV0ZmNRMHBYOCswWjBpaWQ3YQpZNnRIdkFEWkhVbDhTZVB0Y1l1cHg5eUZIRlFOMHJLbDFZNk9JelplVFEyUVhpOTRnaTFpRlYwU1FzNU9JZTVJMWxRKzBiCkF1R3d2ZGM5L1dOUFlQcng3OWZuV1hrWEYzbS8rZ0xKdEE4Ym1nNCtxbEFWYUNQWXRLTlNaOEc5cWVOUlZvNUpQWExEY1oKSUlJOTkwczl6RzBERXJadFNvbnVwYkVJNGkwTUJUcmRNTWhEYy81SFV4cDI3eEMwTjhJb0U3a0pNMERjaXhvSC9xbG44WQovMkx0Wk1xQzVBR1l6cTZyU3BvMUIvL2UzTW9Lb1FBQUFBTUJBQUVBQUFHQkFKSnJUVTlqY0Z4ZlE1UHdZUGRRbS95MG10CjR3QUEwYnY0WlNOcjh0dy9hWWtqeWFybnJPMWtwd3BiNkpySkpKcjZRL3Vjdi9CK3RFejhMRVQ1REViMTBKQzVlRWJ5THMKRTdnbEl5Q0Y3eWp1bnJZVkpwbzFiVEZhVWtYd24wTkdlQ2JkWHNlODdhWDFISmdQemdmZ2dhcTk2aks5ZWtKcXJzQXM4VwpGWjZWNDgrR0N3WU9LU1dpclBmdWx5b3YvQURCOVZJVzdTQ3lWek9uTGRGTWRVZXJBMjI3Y3NUaEtTZnI0MzFDQjU2SE43CmFkdnRmNnR4alV0TXBoTjV5ZVBiRmxVZS9Wb2VQY1hNdXA4OXN3V2gvd3ZScklCbytUYXo2SzQxcGFzOEVObjFyemFxL3kKRHlWelJuSGtlMGhKR2ZZelJhbzlZQm5jeHFMOCtXdDQxZFFzQUdhdlIwd3ZNSit5TFpuR0x5amVXaVZkcExjT0FWSGpIOQpITGMrTDdnaGpIZ1VidDNDWG9Wd0gyWktnelI5cmk3bU93YnorejZsN1pwWjlQalJxeU1HcTloYU5vNHVEdjJqbWhGNlZVClBMU2Q3WTczWCtWTFAvWUZqbTBlUzJUbGFRQ3E2Vms0dzJqSHVWcXorcng4SllYb2tidFZXYnFYcmg3VzF5VGk4MXVRQUEKQU1Ba0JaQzF0SThvd29SNDYvL1h1SWQxQjBGRUhGUXBvSHFuVGNSVlVKS2RXb2xJRU5tYVVtdG1UZFVicVYyNGJMa1RtZQpiWHZQdlF3LzJoVk5VVmhWbDNjays1SUZBS0hYVWJ3ZklSWE8vUVlUbFM0ZVdabkFsN0JQSzJQa080SXkvOG1zQVZKRGl4CmkvVm1oaTBYb05lSmxERU9sdzNaY084aTlRZjVSbTNEWmRHUDRha0JsYmk5ekdBWUpqRGFjM0dWdTMxK2pJVG9hUHplbysKeUFDL2svM0J5Slg4enQ1cDRHVXpsNVFKcEVHMnBpQXdJeElKZS8yK3pBMXU5dmhma0FBQURCQU5NZHdhemx5MXNpd0dXbQpJWSs4VFZMN1EwQ1pFTWxTL0VraE1YM2FNQnZYaURXd2cwVk8zKytXUDhlMWhDSUxvNmdqL0N2dFdLdGEzVlozUWFScHZ5CkhCVEp4Q205NHZQOXFPelhTRGZ0WVRrSHh1SFdQaklhb010N0YyL0srejJiZTdESmhvL0ZwMVY0U2x2R1ljWHdqaWhEaDAKbHF1bUltOEJJei9taHpjZTFKR0VMUUdJeXk4RDI0dTNtY2NhSFoxYWY1V3A5Y1VCZ09POXEwa3B1WVhEdHpPSk9UTVozUQpNUm5xdXVVM1ppRHdmRGltZzdsZktwWGkxZzFxeWZUd0FBQU1FQXpoWEdhTVdBM1pUT1hqWWhPTUhkdTk0R2RNcHNXYWo0CjBsMmZ6YzdFWTlzWEdLZ01XMllvRXk5UVNSTDRPUmNMaUFKTDRLZGdZeGZzeVdma1U1d21TbGZXNjlrb0R2WTE0LzNWbWYKZ0NTUkxvL0RnTUZtOGFNK3pUVzhWYTVpclJXWFpEeHNXb0RiNzdIZ2JZaE90M29iOEFWWUh4akk3N1k3MXlBUzhXS2xRSQpYQi9qZ01vN1BCL3BTMVVYSEhCcndxQkdwM3M5aThab0E0L2hLY0pvaEtWSDZGL0Z2Rk1jWHZTNjZOcGNUWHNWQzBVUzNkCkJVY0taNTVvUUhVcnNQQUFBQUdIQnlZWFJvYVd0eVFFeEJVRlJQVUMxU00wZFVUa2xDVXdFQwotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K"}, - "operatorScope": "namespace", "sshKnownHostsContents": "Z2l0b3BzLWJpdGJ1Y2tldC10ZXN0LXNlcnZlci5lYXN0dXMuY2xvdWRhcHAuYXp1cmUuY29tIHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQURBUUFCQUFBQkFRQytNT0w3bjk2aGs3emVmMDNwak9vMGF3UENISkZ4NU04TjJ2L2tvODgvc202Y2VzOFljdnYyL0hoUlhRSFZHRUxqZjNuTXVGSVJPMEdMdTFabFNreGRUTUhGcXBxYzFjcUM2R3kveUJXRGM1SWFwWnJBMXFxeSsrZVdpelAzQXdMbWsrMUhXWGdtcHljZUtYNU9vd3VNT3cwd3RYRUdTcDhtVk0wV2VpUzEwWnZ5ZVVKK04zbkNvczMyWDhIeVpnc1pMUS9zSTB4NXN6ODQ2am5JZEFOckZsYU9MUTJ1ejRUa0M2ekNvd3lIdzlLWXJ5V2hJZDAraCt5SXQ5dUtqVHZsWFNpdm1ISjViZzdUWWlkbnFtbjI0UGE4WnFpbTE5UGszUjg0cW9qclVmYm1XT3VwUjdYNXZVVWZqYzhERFRxa3FnRmkxcWdVdE1mWGlMRXErZFVa", - "enableHelmOperator": true, "helmOperatorProperties": {"chartVersion": "1.2.0", - "chartValues": "--set git.ssh.secretName=gitops-privatekey-cli-test-config10-opin - --set tillerNamespace=kube-system"}}}' - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - CommandName: - - k8s-configuration create - Connection: - - keep-alive - Content-Length: - - '4614' - Content-Type: - - application/json; charset=utf-8 - ParameterSetName: - - -g -n -c -u --cluster-type --scope --operator-instance-name --operator-namespace - --operator-params --git-readonly --ssh-private-key --ssh-known-hosts --enable-helm-operator - --helm-operator-chart-version --helm-operator-params --set git.ssh.secretName - User-Agent: - - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 - azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 - accept-language: - - en-US - method: PUT - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10?api-version=2021-03-01 - response: - body: - string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10","name":"cli-test-config10","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"cli-test-config10-opns","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set - git.ssh.secretName=gitops-privatekey-cli-test-config10-opin --set tillerNamespace=kube-system"},"repositoryUrl":"git://github.com/anubhav929/flux-get-started","operatorInstanceName":"cli-test-config10-opin","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"Z2l0b3BzLWJpdGJ1Y2tldC10ZXN0LXNlcnZlci5lYXN0dXMuY2xvdWRhcHAuYXp1cmUuY29tIHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQURBUUFCQUFBQkFRQytNT0w3bjk2aGs3emVmMDNwak9vMGF3UENISkZ4NU04TjJ2L2tvODgvc202Y2VzOFljdnYyL0hoUlhRSFZHRUxqZjNuTXVGSVJPMEdMdTFabFNreGRUTUhGcXBxYzFjcUM2R3kveUJXRGM1SWFwWnJBMXFxeSsrZVdpelAzQXdMbWsrMUhXWGdtcHljZUtYNU9vd3VNT3cwd3RYRUdTcDhtVk0wV2VpUzEwWnZ5ZVVKK04zbkNvczMyWDhIeVpnc1pMUS9zSTB4NXN6ODQ2am5JZEFOckZsYU9MUTJ1ejRUa0M2ekNvd3lIdzlLWXJ5V2hJZDAraCt5SXQ5dUtqVHZsWFNpdm1ISjViZzdUWWlkbnFtbjI0UGE4WnFpbTE5UGszUjg0cW9qclVmYm1XT3VwUjdYNXZVVWZqYzhERFRxa3FnRmkxcWdVdE1mWGlMRXErZFVa","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-02-10T22:59:03.2209+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-02-10T22:59:03.2209001+00:00"}}' - headers: - api-supported-versions: - - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 - cache-control: - - no-cache - content-length: - - '1876' - content-type: - - application/json; charset=utf-8 - date: - - Wed, 10 Feb 2021 22:59:02 GMT - expires: - - '-1' - location: - - file:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10 - pragma: - - no-cache - server: - - openresty/1.15.8.2 - strict-transport-security: - - max-age=31536000; includeSubDomains - x-content-type-options: - - nosniff - x-ms-ratelimit-remaining-subscription-writes: - - '1199' - status: - code: 201 - message: Created -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - CommandName: - - k8s-configuration show - Connection: - - keep-alive - ParameterSetName: - - -g -c -n --cluster-type - User-Agent: - - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 - azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 - accept-language: - - en-US - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10?api-version=2021-03-01 - response: - body: - string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10","name":"cli-test-config10","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"cli-test-config10-opns","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set - git.ssh.secretName=gitops-privatekey-cli-test-config10-opin --set tillerNamespace=kube-system"},"repositoryUrl":"git://github.com/anubhav929/flux-get-started","operatorInstanceName":"cli-test-config10-opin","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"Z2l0b3BzLWJpdGJ1Y2tldC10ZXN0LXNlcnZlci5lYXN0dXMuY2xvdWRhcHAuYXp1cmUuY29tIHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQURBUUFCQUFBQkFRQytNT0w3bjk2aGs3emVmMDNwak9vMGF3UENISkZ4NU04TjJ2L2tvODgvc202Y2VzOFljdnYyL0hoUlhRSFZHRUxqZjNuTXVGSVJPMEdMdTFabFNreGRUTUhGcXBxYzFjcUM2R3kveUJXRGM1SWFwWnJBMXFxeSsrZVdpelAzQXdMbWsrMUhXWGdtcHljZUtYNU9vd3VNT3cwd3RYRUdTcDhtVk0wV2VpUzEwWnZ5ZVVKK04zbkNvczMyWDhIeVpnc1pMUS9zSTB4NXN6ODQ2am5JZEFOckZsYU9MUTJ1ejRUa0M2ekNvd3lIdzlLWXJ5V2hJZDAraCt5SXQ5dUtqVHZsWFNpdm1ISjViZzdUWWlkbnFtbjI0UGE4WnFpbTE5UGszUjg0cW9qclVmYm1XT3VwUjdYNXZVVWZqYzhERFRxa3FnRmkxcWdVdE1mWGlMRXErZFVa","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-02-10T22:59:03.2209+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-02-10T22:59:03.2209001+00:00"}}' - headers: - api-supported-versions: - - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 - cache-control: - - no-cache - content-length: - - '1876' - content-type: - - application/json; charset=utf-8 - date: - - Wed, 10 Feb 2021 22:59:03 GMT - expires: - - '-1' - pragma: - - no-cache - server: - - openresty/1.15.8.2 - strict-transport-security: - - max-age=31536000; includeSubDomains - transfer-encoding: - - chunked - vary: - - Accept-Encoding,Accept-Encoding - x-content-type-options: - - nosniff - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - CommandName: - - k8s-configuration delete - Connection: - - keep-alive - Content-Length: - - '0' - ParameterSetName: - - -g -c -n --cluster-type -y - User-Agent: - - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 - azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 - accept-language: - - en-US - method: DELETE - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10?api-version=2021-03-01 - response: - body: - string: '{"version":"1.1","content":null,"statusCode":200,"reasonPhrase":"OK","headers":[],"trailingHeaders":[],"requestMessage":null,"isSuccessStatusCode":true}' - headers: - api-supported-versions: - - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 - cache-control: - - no-cache - content-length: - - '152' - content-type: - - application/json; charset=utf-8 - date: - - Wed, 10 Feb 2021 22:59:05 GMT - expires: - - '-1' - pragma: - - no-cache - server: - - openresty/1.15.8.2 - strict-transport-security: - - max-age=31536000; includeSubDomains - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-content-type-options: - - nosniff - x-ms-ratelimit-remaining-subscription-deletes: - - '14999' - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - CommandName: - - k8s-configuration show - Connection: - - keep-alive - ParameterSetName: - - -g -c -n --cluster-type - User-Agent: - - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 - azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 - accept-language: - - en-US - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11?api-version=2021-03-01 - response: - body: - string: '{"error":{"code":"ResourceNotFound","message":"SourceControlConfiguration - with name ''cli-test-config11'' not found."}}' - headers: - api-supported-versions: - - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 - cache-control: - - no-cache - content-length: - - '117' - content-type: - - application/json; charset=utf-8 - date: - - Wed, 10 Feb 2021 22:59:05 GMT - expires: - - '-1' - pragma: - - no-cache - server: - - openresty/1.15.8.2 - strict-transport-security: - - max-age=31536000; includeSubDomains - x-content-type-options: - - nosniff - status: - code: 404 - message: Not Found -- request: - body: '{"properties": {"repositoryUrl": "https://github.com/jonathan-innis/helm-operator-get-started-private.git", - "operatorNamespace": "cli-test-config11-opns", "operatorInstanceName": "cli-test-config11-opin", - "operatorType": "flux", "operatorParams": "--git-readonly ", "configurationProtectedSettings": - {"httpsUser": "ZmFrZS11c2VybmFtZQ==", "httpsKey": "ZmFrZXBhc3N3b3JkdGhhdGl3b3VsZHVzZWZvcmdpdGh1Yg=="}, - "operatorScope": "namespace", "sshKnownHostsContents": "", "enableHelmOperator": - true, "helmOperatorProperties": {"chartVersion": "1.2.0", "chartValues": "--set - tillerNamespace=kube-system"}}}' - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - CommandName: - - k8s-configuration create - Connection: - - keep-alive - Content-Length: - - '595' - Content-Type: - - application/json; charset=utf-8 - ParameterSetName: - - -g -n -c -u --cluster-type --scope --operator-instance-name --operator-namespace - --operator-params --git-readonly --https-user --https-key --enable-helm-operator - --helm-operator-chart-version --helm-operator-params --set tillerNamespace - User-Agent: - - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 - azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 - accept-language: - - en-US - method: PUT - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11?api-version=2021-03-01 - response: - body: - string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11","name":"cli-test-config11","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"cli-test-config11-opns","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set - tillerNamespace=kube-system"},"repositoryUrl":"https://github.com/jonathan-innis/helm-operator-get-started-private.git","operatorInstanceName":"cli-test-config11-opin","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-02-10T22:59:07.5893423+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-02-10T22:59:07.5893424+00:00"}}' - headers: - api-supported-versions: - - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 - cache-control: - - no-cache - content-length: - - '1260' - content-type: - - application/json; charset=utf-8 - date: - - Wed, 10 Feb 2021 22:59:07 GMT - expires: - - '-1' - location: - - file:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11 - pragma: - - no-cache - server: - - openresty/1.15.8.2 - strict-transport-security: - - max-age=31536000; includeSubDomains - x-content-type-options: - - nosniff - x-ms-ratelimit-remaining-subscription-writes: - - '1199' - status: - code: 201 - message: Created -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - CommandName: - - k8s-configuration show - Connection: - - keep-alive - ParameterSetName: - - -g -c -n --cluster-type - User-Agent: - - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 - azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 - accept-language: - - en-US - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11?api-version=2021-03-01 - response: - body: - string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11","name":"cli-test-config11","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"cli-test-config11-opns","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set - tillerNamespace=kube-system"},"repositoryUrl":"https://github.com/jonathan-innis/helm-operator-get-started-private.git","operatorInstanceName":"cli-test-config11-opin","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-02-10T22:59:07.5893423+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-02-10T22:59:07.5893424+00:00"}}' - headers: - api-supported-versions: - - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 - cache-control: - - no-cache - content-length: - - '1260' - content-type: - - application/json; charset=utf-8 - date: - - Wed, 10 Feb 2021 22:59:08 GMT - expires: - - '-1' - pragma: - - no-cache - server: - - openresty/1.15.8.2 - strict-transport-security: - - max-age=31536000; includeSubDomains - transfer-encoding: - - chunked - vary: - - Accept-Encoding,Accept-Encoding - x-content-type-options: - - nosniff - status: - code: 200 - message: OK -- request: - body: null - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - CommandName: - - k8s-configuration delete - Connection: - - keep-alive - Content-Length: - - '0' - ParameterSetName: - - -g -c -n --cluster-type -y - User-Agent: - - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 - azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 - accept-language: - - en-US - method: DELETE - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11?api-version=2021-03-01 - response: - body: - string: '{"version":"1.1","content":null,"statusCode":200,"reasonPhrase":"OK","headers":[],"trailingHeaders":[],"requestMessage":null,"isSuccessStatusCode":true}' - headers: - api-supported-versions: - - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 - cache-control: - - no-cache - content-length: - - '152' - content-type: - - application/json; charset=utf-8 - date: - - Wed, 10 Feb 2021 22:59:08 GMT - expires: - - '-1' - pragma: - - no-cache - server: - - openresty/1.15.8.2 - strict-transport-security: - - max-age=31536000; includeSubDomains - transfer-encoding: - - chunked - vary: - - Accept-Encoding - x-content-type-options: - - nosniff - x-ms-ratelimit-remaining-subscription-deletes: - - '14999' - status: - code: 200 - message: OK -version: 1 +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration show + Connection: + - keep-alive + ParameterSetName: + - -g -c -n --cluster-type + User-Agent: + - AZURECLI/2.28.0 azsdk-python-azure-mgmt-kubernetesconfiguration/1.0.0b1 Python/3.9.6 + (Windows-10-10.0.19043-SP0) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config?api-version=2021-03-01 + response: + body: + string: '{"error":{"code":"ResourceNotFound","message":"SourceControlConfiguration + with name ''test-config'' not found."}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01, 2021-05-01-preview + cache-control: + - no-cache + content-length: + - '111' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 08 Sep 2021 19:26:43 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + status: + code: 404 + message: Not Found +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration create + Connection: + - keep-alive + ParameterSetName: + - -g -n -c -u --cluster-type --scope --operator-instance-name --operator-namespace + --operator-params --git-readonly --ssh-private-key --ssh-known-hosts --enable-helm-operator + --helm-operator-chart-version --helm-operator-params --set git.ssh.secretName + User-Agent: + - AZURECLI/2.28.0 azsdk-python-azure-mgmt-resource/19.0.0 Python/3.9.6 (Windows-10-10.0.19043-SP0) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.KubernetesConfiguration?api-version=2021-04-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.KubernetesConfiguration","namespace":"Microsoft.KubernetesConfiguration","authorizations":[{"applicationId":"c699bf69-fb1d-4eaf-999b-99e6b2ae4d85","roleDefinitionId":"90155430-a360-410f-af5d-89dc284d85c6"},{"applicationId":"03db181c-e9d3-4868-9097-f0b728327182","roleDefinitionId":"DE2ADB97-42D8-49C8-8FCF-DBB53EF936AC"},{"applicationId":"a0f92522-89de-4c5e-9a75-0044ccf66efd","roleDefinitionId":"b3429810-7d5c-420e-8605-cf280f3099f2"},{"applicationId":"bd9b7cd5-dac1-495f-b013-ac871e98fa5f","roleDefinitionId":"0d44c8f0-08b9-44d4-9f59-e51c83f95200"}],"resourceTypes":[{"resourceType":"sourceControlConfigurations","locations":["East + US","West Europe","West Central US","West US 2","South Central US","East US + 2","North Europe","UK South","Southeast Asia","Australia East","France Central","Central + US","North Central US","West US","Korea Central","East Asia","Japan East","East + US 2 EUAP"],"apiVersions":["2021-03-01","2020-10-01-preview","2020-07-01-preview","2019-11-01-preview"],"defaultApiVersion":"2021-03-01","capabilities":"SupportsExtension"},{"resourceType":"extensions","locations":["East + US","West Europe","West Central US","West US 2","South Central US","East US + 2","North Europe","UK South","Southeast Asia","Australia East","France Central","Central + US","North Central US","West US","Korea Central","East Asia","Japan East","East + US 2 EUAP"],"apiVersions":["2021-05-01-preview","2020-07-01-preview"],"capabilities":"SystemAssignedResourceIdentity, + SupportsExtension"},{"resourceType":"operations","locations":[],"apiVersions":["2021-06-01-preview","2021-05-01-preview","2021-03-01","2020-10-01-preview","2020-07-01-preview","2019-11-01-preview"],"capabilities":"None"},{"resourceType":"fluxConfigurations","locations":["East + US 2 EUAP","East US","West Europe","West Central US","West US 2","South Central + US","East US 2","North Europe","UK South","Southeast Asia","Australia East","France + Central","Central US","North Central US","West US","Korea Central","East Asia","Japan + East"],"apiVersions":["2021-06-01-preview"],"defaultApiVersion":"2021-06-01-preview","capabilities":"SupportsExtension"}],"registrationState":"Registered","registrationPolicy":"RegistrationRequired"}' + headers: + cache-control: + - no-cache + content-length: + - '2268' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 08 Sep 2021 19:26:44 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: '{"properties": {"repositoryUrl": "git://github.com/anubhav929/flux-get-started", + "operatorNamespace": "test-config-namespace", "operatorInstanceName": "test-config-name", + "operatorType": "flux", "operatorParams": "--git-readonly ", "configurationProtectedSettings": + {"sshPrivateKey": "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUJsd0FBQUFkemMyZ3RjbgpOaEFBQUFBd0VBQVFBQUFZRUFxZlBtNlc3YkVLTmVvN3VCQzhTMXYydUpPS1NZWGNmanlpVEk2djNkZUhRSjJtMGFRajB0CmtwM05qMUZkRUsrMkVXTy9xNGFkWUpaS0ZZSjluWTZyREZOSXBZdmVWaVNUQjhITzI5VVdySTRLVGZMRGhiVmVCV0pjQVcKMkFpZ0ZnTU5qdTZXa0JVL1NWK1FCVHJiRVl6RFhpOTVNR1ZveTVKV3drdkdtakRaOHFSaEFxbU0rdUF4S1I4Z1lyRllPZgpRbC9zM2I5ajJKQ1VtVFlwYkxqMkJPd0JNQ1J3NlFQY0lVcVlaaUl3MUNNaXZKZ2tVQTdwUlRCZHVsYXlXNWQ2MTl4RFNsCmZ6N1JuU0tKM3RwanEwZThBTmtkU1h4SjQrMXhpNm5IM0lVY1ZBM1NzcVhWam80ak5sNU5EWkJlTDNpQ0xXSVZYUkpDemsKNGg3a2pXVkQ3UnNDNGJDOTF6MzlZMDlnK3ZIdjErZFplUmNYZWIvNkFzbTBEeHVhRGo2cVVCVm9JOWkwbzFKbndiMnA0MQpGV2prazljc054a2dnajMzU3ozTWJRTVN0bTFLaWU2bHNRamlMUXdGT3Qwd3lFTnova2RUR25idkVMUTN3aWdUdVFrelFOCnlMR2dmK3FXZnhqL1l1MWt5b0xrQVpqT3JxdEttalVILzk3Y3lncWhBQUFGa08zNi9uWHQrdjUxQUFBQUIzTnphQzF5YzIKRUFBQUdCQUtuejV1bHUyeENqWHFPN2dRdkV0YjlyaVRpa21GM0g0OG9reU9yOTNYaDBDZHB0R2tJOUxaS2R6WTlSWFJDdgp0aEZqdjZ1R25XQ1dTaFdDZloyT3F3eFRTS1dMM2xZa2t3ZkJ6dHZWRnF5T0NrM3l3NFcxWGdWaVhBRnRnSW9CWUREWTd1CmxwQVZQMGxma0FVNjJ4R013MTR2ZVRCbGFNdVNWc0pMeHBvdzJmS2tZUUtwalByZ01Ta2ZJR0t4V0RuMEpmN04yL1k5aVEKbEprMktXeTQ5Z1RzQVRBa2NPa0QzQ0ZLbUdZaU1OUWpJcnlZSkZBTzZVVXdYYnBXc2x1WGV0ZmNRMHBYOCswWjBpaWQ3YQpZNnRIdkFEWkhVbDhTZVB0Y1l1cHg5eUZIRlFOMHJLbDFZNk9JelplVFEyUVhpOTRnaTFpRlYwU1FzNU9JZTVJMWxRKzBiCkF1R3d2ZGM5L1dOUFlQcng3OWZuV1hrWEYzbS8rZ0xKdEE4Ym1nNCtxbEFWYUNQWXRLTlNaOEc5cWVOUlZvNUpQWExEY1oKSUlJOTkwczl6RzBERXJadFNvbnVwYkVJNGkwTUJUcmRNTWhEYy81SFV4cDI3eEMwTjhJb0U3a0pNMERjaXhvSC9xbG44WQovMkx0Wk1xQzVBR1l6cTZyU3BvMUIvL2UzTW9Lb1FBQUFBTUJBQUVBQUFHQkFKSnJUVTlqY0Z4ZlE1UHdZUGRRbS95MG10CjR3QUEwYnY0WlNOcjh0dy9hWWtqeWFybnJPMWtwd3BiNkpySkpKcjZRL3Vjdi9CK3RFejhMRVQ1REViMTBKQzVlRWJ5THMKRTdnbEl5Q0Y3eWp1bnJZVkpwbzFiVEZhVWtYd24wTkdlQ2JkWHNlODdhWDFISmdQemdmZ2dhcTk2aks5ZWtKcXJzQXM4VwpGWjZWNDgrR0N3WU9LU1dpclBmdWx5b3YvQURCOVZJVzdTQ3lWek9uTGRGTWRVZXJBMjI3Y3NUaEtTZnI0MzFDQjU2SE43CmFkdnRmNnR4alV0TXBoTjV5ZVBiRmxVZS9Wb2VQY1hNdXA4OXN3V2gvd3ZScklCbytUYXo2SzQxcGFzOEVObjFyemFxL3kKRHlWelJuSGtlMGhKR2ZZelJhbzlZQm5jeHFMOCtXdDQxZFFzQUdhdlIwd3ZNSit5TFpuR0x5amVXaVZkcExjT0FWSGpIOQpITGMrTDdnaGpIZ1VidDNDWG9Wd0gyWktnelI5cmk3bU93YnorejZsN1pwWjlQalJxeU1HcTloYU5vNHVEdjJqbWhGNlZVClBMU2Q3WTczWCtWTFAvWUZqbTBlUzJUbGFRQ3E2Vms0dzJqSHVWcXorcng4SllYb2tidFZXYnFYcmg3VzF5VGk4MXVRQUEKQU1Ba0JaQzF0SThvd29SNDYvL1h1SWQxQjBGRUhGUXBvSHFuVGNSVlVKS2RXb2xJRU5tYVVtdG1UZFVicVYyNGJMa1RtZQpiWHZQdlF3LzJoVk5VVmhWbDNjays1SUZBS0hYVWJ3ZklSWE8vUVlUbFM0ZVdabkFsN0JQSzJQa080SXkvOG1zQVZKRGl4CmkvVm1oaTBYb05lSmxERU9sdzNaY084aTlRZjVSbTNEWmRHUDRha0JsYmk5ekdBWUpqRGFjM0dWdTMxK2pJVG9hUHplbysKeUFDL2svM0J5Slg4enQ1cDRHVXpsNVFKcEVHMnBpQXdJeElKZS8yK3pBMXU5dmhma0FBQURCQU5NZHdhemx5MXNpd0dXbQpJWSs4VFZMN1EwQ1pFTWxTL0VraE1YM2FNQnZYaURXd2cwVk8zKytXUDhlMWhDSUxvNmdqL0N2dFdLdGEzVlozUWFScHZ5CkhCVEp4Q205NHZQOXFPelhTRGZ0WVRrSHh1SFdQaklhb010N0YyL0srejJiZTdESmhvL0ZwMVY0U2x2R1ljWHdqaWhEaDAKbHF1bUltOEJJei9taHpjZTFKR0VMUUdJeXk4RDI0dTNtY2NhSFoxYWY1V3A5Y1VCZ09POXEwa3B1WVhEdHpPSk9UTVozUQpNUm5xdXVVM1ppRHdmRGltZzdsZktwWGkxZzFxeWZUd0FBQU1FQXpoWEdhTVdBM1pUT1hqWWhPTUhkdTk0R2RNcHNXYWo0CjBsMmZ6YzdFWTlzWEdLZ01XMllvRXk5UVNSTDRPUmNMaUFKTDRLZGdZeGZzeVdma1U1d21TbGZXNjlrb0R2WTE0LzNWbWYKZ0NTUkxvL0RnTUZtOGFNK3pUVzhWYTVpclJXWFpEeHNXb0RiNzdIZ2JZaE90M29iOEFWWUh4akk3N1k3MXlBUzhXS2xRSQpYQi9qZ01vN1BCL3BTMVVYSEhCcndxQkdwM3M5aThab0E0L2hLY0pvaEtWSDZGL0Z2Rk1jWHZTNjZOcGNUWHNWQzBVUzNkCkJVY0taNTVvUUhVcnNQQUFBQUdIQnlZWFJvYVd0eVFFeEJVRlJQVUMxU00wZFVUa2xDVXdFQwotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K"}, + "operatorScope": "namespace", "sshKnownHostsContents": "Z2l0b3BzLWJpdGJ1Y2tldC10ZXN0LXNlcnZlci5lYXN0dXMuY2xvdWRhcHAuYXp1cmUuY29tIHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQURBUUFCQUFBQkFRQytNT0w3bjk2aGs3emVmMDNwak9vMGF3UENISkZ4NU04TjJ2L2tvODgvc202Y2VzOFljdnYyL0hoUlhRSFZHRUxqZjNuTXVGSVJPMEdMdTFabFNreGRUTUhGcXBxYzFjcUM2R3kveUJXRGM1SWFwWnJBMXFxeSsrZVdpelAzQXdMbWsrMUhXWGdtcHljZUtYNU9vd3VNT3cwd3RYRUdTcDhtVk0wV2VpUzEwWnZ5ZVVKK04zbkNvczMyWDhIeVpnc1pMUS9zSTB4NXN6ODQ2am5JZEFOckZsYU9MUTJ1ejRUa0M2ekNvd3lIdzlLWXJ5V2hJZDAraCt5SXQ5dUtqVHZsWFNpdm1ISjViZzdUWWlkbnFtbjI0UGE4WnFpbTE5UGszUjg0cW9qclVmYm1XT3VwUjdYNXZVVWZqYzhERFRxa3FnRmkxcWdVdE1mWGlMRXErZFVa", + "enableHelmOperator": true, "helmOperatorProperties": {"chartVersion": "1.2.0", + "chartValues": "--set git.ssh.secretName=gitops-privatekey-test-config-name + --set tillerNamespace=kube-system"}}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration create + Connection: + - keep-alive + Content-Length: + - '4601' + Content-Type: + - application/json + ParameterSetName: + - -g -n -c -u --cluster-type --scope --operator-instance-name --operator-namespace + --operator-params --git-readonly --ssh-private-key --ssh-known-hosts --enable-helm-operator + --helm-operator-chart-version --helm-operator-params --set git.ssh.secretName + User-Agent: + - AZURECLI/2.28.0 azsdk-python-azure-mgmt-kubernetesconfiguration/1.0.0b1 Python/3.9.6 + (Windows-10-10.0.19043-SP0) + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config?api-version=2021-03-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config","name":"test-config","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"test-config-namespace","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set + git.ssh.secretName=gitops-privatekey-test-config-name --set tillerNamespace=kube-system"},"repositoryUrl":"git://github.com/anubhav929/flux-get-started","operatorInstanceName":"test-config-name","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"Z2l0b3BzLWJpdGJ1Y2tldC10ZXN0LXNlcnZlci5lYXN0dXMuY2xvdWRhcHAuYXp1cmUuY29tIHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQURBUUFCQUFBQkFRQytNT0w3bjk2aGs3emVmMDNwak9vMGF3UENISkZ4NU04TjJ2L2tvODgvc202Y2VzOFljdnYyL0hoUlhRSFZHRUxqZjNuTXVGSVJPMEdMdTFabFNreGRUTUhGcXBxYzFjcUM2R3kveUJXRGM1SWFwWnJBMXFxeSsrZVdpelAzQXdMbWsrMUhXWGdtcHljZUtYNU9vd3VNT3cwd3RYRUdTcDhtVk0wV2VpUzEwWnZ5ZVVKK04zbkNvczMyWDhIeVpnc1pMUS9zSTB4NXN6ODQ2am5JZEFOckZsYU9MUTJ1ejRUa0M2ekNvd3lIdzlLWXJ5V2hJZDAraCt5SXQ5dUtqVHZsWFNpdm1ISjViZzdUWWlkbnFtbjI0UGE4WnFpbTE5UGszUjg0cW9qclVmYm1XT3VwUjdYNXZVVWZqYzhERFRxa3FnRmkxcWdVdE1mWGlMRXErZFVa","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-09-08T19:26:46.585496+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-09-08T19:26:46.585496+00:00"}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01, 2021-05-01-preview + cache-control: + - no-cache + content-length: + - '1857' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 08 Sep 2021 19:26:46 GMT + expires: + - '-1' + location: + - file:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration show + Connection: + - keep-alive + ParameterSetName: + - -g -c -n --cluster-type + User-Agent: + - AZURECLI/2.28.0 azsdk-python-azure-mgmt-kubernetesconfiguration/1.0.0b1 Python/3.9.6 + (Windows-10-10.0.19043-SP0) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config?api-version=2021-03-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config","name":"test-config","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"test-config-namespace","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set + git.ssh.secretName=gitops-privatekey-test-config-name --set tillerNamespace=kube-system"},"repositoryUrl":"git://github.com/anubhav929/flux-get-started","operatorInstanceName":"test-config-name","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"Z2l0b3BzLWJpdGJ1Y2tldC10ZXN0LXNlcnZlci5lYXN0dXMuY2xvdWRhcHAuYXp1cmUuY29tIHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQURBUUFCQUFBQkFRQytNT0w3bjk2aGs3emVmMDNwak9vMGF3UENISkZ4NU04TjJ2L2tvODgvc202Y2VzOFljdnYyL0hoUlhRSFZHRUxqZjNuTXVGSVJPMEdMdTFabFNreGRUTUhGcXBxYzFjcUM2R3kveUJXRGM1SWFwWnJBMXFxeSsrZVdpelAzQXdMbWsrMUhXWGdtcHljZUtYNU9vd3VNT3cwd3RYRUdTcDhtVk0wV2VpUzEwWnZ5ZVVKK04zbkNvczMyWDhIeVpnc1pMUS9zSTB4NXN6ODQ2am5JZEFOckZsYU9MUTJ1ejRUa0M2ekNvd3lIdzlLWXJ5V2hJZDAraCt5SXQ5dUtqVHZsWFNpdm1ISjViZzdUWWlkbnFtbjI0UGE4WnFpbTE5UGszUjg0cW9qclVmYm1XT3VwUjdYNXZVVWZqYzhERFRxa3FnRmkxcWdVdE1mWGlMRXErZFVa","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-09-08T19:26:46.585496+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-09-08T19:26:46.585496+00:00"}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01, 2021-05-01-preview + cache-control: + - no-cache + content-length: + - '1857' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 08 Sep 2021 19:26:46 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration delete + Connection: + - keep-alive + Content-Length: + - '0' + ParameterSetName: + - -g -c -n --cluster-type -y + User-Agent: + - AZURECLI/2.28.0 azsdk-python-azure-mgmt-kubernetesconfiguration/1.0.0b1 Python/3.9.6 + (Windows-10-10.0.19043-SP0) + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config?api-version=2021-03-01 + response: + body: + string: '{"content":null,"statusCode":200,"headers":[],"version":"1.1","reasonPhrase":"OK","trailingHeaders":[],"requestMessage":null,"isSuccessStatusCode":true}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01, 2021-05-01-preview + cache-control: + - no-cache + content-length: + - '152' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 08 Sep 2021 19:26:47 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-deletes: + - '14999' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration show + Connection: + - keep-alive + ParameterSetName: + - -g -c -n --cluster-type + User-Agent: + - AZURECLI/2.28.0 azsdk-python-azure-mgmt-kubernetesconfiguration/1.0.0b1 Python/3.9.6 + (Windows-10-10.0.19043-SP0) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config2?api-version=2021-03-01 + response: + body: + string: '{"error":{"code":"ResourceNotFound","message":"SourceControlConfiguration + with name ''test-config2'' not found."}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01, 2021-05-01-preview + cache-control: + - no-cache + content-length: + - '112' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 08 Sep 2021 19:26:48 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + status: + code: 404 + message: Not Found +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration create + Connection: + - keep-alive + ParameterSetName: + - -g -n -c -u --cluster-type --scope --operator-instance-name --operator-namespace + --operator-params --git-readonly --https-user --https-key --enable-helm-operator + --helm-operator-chart-version --helm-operator-params --set tillerNamespace + User-Agent: + - AZURECLI/2.28.0 azsdk-python-azure-mgmt-resource/19.0.0 Python/3.9.6 (Windows-10-10.0.19043-SP0) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.KubernetesConfiguration?api-version=2021-04-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.KubernetesConfiguration","namespace":"Microsoft.KubernetesConfiguration","authorizations":[{"applicationId":"c699bf69-fb1d-4eaf-999b-99e6b2ae4d85","roleDefinitionId":"90155430-a360-410f-af5d-89dc284d85c6"},{"applicationId":"03db181c-e9d3-4868-9097-f0b728327182","roleDefinitionId":"DE2ADB97-42D8-49C8-8FCF-DBB53EF936AC"},{"applicationId":"a0f92522-89de-4c5e-9a75-0044ccf66efd","roleDefinitionId":"b3429810-7d5c-420e-8605-cf280f3099f2"},{"applicationId":"bd9b7cd5-dac1-495f-b013-ac871e98fa5f","roleDefinitionId":"0d44c8f0-08b9-44d4-9f59-e51c83f95200"}],"resourceTypes":[{"resourceType":"sourceControlConfigurations","locations":["East + US","West Europe","West Central US","West US 2","South Central US","East US + 2","North Europe","UK South","Southeast Asia","Australia East","France Central","Central + US","North Central US","West US","Korea Central","East Asia","Japan East","East + US 2 EUAP"],"apiVersions":["2021-03-01","2020-10-01-preview","2020-07-01-preview","2019-11-01-preview"],"defaultApiVersion":"2021-03-01","capabilities":"SupportsExtension"},{"resourceType":"extensions","locations":["East + US","West Europe","West Central US","West US 2","South Central US","East US + 2","North Europe","UK South","Southeast Asia","Australia East","France Central","Central + US","North Central US","West US","Korea Central","East Asia","Japan East","East + US 2 EUAP"],"apiVersions":["2021-05-01-preview","2020-07-01-preview"],"capabilities":"SystemAssignedResourceIdentity, + SupportsExtension"},{"resourceType":"operations","locations":[],"apiVersions":["2021-06-01-preview","2021-05-01-preview","2021-03-01","2020-10-01-preview","2020-07-01-preview","2019-11-01-preview"],"capabilities":"None"},{"resourceType":"fluxConfigurations","locations":["East + US 2 EUAP","East US","West Europe","West Central US","West US 2","South Central + US","East US 2","North Europe","UK South","Southeast Asia","Australia East","France + Central","Central US","North Central US","West US","Korea Central","East Asia","Japan + East"],"apiVersions":["2021-06-01-preview"],"defaultApiVersion":"2021-06-01-preview","capabilities":"SupportsExtension"}],"registrationState":"Registered","registrationPolicy":"RegistrationRequired"}' + headers: + cache-control: + - no-cache + content-length: + - '2268' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 08 Sep 2021 19:26:49 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: '{"properties": {"repositoryUrl": "https://github.com/jonathan-innis/helm-operator-get-started-private.git", + "operatorNamespace": "test-config2-namespace", "operatorInstanceName": "test-config2-name", + "operatorType": "flux", "operatorParams": "--git-readonly ", "configurationProtectedSettings": + {"httpsUser": "ZmFrZS11c2VybmFtZQ==", "httpsKey": "ZmFrZXBhc3N3b3JkdGhhdGl3b3VsZHVzZWZvcmdpdGh1Yg=="}, + "operatorScope": "namespace", "sshKnownHostsContents": "", "enableHelmOperator": + true, "helmOperatorProperties": {"chartVersion": "1.2.0", "chartValues": "--set + tillerNamespace=kube-system"}}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration create + Connection: + - keep-alive + Content-Length: + - '590' + Content-Type: + - application/json + ParameterSetName: + - -g -n -c -u --cluster-type --scope --operator-instance-name --operator-namespace + --operator-params --git-readonly --https-user --https-key --enable-helm-operator + --helm-operator-chart-version --helm-operator-params --set tillerNamespace + User-Agent: + - AZURECLI/2.28.0 azsdk-python-azure-mgmt-kubernetesconfiguration/1.0.0b1 Python/3.9.6 + (Windows-10-10.0.19043-SP0) + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config2?api-version=2021-03-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config2","name":"test-config2","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"test-config2-namespace","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set + tillerNamespace=kube-system"},"repositoryUrl":"https://github.com/jonathan-innis/helm-operator-get-started-private.git","operatorInstanceName":"test-config2-name","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-09-08T19:26:51.6588187+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-09-08T19:26:51.6588187+00:00"}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01, 2021-05-01-preview + cache-control: + - no-cache + content-length: + - '1250' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 08 Sep 2021 19:26:51 GMT + expires: + - '-1' + location: + - file:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config2 + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration show + Connection: + - keep-alive + ParameterSetName: + - -g -c -n --cluster-type + User-Agent: + - AZURECLI/2.28.0 azsdk-python-azure-mgmt-kubernetesconfiguration/1.0.0b1 Python/3.9.6 + (Windows-10-10.0.19043-SP0) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config2?api-version=2021-03-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config2","name":"test-config2","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"test-config2-namespace","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set + tillerNamespace=kube-system"},"repositoryUrl":"https://github.com/jonathan-innis/helm-operator-get-started-private.git","operatorInstanceName":"test-config2-name","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-09-08T19:26:51.6588187+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-09-08T19:26:51.6588187+00:00"}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01, 2021-05-01-preview + cache-control: + - no-cache + content-length: + - '1250' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 08 Sep 2021 19:26:52 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration delete + Connection: + - keep-alive + Content-Length: + - '0' + ParameterSetName: + - -g -c -n --cluster-type -y + User-Agent: + - AZURECLI/2.28.0 azsdk-python-azure-mgmt-kubernetesconfiguration/1.0.0b1 Python/3.9.6 + (Windows-10-10.0.19043-SP0) + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_recordings_testing/providers/Microsoft.Kubernetes/connectedClusters/test-cluster/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/test-config2?api-version=2021-03-01 + response: + body: + string: '{"content":null,"statusCode":200,"headers":[],"version":"1.1","reasonPhrase":"OK","trailingHeaders":[],"requestMessage":null,"isSuccessStatusCode":true}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01, 2021-05-01-preview + cache-control: + - no-cache + content-length: + - '152' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 08 Sep 2021 19:26:52 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-deletes: + - '14999' + status: + code: 200 + message: OK +version: 1 diff --git a/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_kubernetesconfiguration_scenario.py b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_kubernetesconfiguration_scenario.py index 11b6a43f512..e0e3b256d4e 100644 --- a/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_kubernetesconfiguration_scenario.py +++ b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_kubernetesconfiguration_scenario.py @@ -20,12 +20,12 @@ def test_k8s_configuration_success(self): # SSH SCENARIO TEST # -------------------------------------------------------------------- self.kwargs.update({ - 'name': 'cli-test-config10', - 'cluster_name': 'nanthicluster0923', - 'rg': 'nanthirg0923', + 'name': 'test-config', + 'cluster_name': 'test-cluster', + 'rg': 'cli_recordings_testing', 'repo_url': 'git://github.com/anubhav929/flux-get-started', - 'operator_instance_name': 'cli-test-config10-opin', - 'operator_namespace': 'cli-test-config10-opns', + 'operator_instance_name': 'test-config-name', + 'operator_namespace': 'test-config-namespace', 'cluster_type': 'connectedClusters', 'scope': 'namespace', 'ssh_private_key': 'LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUJsd0FBQUFkemMyZ3RjbgpOaEFBQUFBd0VBQVFBQUFZRUFxZlBtNlc3YkVLTmVvN3VCQzhTMXYydUpPS1NZWGNmanlpVEk2djNkZUhRSjJtMGFRajB0CmtwM05qMUZkRUsrMkVXTy9xNGFkWUpaS0ZZSjluWTZyREZOSXBZdmVWaVNUQjhITzI5VVdySTRLVGZMRGhiVmVCV0pjQVcKMkFpZ0ZnTU5qdTZXa0JVL1NWK1FCVHJiRVl6RFhpOTVNR1ZveTVKV3drdkdtakRaOHFSaEFxbU0rdUF4S1I4Z1lyRllPZgpRbC9zM2I5ajJKQ1VtVFlwYkxqMkJPd0JNQ1J3NlFQY0lVcVlaaUl3MUNNaXZKZ2tVQTdwUlRCZHVsYXlXNWQ2MTl4RFNsCmZ6N1JuU0tKM3RwanEwZThBTmtkU1h4SjQrMXhpNm5IM0lVY1ZBM1NzcVhWam80ak5sNU5EWkJlTDNpQ0xXSVZYUkpDemsKNGg3a2pXVkQ3UnNDNGJDOTF6MzlZMDlnK3ZIdjErZFplUmNYZWIvNkFzbTBEeHVhRGo2cVVCVm9JOWkwbzFKbndiMnA0MQpGV2prazljc054a2dnajMzU3ozTWJRTVN0bTFLaWU2bHNRamlMUXdGT3Qwd3lFTnova2RUR25idkVMUTN3aWdUdVFrelFOCnlMR2dmK3FXZnhqL1l1MWt5b0xrQVpqT3JxdEttalVILzk3Y3lncWhBQUFGa08zNi9uWHQrdjUxQUFBQUIzTnphQzF5YzIKRUFBQUdCQUtuejV1bHUyeENqWHFPN2dRdkV0YjlyaVRpa21GM0g0OG9reU9yOTNYaDBDZHB0R2tJOUxaS2R6WTlSWFJDdgp0aEZqdjZ1R25XQ1dTaFdDZloyT3F3eFRTS1dMM2xZa2t3ZkJ6dHZWRnF5T0NrM3l3NFcxWGdWaVhBRnRnSW9CWUREWTd1CmxwQVZQMGxma0FVNjJ4R013MTR2ZVRCbGFNdVNWc0pMeHBvdzJmS2tZUUtwalByZ01Ta2ZJR0t4V0RuMEpmN04yL1k5aVEKbEprMktXeTQ5Z1RzQVRBa2NPa0QzQ0ZLbUdZaU1OUWpJcnlZSkZBTzZVVXdYYnBXc2x1WGV0ZmNRMHBYOCswWjBpaWQ3YQpZNnRIdkFEWkhVbDhTZVB0Y1l1cHg5eUZIRlFOMHJLbDFZNk9JelplVFEyUVhpOTRnaTFpRlYwU1FzNU9JZTVJMWxRKzBiCkF1R3d2ZGM5L1dOUFlQcng3OWZuV1hrWEYzbS8rZ0xKdEE4Ym1nNCtxbEFWYUNQWXRLTlNaOEc5cWVOUlZvNUpQWExEY1oKSUlJOTkwczl6RzBERXJadFNvbnVwYkVJNGkwTUJUcmRNTWhEYy81SFV4cDI3eEMwTjhJb0U3a0pNMERjaXhvSC9xbG44WQovMkx0Wk1xQzVBR1l6cTZyU3BvMUIvL2UzTW9Lb1FBQUFBTUJBQUVBQUFHQkFKSnJUVTlqY0Z4ZlE1UHdZUGRRbS95MG10CjR3QUEwYnY0WlNOcjh0dy9hWWtqeWFybnJPMWtwd3BiNkpySkpKcjZRL3Vjdi9CK3RFejhMRVQ1REViMTBKQzVlRWJ5THMKRTdnbEl5Q0Y3eWp1bnJZVkpwbzFiVEZhVWtYd24wTkdlQ2JkWHNlODdhWDFISmdQemdmZ2dhcTk2aks5ZWtKcXJzQXM4VwpGWjZWNDgrR0N3WU9LU1dpclBmdWx5b3YvQURCOVZJVzdTQ3lWek9uTGRGTWRVZXJBMjI3Y3NUaEtTZnI0MzFDQjU2SE43CmFkdnRmNnR4alV0TXBoTjV5ZVBiRmxVZS9Wb2VQY1hNdXA4OXN3V2gvd3ZScklCbytUYXo2SzQxcGFzOEVObjFyemFxL3kKRHlWelJuSGtlMGhKR2ZZelJhbzlZQm5jeHFMOCtXdDQxZFFzQUdhdlIwd3ZNSit5TFpuR0x5amVXaVZkcExjT0FWSGpIOQpITGMrTDdnaGpIZ1VidDNDWG9Wd0gyWktnelI5cmk3bU93YnorejZsN1pwWjlQalJxeU1HcTloYU5vNHVEdjJqbWhGNlZVClBMU2Q3WTczWCtWTFAvWUZqbTBlUzJUbGFRQ3E2Vms0dzJqSHVWcXorcng4SllYb2tidFZXYnFYcmg3VzF5VGk4MXVRQUEKQU1Ba0JaQzF0SThvd29SNDYvL1h1SWQxQjBGRUhGUXBvSHFuVGNSVlVKS2RXb2xJRU5tYVVtdG1UZFVicVYyNGJMa1RtZQpiWHZQdlF3LzJoVk5VVmhWbDNjays1SUZBS0hYVWJ3ZklSWE8vUVlUbFM0ZVdabkFsN0JQSzJQa080SXkvOG1zQVZKRGl4CmkvVm1oaTBYb05lSmxERU9sdzNaY084aTlRZjVSbTNEWmRHUDRha0JsYmk5ekdBWUpqRGFjM0dWdTMxK2pJVG9hUHplbysKeUFDL2svM0J5Slg4enQ1cDRHVXpsNVFKcEVHMnBpQXdJeElKZS8yK3pBMXU5dmhma0FBQURCQU5NZHdhemx5MXNpd0dXbQpJWSs4VFZMN1EwQ1pFTWxTL0VraE1YM2FNQnZYaURXd2cwVk8zKytXUDhlMWhDSUxvNmdqL0N2dFdLdGEzVlozUWFScHZ5CkhCVEp4Q205NHZQOXFPelhTRGZ0WVRrSHh1SFdQaklhb010N0YyL0srejJiZTdESmhvL0ZwMVY0U2x2R1ljWHdqaWhEaDAKbHF1bUltOEJJei9taHpjZTFKR0VMUUdJeXk4RDI0dTNtY2NhSFoxYWY1V3A5Y1VCZ09POXEwa3B1WVhEdHpPSk9UTVozUQpNUm5xdXVVM1ppRHdmRGltZzdsZktwWGkxZzFxeWZUd0FBQU1FQXpoWEdhTVdBM1pUT1hqWWhPTUhkdTk0R2RNcHNXYWo0CjBsMmZ6YzdFWTlzWEdLZ01XMllvRXk5UVNSTDRPUmNMaUFKTDRLZGdZeGZzeVdma1U1d21TbGZXNjlrb0R2WTE0LzNWbWYKZ0NTUkxvL0RnTUZtOGFNK3pUVzhWYTVpclJXWFpEeHNXb0RiNzdIZ2JZaE90M29iOEFWWUh4akk3N1k3MXlBUzhXS2xRSQpYQi9qZ01vN1BCL3BTMVVYSEhCcndxQkdwM3M5aThab0E0L2hLY0pvaEtWSDZGL0Z2Rk1jWHZTNjZOcGNUWHNWQzBVUzNkCkJVY0taNTVvUUhVcnNQQUFBQUdIQnlZWFJvYVd0eVFFeEJVRlJQVUMxU00wZFVUa2xDVXdFQwotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K', @@ -82,12 +82,12 @@ def test_k8s_configuration_success(self): # HTTPS SCENARIO TEST # -------------------------------------------------------------------- self.kwargs.update({ - 'name': 'cli-test-config11', - 'cluster_name': 'nanthicluster0923', - 'rg': 'nanthirg0923', + 'name': 'test-config2', + 'cluster_name': 'test-cluster', + 'rg': 'cli_recordings_testing', 'repo_url': 'https://github.com/jonathan-innis/helm-operator-get-started-private.git', - 'operator_instance_name': 'cli-test-config11-opin', - 'operator_namespace': 'cli-test-config11-opns', + 'operator_instance_name': 'test-config2-name', + 'operator_namespace': 'test-config2-namespace', 'cluster_type': 'connectedClusters', 'scope': 'namespace', 'https_user': 'fake-username', diff --git a/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py index a83a5ae2071..03113f3ae17 100644 --- a/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py +++ b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py @@ -5,9 +5,16 @@ import unittest import base64 +from azext_k8s_configuration.providers.SourceControlConfigurationProvider import get_protected_settings from azure.cli.core.azclierror import InvalidArgumentValueError, MutuallyExclusiveArgumentError -from azext_k8s_configuration.custom import _get_protected_settings -import azext_k8s_configuration._validators as validators +from azext_k8s_configuration.validators import ( + validate_configuration_name, + validate_known_hosts, + validate_operator_instance_name, + validate_operator_namespace, + validate_private_key, + validate_url_with_params, +) from Crypto.PublicKey import DSA class TestValidateKeyTypes(unittest.TestCase): @@ -15,33 +22,25 @@ def test_bad_private_key(self): private_key_encoded = base64.b64encode("this is not a valid private key".encode('utf-8')).decode('utf-8') err = "Error! --ssh-private-key provided in invalid format" with self.assertRaises(InvalidArgumentValueError) as cm: - _get_protected_settings(private_key_encoded, '', '', '') + validate_private_key(private_key_encoded) self.assertEqual(str(cm.exception), err) def test_rsa_private_key(self): rsa_key = "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUJsd0FBQUFkemMyZ3RjbgpOaEFBQUFBd0VBQVFBQUFZRUF1bVA5M09qRHdjdlEyZHZhRlJNNWYrMEhVSnFvOFJnbmdwaGN3NFZidnd1TVNoQTZFc2FyCjFsam1CNUNnT1NGNHJqNDIvcmdxMW1hWndoSUgvckdPSElNa0lIcjFrZmNKMnBrR3ZhK1NxVm4wWUhzMjBpUW02ay92ZXQKdXdVQ2J1QjlxSU5zL2h2b0ppQ21JMUVpVWZ4VGoxRFJCUG15OXR3Qm52bW5FS1kxZ2NhT2YrS2Y1aGhCc09pd00yZnBRTwp0aTlIcHVzM1JhNXpFeElWbjJzVitpRjVvV3ZZM1JQTTlKNXFPMXRObUtOWll6TjgzbDYxMlBzRmR1Vm1QM2NUUlJtK2pzCjdzZW5jY0U0RitzU0hQMlJpMk5DU0JvZ2RJOFR5VTlzeTM3Szl3bFJ5NGZkWWI1K1o3YUZjMjhTNDdDWlo5dTRFVXdWUEYKbjU4dTUzajU0empwdXNpei9ZWmx3MG5NeEQ5SXI0aHlJZ2s0NlUzVmdHR0NPUytZVTVZT2JURGhPRG5udk5VRkg2NVhCagpEM3l6WVJuRDA3b2swQ1JUR3RCOWMzTjBFNDBjUnlPeVpEQ0l5a0FPdHZXYnBUZzdnaXA2UDc4K2pLVlFnanFwRTVQdi9ICnl1dlB6cUJoUkpWcG5VR1dvWnFlcWJhd2N5RWZwdHFLaTNtWUdVMHBBQUFGa0U5cUs3SlBhaXV5QUFBQUIzTnphQzF5YzIKRUFBQUdCQUxwai9kem93OEhMME5uYjJoVVRPWC90QjFDYXFQRVlKNEtZWE1PRlc3OExqRW9RT2hMR3E5Wlk1Z2VRb0RraAplSzQrTnY2NEt0Wm1tY0lTQi82eGpoeURKQ0I2OVpIM0NkcVpCcjJ2a3FsWjlHQjdOdElrSnVwUDczcmJzRkFtN2dmYWlECmJQNGI2Q1lncGlOUklsSDhVNDlRMFFUNXN2YmNBWjc1cHhDbU5ZSEdqbi9pbitZWVFiRG9zRE5uNlVEcll2UjZick4wV3UKY3hNU0ZaOXJGZm9oZWFGcjJOMFR6UFNlYWp0YlRaaWpXV016Zk41ZXRkajdCWGJsWmo5M0UwVVp2bzdPN0hwM0hCT0JmcgpFaHo5a1l0alFrZ2FJSFNQRThsUGJNdCt5dmNKVWN1SDNXRytmbWUyaFhOdkV1T3dtV2ZidUJGTUZUeForZkx1ZDQrZU00CjZicklzLzJHWmNOSnpNUS9TSytJY2lJSk9PbE4xWUJoZ2prdm1GT1dEbTB3NFRnNTU3elZCUit1VndZdzk4czJFWnc5TzYKSk5Ba1V4clFmWE56ZEJPTkhFY2pzbVF3aU1wQURyYjFtNlU0TzRJcWVqKy9Qb3lsVUlJNnFST1Q3L3g4cnJ6ODZnWVVTVgphWjFCbHFHYW5xbTJzSE1oSDZiYWlvdDVtQmxOS1FBQUFBTUJBQUVBQUFHQkFMaElmSXFacUZKSFRXcllyN24rays4alR3ClFtcGJvWmc1YmZSWGdhdGljaEo4ZGlXOGlNblFFRVRBcFd0OU5FZ0tqbDRrSGRuSnoyUERkZzFIN0ExaHppbkNsdzZMTTAKYUkyMGxyR2NrWWpXNDRNd3ozYmRQNHlURTllSXRiM0pmN1pNSGpqek4rSy96bWN0eWdMeXFZSzVXYTljM1JnMXdIRWFNNAplakUvNDg4M25WUmJvSFJDcjFCVi8wQVVFTTZhNisrRHpVZW9WdWdWL3RsV3RVMlJuQlZ4eCtJS0FVSDZRTHJFU2JkUkRoCkVGUEFhRWtEb3crd3dDcFpqTXBhMHdRZXBDSkhwWkJLN1pBU25EU3R3Y2RKRE4yeHZzdVNOOGg0bkN0MlZWd0xRenJKeVAKU2VjcWM3M1hIc3E3VWx6ZU5veHlTVW9KZ2JjNTZoRzhWYS9ITlhsOUtkdkFlWUVzS1l1OW5NRUprVSt3VHo1KzUvM2wwVQpxSkErb0pTVTducjYydlVKQnljbXg0SFdBcjJ6QkR2QnFBUWMzRG9LWHczeVM1Z0c5Zkc0c25OUUkxOHVRSjdOSjdndHZHClpKRU56bTNJMmFTMzl5dndWZnFIMXpXVERxU2VNeWhYeWFnTkFEcGtCVEJIMVJQR2NtTFplclFmWWx1djVVUmFNTXdRQUEKQU1BdE9oNHFwUUhidm5tQ1RVakx4dXRrWnRaRlhNa0hmSTk5NS9Nd2RvWVY1eWRKV0pUVGsyKzB1QVBIcTZEejk2b3dWbQpjUkF2WDBDOVU5d3ZRMkpnR0Y1MDZzcmgzZkVpUzM2d1ArOFd0RjZ6ODd0enJwQnpQVHIxOGRONURCOEx5L3dXRk5BVTdqClBUbXM0dHlUY1VsRXR3eEt4TXJTNC9ROUZwMWozL3JNdnNZdGVaSVgycmN4YUhkWWJDVGJtTUpZS3lVTWVXTk56NXpub1EKcFcyd2NDSmpJc1MvS1F2WmR4cHZwNWd0RXE1WlEva3FvLzJVRWd1NHhwdDNWeUNma0FBQURCQVBOSHVEU1R0ZEpJWjdzcwpaQkVwcUE4TE54b1dMQ2RURnlpRERiUnpYOWVPTldkRFQ3NklaRE9HejczNXJhZUFSM2FiY0FhaUM0dDQwTFJTNGEyN29sCm9wK1dSak9wcjVNYUtOUnk4MCt6VWw3WUlSMjErKzVnMFVnNkRnQlBEdmFJSHFSTnRsZ2gyVXdTL0cva1lOaUlEY0JiS1EKOUcvdTI4ekRIRUtNL21YYS8wYnFtSm16ZUYvY1BLdHdScFE3clFoRnAwUkdFcnZtc0l4dDl6K0ZZZUdncjFBYUVTV0ZlTApmUmZsa0lnOVBWOEl0b09GN25qK2VtMkxkNTNCS1hSUUFBQU1FQXhDTFBueHFFVEsyMW5QOXFxQVYzMEZUUkhGNW9kRHg4ClpiYnZIbjgwdEgxQjYwZjRtTGJFRm56REZFR0NwS2Rwb3dyUXR6WUhnQzNBaGNJUE9BbXFXaDg0UEFPbisreHhFanNaQkwKRWhVWmNFUndkYTMzTnJDNTVEMzZxbDBMZEsrSGRuZUFzVGZhazh0bWVlOTJWb0RxdWovNGFSMjBmUTBJUFVzMU8rWHNRNQpGWVFYQzZndExHZGRzRVFoSDF6MTh6RGtWa1UwdEhlZkJaL2pFZXBiOEZScXoxR1hpT0hGK2xBZVE2b3crS0xlcWtCcXQ4CkZxMHhGdG90SlF4VnFWQUFBQUYycHZhVzV1YVhOQVJFVlRTMVJQVUMxUVRWVkdVRFpOQVFJRAotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K" - protected_settings = _get_protected_settings(rsa_key, '', '', '') - self.assertEqual('sshPrivateKey' in protected_settings, True) - self.assertEqual(protected_settings.get('sshPrivateKey'), rsa_key) + validate_private_key(rsa_key) def test_dsa_private_key(self): key = DSA.generate(2048) private_key_encoded = base64.b64encode(key.export_key()).decode('utf-8') - protected_settings = _get_protected_settings(private_key_encoded, '', '', '') - self.assertEqual('sshPrivateKey' in protected_settings, True) - self.assertEqual(protected_settings.get('sshPrivateKey'), private_key_encoded) + validate_private_key(private_key_encoded) def test_ecdsa_private_key(self): ecdsa_key = "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUFhQUFBQUJObFkyUnpZUwoxemFHRXlMVzVwYzNSd01qVTJBQUFBQ0c1cGMzUndNalUyQUFBQVFRUjBRc1BjWmJKeWZPaXE2a1M1d0VaeE5DbmR2YVJHCm1ETEUvVVBjakpDTDZQTVIyZmdPS2NnWlhzTEZkTUFzSnExS2d6TmNDN0ZXNGE0L0wrYTFWWUxDQUFBQXNIZ1RqTFY0RTQKeTFBQUFBRTJWalpITmhMWE5vWVRJdGJtbHpkSEF5TlRZQUFBQUlibWx6ZEhBeU5UWUFBQUJCQkhSQ3c5eGxzbko4NktycQpSTG5BUm5FMEtkMjlwRWFZTXNUOVE5eU1rSXZvOHhIWitBNHB5Qmxld3NWMHdDd21yVXFETTF3THNWYmhyajh2NXJWVmdzCklBQUFBZ0h1U3laU0NUZzJZbVNpOG9aY2c0cnVpODh0T1NUSm1aRVhkR09hdExySHNBQUFBWGFtOXBibTVwYzBCRVJWTkwKVkU5UUxWQk5WVVpRTmswQgotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K" - protected_settings = _get_protected_settings(ecdsa_key, '', '', '') - self.assertEqual('sshPrivateKey' in protected_settings, True) - self.assertEqual(protected_settings.get('sshPrivateKey'), ecdsa_key) + validate_private_key(ecdsa_key) def test_ed25519_private_key(self): ed25519_key = "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUFNd0FBQUF0emMyZ3RaVwpReU5UVXhPUUFBQUNCNjF0RzkrNGFmOTZsWGoyUStjWjJMT2JpV1liMlRtWVR6N3NSV0JDM1hVZ0FBQUtCRzFWRWZSdFZSCkh3QUFBQXR6YzJndFpXUXlOVFV4T1FBQUFDQjYxdEc5KzRhZjk2bFhqMlErY1oyTE9iaVdZYjJUbVlUejdzUldCQzNYVWcKQUFBRURRTStLcCtOSWpJVUhSUklqRFE5VDZ0U0V0SG9Ic0w1QjlwbHpCNlZ2MnluclcwYjM3aHAvM3FWZVBaRDV4bllzNQp1SlpodlpPWmhQUHV4RllFTGRkU0FBQUFGMnB2YVc1dWFYTkFSRVZUUzFSUFVDMVFUVlZHVURaTkFRSURCQVVHCi0tLS0tRU5EIE9QRU5TU0ggUFJJVkFURSBLRVktLS0tLQo=" - protected_settings = _get_protected_settings(ed25519_key, '', '', '') - self.assertEqual('sshPrivateKey' in protected_settings, True) - self.assertEqual(protected_settings.get('sshPrivateKey'), ed25519_key) + validate_private_key(ed25519_key) class TestValidateK8sNaming(unittest.TestCase): @@ -50,7 +49,7 @@ def test_long_operator_namespace(self): namespace = OperatorNamespace(operator_namespace) err = 'Error! Invalid --operator-namespace' with self.assertRaises(InvalidArgumentValueError) as cm: - validators._validate_operator_namespace(namespace) + validate_operator_namespace(namespace) self.assertEqual(str(cm.exception), err) def test_long_operator_instance_name(self): @@ -58,7 +57,7 @@ def test_long_operator_instance_name(self): namespace = OperatorInstanceName(operator_instance_name) err = 'Error! Invalid --operator-instance-name' with self.assertRaises(InvalidArgumentValueError) as cm: - validators._validate_operator_instance_name(namespace) + validate_operator_instance_name(namespace) self.assertEqual(str(cm.exception), err) def test_caps_operator_namespace(self): @@ -66,7 +65,7 @@ def test_caps_operator_namespace(self): namespace = OperatorNamespace(operator_namespace) err = 'Error! Invalid --operator-namespace' with self.assertRaises(InvalidArgumentValueError) as cm: - validators._validate_operator_namespace(namespace) + validate_operator_namespace(namespace) self.assertEqual(str(cm.exception), err) def test_caps_operator_instance_name(self): @@ -74,68 +73,73 @@ def test_caps_operator_instance_name(self): namespace = OperatorInstanceName(operator_instance_name) err = 'Error! Invalid --operator-instance-name' with self.assertRaises(InvalidArgumentValueError) as cm: - validators._validate_operator_instance_name(namespace) + validate_operator_instance_name(namespace) self.assertEqual(str(cm.exception), err) def test_long_config_name(self): config_name = "thisisaverylongnamethatistoolongtobeusedthisisaverylongnamethatistoolongtobeused" err = 'Error! Invalid --name' + namespace = ConfigurationName(config_name) with self.assertRaises(InvalidArgumentValueError) as cm: - validators._validate_configuration_name(config_name) + validate_configuration_name(namespace) self.assertEqual(str(cm.exception), err) def test_valid_config_name(self): config_name = "this-is-a-valid-config" - validators._validate_configuration_name(config_name) + namespace = ConfigurationName(config_name) + validate_configuration_name(namespace) def test_caps_config_name(self): config_name = "ThisIsaCapsConfigName" err = 'Error! Invalid --name' + namespace = ConfigurationName(config_name) with self.assertRaises(InvalidArgumentValueError) as cm: - validators._validate_configuration_name(config_name) + validate_configuration_name(namespace) self.assertEqual(str(cm.exception), err) def test_dot_config_name(self): config_name = "a234567890b234567890c234567890d234567890e234567890f234567890.23" err = 'Error! Invalid --name' + namespace = ConfigurationName(config_name) with self.assertRaises(InvalidArgumentValueError) as cm: - validators._validate_configuration_name(config_name) + validate_configuration_name(namespace) self.assertEqual(str(cm.exception), err) def test_end_hyphen_config_name(self): config_name = "a234567890b234567890c234567890d234567890e234567890f23456789023-" err = 'Error! Invalid --name' + namespace = ConfigurationName(config_name) with self.assertRaises(InvalidArgumentValueError) as cm: - validators._validate_configuration_name(config_name) + validate_configuration_name(namespace) self.assertEqual(str(cm.exception), err) class TestValidateURLWithParams(unittest.TestCase): def test_ssh_private_key_with_ssh_url(self): - validators._validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', True, False, False) + validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', True, False, False, False, False, False) def test_ssh_known_hosts_with_ssh_url(self): - validators._validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', False, True, False) + validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', False, False, True, False, False, False) def test_https_auth_with_https_url(self): - validators._validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', False, False, True) + validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', False, False, False, False, True, True) def test_ssh_private_key_with_https_url(self): err = 'Error! An --ssh-private-key cannot be used with an http(s) url' with self.assertRaises(MutuallyExclusiveArgumentError) as cm: - validators._validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', True, False, False) + validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', True, False, False, False, False, False) self.assertEqual(str(cm.exception), err) def test_ssh_known_hosts_with_https_url(self): err = 'Error! --ssh-known-hosts cannot be used with an http(s) url' with self.assertRaises(MutuallyExclusiveArgumentError) as cm: - validators._validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', False, True, False) + validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', False, False, True, False, False, False) self.assertEqual(str(cm.exception), err) def test_https_auth_with_ssh_url(self): err = 'Error! https auth (--https-user and --https-key) cannot be used with a non-http(s) url' with self.assertRaises(MutuallyExclusiveArgumentError) as cm: - validators._validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', False, False, True) + validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', False, False, False, False, True, True) self.assertEqual(str(cm.exception), err) @@ -143,24 +147,24 @@ class TestValidateKnownHosts(unittest.TestCase): def test_valid_known_hosts(self): known_hosts_raw = "ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H" known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') - validators._validate_known_hosts(known_hosts_encoded) + validate_known_hosts(known_hosts_encoded) def test_valid_known_hosts_with_comment(self): known_hosts_raw = "ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H ThisIsAValidComment" known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') - validators._validate_known_hosts(known_hosts_encoded) + validate_known_hosts(known_hosts_encoded) def test_valid_known_hosts_with_comment_own_line(self): known_hosts_raw = "#this is a comment on its own line\nssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H" known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') - validators._validate_known_hosts(known_hosts_encoded) + validate_known_hosts(known_hosts_encoded) def test_invalid_known_hosts(self): known_hosts_raw = "thisisabadknownhostsfilethatisaninvalidformat" known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') err = 'Error! ssh known_hosts provided in wrong format' with self.assertRaises(InvalidArgumentValueError) as cm: - validators._validate_known_hosts(known_hosts_encoded) + validate_known_hosts(known_hosts_encoded) self.assertEqual(str(cm.exception), err) @@ -172,3 +176,8 @@ def __init__(self, operator_namespace): class OperatorInstanceName: def __init__(self, operator_instance_name): self.operator_instance_name = operator_instance_name + + +class ConfigurationName: + def __init__(self, name): + self.name = name \ No newline at end of file diff --git a/src/k8s-configuration/azext_k8s_configuration/utils.py b/src/k8s-configuration/azext_k8s_configuration/utils.py new file mode 100644 index 00000000000..b90381aa8e8 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/utils.py @@ -0,0 +1,145 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import base64 +import json +import re +from datetime import timedelta +from azure.cli.core.azclierror import ( + MutuallyExclusiveArgumentError, + InvalidArgumentValueError +) +from . import consts + + +def get_cluster_rp(cluster_type): + if cluster_type.lower() == consts.CONNECTED_CLUSTERS: + return consts.CONNECTED_RP_NAMESPACE + if cluster_type.lower() == consts.APPLIANCES: + return consts.APPLIANCE_RP_NAMESPACE + if cluster_type.lower() == '' or cluster_type.lower() == 'managedclusters': + return consts.MANAGED_RP_NAMESPACE + raise InvalidArgumentValueError("Error! Cluster type '{}' is not supported".format(cluster_type)) + + +def get_data_from_key_or_file(key, filepath, strip_newline=False): + if key and filepath: + raise MutuallyExclusiveArgumentError( + consts.KEY_AND_FILE_TOGETHER_ERROR, + consts.KEY_AND_FILE_TOGETHER_HELP) + data = None + if filepath: + data = read_key_file(filepath, strip_newline) + elif key: + data = key + return data + + +def read_config_settings_file(file_path): + try: + with open(file_path, 'r') as f: + settings = json.load(f) + if len(settings) == 0: + raise Exception("File {} is empty".format(file_path)) + return settings + except ValueError as ex: + raise Exception("File {} is not a valid JSON file".format(file_path)) from ex + + +def read_key_file(path, strip_newline=False): + try: + with open(path, "r") as myfile: # user passed in filename + data_list = myfile.readlines() # keeps newline characters intact + data_list_len = len(data_list) + if (data_list_len) <= 0: + raise Exception("File provided does not contain any data") + raw_data = ''.join(data_list) + if strip_newline: + raw_data = raw_data.strip() + return to_base64(raw_data) + except Exception as ex: + raise InvalidArgumentValueError( + consts.KEY_FILE_READ_ERROR.format(ex), + consts.KEY_FILE_READ_HELP) from ex + + +def parse_dependencies(depends_on): + depends_on = depends_on.strip() + if depends_on[0] == '[': + depends_on = depends_on[1:-1] + return depends_on.split(',') + + +def parse_duration(duration): + if not duration: + return duration + regex = re.compile(r'((?P\d+?)h)?((?P\d+?)m)?((?P\d+?)s)?') + parts = regex.match(duration) + parts = parts.groupdict() + time_params = {} + for name, param in parts.items(): + if param: + time_params[name] = int(param) + return int(timedelta(**time_params).total_seconds()) + + +def format_duration(seconds): + if seconds is None: + return None + seconds = int(seconds) + hours = seconds // 3600 + seconds -= hours * 3600 + minutes = seconds // 60 + seconds -= minutes * 60 + res = '' + if hours > 0: + res += '{}h'.format(hours) + if minutes > 0: + res += '{}m'.format(minutes) + if seconds > 0: + res += '{}s'.format(seconds) + return res + + +def from_base64(base64_str): + return base64.b64decode(base64_str) + + +def to_base64(raw_data): + bytes_data = raw_data.encode('utf-8') + return base64.b64encode(bytes_data).decode('utf-8') + + +def fix_compliance_state(config): + # If we get Compliant/NonCompliant as compliance_sate, change them before returning + if config.compliance_status.compliance_state.lower() == 'noncompliant': + config.compliance_status.compliance_state = 'Failed' + elif config.compliance_status.compliance_state.lower() == 'compliant': + config.compliance_status.compliance_state = 'Installed' + + return config + + +def get_parent_api_version(cluster_rp): + if cluster_rp == 'Microsoft.Kubernetes': + return '2020-01-01-preview' + if cluster_rp == 'Microsoft.ResourceConnector': + return '2020-09-15-privatepreview' + if cluster_rp == 'Microsoft.ContainerService': + return '2017-07-01' + raise InvalidArgumentValueError("Error! Cluster RP '{}' is not supported" + " for extension identity".format(cluster_rp)) + + +def is_dogfood_cluster(cmd): + return cmd.cli_ctx.cloud.endpoints.resource_manager == consts.DF_RM_ENDPOINT + + +def has_prune_enabled(config): + if config.kustomizations: + for kustomization in config.kustomizations.values(): + if kustomization.prune: + return True + return False diff --git a/src/k8s-configuration/azext_k8s_configuration/validators.py b/src/k8s-configuration/azext_k8s_configuration/validators.py new file mode 100644 index 00000000000..3eb2142663c --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/validators.py @@ -0,0 +1,276 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import re +import io +from urllib.parse import urlparse +from knack.log import get_logger +from azure.cli.core.azclierror import ( + InvalidArgumentValueError, + RequiredArgumentMissingError, + MutuallyExclusiveArgumentError +) +from paramiko.hostkeys import HostKeyEntry +from paramiko.ed25519key import Ed25519Key +from paramiko.ssh_exception import SSHException +from Crypto.PublicKey import RSA, ECC, DSA + +from .utils import from_base64 +from ._client_factory import resource_providers_client +from . import consts + + +logger = get_logger(__name__) + + +def validate_namespace(namespace): + if namespace.namespace: + __validate_k8s_name(namespace.namespace, "--namespace", 253) + + +def validate_configuration_name(namespace): + __validate_k8s_name(namespace.name, "--name", 63) + + +def validate_fluxconfig_name(namespace): + __validate_k8s_cr_name(namespace.name, "--name", 63) + + +def validate_operator_instance_name(namespace): + if namespace.operator_instance_name: + __validate_k8s_name(namespace.operator_instance_name, "--operator-instance-name", 23) + + +def validate_operator_namespace(namespace): + if namespace.operator_namespace: + __validate_k8s_name(namespace.operator_namespace, "--operator-namespace", 23) + + +def validate_kustomization(values): + required_keys = consts.REQUIRED_KUSTOMIZATION_KEYS + for item in values: + key, value = item.split('=', 1) + if key == "name": + __validate_k8s_cr_name(value, key, 63) + elif key in consts.SYNC_INTERVAL_KEYS: + validate_duration("sync-interval", value) + elif key in consts.TIMEOUT_KEYS: + validate_duration("timeout", value) + elif key in consts.RETRY_INTERVAL_KEYS: + validate_duration("retry-interval", value) + if key in required_keys: + required_keys.remove(key) + if required_keys: + raise RequiredArgumentMissingError( + consts.KUSTOMIZATION_REQUIRED_VALUES_MISSING_ERROR.format(required_keys), + consts.KUSTOMIZATION_REQUIRED_VALUES_MISSING_HELP + ) + + +def validate_repository_ref(branch: str, tag: str, semver: str, commit: str): + num_set_args = 0 + for elem in [branch, tag, semver, commit]: + if elem: + num_set_args += 1 + if num_set_args == 0: + raise RequiredArgumentMissingError( + consts.REPOSITORY_REF_REQUIRED_VALUES_MISSING_ERROR, + consts.REPOSITORY_REF_REQUIRED_VALUES_MISSING_HELP + ) + if num_set_args == 1: + return + raise MutuallyExclusiveArgumentError( + consts.REPOSITORY_REF_TOO_MANY_VALUES_ERROR, + consts.REPOSITORY_REF_TOO_MANY_VALUES_HELP + ) + + +def validate_duration(arg_name: str, duration: str): + if duration and not re.match(consts.VALID_DURATION_REGEX, duration): + raise InvalidArgumentValueError( + consts.INVALID_DURATION_ERROR.format(arg_name), + consts.INVALID_DURATION_HELP + ) + + +def validate_git_repository(url: str): + if not url: + raise RequiredArgumentMissingError( + consts.GIT_REPOSITORY_REQUIRED_VALUES_MISSING_ERROR.format("--url"), + consts.GIT_REPOSITORY_REQUIRED_VALUES_MISSING_HELP + ) + validate_git_url(url) + + +def validate_git_url(url: str): + if not re.match(consts.VALID_URL_REGEX, url): + raise InvalidArgumentValueError( + consts.INVALID_URL_ERROR, + consts.INVALID_URL_HELP + ) + + +# Helper +def __validate_k8s_name(param_value, param_name, max_len): + if len(param_value) > max_len: + raise InvalidArgumentValueError( + consts.INVALID_KUBERNETES_NAME_LENGTH_ERROR.format(param_name), + consts.INVALID_KUBERNETES_NAME_LENGTH_HELP.format(param_name, max_len) + ) + if not re.match(consts.VALID_KUBERNETES_DNS_NAME_REGEX, param_value): + if param_value[0] == "-" or param_value[-1] == "-": + raise InvalidArgumentValueError( + consts.INVALID_KUBERNETES_NAME_HYPHEN_ERROR.format(param_name), + consts.INVALID_KUBERNETES_NAME_HYPHEN_HELP.format(param_name) + ) + raise InvalidArgumentValueError( + consts.INVALID_KUBERNETES_DNS_NAME_ERROR.format(param_name), + consts.INVALID_KUBERNETES_DNS_NAME_HELP.format(param_name) + ) + + +def __validate_k8s_cr_name(param_value, param_name, max_len): + if len(param_value) > max_len: + raise InvalidArgumentValueError( + consts.INVALID_KUBERNETES_NAME_LENGTH_ERROR.format(param_name), + consts.INVALID_KUBERNETES_NAME_LENGTH_HELP.format(param_name, max_len) + ) + if not re.match(consts.VALID_KUBERNETES_DNS_SUBDOMAIN_NAME_REGEX, param_value): + if param_value[0] == "-" or param_value[-1] == "-": + raise InvalidArgumentValueError( + consts.INVALID_KUBERNETES_NAME_HYPHEN_ERROR.format(param_name), + consts.INVALID_KUBERNETES_NAME_HYPHEN_HELP.format(param_name) + ) + if param_value[0] == "." or param_value[-1] == ".": + raise InvalidArgumentValueError( + consts.INVALID_KUBERNETES_NAME_PERIOD_ERROR.format(param_name), + consts.INVALID_KUBERNETES_NAME_PERIOD_HELP.format(param_name) + ) + raise InvalidArgumentValueError( + consts.INVALID_KUBERNETES_DNS_SUBDOMAIN_NAME_ERROR.format(param_name), + consts.INVALID_KUBERNETES_DNS_SUBDOMAIN_NAME_ERROR.format(param_name) + ) + + +def validate_url_with_params(url: str, ssh_private_key, ssh_private_key_file, + known_hosts, known_hosts_file, https_user, https_key): + + scheme = urlparse(url).scheme + if scheme.lower() in ('http', 'https'): + if ssh_private_key or ssh_private_key_file: + raise MutuallyExclusiveArgumentError( + consts.SSH_PRIVATE_KEY_WITH_HTTP_URL_ERROR, + consts.SSH_PRIVATE_KEY_WITH_HTTP_URL_HELP + ) + if known_hosts or known_hosts_file: + raise MutuallyExclusiveArgumentError( + consts.KNOWN_HOSTS_WITH_HTTP_URL_ERROR, + consts.KNOWN_HOSTS_WITH_HTTP_URL_HELP + ) + if not (https_user and https_key) and scheme == 'https': + logger.warning(consts.HTTP_URL_NO_AUTH_WARNING) + else: + if https_user or https_key: + raise MutuallyExclusiveArgumentError( + consts.HTTPS_AUTH_WITH_SSH_URL_ERROR, + consts.HTTPS_AUTH_WITH_SSH_URL_HELP + ) + + if https_user and https_key: + return + # If we just provide one or the other raise an error + if https_user or https_key: + raise RequiredArgumentMissingError( + consts.HTTPS_USER_KEY_MATCH_ERROR, + consts.HTTPS_USER_KEY_MATCH_HELP) + + +def validate_known_hosts(knownhost_data): + try: + knownhost_str = from_base64(knownhost_data).decode('utf-8') + except Exception as ex: + raise InvalidArgumentValueError( + consts.KNOWN_HOSTS_BASE64_ENCODING_ERROR, + consts.KNOWN_HOSTS_BASE64_ENCODING_HELP) from ex + lines = knownhost_str.split('\n') + for line in lines: + line = line.strip(' ') + line_len = len(line) + if (line_len == 0) or (line[0] == "#"): + continue + try: + host_key = HostKeyEntry.from_line(line) + if not host_key: + raise Exception('not enough fields found in known_hosts line') + except Exception as ex: + raise InvalidArgumentValueError( + consts.KNOWN_HOSTS_FORMAT_ERROR, + consts.KNOWN_HOSTS_FORMAT_HELP + ) from ex + + +def validate_private_key(ssh_private_key_data): + try: + RSA.import_key(from_base64(ssh_private_key_data)) + return + except ValueError: + try: + ECC.import_key(from_base64(ssh_private_key_data)) + return + except ValueError: + try: + DSA.import_key(from_base64(ssh_private_key_data)) + return + except ValueError: + try: + key_obj = io.StringIO(from_base64(ssh_private_key_data).decode('utf-8')) + Ed25519Key(file_obj=key_obj) + return + except SSHException as ex: + raise InvalidArgumentValueError( + consts.SSH_PRIVATE_KEY_ERROR, + consts.SSH_PRIVATE_KEY_HELP + ) from ex + + +# pylint: disable=broad-except +def validate_cc_registration(cmd): + try: + rp_client = resource_providers_client(cmd.cli_ctx) + registration_state = rp_client.get(consts.CC_PROVIDER_NAMESPACE).registration_state + + if registration_state.lower() != consts.REGISTERED.lower(): + logger.warning(consts.CC_REGISTRATION_WARNING, + consts.CC_PROVIDER_NAMESPACE, + consts.CC_REGISTRATION_LINK) + except Exception: + logger.warning(consts.CC_REGISTRATION_ERROR, + consts.CC_PROVIDER_NAMESPACE) + + +def validate_scope_and_namespace(scope, release_namespace, target_namespace): + if scope == 'cluster': + if target_namespace is not None: + message = "When --scope is 'cluster', --target-namespace must not be given." + raise MutuallyExclusiveArgumentError(message) + else: + if release_namespace is not None: + message = "When --scope is 'namespace', --release-namespace must not be given." + raise MutuallyExclusiveArgumentError(message) + + +def validate_scope_after_customization(scope_obj): + if scope_obj is not None and scope_obj.namespace is not None and scope_obj.namespace.target_namespace is None: + message = "When --scope is 'namespace', --target-namespace must be given." + raise RequiredArgumentMissingError(message) + + +def validate_version_and_auto_upgrade(version, auto_upgrade_minor_version): + if version is not None: + if auto_upgrade_minor_version: + message = "To pin to specific version, auto-upgrade-minor-version must be set to 'false'." + raise MutuallyExclusiveArgumentError(message) + + auto_upgrade_minor_version = False diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/__init__.py index f13062376d7..b0a136e072d 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/__init__.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/__init__.py @@ -7,9 +7,6 @@ # -------------------------------------------------------------------------- from ._source_control_configuration_client import SourceControlConfigurationClient -from ._version import VERSION - -__version__ = VERSION __all__ = ['SourceControlConfigurationClient'] try: diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_configuration.py index 645328abb1f..6ecda0480c4 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_configuration.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_configuration.py @@ -1,11 +1,13 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. # -------------------------------------------------------------------------- - from typing import TYPE_CHECKING from azure.core.configuration import Configuration @@ -20,7 +22,6 @@ from azure.core.credentials import TokenCredential - class SourceControlConfigurationClientConfiguration(Configuration): """Configuration for SourceControlConfigurationClient. @@ -29,7 +30,7 @@ class SourceControlConfigurationClientConfiguration(Configuration): :param credential: Credential needed for the client to connect to Azure. :type credential: ~azure.core.credentials.TokenCredential - :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :param subscription_id: The ID of the target subscription. :type subscription_id: str """ @@ -48,9 +49,8 @@ def __init__( self.credential = credential self.subscription_id = subscription_id - self.api_version = "2021-03-01" self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) - kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + kwargs.setdefault('sdk_moniker', 'azure-mgmt-kubernetesconfiguration/{}'.format(VERSION)) self._configure(**kwargs) def _configure( diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_source_control_configuration_client.py index 50b673797b5..f0749f25ad1 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_source_control_configuration_client.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_source_control_configuration_client.py @@ -1,16 +1,23 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. # -------------------------------------------------------------------------- from typing import TYPE_CHECKING from azure.mgmt.core import ARMPipelineClient +from azure.profiles import KnownProfiles, ProfileDefinition +from azure.profiles.multiapiclient import MultiApiClientMixin from msrest import Deserializer, Serializer +from ._configuration import SourceControlConfigurationClientConfiguration + if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports from typing import Any, Optional @@ -18,77 +25,288 @@ from azure.core.credentials import TokenCredential from azure.core.pipeline.transport import HttpRequest, HttpResponse -from ._configuration import SourceControlConfigurationClientConfiguration -from .operations import SourceControlConfigurationsOperations -from .operations import Operations -from . import models - +class _SDKClient(object): + def __init__(self, *args, **kwargs): + """This is a fake class to support current implemetation of MultiApiClientMixin." + Will be removed in final version of multiapi azure-core based client + """ + pass -class SourceControlConfigurationClient(object): +class SourceControlConfigurationClient(MultiApiClientMixin, _SDKClient): """KubernetesConfiguration Client. - :ivar source_control_configurations: SourceControlConfigurationsOperations operations - :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2021_03_01.operations.SourceControlConfigurationsOperations - :ivar operations: Operations operations - :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_03_01.operations.Operations + This ready contains multiple API versions, to help you deal with all of the Azure clouds + (Azure Stack, Azure Government, Azure China, etc.). + By default, it uses the latest API version available on public Azure. + For production, you should stick to a particular api-version and/or profile. + The profile sets a mapping between an operation group and its API version. + The api-version parameter sets the default API version if the operation + group is not described in the profile. + :param credential: Credential needed for the client to connect to Azure. :type credential: ~azure.core.credentials.TokenCredential - :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :param subscription_id: The ID of the target subscription. :type subscription_id: str - :param str base_url: Service URL + :param api_version: API version to use if no profile is provided, or if missing in profile. + :type api_version: str + :param base_url: Service URL + :type base_url: str + :param profile: A profile definition, from KnownProfiles to dict. + :type profile: azure.profiles.KnownProfiles :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. """ + DEFAULT_API_VERSION = '2021-09-01' + _PROFILE_TAG = "azure.mgmt.kubernetesconfiguration.SourceControlConfigurationClient" + LATEST_PROFILE = ProfileDefinition({ + _PROFILE_TAG: { + None: DEFAULT_API_VERSION, + 'source_control_configurations': '2021-03-01', + }}, + _PROFILE_TAG + " latest" + ) + def __init__( self, credential, # type: "TokenCredential" subscription_id, # type: str + api_version=None, # type: Optional[str] base_url=None, # type: Optional[str] + profile=KnownProfiles.default, # type: KnownProfiles **kwargs # type: Any ): - # type: (...) -> None if not base_url: base_url = 'https://management.azure.com' self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) self._client = ARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + super(SourceControlConfigurationClient, self).__init__( + api_version=api_version, + profile=profile + ) + + @classmethod + def _models_dict(cls, api_version): + return {k: v for k, v in cls.models(api_version).__dict__.items() if isinstance(v, type)} + + @classmethod + def models(cls, api_version=DEFAULT_API_VERSION): + """Module depends on the API version: + + * 2020-07-01-preview: :mod:`v2020_07_01_preview.models` + * 2020-10-01-preview: :mod:`v2020_10_01_preview.models` + * 2021-03-01: :mod:`v2021_03_01.models` + * 2021-05-01-preview: :mod:`v2021_05_01_preview.models` + * 2021-09-01: :mod:`v2021_09_01.models` + * 2021-11-01-preview: :mod:`v2021_11_01_preview.models` + """ + if api_version == '2020-07-01-preview': + from .v2020_07_01_preview import models + return models + elif api_version == '2020-10-01-preview': + from .v2020_10_01_preview import models + return models + elif api_version == '2021-03-01': + from .v2021_03_01 import models + return models + elif api_version == '2021-05-01-preview': + from .v2021_05_01_preview import models + return models + elif api_version == '2021-09-01': + from .v2021_09_01 import models + return models + elif api_version == '2021-11-01-preview': + from .v2021_11_01_preview import models + return models + raise ValueError("API version {} is not available".format(api_version)) + + @property + def cluster_extension_type(self): + """Instance depends on the API version: + + * 2021-05-01-preview: :class:`ClusterExtensionTypeOperations` + * 2021-11-01-preview: :class:`ClusterExtensionTypeOperations` + """ + api_version = self._get_api_version('cluster_extension_type') + if api_version == '2021-05-01-preview': + from .v2021_05_01_preview.operations import ClusterExtensionTypeOperations as OperationClass + elif api_version == '2021-11-01-preview': + from .v2021_11_01_preview.operations import ClusterExtensionTypeOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'cluster_extension_type'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def cluster_extension_types(self): + """Instance depends on the API version: + + * 2021-05-01-preview: :class:`ClusterExtensionTypesOperations` + * 2021-11-01-preview: :class:`ClusterExtensionTypesOperations` + """ + api_version = self._get_api_version('cluster_extension_types') + if api_version == '2021-05-01-preview': + from .v2021_05_01_preview.operations import ClusterExtensionTypesOperations as OperationClass + elif api_version == '2021-11-01-preview': + from .v2021_11_01_preview.operations import ClusterExtensionTypesOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'cluster_extension_types'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def extension_type_versions(self): + """Instance depends on the API version: + + * 2021-05-01-preview: :class:`ExtensionTypeVersionsOperations` + * 2021-11-01-preview: :class:`ExtensionTypeVersionsOperations` + """ + api_version = self._get_api_version('extension_type_versions') + if api_version == '2021-05-01-preview': + from .v2021_05_01_preview.operations import ExtensionTypeVersionsOperations as OperationClass + elif api_version == '2021-11-01-preview': + from .v2021_11_01_preview.operations import ExtensionTypeVersionsOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'extension_type_versions'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def extensions(self): + """Instance depends on the API version: - client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} - self._serialize = Serializer(client_models) - self._serialize.client_side_validation = False - self._deserialize = Deserializer(client_models) - - self.source_control_configurations = SourceControlConfigurationsOperations( - self._client, self._config, self._serialize, self._deserialize) - self.operations = Operations( - self._client, self._config, self._serialize, self._deserialize) - - def _send_request(self, http_request, **kwargs): - # type: (HttpRequest, Any) -> HttpResponse - """Runs the network request through the client's chained policies. - - :param http_request: The network request you want to make. Required. - :type http_request: ~azure.core.pipeline.transport.HttpRequest - :keyword bool stream: Whether the response payload will be streamed. Defaults to True. - :return: The response of your network call. Does not do error handling on your response. - :rtype: ~azure.core.pipeline.transport.HttpResponse + * 2020-07-01-preview: :class:`ExtensionsOperations` + * 2021-05-01-preview: :class:`ExtensionsOperations` + * 2021-09-01: :class:`ExtensionsOperations` + * 2021-11-01-preview: :class:`ExtensionsOperations` """ - path_format_arguments = { - 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), - } - http_request.url = self._client.format_url(http_request.url, **path_format_arguments) - stream = kwargs.pop("stream", True) - pipeline_response = self._client._pipeline.run(http_request, stream=stream, **kwargs) - return pipeline_response.http_response + api_version = self._get_api_version('extensions') + if api_version == '2020-07-01-preview': + from .v2020_07_01_preview.operations import ExtensionsOperations as OperationClass + elif api_version == '2021-05-01-preview': + from .v2021_05_01_preview.operations import ExtensionsOperations as OperationClass + elif api_version == '2021-09-01': + from .v2021_09_01.operations import ExtensionsOperations as OperationClass + elif api_version == '2021-11-01-preview': + from .v2021_11_01_preview.operations import ExtensionsOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'extensions'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def flux_config_operation_status(self): + """Instance depends on the API version: + + * 2021-11-01-preview: :class:`FluxConfigOperationStatusOperations` + """ + api_version = self._get_api_version('flux_config_operation_status') + if api_version == '2021-11-01-preview': + from .v2021_11_01_preview.operations import FluxConfigOperationStatusOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'flux_config_operation_status'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def flux_configurations(self): + """Instance depends on the API version: + + * 2021-11-01-preview: :class:`FluxConfigurationsOperations` + """ + api_version = self._get_api_version('flux_configurations') + if api_version == '2021-11-01-preview': + from .v2021_11_01_preview.operations import FluxConfigurationsOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'flux_configurations'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def location_extension_types(self): + """Instance depends on the API version: + + * 2021-05-01-preview: :class:`LocationExtensionTypesOperations` + * 2021-11-01-preview: :class:`LocationExtensionTypesOperations` + """ + api_version = self._get_api_version('location_extension_types') + if api_version == '2021-05-01-preview': + from .v2021_05_01_preview.operations import LocationExtensionTypesOperations as OperationClass + elif api_version == '2021-11-01-preview': + from .v2021_11_01_preview.operations import LocationExtensionTypesOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'location_extension_types'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def operation_status(self): + """Instance depends on the API version: + + * 2021-05-01-preview: :class:`OperationStatusOperations` + * 2021-09-01: :class:`OperationStatusOperations` + * 2021-11-01-preview: :class:`OperationStatusOperations` + """ + api_version = self._get_api_version('operation_status') + if api_version == '2021-05-01-preview': + from .v2021_05_01_preview.operations import OperationStatusOperations as OperationClass + elif api_version == '2021-09-01': + from .v2021_09_01.operations import OperationStatusOperations as OperationClass + elif api_version == '2021-11-01-preview': + from .v2021_11_01_preview.operations import OperationStatusOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'operation_status'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def operations(self): + """Instance depends on the API version: + + * 2020-07-01-preview: :class:`Operations` + * 2020-10-01-preview: :class:`Operations` + * 2021-03-01: :class:`Operations` + * 2021-05-01-preview: :class:`Operations` + * 2021-09-01: :class:`Operations` + * 2021-11-01-preview: :class:`Operations` + """ + api_version = self._get_api_version('operations') + if api_version == '2020-07-01-preview': + from .v2020_07_01_preview.operations import Operations as OperationClass + elif api_version == '2020-10-01-preview': + from .v2020_10_01_preview.operations import Operations as OperationClass + elif api_version == '2021-03-01': + from .v2021_03_01.operations import Operations as OperationClass + elif api_version == '2021-05-01-preview': + from .v2021_05_01_preview.operations import Operations as OperationClass + elif api_version == '2021-09-01': + from .v2021_09_01.operations import Operations as OperationClass + elif api_version == '2021-11-01-preview': + from .v2021_11_01_preview.operations import Operations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'operations'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def source_control_configurations(self): + """Instance depends on the API version: + + * 2020-07-01-preview: :class:`SourceControlConfigurationsOperations` + * 2020-10-01-preview: :class:`SourceControlConfigurationsOperations` + * 2021-03-01: :class:`SourceControlConfigurationsOperations` + * 2021-05-01-preview: :class:`SourceControlConfigurationsOperations` + * 2021-11-01-preview: :class:`SourceControlConfigurationsOperations` + """ + api_version = self._get_api_version('source_control_configurations') + if api_version == '2020-07-01-preview': + from .v2020_07_01_preview.operations import SourceControlConfigurationsOperations as OperationClass + elif api_version == '2020-10-01-preview': + from .v2020_10_01_preview.operations import SourceControlConfigurationsOperations as OperationClass + elif api_version == '2021-03-01': + from .v2021_03_01.operations import SourceControlConfigurationsOperations as OperationClass + elif api_version == '2021-05-01-preview': + from .v2021_05_01_preview.operations import SourceControlConfigurationsOperations as OperationClass + elif api_version == '2021-11-01-preview': + from .v2021_11_01_preview.operations import SourceControlConfigurationsOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'source_control_configurations'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) def close(self): - # type: () -> None self._client.close() - def __enter__(self): - # type: () -> SourceControlConfigurationClient self._client.__enter__() return self - def __exit__(self, *exc_details): - # type: (Any) -> None self._client.__exit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_version.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_version.py index e5754a47ce6..b538e1b4f03 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_version.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_version.py @@ -6,4 +6,4 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -VERSION = "1.0.0b1" +VERSION = "1.0.0b1" \ No newline at end of file diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_configuration.py index 682d2762893..e86e06bef71 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_configuration.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_configuration.py @@ -1,11 +1,13 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. # -------------------------------------------------------------------------- - from typing import Any, TYPE_CHECKING from azure.core.configuration import Configuration @@ -18,7 +20,6 @@ # pylint: disable=unused-import,ungrouped-imports from azure.core.credentials_async import AsyncTokenCredential - class SourceControlConfigurationClientConfiguration(Configuration): """Configuration for SourceControlConfigurationClient. @@ -27,7 +28,7 @@ class SourceControlConfigurationClientConfiguration(Configuration): :param credential: Credential needed for the client to connect to Azure. :type credential: ~azure.core.credentials_async.AsyncTokenCredential - :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :param subscription_id: The ID of the target subscription. :type subscription_id: str """ @@ -35,7 +36,7 @@ def __init__( self, credential: "AsyncTokenCredential", subscription_id: str, - **kwargs: Any + **kwargs # type: Any ) -> None: if credential is None: raise ValueError("Parameter 'credential' must not be None.") @@ -45,9 +46,8 @@ def __init__( self.credential = credential self.subscription_id = subscription_id - self.api_version = "2021-03-01" self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) - kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + kwargs.setdefault('sdk_moniker', 'azure-mgmt-kubernetesconfiguration/{}'.format(VERSION)) self._configure(**kwargs) def _configure( diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_source_control_configuration_client.py index 2db9ca6cfeb..0207133fc2a 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_source_control_configuration_client.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/_source_control_configuration_client.py @@ -1,87 +1,310 @@ # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# # Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. # -------------------------------------------------------------------------- from typing import Any, Optional, TYPE_CHECKING from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest from azure.mgmt.core import AsyncARMPipelineClient +from azure.profiles import KnownProfiles, ProfileDefinition +from azure.profiles.multiapiclient import MultiApiClientMixin from msrest import Deserializer, Serializer +from ._configuration import SourceControlConfigurationClientConfiguration + if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports from azure.core.credentials_async import AsyncTokenCredential -from ._configuration import SourceControlConfigurationClientConfiguration -from .operations import SourceControlConfigurationsOperations -from .operations import Operations -from .. import models - +class _SDKClient(object): + def __init__(self, *args, **kwargs): + """This is a fake class to support current implemetation of MultiApiClientMixin." + Will be removed in final version of multiapi azure-core based client + """ + pass -class SourceControlConfigurationClient(object): +class SourceControlConfigurationClient(MultiApiClientMixin, _SDKClient): """KubernetesConfiguration Client. - :ivar source_control_configurations: SourceControlConfigurationsOperations operations - :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2021_03_01.aio.operations.SourceControlConfigurationsOperations - :ivar operations: Operations operations - :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_03_01.aio.operations.Operations + This ready contains multiple API versions, to help you deal with all of the Azure clouds + (Azure Stack, Azure Government, Azure China, etc.). + By default, it uses the latest API version available on public Azure. + For production, you should stick to a particular api-version and/or profile. + The profile sets a mapping between an operation group and its API version. + The api-version parameter sets the default API version if the operation + group is not described in the profile. + :param credential: Credential needed for the client to connect to Azure. :type credential: ~azure.core.credentials_async.AsyncTokenCredential - :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :param subscription_id: The ID of the target subscription. :type subscription_id: str - :param str base_url: Service URL + :param api_version: API version to use if no profile is provided, or if missing in profile. + :type api_version: str + :param base_url: Service URL + :type base_url: str + :param profile: A profile definition, from KnownProfiles to dict. + :type profile: azure.profiles.KnownProfiles :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. """ + DEFAULT_API_VERSION = '2021-09-01' + _PROFILE_TAG = "azure.mgmt.kubernetesconfiguration.SourceControlConfigurationClient" + LATEST_PROFILE = ProfileDefinition({ + _PROFILE_TAG: { + None: DEFAULT_API_VERSION, + 'source_control_configurations': '2021-03-01', + }}, + _PROFILE_TAG + " latest" + ) + def __init__( self, credential: "AsyncTokenCredential", subscription_id: str, + api_version: Optional[str] = None, base_url: Optional[str] = None, - **kwargs: Any + profile: KnownProfiles = KnownProfiles.default, + **kwargs # type: Any ) -> None: if not base_url: base_url = 'https://management.azure.com' self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) self._client = AsyncARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + super(SourceControlConfigurationClient, self).__init__( + api_version=api_version, + profile=profile + ) - client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} - self._serialize = Serializer(client_models) - self._serialize.client_side_validation = False - self._deserialize = Deserializer(client_models) + @classmethod + def _models_dict(cls, api_version): + return {k: v for k, v in cls.models(api_version).__dict__.items() if isinstance(v, type)} - self.source_control_configurations = SourceControlConfigurationsOperations( - self._client, self._config, self._serialize, self._deserialize) - self.operations = Operations( - self._client, self._config, self._serialize, self._deserialize) + @classmethod + def models(cls, api_version=DEFAULT_API_VERSION): + """Module depends on the API version: - async def _send_request(self, http_request: HttpRequest, **kwargs: Any) -> AsyncHttpResponse: - """Runs the network request through the client's chained policies. + * 2020-07-01-preview: :mod:`v2020_07_01_preview.models` + * 2020-10-01-preview: :mod:`v2020_10_01_preview.models` + * 2021-03-01: :mod:`v2021_03_01.models` + * 2021-05-01-preview: :mod:`v2021_05_01_preview.models` + * 2021-09-01: :mod:`v2021_09_01.models` + * 2021-11-01-preview: :mod:`v2021_11_01_preview.models` + """ + if api_version == '2020-07-01-preview': + from ..v2020_07_01_preview import models + return models + elif api_version == '2020-10-01-preview': + from ..v2020_10_01_preview import models + return models + elif api_version == '2021-03-01': + from ..v2021_03_01 import models + return models + elif api_version == '2021-05-01-preview': + from ..v2021_05_01_preview import models + return models + elif api_version == '2021-09-01': + from ..v2021_09_01 import models + return models + elif api_version == '2021-11-01-preview': + from ..v2021_11_01_preview import models + return models + raise ValueError("API version {} is not available".format(api_version)) - :param http_request: The network request you want to make. Required. - :type http_request: ~azure.core.pipeline.transport.HttpRequest - :keyword bool stream: Whether the response payload will be streamed. Defaults to True. - :return: The response of your network call. Does not do error handling on your response. - :rtype: ~azure.core.pipeline.transport.AsyncHttpResponse + @property + def cluster_extension_type(self): + """Instance depends on the API version: + + * 2021-05-01-preview: :class:`ClusterExtensionTypeOperations` + * 2021-11-01-preview: :class:`ClusterExtensionTypeOperations` """ - path_format_arguments = { - 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), - } - http_request.url = self._client.format_url(http_request.url, **path_format_arguments) - stream = kwargs.pop("stream", True) - pipeline_response = await self._client._pipeline.run(http_request, stream=stream, **kwargs) - return pipeline_response.http_response - - async def close(self) -> None: - await self._client.close() + api_version = self._get_api_version('cluster_extension_type') + if api_version == '2021-05-01-preview': + from ..v2021_05_01_preview.aio.operations import ClusterExtensionTypeOperations as OperationClass + elif api_version == '2021-11-01-preview': + from ..v2021_11_01_preview.aio.operations import ClusterExtensionTypeOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'cluster_extension_type'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def cluster_extension_types(self): + """Instance depends on the API version: + + * 2021-05-01-preview: :class:`ClusterExtensionTypesOperations` + * 2021-11-01-preview: :class:`ClusterExtensionTypesOperations` + """ + api_version = self._get_api_version('cluster_extension_types') + if api_version == '2021-05-01-preview': + from ..v2021_05_01_preview.aio.operations import ClusterExtensionTypesOperations as OperationClass + elif api_version == '2021-11-01-preview': + from ..v2021_11_01_preview.aio.operations import ClusterExtensionTypesOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'cluster_extension_types'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def extension_type_versions(self): + """Instance depends on the API version: + + * 2021-05-01-preview: :class:`ExtensionTypeVersionsOperations` + * 2021-11-01-preview: :class:`ExtensionTypeVersionsOperations` + """ + api_version = self._get_api_version('extension_type_versions') + if api_version == '2021-05-01-preview': + from ..v2021_05_01_preview.aio.operations import ExtensionTypeVersionsOperations as OperationClass + elif api_version == '2021-11-01-preview': + from ..v2021_11_01_preview.aio.operations import ExtensionTypeVersionsOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'extension_type_versions'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def extensions(self): + """Instance depends on the API version: + + * 2020-07-01-preview: :class:`ExtensionsOperations` + * 2021-05-01-preview: :class:`ExtensionsOperations` + * 2021-09-01: :class:`ExtensionsOperations` + * 2021-11-01-preview: :class:`ExtensionsOperations` + """ + api_version = self._get_api_version('extensions') + if api_version == '2020-07-01-preview': + from ..v2020_07_01_preview.aio.operations import ExtensionsOperations as OperationClass + elif api_version == '2021-05-01-preview': + from ..v2021_05_01_preview.aio.operations import ExtensionsOperations as OperationClass + elif api_version == '2021-09-01': + from ..v2021_09_01.aio.operations import ExtensionsOperations as OperationClass + elif api_version == '2021-11-01-preview': + from ..v2021_11_01_preview.aio.operations import ExtensionsOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'extensions'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def flux_config_operation_status(self): + """Instance depends on the API version: - async def __aenter__(self) -> "SourceControlConfigurationClient": + * 2021-11-01-preview: :class:`FluxConfigOperationStatusOperations` + """ + api_version = self._get_api_version('flux_config_operation_status') + if api_version == '2021-11-01-preview': + from ..v2021_11_01_preview.aio.operations import FluxConfigOperationStatusOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'flux_config_operation_status'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def flux_configurations(self): + """Instance depends on the API version: + + * 2021-11-01-preview: :class:`FluxConfigurationsOperations` + """ + api_version = self._get_api_version('flux_configurations') + if api_version == '2021-11-01-preview': + from ..v2021_11_01_preview.aio.operations import FluxConfigurationsOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'flux_configurations'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def location_extension_types(self): + """Instance depends on the API version: + + * 2021-05-01-preview: :class:`LocationExtensionTypesOperations` + * 2021-11-01-preview: :class:`LocationExtensionTypesOperations` + """ + api_version = self._get_api_version('location_extension_types') + if api_version == '2021-05-01-preview': + from ..v2021_05_01_preview.aio.operations import LocationExtensionTypesOperations as OperationClass + elif api_version == '2021-11-01-preview': + from ..v2021_11_01_preview.aio.operations import LocationExtensionTypesOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'location_extension_types'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def operation_status(self): + """Instance depends on the API version: + + * 2021-05-01-preview: :class:`OperationStatusOperations` + * 2021-09-01: :class:`OperationStatusOperations` + * 2021-11-01-preview: :class:`OperationStatusOperations` + """ + api_version = self._get_api_version('operation_status') + if api_version == '2021-05-01-preview': + from ..v2021_05_01_preview.aio.operations import OperationStatusOperations as OperationClass + elif api_version == '2021-09-01': + from ..v2021_09_01.aio.operations import OperationStatusOperations as OperationClass + elif api_version == '2021-11-01-preview': + from ..v2021_11_01_preview.aio.operations import OperationStatusOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'operation_status'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def operations(self): + """Instance depends on the API version: + + * 2020-07-01-preview: :class:`Operations` + * 2020-10-01-preview: :class:`Operations` + * 2021-03-01: :class:`Operations` + * 2021-05-01-preview: :class:`Operations` + * 2021-09-01: :class:`Operations` + * 2021-11-01-preview: :class:`Operations` + """ + api_version = self._get_api_version('operations') + if api_version == '2020-07-01-preview': + from ..v2020_07_01_preview.aio.operations import Operations as OperationClass + elif api_version == '2020-10-01-preview': + from ..v2020_10_01_preview.aio.operations import Operations as OperationClass + elif api_version == '2021-03-01': + from ..v2021_03_01.aio.operations import Operations as OperationClass + elif api_version == '2021-05-01-preview': + from ..v2021_05_01_preview.aio.operations import Operations as OperationClass + elif api_version == '2021-09-01': + from ..v2021_09_01.aio.operations import Operations as OperationClass + elif api_version == '2021-11-01-preview': + from ..v2021_11_01_preview.aio.operations import Operations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'operations'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + @property + def source_control_configurations(self): + """Instance depends on the API version: + + * 2020-07-01-preview: :class:`SourceControlConfigurationsOperations` + * 2020-10-01-preview: :class:`SourceControlConfigurationsOperations` + * 2021-03-01: :class:`SourceControlConfigurationsOperations` + * 2021-05-01-preview: :class:`SourceControlConfigurationsOperations` + * 2021-11-01-preview: :class:`SourceControlConfigurationsOperations` + """ + api_version = self._get_api_version('source_control_configurations') + if api_version == '2020-07-01-preview': + from ..v2020_07_01_preview.aio.operations import SourceControlConfigurationsOperations as OperationClass + elif api_version == '2020-10-01-preview': + from ..v2020_10_01_preview.aio.operations import SourceControlConfigurationsOperations as OperationClass + elif api_version == '2021-03-01': + from ..v2021_03_01.aio.operations import SourceControlConfigurationsOperations as OperationClass + elif api_version == '2021-05-01-preview': + from ..v2021_05_01_preview.aio.operations import SourceControlConfigurationsOperations as OperationClass + elif api_version == '2021-11-01-preview': + from ..v2021_11_01_preview.aio.operations import SourceControlConfigurationsOperations as OperationClass + else: + raise ValueError("API version {} does not have operation group 'source_control_configurations'".format(api_version)) + return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version))) + + async def close(self): + await self._client.close() + async def __aenter__(self): await self._client.__aenter__() return self - - async def __aexit__(self, *exc_details) -> None: + async def __aexit__(self, *exc_details): await self._client.__aexit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_operations.py index 09d8376d112..abad6a97377 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_operations.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_operations.py @@ -26,7 +26,7 @@ class Operations: instantiates it for you and attaches it as an attribute. :ivar models: Alias to model classes used in this operation group. - :type models: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models + :type models: ~azure.mgmt.kubernetesconfiguration.models :param client: Client for service requests. :param config: Configuration of service client. :param serializer: An object model serializer. @@ -43,13 +43,13 @@ def __init__(self, client, config, serializer, deserializer) -> None: def list( self, - **kwargs: Any + **kwargs ) -> AsyncIterable["_models.ResourceProviderOperationList"]: """List all the available operations the KubernetesConfiguration resource provider supports. :keyword callable cls: A custom type or function that will be passed the direct response :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ResourceProviderOperationList] + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationList] :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] @@ -57,7 +57,7 @@ def list( 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError } error_map.update(kwargs.pop('error_map', {})) - api_version = "2021-03-01" + api_version = "2020-10-01-preview" accept = "application/json" def prepare_request(next_link=None): @@ -93,9 +93,8 @@ async def get_next(next_link=None): response = pipeline_response.http_response if response.status_code not in [200]: - error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + raise HttpResponseError(response=response, error_format=ARMErrorFormat) return pipeline_response diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_source_control_configurations_operations.py index db8449803bd..2a8fe57a0cf 100644 --- a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_source_control_configurations_operations.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/aio/operations/_source_control_configurations_operations.py @@ -28,7 +28,7 @@ class SourceControlConfigurationsOperations: instantiates it for you and attaches it as an attribute. :ivar models: Alias to model classes used in this operation group. - :type models: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models + :type models: ~azure.mgmt.kubernetesconfiguration.models :param client: Client for service requests. :param config: Configuration of service client. :param serializer: An object model serializer. @@ -50,7 +50,7 @@ async def get( cluster_resource_name: Union[str, "_models.Enum1"], cluster_name: str, source_control_configuration_name: str, - **kwargs: Any + **kwargs ) -> "_models.SourceControlConfiguration": """Gets details of the Source Control Configuration. @@ -58,17 +58,17 @@ async def get( :type resource_group_name: str :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). - :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.models.Enum0 :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). - :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.models.Enum1 :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str :param source_control_configuration_name: Name of the Source Control Configuration. :type source_control_configuration_name: str :keyword callable cls: A custom type or function that will be passed the direct response :return: SourceControlConfiguration, or the result of cls(response) - :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :rtype: ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] @@ -76,7 +76,7 @@ async def get( 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError } error_map.update(kwargs.pop('error_map', {})) - api_version = "2021-03-01" + api_version = "2020-10-01-preview" accept = "application/json" # Construct URL @@ -105,7 +105,7 @@ async def get( if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + error = self._deserialize(_models.ErrorResponse, response) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) @@ -124,7 +124,7 @@ async def create_or_update( cluster_name: str, source_control_configuration_name: str, source_control_configuration: "_models.SourceControlConfiguration", - **kwargs: Any + **kwargs ) -> "_models.SourceControlConfiguration": """Create a new Kubernetes Source Control Configuration. @@ -132,19 +132,19 @@ async def create_or_update( :type resource_group_name: str :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). - :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.models.Enum0 :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). - :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.models.Enum1 :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str :param source_control_configuration_name: Name of the Source Control Configuration. :type source_control_configuration_name: str :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. - :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration :keyword callable cls: A custom type or function that will be passed the direct response :return: SourceControlConfiguration, or the result of cls(response) - :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :rtype: ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] @@ -152,7 +152,7 @@ async def create_or_update( 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError } error_map.update(kwargs.pop('error_map', {})) - api_version = "2021-03-01" + api_version = "2020-10-01-preview" content_type = kwargs.pop("content_type", "application/json") accept = "application/json" @@ -186,7 +186,7 @@ async def create_or_update( if response.status_code not in [200, 201]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + error = self._deserialize(_models.ErrorResponse, response) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) if response.status_code == 200: @@ -208,14 +208,14 @@ async def _delete_initial( cluster_resource_name: Union[str, "_models.Enum1"], cluster_name: str, source_control_configuration_name: str, - **kwargs: Any + **kwargs ) -> None: cls = kwargs.pop('cls', None) # type: ClsType[None] error_map = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError } error_map.update(kwargs.pop('error_map', {})) - api_version = "2021-03-01" + api_version = "2020-10-01-preview" accept = "application/json" # Construct URL @@ -244,7 +244,7 @@ async def _delete_initial( if response.status_code not in [200, 204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + error = self._deserialize(_models.ErrorResponse, response) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) if cls: @@ -259,7 +259,7 @@ async def begin_delete( cluster_resource_name: Union[str, "_models.Enum1"], cluster_name: str, source_control_configuration_name: str, - **kwargs: Any + **kwargs ) -> AsyncLROPoller[None]: """This will delete the YAML file used to set up the Source control configuration, thus stopping future sync from the source repo. @@ -268,18 +268,18 @@ async def begin_delete( :type resource_group_name: str :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). - :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.models.Enum0 :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). - :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.models.Enum1 :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str :param source_control_configuration_name: Name of the Source Control Configuration. :type source_control_configuration_name: str :keyword callable cls: A custom type or function that will be passed the direct response :keyword str continuation_token: A continuation token to restart a poller from a saved state. - :keyword polling: By default, your polling method will be AsyncARMPolling. - Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :keyword polling: True for ARMPolling, False for no polling, or a + polling object for personal polling strategy :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. :return: An instance of AsyncLROPoller that returns either None or the result of cls(response) @@ -340,7 +340,7 @@ def list( cluster_rp: Union[str, "_models.Enum0"], cluster_resource_name: Union[str, "_models.Enum1"], cluster_name: str, - **kwargs: Any + **kwargs ) -> AsyncIterable["_models.SourceControlConfigurationList"]: """List all Source Control Configurations. @@ -348,15 +348,15 @@ def list( :type resource_group_name: str :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). - :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.models.Enum0 :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). - :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.models.Enum1 :param cluster_name: The name of the kubernetes cluster. :type cluster_name: str :keyword callable cls: A custom type or function that will be passed the direct response :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfigurationList] + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.models.SourceControlConfigurationList] :raises: ~azure.core.exceptions.HttpResponseError """ cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] @@ -364,7 +364,7 @@ def list( 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError } error_map.update(kwargs.pop('error_map', {})) - api_version = "2021-03-01" + api_version = "2020-10-01-preview" accept = "application/json" def prepare_request(next_link=None): @@ -408,7 +408,7 @@ async def get_next(next_link=None): response = pipeline_response.http_response if response.status_code not in [200]: - error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + error = self._deserialize(_models.ErrorResponse, response) map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models.py new file mode 100644 index 00000000000..c82fe8f439c --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models.py @@ -0,0 +1,8 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from .v2021_03_01.models import * +from .v2021_09_01.models import * diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/__init__.py new file mode 100644 index 00000000000..f13062376d7 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +from ._version import VERSION + +__version__ = VERSION +__all__ = ['SourceControlConfigurationClient'] + +try: + from ._patch import patch_sdk # type: ignore + patch_sdk() +except ImportError: + pass diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/_configuration.py new file mode 100644 index 00000000000..89bdc90391d --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/_configuration.py @@ -0,0 +1,71 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from ._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + + from azure.core.credentials import TokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2020-07-01-preview" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs # type: Any + ): + # type: (...) -> None + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.BearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/_source_control_configuration_client.py new file mode 100644 index 00000000000..71f3974f333 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/_source_control_configuration_client.py @@ -0,0 +1,99 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.mgmt.core import ARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Optional + + from azure.core.credentials import TokenCredential + from azure.core.pipeline.transport import HttpRequest, HttpResponse + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from .operations import ExtensionsOperations +from . import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.operations.Operations + :ivar extensions: ExtensionsOperations operations + :vartype extensions: azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.operations.ExtensionsOperations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + base_url=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> None + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = ARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + self.extensions = ExtensionsOperations( + self._client, self._config, self._serialize, self._deserialize) + + def _send_request(self, http_request, **kwargs): + # type: (HttpRequest, Any) -> HttpResponse + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.HttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + def close(self): + # type: () -> None + self._client.close() + + def __enter__(self): + # type: () -> SourceControlConfigurationClient + self._client.__enter__() + return self + + def __exit__(self, *exc_details): + # type: (Any) -> None + self._client.__exit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/_consts.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/_version.py similarity index 58% rename from src/k8s-configuration/azext_k8s_configuration/_consts.py rename to src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/_version.py index e58470e7e78..59deb8c7263 100644 --- a/src/k8s-configuration/azext_k8s_configuration/_consts.py +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/_version.py @@ -1,7 +1,9 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -PROVIDER_NAMESPACE = 'Microsoft.KubernetesConfiguration' -REGISTERED = "Registered" +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +VERSION = "1.1.0" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/__init__.py new file mode 100644 index 00000000000..ba52c91a7ba --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +__all__ = ['SourceControlConfigurationClient'] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/_configuration.py new file mode 100644 index 00000000000..e15dc551cae --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/_configuration.py @@ -0,0 +1,67 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from .._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + **kwargs: Any + ) -> None: + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2020-07-01-preview" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs: Any + ) -> None: + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.AsyncBearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/_source_control_configuration_client.py new file mode 100644 index 00000000000..a03dc102973 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/_source_control_configuration_client.py @@ -0,0 +1,92 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Optional, TYPE_CHECKING + +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core import AsyncARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from .operations import ExtensionsOperations +from .. import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.aio.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.aio.operations.Operations + :ivar extensions: ExtensionsOperations operations + :vartype extensions: azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.aio.operations.ExtensionsOperations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + base_url: Optional[str] = None, + **kwargs: Any + ) -> None: + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = AsyncARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + self.extensions = ExtensionsOperations( + self._client, self._config, self._serialize, self._deserialize) + + async def _send_request(self, http_request: HttpRequest, **kwargs: Any) -> AsyncHttpResponse: + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.AsyncHttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = await self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "SourceControlConfigurationClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details) -> None: + await self._client.__aexit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/__init__.py new file mode 100644 index 00000000000..2e68d5ecb0c --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/__init__.py @@ -0,0 +1,17 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._operations import Operations +from ._extensions_operations import ExtensionsOperations + +__all__ = [ + 'SourceControlConfigurationsOperations', + 'Operations', + 'ExtensionsOperations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_extensions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_extensions_operations.py new file mode 100644 index 00000000000..e92980035ad --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_extensions_operations.py @@ -0,0 +1,433 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionsOperations: + """ExtensionsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def create( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_instance_name: str, + extension_instance: "_models.ExtensionInstance", + **kwargs: Any + ) -> "_models.ExtensionInstance": + """Create a new Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param extension_instance: Properties necessary to Create an Extension Instance. + :type extension_instance: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstance + :keyword callable cls: A custom type or function that will be passed the direct response + :return: ExtensionInstance, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstance + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionInstance"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(extension_instance, 'ExtensionInstance') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('ExtensionInstance', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} # type: ignore + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_instance_name: str, + **kwargs: Any + ) -> "_models.ExtensionInstance": + """Gets details of the Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: ExtensionInstance, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstance + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionInstance"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('ExtensionInstance', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} # type: ignore + + async def update( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_instance_name: str, + extension_instance: "_models.ExtensionInstanceUpdate", + **kwargs: Any + ) -> "_models.ExtensionInstance": + """Update an existing Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param extension_instance: Properties to Update in the Extension Instance. + :type extension_instance: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstanceUpdate + :keyword callable cls: A custom type or function that will be passed the direct response + :return: ExtensionInstance, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstance + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionInstance"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(extension_instance, 'ExtensionInstanceUpdate') + body_content_kwargs['content'] = body_content + request = self._client.patch(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('ExtensionInstance', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} # type: ignore + + async def delete( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_instance_name: str, + **kwargs: Any + ) -> None: + """Delete a Kubernetes Cluster Extension Instance. This will cause the Agent to Uninstall the + extension instance from the cluster. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: None, or the result of cls(response) + :rtype: None + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + # Construct URL + url = self.delete.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.ExtensionInstancesList"]: + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionInstancesList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstancesList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionInstancesList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionInstancesList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_operations.py new file mode 100644 index 00000000000..b9e2205f961 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_operations.py @@ -0,0 +1,105 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class Operations: + """Operations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs: Any + ) -> AsyncIterable["_models.ResourceProviderOperationList"]: + """List all the available operations the KubernetesConfiguration resource provider supports. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..116ecb3713e --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/aio/operations/_source_control_configurations_operations.py @@ -0,0 +1,420 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class SourceControlConfigurationsOperations: + """SourceControlConfigurationsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def create_or_update( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + source_control_configuration: "_models.SourceControlConfiguration", + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SourceControlConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create_or_update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def _delete_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> None: + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def begin_delete( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> AsyncLROPoller[None]: + """This will delete the YAML file used to set up the Source control configuration, thus stopping + future sync from the source repo. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.SourceControlConfigurationList"]: + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SourceControlConfigurationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('SourceControlConfigurationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/__init__.py new file mode 100644 index 00000000000..5d3f8aea197 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/__init__.py @@ -0,0 +1,99 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +try: + from ._models_py3 import ComplianceStatus + from ._models_py3 import ConfigurationIdentity + from ._models_py3 import ErrorDefinition + from ._models_py3 import ErrorResponse + from ._models_py3 import ExtensionInstance + from ._models_py3 import ExtensionInstanceUpdate + from ._models_py3 import ExtensionInstancesList + from ._models_py3 import ExtensionStatus + from ._models_py3 import HelmOperatorProperties + from ._models_py3 import ProxyResource + from ._models_py3 import Resource + from ._models_py3 import ResourceProviderOperation + from ._models_py3 import ResourceProviderOperationDisplay + from ._models_py3 import ResourceProviderOperationList + from ._models_py3 import Result + from ._models_py3 import Scope + from ._models_py3 import ScopeCluster + from ._models_py3 import ScopeNamespace + from ._models_py3 import SourceControlConfiguration + from ._models_py3 import SourceControlConfigurationList + from ._models_py3 import SystemData +except (SyntaxError, ImportError): + from ._models import ComplianceStatus # type: ignore + from ._models import ConfigurationIdentity # type: ignore + from ._models import ErrorDefinition # type: ignore + from ._models import ErrorResponse # type: ignore + from ._models import ExtensionInstance # type: ignore + from ._models import ExtensionInstanceUpdate # type: ignore + from ._models import ExtensionInstancesList # type: ignore + from ._models import ExtensionStatus # type: ignore + from ._models import HelmOperatorProperties # type: ignore + from ._models import ProxyResource # type: ignore + from ._models import Resource # type: ignore + from ._models import ResourceProviderOperation # type: ignore + from ._models import ResourceProviderOperationDisplay # type: ignore + from ._models import ResourceProviderOperationList # type: ignore + from ._models import Result # type: ignore + from ._models import Scope # type: ignore + from ._models import ScopeCluster # type: ignore + from ._models import ScopeNamespace # type: ignore + from ._models import SourceControlConfiguration # type: ignore + from ._models import SourceControlConfigurationList # type: ignore + from ._models import SystemData # type: ignore + +from ._source_control_configuration_client_enums import ( + ComplianceStateType, + Enum0, + Enum1, + InstallStateType, + LevelType, + MessageLevelType, + OperatorScopeType, + OperatorType, + ProvisioningStateType, + ResourceIdentityType, +) + +__all__ = [ + 'ComplianceStatus', + 'ConfigurationIdentity', + 'ErrorDefinition', + 'ErrorResponse', + 'ExtensionInstance', + 'ExtensionInstanceUpdate', + 'ExtensionInstancesList', + 'ExtensionStatus', + 'HelmOperatorProperties', + 'ProxyResource', + 'Resource', + 'ResourceProviderOperation', + 'ResourceProviderOperationDisplay', + 'ResourceProviderOperationList', + 'Result', + 'Scope', + 'ScopeCluster', + 'ScopeNamespace', + 'SourceControlConfiguration', + 'SourceControlConfigurationList', + 'SystemData', + 'ComplianceStateType', + 'Enum0', + 'Enum1', + 'InstallStateType', + 'LevelType', + 'MessageLevelType', + 'OperatorScopeType', + 'OperatorType', + 'ProvisioningStateType', + 'ResourceIdentityType', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_models.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_models.py new file mode 100644 index 00000000000..ef31b453ddc --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_models.py @@ -0,0 +1,817 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from azure.core.exceptions import HttpResponseError +import msrest.serialization + + +class ComplianceStatus(msrest.serialization.Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar compliance_state: The compliance state of the configuration. Possible values include: + "Pending", "Compliant", "Noncompliant", "Installed", "Failed". + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: ~datetime.datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: "Error", "Warning", + "Information". + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = kwargs.get('last_config_applied', None) + self.message = kwargs.get('message', None) + self.message_level = kwargs.get('message_level', None) + + +class ConfigurationIdentity(msrest.serialization.Model): + """Identity for the managed cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal id of the system assigned identity which is used by the + configuration. + :vartype principal_id: str + :ivar tenant_id: The tenant id of the system assigned identity which is used by the + configuration. + :vartype tenant_id: str + :param type: The type of identity used for the configuration. Type 'SystemAssigned' will use an + implicitly created identity. Type 'None' will not use Managed Identity for the configuration. + Possible values include: "SystemAssigned", "None". + :type type: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ResourceIdentityType + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ConfigurationIdentity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = kwargs.get('type', None) + + +class ErrorDefinition(msrest.serialization.Model): + """Error definition. + + All required parameters must be populated in order to send to Azure. + + :param code: Required. Service specific error code which serves as the substatus for the HTTP + error code. + :type code: str + :param message: Required. Description of the error. + :type message: str + """ + + _validation = { + 'code': {'required': True}, + 'message': {'required': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorDefinition, self).__init__(**kwargs) + self.code = kwargs['code'] + self.message = kwargs['message'] + + +class ErrorResponse(msrest.serialization.Model): + """Error response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar error: Error definition. + :vartype error: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ErrorDefinition + """ + + _validation = { + 'error': {'readonly': True}, + } + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDefinition'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorResponse, self).__init__(**kwargs) + self.error = None + + +class Resource(msrest.serialization.Model): + """The Resource model definition. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + self.system_data = kwargs.get('system_data', None) + + +class ProxyResource(Resource): + """ARM proxy resource. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + **kwargs + ): + super(ProxyResource, self).__init__(**kwargs) + + +class ExtensionInstance(ProxyResource): + """The Extension Instance object. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SystemData + :param extension_type: Type of the Extension, of which this resource is an instance of. It + must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the + Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this instance participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in for auto-upgrade + (e.g. Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension instance, if it is 'pinned' to a + specific version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param scope: Scope at which the extension instance is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + instance of the extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this instance of the extension. + :type configuration_protected_settings: dict[str, str] + :ivar install_state: Status of installation of this instance of the extension. Possible values + include: "Pending", "Installed", "Failed". + :vartype install_state: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.InstallStateType + :param statuses: Status from this instance of the extension. + :type statuses: + list[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionStatus] + :ivar creation_time: DateLiteral (per ISO8601) noting the time the resource was created by the + client (user). + :vartype creation_time: str + :ivar last_modified_time: DateLiteral (per ISO8601) noting the time the resource was modified + by the client (user). + :vartype last_modified_time: str + :ivar last_status_time: DateLiteral (per ISO8601) noting the time of last status from the + agent. + :vartype last_status_time: str + :ivar error_info: Error information from the Agent - e.g. errors during installation. + :vartype error_info: + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ErrorDefinition + :param identity: The identity of the configuration. + :type identity: + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ConfigurationIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'install_state': {'readonly': True}, + 'creation_time': {'readonly': True}, + 'last_modified_time': {'readonly': True}, + 'last_status_time': {'readonly': True}, + 'error_info': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'install_state': {'key': 'properties.installState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, + 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, + 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, + 'identity': {'key': 'properties.identity', 'type': 'ConfigurationIdentity'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionInstance, self).__init__(**kwargs) + self.extension_type = kwargs.get('extension_type', None) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', None) + self.release_train = kwargs.get('release_train', "Stable") + self.version = kwargs.get('version', None) + self.scope = kwargs.get('scope', None) + self.configuration_settings = kwargs.get('configuration_settings', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.install_state = None + self.statuses = kwargs.get('statuses', None) + self.creation_time = None + self.last_modified_time = None + self.last_status_time = None + self.error_info = None + self.identity = kwargs.get('identity', None) + + +class ExtensionInstancesList(msrest.serialization.Model): + """Result of the request to list Extension Instances. It contains a list of ExtensionInstance objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Extension Instances within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstance] + :ivar next_link: URL to get the next set of extension instance objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ExtensionInstance]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionInstancesList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class ExtensionInstanceUpdate(msrest.serialization.Model): + """Update Extension Instance request object. + + :param auto_upgrade_minor_version: Flag to note if this instance participates in Extension + Lifecycle Management or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in for auto-upgrade + (e.g. Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version number of extension, to 'pin' to a specific version. + autoUpgradeMinorVersion must be 'false'. + :type version: str + """ + + _attribute_map = { + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionInstanceUpdate, self).__init__(**kwargs) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', None) + self.release_train = kwargs.get('release_train', "Stable") + self.version = kwargs.get('version', None) + + +class ExtensionStatus(msrest.serialization.Model): + """Status from this instance of the extension. + + :param code: Status code provided by the Extension. + :type code: str + :param display_status: Short description of status of this instance of the extension. + :type display_status: str + :param level: Level of the status. Possible values include: "Error", "Warning", "Information". + Default value: "Information". + :type level: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.LevelType + :param message: Detailed message of the status from the Extension instance. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionStatus, self).__init__(**kwargs) + self.code = kwargs.get('code', None) + self.display_status = kwargs.get('display_status', None) + self.level = kwargs.get('level', "Information") + self.message = kwargs.get('message', None) + self.time = kwargs.get('time', None) + + +class HelmOperatorProperties(msrest.serialization.Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = kwargs.get('chart_version', None) + self.chart_values = kwargs.get('chart_values', None) + + +class ResourceProviderOperation(msrest.serialization.Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param name: Operation name, in format of {provider}/{resource}/{operation}. + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = kwargs.get('name', None) + self.display = kwargs.get('display', None) + self.is_data_action = None + + +class ResourceProviderOperationDisplay(msrest.serialization.Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = kwargs.get('provider', None) + self.resource = kwargs.get('resource', None) + self.operation = kwargs.get('operation', None) + self.description = kwargs.get('description', None) + + +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = kwargs.get('value', None) + self.next_link = None + + +class Result(msrest.serialization.Model): + """Sample result definition. + + :param sample_property: Sample property of type string. + :type sample_property: str + """ + + _attribute_map = { + 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Result, self).__init__(**kwargs) + self.sample_property = kwargs.get('sample_property', None) + + +class Scope(msrest.serialization.Model): + """Scope of the extensionInstance. It can be either Cluster or Namespace; but not both. + + :param cluster: Specifies that the scope of the extensionInstance is Cluster. + :type cluster: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ScopeCluster + :param namespace: Specifies that the scope of the extensionInstance is Namespace. + :type namespace: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__( + self, + **kwargs + ): + super(Scope, self).__init__(**kwargs) + self.cluster = kwargs.get('cluster', None) + self.namespace = kwargs.get('namespace', None) + + +class ScopeCluster(msrest.serialization.Model): + """Specifies that the scope of the extensionInstance is Cluster. + + :param release_namespace: Namespace where the extension Release must be placed, for a Cluster + scoped extensionInstance. If this namespace does not exist, it will be created. + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = kwargs.get('release_namespace', None) + + +class ScopeNamespace(msrest.serialization.Model): + """Specifies that the scope of the extensionInstance is Namespace. + + :param target_namespace: Namespace where the extensionInstance will be created for an Namespace + scoped extensionInstance. If this namespace does not exist, it will be created. + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = kwargs.get('target_namespace', None) + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying the specific + configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: "Flux". + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl configuration + (either generated within the cluster or provided by the user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents containing public SSH keys + required to access private Git instances. + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. Possible values + include: "Accepted", "Deleting", "Running", "Succeeded", "Failed". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration. + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfiguration, self).__init__(**kwargs) + self.repository_url = kwargs.get('repository_url', None) + self.operator_namespace = kwargs.get('operator_namespace', "default") + self.operator_instance_name = kwargs.get('operator_instance_name', None) + self.operator_type = kwargs.get('operator_type', None) + self.operator_params = kwargs.get('operator_params', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.operator_scope = kwargs.get('operator_scope', "cluster") + self.repository_public_key = None + self.ssh_known_hosts_contents = kwargs.get('ssh_known_hosts_contents', None) + self.enable_helm_operator = kwargs.get('enable_helm_operator', None) + self.helm_operator_properties = kwargs.get('helm_operator_properties', None) + self.provisioning_state = None + self.compliance_status = None + + +class SourceControlConfigurationList(msrest.serialization.Model): + """Result of the request to list Source Control Configurations. It contains a list of SourceControlConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Source Control Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SourceControlConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SourceControlConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfigurationList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class SystemData(msrest.serialization.Model): + """Top level metadata https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar created_by: A string identifier for the identity that created the resource. + :vartype created_by: str + :ivar created_by_type: The type of identity that created the resource: user, application, + managedIdentity, key. + :vartype created_by_type: str + :ivar created_at: The timestamp of resource creation (UTC). + :vartype created_at: ~datetime.datetime + :ivar last_modified_by: A string identifier for the identity that last modified the resource. + :vartype last_modified_by: str + :ivar last_modified_by_type: The type of identity that last modified the resource: user, + application, managedIdentity, key. + :vartype last_modified_by_type: str + :ivar last_modified_at: The timestamp of resource last modification (UTC). + :vartype last_modified_at: ~datetime.datetime + """ + + _validation = { + 'created_by': {'readonly': True}, + 'created_by_type': {'readonly': True}, + 'created_at': {'readonly': True}, + 'last_modified_by': {'readonly': True}, + 'last_modified_by_type': {'readonly': True}, + 'last_modified_at': {'readonly': True}, + } + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__( + self, + **kwargs + ): + super(SystemData, self).__init__(**kwargs) + self.created_by = None + self.created_by_type = None + self.created_at = None + self.last_modified_by = None + self.last_modified_by_type = None + self.last_modified_at = None diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_models_py3.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_models_py3.py new file mode 100644 index 00000000000..7d8c10c5306 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_models_py3.py @@ -0,0 +1,890 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import datetime +from typing import Dict, List, Optional, Union + +from azure.core.exceptions import HttpResponseError +import msrest.serialization + +from ._source_control_configuration_client_enums import * + + +class ComplianceStatus(msrest.serialization.Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar compliance_state: The compliance state of the configuration. Possible values include: + "Pending", "Compliant", "Noncompliant", "Installed", "Failed". + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: ~datetime.datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: "Error", "Warning", + "Information". + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__( + self, + *, + last_config_applied: Optional[datetime.datetime] = None, + message: Optional[str] = None, + message_level: Optional[Union[str, "MessageLevelType"]] = None, + **kwargs + ): + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = last_config_applied + self.message = message + self.message_level = message_level + + +class ConfigurationIdentity(msrest.serialization.Model): + """Identity for the managed cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal id of the system assigned identity which is used by the + configuration. + :vartype principal_id: str + :ivar tenant_id: The tenant id of the system assigned identity which is used by the + configuration. + :vartype tenant_id: str + :param type: The type of identity used for the configuration. Type 'SystemAssigned' will use an + implicitly created identity. Type 'None' will not use Managed Identity for the configuration. + Possible values include: "SystemAssigned", "None". + :type type: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ResourceIdentityType + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + *, + type: Optional[Union[str, "ResourceIdentityType"]] = None, + **kwargs + ): + super(ConfigurationIdentity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = type + + +class ErrorDefinition(msrest.serialization.Model): + """Error definition. + + All required parameters must be populated in order to send to Azure. + + :param code: Required. Service specific error code which serves as the substatus for the HTTP + error code. + :type code: str + :param message: Required. Description of the error. + :type message: str + """ + + _validation = { + 'code': {'required': True}, + 'message': {'required': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + } + + def __init__( + self, + *, + code: str, + message: str, + **kwargs + ): + super(ErrorDefinition, self).__init__(**kwargs) + self.code = code + self.message = message + + +class ErrorResponse(msrest.serialization.Model): + """Error response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar error: Error definition. + :vartype error: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ErrorDefinition + """ + + _validation = { + 'error': {'readonly': True}, + } + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDefinition'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorResponse, self).__init__(**kwargs) + self.error = None + + +class Resource(msrest.serialization.Model): + """The Resource model definition. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + *, + system_data: Optional["SystemData"] = None, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + self.system_data = system_data + + +class ProxyResource(Resource): + """ARM proxy resource. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + *, + system_data: Optional["SystemData"] = None, + **kwargs + ): + super(ProxyResource, self).__init__(system_data=system_data, **kwargs) + + +class ExtensionInstance(ProxyResource): + """The Extension Instance object. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SystemData + :param extension_type: Type of the Extension, of which this resource is an instance of. It + must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the + Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this instance participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in for auto-upgrade + (e.g. Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension instance, if it is 'pinned' to a + specific version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param scope: Scope at which the extension instance is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + instance of the extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this instance of the extension. + :type configuration_protected_settings: dict[str, str] + :ivar install_state: Status of installation of this instance of the extension. Possible values + include: "Pending", "Installed", "Failed". + :vartype install_state: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.InstallStateType + :param statuses: Status from this instance of the extension. + :type statuses: + list[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionStatus] + :ivar creation_time: DateLiteral (per ISO8601) noting the time the resource was created by the + client (user). + :vartype creation_time: str + :ivar last_modified_time: DateLiteral (per ISO8601) noting the time the resource was modified + by the client (user). + :vartype last_modified_time: str + :ivar last_status_time: DateLiteral (per ISO8601) noting the time of last status from the + agent. + :vartype last_status_time: str + :ivar error_info: Error information from the Agent - e.g. errors during installation. + :vartype error_info: + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ErrorDefinition + :param identity: The identity of the configuration. + :type identity: + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ConfigurationIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'install_state': {'readonly': True}, + 'creation_time': {'readonly': True}, + 'last_modified_time': {'readonly': True}, + 'last_status_time': {'readonly': True}, + 'error_info': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'install_state': {'key': 'properties.installState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'creation_time': {'key': 'properties.creationTime', 'type': 'str'}, + 'last_modified_time': {'key': 'properties.lastModifiedTime', 'type': 'str'}, + 'last_status_time': {'key': 'properties.lastStatusTime', 'type': 'str'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDefinition'}, + 'identity': {'key': 'properties.identity', 'type': 'ConfigurationIdentity'}, + } + + def __init__( + self, + *, + system_data: Optional["SystemData"] = None, + extension_type: Optional[str] = None, + auto_upgrade_minor_version: Optional[bool] = None, + release_train: Optional[str] = "Stable", + version: Optional[str] = None, + scope: Optional["Scope"] = None, + configuration_settings: Optional[Dict[str, str]] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + statuses: Optional[List["ExtensionStatus"]] = None, + identity: Optional["ConfigurationIdentity"] = None, + **kwargs + ): + super(ExtensionInstance, self).__init__(system_data=system_data, **kwargs) + self.extension_type = extension_type + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + self.scope = scope + self.configuration_settings = configuration_settings + self.configuration_protected_settings = configuration_protected_settings + self.install_state = None + self.statuses = statuses + self.creation_time = None + self.last_modified_time = None + self.last_status_time = None + self.error_info = None + self.identity = identity + + +class ExtensionInstancesList(msrest.serialization.Model): + """Result of the request to list Extension Instances. It contains a list of ExtensionInstance objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Extension Instances within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstance] + :ivar next_link: URL to get the next set of extension instance objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ExtensionInstance]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionInstancesList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class ExtensionInstanceUpdate(msrest.serialization.Model): + """Update Extension Instance request object. + + :param auto_upgrade_minor_version: Flag to note if this instance participates in Extension + Lifecycle Management or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension instance participates in for auto-upgrade + (e.g. Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version number of extension, to 'pin' to a specific version. + autoUpgradeMinorVersion must be 'false'. + :type version: str + """ + + _attribute_map = { + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + } + + def __init__( + self, + *, + auto_upgrade_minor_version: Optional[bool] = None, + release_train: Optional[str] = "Stable", + version: Optional[str] = None, + **kwargs + ): + super(ExtensionInstanceUpdate, self).__init__(**kwargs) + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + + +class ExtensionStatus(msrest.serialization.Model): + """Status from this instance of the extension. + + :param code: Status code provided by the Extension. + :type code: str + :param display_status: Short description of status of this instance of the extension. + :type display_status: str + :param level: Level of the status. Possible values include: "Error", "Warning", "Information". + Default value: "Information". + :type level: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.LevelType + :param message: Detailed message of the status from the Extension instance. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__( + self, + *, + code: Optional[str] = None, + display_status: Optional[str] = None, + level: Optional[Union[str, "LevelType"]] = "Information", + message: Optional[str] = None, + time: Optional[str] = None, + **kwargs + ): + super(ExtensionStatus, self).__init__(**kwargs) + self.code = code + self.display_status = display_status + self.level = level + self.message = message + self.time = time + + +class HelmOperatorProperties(msrest.serialization.Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__( + self, + *, + chart_version: Optional[str] = None, + chart_values: Optional[str] = None, + **kwargs + ): + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = chart_version + self.chart_values = chart_values + + +class ResourceProviderOperation(msrest.serialization.Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param name: Operation name, in format of {provider}/{resource}/{operation}. + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__( + self, + *, + name: Optional[str] = None, + display: Optional["ResourceProviderOperationDisplay"] = None, + **kwargs + ): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = name + self.display = display + self.is_data_action = None + + +class ResourceProviderOperationDisplay(msrest.serialization.Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__( + self, + *, + provider: Optional[str] = None, + resource: Optional[str] = None, + operation: Optional[str] = None, + description: Optional[str] = None, + **kwargs + ): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = provider + self.resource = resource + self.operation = operation + self.description = description + + +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + *, + value: Optional[List["ResourceProviderOperation"]] = None, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = value + self.next_link = None + + +class Result(msrest.serialization.Model): + """Sample result definition. + + :param sample_property: Sample property of type string. + :type sample_property: str + """ + + _attribute_map = { + 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, + } + + def __init__( + self, + *, + sample_property: Optional[str] = None, + **kwargs + ): + super(Result, self).__init__(**kwargs) + self.sample_property = sample_property + + +class Scope(msrest.serialization.Model): + """Scope of the extensionInstance. It can be either Cluster or Namespace; but not both. + + :param cluster: Specifies that the scope of the extensionInstance is Cluster. + :type cluster: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ScopeCluster + :param namespace: Specifies that the scope of the extensionInstance is Namespace. + :type namespace: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__( + self, + *, + cluster: Optional["ScopeCluster"] = None, + namespace: Optional["ScopeNamespace"] = None, + **kwargs + ): + super(Scope, self).__init__(**kwargs) + self.cluster = cluster + self.namespace = namespace + + +class ScopeCluster(msrest.serialization.Model): + """Specifies that the scope of the extensionInstance is Cluster. + + :param release_namespace: Namespace where the extension Release must be placed, for a Cluster + scoped extensionInstance. If this namespace does not exist, it will be created. + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + *, + release_namespace: Optional[str] = None, + **kwargs + ): + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = release_namespace + + +class ScopeNamespace(msrest.serialization.Model): + """Specifies that the scope of the extensionInstance is Namespace. + + :param target_namespace: Namespace where the extensionInstance will be created for an Namespace + scoped extensionInstance. If this namespace does not exist, it will be created. + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__( + self, + *, + target_namespace: Optional[str] = None, + **kwargs + ): + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = target_namespace + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying the specific + configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: "Flux". + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl configuration + (either generated within the cluster or provided by the user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents containing public SSH keys + required to access private Git instances. + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. Possible values + include: "Accepted", "Deleting", "Running", "Succeeded", "Failed". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration. + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__( + self, + *, + system_data: Optional["SystemData"] = None, + repository_url: Optional[str] = None, + operator_namespace: Optional[str] = "default", + operator_instance_name: Optional[str] = None, + operator_type: Optional[Union[str, "OperatorType"]] = None, + operator_params: Optional[str] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + operator_scope: Optional[Union[str, "OperatorScopeType"]] = "cluster", + ssh_known_hosts_contents: Optional[str] = None, + enable_helm_operator: Optional[bool] = None, + helm_operator_properties: Optional["HelmOperatorProperties"] = None, + **kwargs + ): + super(SourceControlConfiguration, self).__init__(system_data=system_data, **kwargs) + self.repository_url = repository_url + self.operator_namespace = operator_namespace + self.operator_instance_name = operator_instance_name + self.operator_type = operator_type + self.operator_params = operator_params + self.configuration_protected_settings = configuration_protected_settings + self.operator_scope = operator_scope + self.repository_public_key = None + self.ssh_known_hosts_contents = ssh_known_hosts_contents + self.enable_helm_operator = enable_helm_operator + self.helm_operator_properties = helm_operator_properties + self.provisioning_state = None + self.compliance_status = None + + +class SourceControlConfigurationList(msrest.serialization.Model): + """Result of the request to list Source Control Configurations. It contains a list of SourceControlConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Source Control Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SourceControlConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SourceControlConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfigurationList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class SystemData(msrest.serialization.Model): + """Top level metadata https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar created_by: A string identifier for the identity that created the resource. + :vartype created_by: str + :ivar created_by_type: The type of identity that created the resource: user, application, + managedIdentity, key. + :vartype created_by_type: str + :ivar created_at: The timestamp of resource creation (UTC). + :vartype created_at: ~datetime.datetime + :ivar last_modified_by: A string identifier for the identity that last modified the resource. + :vartype last_modified_by: str + :ivar last_modified_by_type: The type of identity that last modified the resource: user, + application, managedIdentity, key. + :vartype last_modified_by_type: str + :ivar last_modified_at: The timestamp of resource last modification (UTC). + :vartype last_modified_at: ~datetime.datetime + """ + + _validation = { + 'created_by': {'readonly': True}, + 'created_by_type': {'readonly': True}, + 'created_at': {'readonly': True}, + 'last_modified_by': {'readonly': True}, + 'last_modified_by_type': {'readonly': True}, + 'last_modified_at': {'readonly': True}, + } + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__( + self, + **kwargs + ): + super(SystemData, self).__init__(**kwargs) + self.created_by = None + self.created_by_type = None + self.created_at = None + self.last_modified_by = None + self.last_modified_by_type = None + self.last_modified_at = None diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_source_control_configuration_client_enums.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_source_control_configuration_client_enums.py new file mode 100644 index 00000000000..825cfccadd1 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/models/_source_control_configuration_client_enums.py @@ -0,0 +1,102 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from enum import Enum, EnumMeta +from six import with_metaclass + +class _CaseInsensitiveEnumMeta(EnumMeta): + def __getitem__(self, name): + return super().__getitem__(name.upper()) + + def __getattr__(cls, name): + """Return the enum member matching `name` + We use __getattr__ instead of descriptors or inserting into the enum + class' __dict__ in order to support `name` and `value` being both + properties for enum members (which live in the class' __dict__) and + enum members themselves. + """ + try: + return cls._member_map_[name.upper()] + except KeyError: + raise AttributeError(name) + + +class ComplianceStateType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The compliance state of the configuration. + """ + + PENDING = "Pending" + COMPLIANT = "Compliant" + NONCOMPLIANT = "Noncompliant" + INSTALLED = "Installed" + FAILED = "Failed" + +class Enum0(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + + MICROSOFT_CONTAINER_SERVICE = "Microsoft.ContainerService" + MICROSOFT_KUBERNETES = "Microsoft.Kubernetes" + +class Enum1(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + + MANAGED_CLUSTERS = "managedClusters" + CONNECTED_CLUSTERS = "connectedClusters" + +class InstallStateType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Status of installation of this instance of the extension. + """ + + PENDING = "Pending" + INSTALLED = "Installed" + FAILED = "Failed" + +class LevelType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Level of the status. + """ + + ERROR = "Error" + WARNING = "Warning" + INFORMATION = "Information" + +class MessageLevelType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Level of the message. + """ + + ERROR = "Error" + WARNING = "Warning" + INFORMATION = "Information" + +class OperatorScopeType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Scope at which the operator will be installed. + """ + + CLUSTER = "cluster" + NAMESPACE = "namespace" + +class OperatorType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Type of the operator + """ + + FLUX = "Flux" + +class ProvisioningStateType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The provisioning state of the resource provider. + """ + + ACCEPTED = "Accepted" + DELETING = "Deleting" + RUNNING = "Running" + SUCCEEDED = "Succeeded" + FAILED = "Failed" + +class ResourceIdentityType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The type of identity used for the configuration. Type 'SystemAssigned' will use an implicitly + created identity. Type 'None' will not use Managed Identity for the configuration. + """ + + SYSTEM_ASSIGNED = "SystemAssigned" + NONE = "None" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/__init__.py new file mode 100644 index 00000000000..2e68d5ecb0c --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/__init__.py @@ -0,0 +1,17 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._operations import Operations +from ._extensions_operations import ExtensionsOperations + +__all__ = [ + 'SourceControlConfigurationsOperations', + 'Operations', + 'ExtensionsOperations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_extensions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_extensions_operations.py new file mode 100644 index 00000000000..c3e2b0cf5f4 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_extensions_operations.py @@ -0,0 +1,442 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionsOperations(object): + """ExtensionsOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def create( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_instance_name, # type: str + extension_instance, # type: "_models.ExtensionInstance" + **kwargs # type: Any + ): + # type: (...) -> "_models.ExtensionInstance" + """Create a new Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param extension_instance: Properties necessary to Create an Extension Instance. + :type extension_instance: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstance + :keyword callable cls: A custom type or function that will be passed the direct response + :return: ExtensionInstance, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstance + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionInstance"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(extension_instance, 'ExtensionInstance') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('ExtensionInstance', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} # type: ignore + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_instance_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.ExtensionInstance" + """Gets details of the Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: ExtensionInstance, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstance + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionInstance"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('ExtensionInstance', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} # type: ignore + + def update( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_instance_name, # type: str + extension_instance, # type: "_models.ExtensionInstanceUpdate" + **kwargs # type: Any + ): + # type: (...) -> "_models.ExtensionInstance" + """Update an existing Kubernetes Cluster Extension Instance. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :param extension_instance: Properties to Update in the Extension Instance. + :type extension_instance: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstanceUpdate + :keyword callable cls: A custom type or function that will be passed the direct response + :return: ExtensionInstance, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstance + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionInstance"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(extension_instance, 'ExtensionInstanceUpdate') + body_content_kwargs['content'] = body_content + request = self._client.patch(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('ExtensionInstance', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} # type: ignore + + def delete( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_instance_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + """Delete a Kubernetes Cluster Extension Instance. This will cause the Agent to Uninstall the + extension instance from the cluster. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_instance_name: Name of an instance of the Extension. + :type extension_instance_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: None, or the result of cls(response) + :rtype: None + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + # Construct URL + url = self.delete.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionInstanceName': self._serialize.url("extension_instance_name", extension_instance_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionInstanceName}'} # type: ignore + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ExtensionInstancesList"] + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionInstancesList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ExtensionInstancesList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionInstancesList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionInstancesList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_operations.py new file mode 100644 index 00000000000..1fe1fbf39b1 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_operations.py @@ -0,0 +1,110 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class Operations(object): + """Operations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ResourceProviderOperationList"] + """List all the available operations the KubernetesConfiguration resource provider supports. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..d192efa6d03 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_07_01_preview/operations/_source_control_configurations_operations.py @@ -0,0 +1,429 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.core.polling import LROPoller, NoPolling, PollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.arm_polling import ARMPolling + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class SourceControlConfigurationsOperations(object): + """SourceControlConfigurationsOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.SourceControlConfiguration" + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def create_or_update( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + source_control_configuration, # type: "_models.SourceControlConfiguration" + **kwargs # type: Any + ): + # type: (...) -> "_models.SourceControlConfiguration" + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SourceControlConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create_or_update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def _delete_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def begin_delete( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> LROPoller[None] + """This will delete the YAML file used to set up the Source control configuration, thus stopping + future sync from the source repo. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.SourceControlConfigurationList"] + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2020_07_01_preview.models.SourceControlConfigurationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-07-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('SourceControlConfigurationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/__init__.py new file mode 100644 index 00000000000..f13062376d7 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +from ._version import VERSION + +__version__ = VERSION +__all__ = ['SourceControlConfigurationClient'] + +try: + from ._patch import patch_sdk # type: ignore + patch_sdk() +except ImportError: + pass diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_configuration.py new file mode 100644 index 00000000000..d5969e53212 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_configuration.py @@ -0,0 +1,71 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from ._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + + from azure.core.credentials import TokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2020-10-01-preview" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs # type: Any + ): + # type: (...) -> None + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.BearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_source_control_configuration_client.py new file mode 100644 index 00000000000..c079c472da6 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_source_control_configuration_client.py @@ -0,0 +1,94 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.mgmt.core import ARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Optional + + from azure.core.credentials import TokenCredential + from azure.core.pipeline.transport import HttpRequest, HttpResponse + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from . import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + base_url=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> None + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = ARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + + def _send_request(self, http_request, **kwargs): + # type: (HttpRequest, Any) -> HttpResponse + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.HttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + def close(self): + # type: () -> None + self._client.close() + + def __enter__(self): + # type: () -> SourceControlConfigurationClient + self._client.__enter__() + return self + + def __exit__(self, *exc_details): + # type: (Any) -> None + self._client.__exit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_version.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_version.py new file mode 100644 index 00000000000..59deb8c7263 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/_version.py @@ -0,0 +1,9 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +VERSION = "1.1.0" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/__init__.py new file mode 100644 index 00000000000..ba52c91a7ba --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +__all__ = ['SourceControlConfigurationClient'] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/_configuration.py new file mode 100644 index 00000000000..8002c1a9fbc --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/_configuration.py @@ -0,0 +1,67 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from .._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + **kwargs: Any + ) -> None: + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2020-10-01-preview" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs: Any + ) -> None: + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.AsyncBearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/_source_control_configuration_client.py new file mode 100644 index 00000000000..1e3021bd71a --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/_source_control_configuration_client.py @@ -0,0 +1,87 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Optional, TYPE_CHECKING + +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core import AsyncARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from .. import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.aio.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.aio.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + base_url: Optional[str] = None, + **kwargs: Any + ) -> None: + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = AsyncARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + + async def _send_request(self, http_request: HttpRequest, **kwargs: Any) -> AsyncHttpResponse: + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.AsyncHttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = await self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "SourceControlConfigurationClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details) -> None: + await self._client.__aexit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/operations/__init__.py similarity index 100% rename from src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/__init__.py rename to src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/operations/__init__.py diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/operations/_operations.py new file mode 100644 index 00000000000..3f70e7e1e81 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/operations/_operations.py @@ -0,0 +1,105 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class Operations: + """Operations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs: Any + ) -> AsyncIterable["_models.ResourceProviderOperationList"]: + """List all the available operations the KubernetesConfiguration resource provider supports. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-10-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..52063acf78e --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/aio/operations/_source_control_configurations_operations.py @@ -0,0 +1,420 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class SourceControlConfigurationsOperations: + """SourceControlConfigurationsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-10-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def create_or_update( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + source_control_configuration: "_models.SourceControlConfiguration", + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SourceControlConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-10-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create_or_update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def _delete_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> None: + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-10-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def begin_delete( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> AsyncLROPoller[None]: + """This will delete the YAML file used to set up the Source control configuration, thus stopping + future sync from the source repo. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.SourceControlConfigurationList"]: + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SourceControlConfigurationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-10-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('SourceControlConfigurationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/__init__.py new file mode 100644 index 00000000000..b1e23c9e1d7 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/__init__.py @@ -0,0 +1,69 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +try: + from ._models_py3 import ComplianceStatus + from ._models_py3 import ErrorDefinition + from ._models_py3 import ErrorResponse + from ._models_py3 import HelmOperatorProperties + from ._models_py3 import ProxyResource + from ._models_py3 import Resource + from ._models_py3 import ResourceProviderOperation + from ._models_py3 import ResourceProviderOperationDisplay + from ._models_py3 import ResourceProviderOperationList + from ._models_py3 import Result + from ._models_py3 import SourceControlConfiguration + from ._models_py3 import SourceControlConfigurationList + from ._models_py3 import SystemData +except (SyntaxError, ImportError): + from ._models import ComplianceStatus # type: ignore + from ._models import ErrorDefinition # type: ignore + from ._models import ErrorResponse # type: ignore + from ._models import HelmOperatorProperties # type: ignore + from ._models import ProxyResource # type: ignore + from ._models import Resource # type: ignore + from ._models import ResourceProviderOperation # type: ignore + from ._models import ResourceProviderOperationDisplay # type: ignore + from ._models import ResourceProviderOperationList # type: ignore + from ._models import Result # type: ignore + from ._models import SourceControlConfiguration # type: ignore + from ._models import SourceControlConfigurationList # type: ignore + from ._models import SystemData # type: ignore + +from ._source_control_configuration_client_enums import ( + ComplianceStateType, + Enum0, + Enum1, + MessageLevelType, + OperatorScopeType, + OperatorType, + ProvisioningStateType, +) + +__all__ = [ + 'ComplianceStatus', + 'ErrorDefinition', + 'ErrorResponse', + 'HelmOperatorProperties', + 'ProxyResource', + 'Resource', + 'ResourceProviderOperation', + 'ResourceProviderOperationDisplay', + 'ResourceProviderOperationList', + 'Result', + 'SourceControlConfiguration', + 'SourceControlConfigurationList', + 'SystemData', + 'ComplianceStateType', + 'Enum0', + 'Enum1', + 'MessageLevelType', + 'OperatorScopeType', + 'OperatorType', + 'ProvisioningStateType', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_models.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_models.py new file mode 100644 index 00000000000..12ebfd16f6d --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_models.py @@ -0,0 +1,506 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from azure.core.exceptions import HttpResponseError +import msrest.serialization + + +class ComplianceStatus(msrest.serialization.Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar compliance_state: The compliance state of the configuration. Possible values include: + "Pending", "Compliant", "Noncompliant", "Installed", "Failed". + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: ~datetime.datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: "Error", "Warning", + "Information". + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = kwargs.get('last_config_applied', None) + self.message = kwargs.get('message', None) + self.message_level = kwargs.get('message_level', None) + + +class ErrorDefinition(msrest.serialization.Model): + """Error definition. + + All required parameters must be populated in order to send to Azure. + + :param code: Required. Service specific error code which serves as the substatus for the HTTP + error code. + :type code: str + :param message: Required. Description of the error. + :type message: str + """ + + _validation = { + 'code': {'required': True}, + 'message': {'required': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorDefinition, self).__init__(**kwargs) + self.code = kwargs['code'] + self.message = kwargs['message'] + + +class ErrorResponse(msrest.serialization.Model): + """Error response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar error: Error definition. + :vartype error: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ErrorDefinition + """ + + _validation = { + 'error': {'readonly': True}, + } + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDefinition'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorResponse, self).__init__(**kwargs) + self.error = None + + +class HelmOperatorProperties(msrest.serialization.Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = kwargs.get('chart_version', None) + self.chart_values = kwargs.get('chart_values', None) + + +class Resource(msrest.serialization.Model): + """The Resource model definition. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + self.system_data = kwargs.get('system_data', None) + + +class ProxyResource(Resource): + """ARM proxy resource. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + **kwargs + ): + super(ProxyResource, self).__init__(**kwargs) + + +class ResourceProviderOperation(msrest.serialization.Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param name: Operation name, in format of {provider}/{resource}/{operation}. + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = kwargs.get('name', None) + self.display = kwargs.get('display', None) + self.is_data_action = None + + +class ResourceProviderOperationDisplay(msrest.serialization.Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = kwargs.get('provider', None) + self.resource = kwargs.get('resource', None) + self.operation = kwargs.get('operation', None) + self.description = kwargs.get('description', None) + + +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = kwargs.get('value', None) + self.next_link = None + + +class Result(msrest.serialization.Model): + """Sample result definition. + + :param sample_property: Sample property of type string. + :type sample_property: str + """ + + _attribute_map = { + 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Result, self).__init__(**kwargs) + self.sample_property = kwargs.get('sample_property', None) + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying the specific + configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: "Flux". + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl configuration + (either generated within the cluster or provided by the user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents containing public SSH keys + required to access private Git instances. + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. Possible values + include: "Accepted", "Deleting", "Running", "Succeeded", "Failed". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration. + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfiguration, self).__init__(**kwargs) + self.repository_url = kwargs.get('repository_url', None) + self.operator_namespace = kwargs.get('operator_namespace', "default") + self.operator_instance_name = kwargs.get('operator_instance_name', None) + self.operator_type = kwargs.get('operator_type', None) + self.operator_params = kwargs.get('operator_params', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.operator_scope = kwargs.get('operator_scope', "cluster") + self.repository_public_key = None + self.ssh_known_hosts_contents = kwargs.get('ssh_known_hosts_contents', None) + self.enable_helm_operator = kwargs.get('enable_helm_operator', None) + self.helm_operator_properties = kwargs.get('helm_operator_properties', None) + self.provisioning_state = None + self.compliance_status = None + + +class SourceControlConfigurationList(msrest.serialization.Model): + """Result of the request to list Source Control Configurations. It contains a list of SourceControlConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Source Control Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SourceControlConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SourceControlConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfigurationList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class SystemData(msrest.serialization.Model): + """Top level metadata https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar created_by: A string identifier for the identity that created the resource. + :vartype created_by: str + :ivar created_by_type: The type of identity that created the resource: user, application, + managedIdentity, key. + :vartype created_by_type: str + :ivar created_at: The timestamp of resource creation (UTC). + :vartype created_at: ~datetime.datetime + :ivar last_modified_by: A string identifier for the identity that last modified the resource. + :vartype last_modified_by: str + :ivar last_modified_by_type: The type of identity that last modified the resource: user, + application, managedIdentity, key. + :vartype last_modified_by_type: str + :ivar last_modified_at: The timestamp of resource last modification (UTC). + :vartype last_modified_at: ~datetime.datetime + """ + + _validation = { + 'created_by': {'readonly': True}, + 'created_by_type': {'readonly': True}, + 'created_at': {'readonly': True}, + 'last_modified_by': {'readonly': True}, + 'last_modified_by_type': {'readonly': True}, + 'last_modified_at': {'readonly': True}, + } + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__( + self, + **kwargs + ): + super(SystemData, self).__init__(**kwargs) + self.created_by = None + self.created_by_type = None + self.created_at = None + self.last_modified_by = None + self.last_modified_by_type = None + self.last_modified_at = None diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_models_py3.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_models_py3.py new file mode 100644 index 00000000000..ed2e27c2b8f --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_models_py3.py @@ -0,0 +1,549 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import datetime +from typing import Dict, List, Optional, Union + +from azure.core.exceptions import HttpResponseError +import msrest.serialization + +from ._source_control_configuration_client_enums import * + + +class ComplianceStatus(msrest.serialization.Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar compliance_state: The compliance state of the configuration. Possible values include: + "Pending", "Compliant", "Noncompliant", "Installed", "Failed". + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: ~datetime.datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: "Error", "Warning", + "Information". + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__( + self, + *, + last_config_applied: Optional[datetime.datetime] = None, + message: Optional[str] = None, + message_level: Optional[Union[str, "MessageLevelType"]] = None, + **kwargs + ): + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = last_config_applied + self.message = message + self.message_level = message_level + + +class ErrorDefinition(msrest.serialization.Model): + """Error definition. + + All required parameters must be populated in order to send to Azure. + + :param code: Required. Service specific error code which serves as the substatus for the HTTP + error code. + :type code: str + :param message: Required. Description of the error. + :type message: str + """ + + _validation = { + 'code': {'required': True}, + 'message': {'required': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + } + + def __init__( + self, + *, + code: str, + message: str, + **kwargs + ): + super(ErrorDefinition, self).__init__(**kwargs) + self.code = code + self.message = message + + +class ErrorResponse(msrest.serialization.Model): + """Error response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar error: Error definition. + :vartype error: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ErrorDefinition + """ + + _validation = { + 'error': {'readonly': True}, + } + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDefinition'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorResponse, self).__init__(**kwargs) + self.error = None + + +class HelmOperatorProperties(msrest.serialization.Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__( + self, + *, + chart_version: Optional[str] = None, + chart_values: Optional[str] = None, + **kwargs + ): + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = chart_version + self.chart_values = chart_values + + +class Resource(msrest.serialization.Model): + """The Resource model definition. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + *, + system_data: Optional["SystemData"] = None, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + self.system_data = system_data + + +class ProxyResource(Resource): + """ARM proxy resource. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + *, + system_data: Optional["SystemData"] = None, + **kwargs + ): + super(ProxyResource, self).__init__(system_data=system_data, **kwargs) + + +class ResourceProviderOperation(msrest.serialization.Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param name: Operation name, in format of {provider}/{resource}/{operation}. + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__( + self, + *, + name: Optional[str] = None, + display: Optional["ResourceProviderOperationDisplay"] = None, + **kwargs + ): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = name + self.display = display + self.is_data_action = None + + +class ResourceProviderOperationDisplay(msrest.serialization.Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__( + self, + *, + provider: Optional[str] = None, + resource: Optional[str] = None, + operation: Optional[str] = None, + description: Optional[str] = None, + **kwargs + ): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = provider + self.resource = resource + self.operation = operation + self.description = description + + +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + *, + value: Optional[List["ResourceProviderOperation"]] = None, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = value + self.next_link = None + + +class Result(msrest.serialization.Model): + """Sample result definition. + + :param sample_property: Sample property of type string. + :type sample_property: str + """ + + _attribute_map = { + 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, + } + + def __init__( + self, + *, + sample_property: Optional[str] = None, + **kwargs + ): + super(Result, self).__init__(**kwargs) + self.sample_property = sample_property + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Resource Id. + :vartype id: str + :ivar name: Resource name. + :vartype name: str + :ivar type: Resource type. + :vartype type: str + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :type system_data: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying the specific + configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: "Flux". + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl configuration + (either generated within the cluster or provided by the user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents containing public SSH keys + required to access private Git instances. + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. Possible values + include: "Accepted", "Deleting", "Running", "Succeeded", "Failed". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration. + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__( + self, + *, + system_data: Optional["SystemData"] = None, + repository_url: Optional[str] = None, + operator_namespace: Optional[str] = "default", + operator_instance_name: Optional[str] = None, + operator_type: Optional[Union[str, "OperatorType"]] = None, + operator_params: Optional[str] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + operator_scope: Optional[Union[str, "OperatorScopeType"]] = "cluster", + ssh_known_hosts_contents: Optional[str] = None, + enable_helm_operator: Optional[bool] = None, + helm_operator_properties: Optional["HelmOperatorProperties"] = None, + **kwargs + ): + super(SourceControlConfiguration, self).__init__(system_data=system_data, **kwargs) + self.repository_url = repository_url + self.operator_namespace = operator_namespace + self.operator_instance_name = operator_instance_name + self.operator_type = operator_type + self.operator_params = operator_params + self.configuration_protected_settings = configuration_protected_settings + self.operator_scope = operator_scope + self.repository_public_key = None + self.ssh_known_hosts_contents = ssh_known_hosts_contents + self.enable_helm_operator = enable_helm_operator + self.helm_operator_properties = helm_operator_properties + self.provisioning_state = None + self.compliance_status = None + + +class SourceControlConfigurationList(msrest.serialization.Model): + """Result of the request to list Source Control Configurations. It contains a list of SourceControlConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Source Control Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SourceControlConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SourceControlConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfigurationList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class SystemData(msrest.serialization.Model): + """Top level metadata https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar created_by: A string identifier for the identity that created the resource. + :vartype created_by: str + :ivar created_by_type: The type of identity that created the resource: user, application, + managedIdentity, key. + :vartype created_by_type: str + :ivar created_at: The timestamp of resource creation (UTC). + :vartype created_at: ~datetime.datetime + :ivar last_modified_by: A string identifier for the identity that last modified the resource. + :vartype last_modified_by: str + :ivar last_modified_by_type: The type of identity that last modified the resource: user, + application, managedIdentity, key. + :vartype last_modified_by_type: str + :ivar last_modified_at: The timestamp of resource last modification (UTC). + :vartype last_modified_at: ~datetime.datetime + """ + + _validation = { + 'created_by': {'readonly': True}, + 'created_by_type': {'readonly': True}, + 'created_at': {'readonly': True}, + 'last_modified_by': {'readonly': True}, + 'last_modified_by_type': {'readonly': True}, + 'last_modified_at': {'readonly': True}, + } + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__( + self, + **kwargs + ): + super(SystemData, self).__init__(**kwargs) + self.created_by = None + self.created_by_type = None + self.created_at = None + self.last_modified_by = None + self.last_modified_by_type = None + self.last_modified_at = None diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_source_control_configuration_client_enums.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_source_control_configuration_client_enums.py new file mode 100644 index 00000000000..3803d916bfd --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/models/_source_control_configuration_client_enums.py @@ -0,0 +1,78 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from enum import Enum, EnumMeta +from six import with_metaclass + +class _CaseInsensitiveEnumMeta(EnumMeta): + def __getitem__(self, name): + return super().__getitem__(name.upper()) + + def __getattr__(cls, name): + """Return the enum member matching `name` + We use __getattr__ instead of descriptors or inserting into the enum + class' __dict__ in order to support `name` and `value` being both + properties for enum members (which live in the class' __dict__) and + enum members themselves. + """ + try: + return cls._member_map_[name.upper()] + except KeyError: + raise AttributeError(name) + + +class ComplianceStateType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The compliance state of the configuration. + """ + + PENDING = "Pending" + COMPLIANT = "Compliant" + NONCOMPLIANT = "Noncompliant" + INSTALLED = "Installed" + FAILED = "Failed" + +class Enum0(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + + MICROSOFT_CONTAINER_SERVICE = "Microsoft.ContainerService" + MICROSOFT_KUBERNETES = "Microsoft.Kubernetes" + +class Enum1(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + + MANAGED_CLUSTERS = "managedClusters" + CONNECTED_CLUSTERS = "connectedClusters" + +class MessageLevelType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Level of the message. + """ + + ERROR = "Error" + WARNING = "Warning" + INFORMATION = "Information" + +class OperatorScopeType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Scope at which the operator will be installed. + """ + + CLUSTER = "cluster" + NAMESPACE = "namespace" + +class OperatorType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Type of the operator + """ + + FLUX = "Flux" + +class ProvisioningStateType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The provisioning state of the resource provider. + """ + + ACCEPTED = "Accepted" + DELETING = "Deleting" + RUNNING = "Running" + SUCCEEDED = "Succeeded" + FAILED = "Failed" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/__init__.py new file mode 100644 index 00000000000..07db19b318c --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/__init__.py @@ -0,0 +1,15 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._operations import Operations + +__all__ = [ + 'SourceControlConfigurationsOperations', + 'Operations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/_operations.py new file mode 100644 index 00000000000..09bd96085f7 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/_operations.py @@ -0,0 +1,110 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class Operations(object): + """Operations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ResourceProviderOperationList"] + """List all the available operations the KubernetesConfiguration resource provider supports. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-10-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..fa926900038 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2020_10_01_preview/operations/_source_control_configurations_operations.py @@ -0,0 +1,429 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.core.polling import LROPoller, NoPolling, PollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.arm_polling import ARMPolling + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class SourceControlConfigurationsOperations(object): + """SourceControlConfigurationsOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.SourceControlConfiguration" + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-10-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def create_or_update( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + source_control_configuration, # type: "_models.SourceControlConfiguration" + **kwargs # type: Any + ): + # type: (...) -> "_models.SourceControlConfiguration" + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SourceControlConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-10-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create_or_update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def _delete_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-10-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def begin_delete( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> LROPoller[None] + """This will delete the YAML file used to set up the Source control configuration, thus stopping + future sync from the source repo. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.SourceControlConfigurationList"] + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2020_10_01_preview.models.SourceControlConfigurationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2020-10-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('SourceControlConfigurationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/__init__.py new file mode 100644 index 00000000000..f13062376d7 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +from ._version import VERSION + +__version__ = VERSION +__all__ = ['SourceControlConfigurationClient'] + +try: + from ._patch import patch_sdk # type: ignore + patch_sdk() +except ImportError: + pass diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_configuration.py new file mode 100644 index 00000000000..645328abb1f --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_configuration.py @@ -0,0 +1,71 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from ._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + + from azure.core.credentials import TokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2021-03-01" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs # type: Any + ): + # type: (...) -> None + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.BearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_source_control_configuration_client.py new file mode 100644 index 00000000000..50b673797b5 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_source_control_configuration_client.py @@ -0,0 +1,94 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.mgmt.core import ARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Optional + + from azure.core.credentials import TokenCredential + from azure.core.pipeline.transport import HttpRequest, HttpResponse + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from . import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2021_03_01.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_03_01.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + base_url=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> None + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = ARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + + def _send_request(self, http_request, **kwargs): + # type: (HttpRequest, Any) -> HttpResponse + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.HttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + def close(self): + # type: () -> None + self._client.close() + + def __enter__(self): + # type: () -> SourceControlConfigurationClient + self._client.__enter__() + return self + + def __exit__(self, *exc_details): + # type: (Any) -> None + self._client.__exit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_version.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_version.py new file mode 100644 index 00000000000..59deb8c7263 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/_version.py @@ -0,0 +1,9 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +VERSION = "1.1.0" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/__init__.py new file mode 100644 index 00000000000..ba52c91a7ba --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +__all__ = ['SourceControlConfigurationClient'] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/_configuration.py new file mode 100644 index 00000000000..682d2762893 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/_configuration.py @@ -0,0 +1,67 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from .._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + **kwargs: Any + ) -> None: + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2021-03-01" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs: Any + ) -> None: + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.AsyncBearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/_source_control_configuration_client.py new file mode 100644 index 00000000000..2db9ca6cfeb --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/_source_control_configuration_client.py @@ -0,0 +1,87 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Optional, TYPE_CHECKING + +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core import AsyncARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from .. import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2021_03_01.aio.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_03_01.aio.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The Azure subscription ID. This is a GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000). + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + base_url: Optional[str] = None, + **kwargs: Any + ) -> None: + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = AsyncARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + + async def _send_request(self, http_request: HttpRequest, **kwargs: Any) -> AsyncHttpResponse: + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.AsyncHttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = await self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "SourceControlConfigurationClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details) -> None: + await self._client.__aexit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/__init__.py new file mode 100644 index 00000000000..07db19b318c --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/__init__.py @@ -0,0 +1,15 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._operations import Operations + +__all__ = [ + 'SourceControlConfigurationsOperations', + 'Operations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/_operations.py new file mode 100644 index 00000000000..09d8376d112 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/_operations.py @@ -0,0 +1,105 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class Operations: + """Operations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs: Any + ) -> AsyncIterable["_models.ResourceProviderOperationList"]: + """List all the available operations the KubernetesConfiguration resource provider supports. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..db8449803bd --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/aio/operations/_source_control_configurations_operations.py @@ -0,0 +1,420 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class SourceControlConfigurationsOperations: + """SourceControlConfigurationsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def create_or_update( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + source_control_configuration: "_models.SourceControlConfiguration", + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create_or_update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def _delete_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> None: + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def begin_delete( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> AsyncLROPoller[None]: + """This will delete the YAML file used to set up the Source control configuration, thus stopping + future sync from the source repo. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.SourceControlConfigurationList"]: + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_03_01.models.SourceControlConfigurationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-03-01" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('SourceControlConfigurationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/models/__init__.py similarity index 100% rename from src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/__init__.py rename to src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/models/__init__.py diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/models/_models.py similarity index 100% rename from src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models.py rename to src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/models/_models.py diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models_py3.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/models/_models_py3.py similarity index 100% rename from src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models_py3.py rename to src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/models/_models_py3.py diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_source_control_configuration_client_enums.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/models/_source_control_configuration_client_enums.py similarity index 100% rename from src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_source_control_configuration_client_enums.py rename to src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/models/_source_control_configuration_client_enums.py diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/operations/__init__.py new file mode 100644 index 00000000000..07db19b318c --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/operations/__init__.py @@ -0,0 +1,15 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._operations import Operations + +__all__ = [ + 'SourceControlConfigurationsOperations', + 'Operations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/operations/_operations.py similarity index 100% rename from src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_operations.py rename to src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/operations/_operations.py diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/operations/_source_control_configurations_operations.py similarity index 100% rename from src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_source_control_configurations_operations.py rename to src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_03_01/operations/_source_control_configurations_operations.py diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/__init__.py new file mode 100644 index 00000000000..f13062376d7 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +from ._version import VERSION + +__version__ = VERSION +__all__ = ['SourceControlConfigurationClient'] + +try: + from ._patch import patch_sdk # type: ignore + patch_sdk() +except ImportError: + pass diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_configuration.py new file mode 100644 index 00000000000..65baac1ee82 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_configuration.py @@ -0,0 +1,71 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from ._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + + from azure.core.credentials import TokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2021-05-01-preview" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs # type: Any + ): + # type: (...) -> None + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.BearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_source_control_configuration_client.py new file mode 100644 index 00000000000..9b275bd22ad --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_source_control_configuration_client.py @@ -0,0 +1,124 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.mgmt.core import ARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Optional + + from azure.core.credentials import TokenCredential + from azure.core.pipeline.transport import HttpRequest, HttpResponse + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import ExtensionsOperations +from .operations import OperationStatusOperations +from .operations import ClusterExtensionTypeOperations +from .operations import ClusterExtensionTypesOperations +from .operations import ExtensionTypeVersionsOperations +from .operations import LocationExtensionTypesOperations +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from . import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar extensions: ExtensionsOperations operations + :vartype extensions: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.operations.ExtensionsOperations + :ivar operation_status: OperationStatusOperations operations + :vartype operation_status: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.operations.OperationStatusOperations + :ivar cluster_extension_type: ClusterExtensionTypeOperations operations + :vartype cluster_extension_type: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.operations.ClusterExtensionTypeOperations + :ivar cluster_extension_types: ClusterExtensionTypesOperations operations + :vartype cluster_extension_types: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.operations.ClusterExtensionTypesOperations + :ivar extension_type_versions: ExtensionTypeVersionsOperations operations + :vartype extension_type_versions: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.operations.ExtensionTypeVersionsOperations + :ivar location_extension_types: LocationExtensionTypesOperations operations + :vartype location_extension_types: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.operations.LocationExtensionTypesOperations + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + base_url=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> None + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = ARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.extensions = ExtensionsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operation_status = OperationStatusOperations( + self._client, self._config, self._serialize, self._deserialize) + self.cluster_extension_type = ClusterExtensionTypeOperations( + self._client, self._config, self._serialize, self._deserialize) + self.cluster_extension_types = ClusterExtensionTypesOperations( + self._client, self._config, self._serialize, self._deserialize) + self.extension_type_versions = ExtensionTypeVersionsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.location_extension_types = LocationExtensionTypesOperations( + self._client, self._config, self._serialize, self._deserialize) + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + + def _send_request(self, http_request, **kwargs): + # type: (HttpRequest, Any) -> HttpResponse + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.HttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + def close(self): + # type: () -> None + self._client.close() + + def __enter__(self): + # type: () -> SourceControlConfigurationClient + self._client.__enter__() + return self + + def __exit__(self, *exc_details): + # type: (Any) -> None + self._client.__exit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_version.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_version.py new file mode 100644 index 00000000000..59deb8c7263 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/_version.py @@ -0,0 +1,9 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +VERSION = "1.1.0" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/__init__.py new file mode 100644 index 00000000000..ba52c91a7ba --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +__all__ = ['SourceControlConfigurationClient'] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/_configuration.py new file mode 100644 index 00000000000..1f07c12f646 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/_configuration.py @@ -0,0 +1,67 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from .._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + **kwargs: Any + ) -> None: + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2021-05-01-preview" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs: Any + ) -> None: + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.AsyncBearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/_source_control_configuration_client.py new file mode 100644 index 00000000000..cf79cd78669 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/_source_control_configuration_client.py @@ -0,0 +1,117 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Optional, TYPE_CHECKING + +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core import AsyncARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import ExtensionsOperations +from .operations import OperationStatusOperations +from .operations import ClusterExtensionTypeOperations +from .operations import ClusterExtensionTypesOperations +from .operations import ExtensionTypeVersionsOperations +from .operations import LocationExtensionTypesOperations +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from .. import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar extensions: ExtensionsOperations operations + :vartype extensions: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.aio.operations.ExtensionsOperations + :ivar operation_status: OperationStatusOperations operations + :vartype operation_status: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.aio.operations.OperationStatusOperations + :ivar cluster_extension_type: ClusterExtensionTypeOperations operations + :vartype cluster_extension_type: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.aio.operations.ClusterExtensionTypeOperations + :ivar cluster_extension_types: ClusterExtensionTypesOperations operations + :vartype cluster_extension_types: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.aio.operations.ClusterExtensionTypesOperations + :ivar extension_type_versions: ExtensionTypeVersionsOperations operations + :vartype extension_type_versions: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.aio.operations.ExtensionTypeVersionsOperations + :ivar location_extension_types: LocationExtensionTypesOperations operations + :vartype location_extension_types: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.aio.operations.LocationExtensionTypesOperations + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.aio.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.aio.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + base_url: Optional[str] = None, + **kwargs: Any + ) -> None: + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = AsyncARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.extensions = ExtensionsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operation_status = OperationStatusOperations( + self._client, self._config, self._serialize, self._deserialize) + self.cluster_extension_type = ClusterExtensionTypeOperations( + self._client, self._config, self._serialize, self._deserialize) + self.cluster_extension_types = ClusterExtensionTypesOperations( + self._client, self._config, self._serialize, self._deserialize) + self.extension_type_versions = ExtensionTypeVersionsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.location_extension_types = LocationExtensionTypesOperations( + self._client, self._config, self._serialize, self._deserialize) + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + + async def _send_request(self, http_request: HttpRequest, **kwargs: Any) -> AsyncHttpResponse: + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.AsyncHttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = await self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "SourceControlConfigurationClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details) -> None: + await self._client.__aexit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/__init__.py new file mode 100644 index 00000000000..5f4504b206d --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/__init__.py @@ -0,0 +1,27 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._extensions_operations import ExtensionsOperations +from ._operation_status_operations import OperationStatusOperations +from ._cluster_extension_type_operations import ClusterExtensionTypeOperations +from ._cluster_extension_types_operations import ClusterExtensionTypesOperations +from ._extension_type_versions_operations import ExtensionTypeVersionsOperations +from ._location_extension_types_operations import LocationExtensionTypesOperations +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._operations import Operations + +__all__ = [ + 'ExtensionsOperations', + 'OperationStatusOperations', + 'ClusterExtensionTypeOperations', + 'ClusterExtensionTypesOperations', + 'ExtensionTypeVersionsOperations', + 'LocationExtensionTypesOperations', + 'SourceControlConfigurationsOperations', + 'Operations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_cluster_extension_type_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_cluster_extension_type_operations.py new file mode 100644 index 00000000000..224059db330 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_cluster_extension_type_operations.py @@ -0,0 +1,114 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class ClusterExtensionTypeOperations: + """ClusterExtensionTypeOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_type: Union[str, "_models.Enum5"], + cluster_name: str, + extension_type_name: str, + **kwargs: Any + ) -> "_models.ExtensionType": + """Get Extension Type details. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_type: The Kubernetes cluster resource name - either managedClusters (for AKS + clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_type: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum5 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_type_name: Extension type name. + :type extension_type_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: ExtensionType, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionType + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionType"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterType': self._serialize.url("cluster_type", cluster_type, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionTypeName': self._serialize.url("extension_type_name", extension_type_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('ExtensionType', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterType}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensionTypes/{extensionTypeName}'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_cluster_extension_types_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_cluster_extension_types_operations.py new file mode 100644 index 00000000000..b0eaf6af2f6 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_cluster_extension_types_operations.py @@ -0,0 +1,122 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class ClusterExtensionTypesOperations: + """ClusterExtensionTypesOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.ExtensionTypeList"]: + """Get Extension Types. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionTypeList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionTypeList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionTypeList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionTypeList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/connectedClusters/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensionTypes'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_extension_type_versions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_extension_type_versions_operations.py new file mode 100644 index 00000000000..bd9f2c220fc --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_extension_type_versions_operations.py @@ -0,0 +1,117 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionTypeVersionsOperations: + """ExtensionTypeVersionsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + location: str, + extension_type_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.ExtensionVersionList"]: + """List available versions for an Extension Type. + + :param location: extension location. + :type location: str + :param extension_type_name: Extension type name. + :type extension_type_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionVersionList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionVersionList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionVersionList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'location': self._serialize.url("location", location, 'str'), + 'extensionTypeName': self._serialize.url("extension_type_name", extension_type_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionVersionList', pipeline_response) + list_of_elem = deserialized.versions + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/providers/Microsoft.KubernetesConfiguration/locations/{location}/extensionTypes/{extensionTypeName}/versions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_extensions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_extensions_operations.py new file mode 100644 index 00000000000..a09b63b3475 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_extensions_operations.py @@ -0,0 +1,495 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionsOperations: + """ExtensionsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def _create_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + extension: "_models.Extension", + **kwargs: Any + ) -> "_models.Extension": + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._create_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(extension, 'Extension') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('Extension', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _create_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def begin_create( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + extension: "_models.Extension", + **kwargs: Any + ) -> AsyncLROPoller["_models.Extension"]: + """Create a new Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param extension: Properties necessary to Create an Extension. + :type extension: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Extension + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either Extension or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Extension] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._create_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + extension=extension, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + **kwargs: Any + ) -> "_models.Extension": + """Gets Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: Extension, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Extension + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def _delete_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + force_delete: Optional[bool] = None, + **kwargs: Any + ) -> None: + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + if force_delete is not None: + query_parameters['forceDelete'] = self._serialize.query("force_delete", force_delete, 'bool') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 202, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def begin_delete( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + force_delete: Optional[bool] = None, + **kwargs: Any + ) -> AsyncLROPoller[None]: + """Delete a Kubernetes Cluster Extension. This will cause the Agent to Uninstall the extension + from the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param force_delete: Delete the extension resource in Azure - not the normal asynchronous + delete. + :type force_delete: bool + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + force_delete=force_delete, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.ExtensionsList"]: + """List all Extensions in the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionsList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionsList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionsList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionsList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_location_extension_types_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_location_extension_types_operations.py new file mode 100644 index 00000000000..f435cdfdcb5 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_location_extension_types_operations.py @@ -0,0 +1,113 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class LocationExtensionTypesOperations: + """LocationExtensionTypesOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + location: str, + **kwargs: Any + ) -> AsyncIterable["_models.ExtensionTypeList"]: + """List all Extension Types. + + :param location: extension location. + :type location: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionTypeList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionTypeList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionTypeList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'location': self._serialize.url("location", location, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionTypeList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/providers/Microsoft.KubernetesConfiguration/locations/{location}/extensionTypes'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_operation_status_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_operation_status_operations.py new file mode 100644 index 00000000000..db90f6c6660 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_operation_status_operations.py @@ -0,0 +1,204 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class OperationStatusOperations: + """OperationStatusOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.OperationStatusList"]: + """List Async Operations, currently in progress, in a cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either OperationStatusList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.OperationStatusList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('OperationStatusList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + operation_id: str, + **kwargs: Any + ) -> "_models.OperationStatusResult": + """Get Async Operation status. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param operation_id: operation Id. + :type operation_id: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: OperationStatusResult, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.OperationStatusResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusResult"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + 'operationId': self._serialize.url("operation_id", operation_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('OperationStatusResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}/operations/{operationId}'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_operations.py new file mode 100644 index 00000000000..3c82397333f --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_operations.py @@ -0,0 +1,105 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class Operations: + """Operations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs: Any + ) -> AsyncIterable["_models.ResourceProviderOperationList"]: + """List all the available operations the KubernetesConfiguration resource provider supports. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..05183fe90c1 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/aio/operations/_source_control_configurations_operations.py @@ -0,0 +1,420 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class SourceControlConfigurationsOperations: + """SourceControlConfigurationsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def create_or_update( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + source_control_configuration: "_models.SourceControlConfiguration", + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SourceControlConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create_or_update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def _delete_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> None: + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def begin_delete( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> AsyncLROPoller[None]: + """This will delete the YAML file used to set up the Source control configuration, thus stopping + future sync from the source repo. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.SourceControlConfigurationList"]: + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SourceControlConfigurationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('SourceControlConfigurationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/__init__.py new file mode 100644 index 00000000000..e97bdb99166 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/__init__.py @@ -0,0 +1,124 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +try: + from ._models_py3 import ClusterScopeSettings + from ._models_py3 import ComplianceStatus + from ._models_py3 import ErrorAdditionalInfo + from ._models_py3 import ErrorDetail + from ._models_py3 import ErrorResponse + from ._models_py3 import Extension + from ._models_py3 import ExtensionStatus + from ._models_py3 import ExtensionType + from ._models_py3 import ExtensionTypeList + from ._models_py3 import ExtensionVersionList + from ._models_py3 import ExtensionVersionListVersionsItem + from ._models_py3 import ExtensionsList + from ._models_py3 import HelmOperatorProperties + from ._models_py3 import Identity + from ._models_py3 import OperationStatusList + from ._models_py3 import OperationStatusResult + from ._models_py3 import ProxyResource + from ._models_py3 import Resource + from ._models_py3 import ResourceProviderOperation + from ._models_py3 import ResourceProviderOperationDisplay + from ._models_py3 import ResourceProviderOperationList + from ._models_py3 import Scope + from ._models_py3 import ScopeCluster + from ._models_py3 import ScopeNamespace + from ._models_py3 import SourceControlConfiguration + from ._models_py3 import SourceControlConfigurationList + from ._models_py3 import SupportedScopes + from ._models_py3 import SystemData +except (SyntaxError, ImportError): + from ._models import ClusterScopeSettings # type: ignore + from ._models import ComplianceStatus # type: ignore + from ._models import ErrorAdditionalInfo # type: ignore + from ._models import ErrorDetail # type: ignore + from ._models import ErrorResponse # type: ignore + from ._models import Extension # type: ignore + from ._models import ExtensionStatus # type: ignore + from ._models import ExtensionType # type: ignore + from ._models import ExtensionTypeList # type: ignore + from ._models import ExtensionVersionList # type: ignore + from ._models import ExtensionVersionListVersionsItem # type: ignore + from ._models import ExtensionsList # type: ignore + from ._models import HelmOperatorProperties # type: ignore + from ._models import Identity # type: ignore + from ._models import OperationStatusList # type: ignore + from ._models import OperationStatusResult # type: ignore + from ._models import ProxyResource # type: ignore + from ._models import Resource # type: ignore + from ._models import ResourceProviderOperation # type: ignore + from ._models import ResourceProviderOperationDisplay # type: ignore + from ._models import ResourceProviderOperationList # type: ignore + from ._models import Scope # type: ignore + from ._models import ScopeCluster # type: ignore + from ._models import ScopeNamespace # type: ignore + from ._models import SourceControlConfiguration # type: ignore + from ._models import SourceControlConfigurationList # type: ignore + from ._models import SupportedScopes # type: ignore + from ._models import SystemData # type: ignore + +from ._source_control_configuration_client_enums import ( + ClusterTypes, + ComplianceStateType, + CreatedByType, + Enum0, + Enum1, + Enum5, + LevelType, + MessageLevelType, + OperatorScopeType, + OperatorType, + ProvisioningState, + ProvisioningStateType, +) + +__all__ = [ + 'ClusterScopeSettings', + 'ComplianceStatus', + 'ErrorAdditionalInfo', + 'ErrorDetail', + 'ErrorResponse', + 'Extension', + 'ExtensionStatus', + 'ExtensionType', + 'ExtensionTypeList', + 'ExtensionVersionList', + 'ExtensionVersionListVersionsItem', + 'ExtensionsList', + 'HelmOperatorProperties', + 'Identity', + 'OperationStatusList', + 'OperationStatusResult', + 'ProxyResource', + 'Resource', + 'ResourceProviderOperation', + 'ResourceProviderOperationDisplay', + 'ResourceProviderOperationList', + 'Scope', + 'ScopeCluster', + 'ScopeNamespace', + 'SourceControlConfiguration', + 'SourceControlConfigurationList', + 'SupportedScopes', + 'SystemData', + 'ClusterTypes', + 'ComplianceStateType', + 'CreatedByType', + 'Enum0', + 'Enum1', + 'Enum5', + 'LevelType', + 'MessageLevelType', + 'OperatorScopeType', + 'OperatorType', + 'ProvisioningState', + 'ProvisioningStateType', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_models.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_models.py new file mode 100644 index 00000000000..9a722f97fbb --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_models.py @@ -0,0 +1,1056 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from azure.core.exceptions import HttpResponseError +import msrest.serialization + + +class Resource(msrest.serialization.Model): + """Common fields that are returned in the response for all Azure Resource Manager resources. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class ProxyResource(Resource): + """The resource model definition for a Azure Resource Manager proxy resource. It will not have tags and a location. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ProxyResource, self).__init__(**kwargs) + + +class ClusterScopeSettings(ProxyResource): + """Extension scope settings. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :param allow_multiple_instances: Describes if multiple instances of the extension are allowed. + :type allow_multiple_instances: bool + :param default_release_namespace: Default extension release namespace. + :type default_release_namespace: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'allow_multiple_instances': {'key': 'properties.allowMultipleInstances', 'type': 'bool'}, + 'default_release_namespace': {'key': 'properties.defaultReleaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ClusterScopeSettings, self).__init__(**kwargs) + self.allow_multiple_instances = kwargs.get('allow_multiple_instances', None) + self.default_release_namespace = kwargs.get('default_release_namespace', None) + + +class ComplianceStatus(msrest.serialization.Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar compliance_state: The compliance state of the configuration. Possible values include: + "Pending", "Compliant", "Noncompliant", "Installed", "Failed". + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: ~datetime.datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: "Error", "Warning", + "Information". + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = kwargs.get('last_config_applied', None) + self.message = kwargs.get('message', None) + self.message_level = kwargs.get('message_level', None) + + +class ErrorAdditionalInfo(msrest.serialization.Model): + """The resource management error additional info. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar type: The additional info type. + :vartype type: str + :ivar info: The additional info. + :vartype info: any + """ + + _validation = { + 'type': {'readonly': True}, + 'info': {'readonly': True}, + } + + _attribute_map = { + 'type': {'key': 'type', 'type': 'str'}, + 'info': {'key': 'info', 'type': 'object'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorAdditionalInfo, self).__init__(**kwargs) + self.type = None + self.info = None + + +class ErrorDetail(msrest.serialization.Model): + """The error detail. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar code: The error code. + :vartype code: str + :ivar message: The error message. + :vartype message: str + :ivar target: The error target. + :vartype target: str + :ivar details: The error details. + :vartype details: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ErrorDetail] + :ivar additional_info: The error additional info. + :vartype additional_info: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ErrorAdditionalInfo] + """ + + _validation = { + 'code': {'readonly': True}, + 'message': {'readonly': True}, + 'target': {'readonly': True}, + 'details': {'readonly': True}, + 'additional_info': {'readonly': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'target': {'key': 'target', 'type': 'str'}, + 'details': {'key': 'details', 'type': '[ErrorDetail]'}, + 'additional_info': {'key': 'additionalInfo', 'type': '[ErrorAdditionalInfo]'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorDetail, self).__init__(**kwargs) + self.code = None + self.message = None + self.target = None + self.details = None + self.additional_info = None + + +class ErrorResponse(msrest.serialization.Model): + """Common error response for all Azure Resource Manager APIs to return error details for failed operations. (This also follows the OData error response format.). + + :param error: The error object. + :type error: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ErrorDetail + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorResponse, self).__init__(**kwargs) + self.error = kwargs.get('error', None) + + +class Extension(ProxyResource): + """The Extension object. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :param identity: Identity of the Extension resource. + :type identity: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Identity + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SystemData + :param extension_type: Type of the Extension, of which this resource is an instance of. It + must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the + Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this extension participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension participates in for auto-upgrade (e.g. + Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension, if it is 'pinned' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param scope: Scope at which the extension is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this extension. + :type configuration_protected_settings: dict[str, str] + :ivar provisioning_state: Status of installation of this extension. Possible values include: + "Succeeded", "Failed", "Canceled", "Creating", "Updating", "Deleting". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ProvisioningState + :param statuses: Status from this extension. + :type statuses: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionStatus] + :ivar error_info: Error information from the Agent - e.g. errors during installation. + :vartype error_info: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ErrorDetail + :ivar custom_location_settings: Custom Location settings properties. + :vartype custom_location_settings: dict[str, str] + :ivar package_uri: Uri of the Helm package. + :vartype package_uri: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'error_info': {'readonly': True}, + 'custom_location_settings': {'readonly': True}, + 'package_uri': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'identity': {'key': 'identity', 'type': 'Identity'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDetail'}, + 'custom_location_settings': {'key': 'properties.customLocationSettings', 'type': '{str}'}, + 'package_uri': {'key': 'properties.packageUri', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Extension, self).__init__(**kwargs) + self.identity = kwargs.get('identity', None) + self.system_data = None + self.extension_type = kwargs.get('extension_type', None) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', True) + self.release_train = kwargs.get('release_train', "Stable") + self.version = kwargs.get('version', None) + self.scope = kwargs.get('scope', None) + self.configuration_settings = kwargs.get('configuration_settings', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.provisioning_state = None + self.statuses = kwargs.get('statuses', None) + self.error_info = None + self.custom_location_settings = None + self.package_uri = None + + +class ExtensionsList(msrest.serialization.Model): + """Result of the request to list Extensions. It contains a list of Extension objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Extensions within a Kubernetes cluster. + :vartype value: list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Extension] + :ivar next_link: URL to get the next set of extension objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[Extension]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionsList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class ExtensionStatus(msrest.serialization.Model): + """Status from the extension. + + :param code: Status code provided by the Extension. + :type code: str + :param display_status: Short description of status of the extension. + :type display_status: str + :param level: Level of the status. Possible values include: "Error", "Warning", "Information". + Default value: "Information". + :type level: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.LevelType + :param message: Detailed message of the status from the Extension. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionStatus, self).__init__(**kwargs) + self.code = kwargs.get('code', None) + self.display_status = kwargs.get('display_status', None) + self.level = kwargs.get('level', "Information") + self.message = kwargs.get('message', None) + self.time = kwargs.get('time', None) + + +class ExtensionType(msrest.serialization.Model): + """Represents an Extension Type. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar system_data: Metadata pertaining to creation and last modification of the resource. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SystemData + :ivar release_trains: Extension release train: preview or stable. + :vartype release_trains: list[str] + :ivar cluster_types: Cluster types. Possible values include: "connectedClusters", + "managedClusters". + :vartype cluster_types: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ClusterTypes + :ivar supported_scopes: Extension scopes. + :vartype supported_scopes: + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SupportedScopes + """ + + _validation = { + 'system_data': {'readonly': True}, + 'release_trains': {'readonly': True}, + 'cluster_types': {'readonly': True}, + 'supported_scopes': {'readonly': True}, + } + + _attribute_map = { + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'release_trains': {'key': 'properties.releaseTrains', 'type': '[str]'}, + 'cluster_types': {'key': 'properties.clusterTypes', 'type': 'str'}, + 'supported_scopes': {'key': 'properties.supportedScopes', 'type': 'SupportedScopes'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionType, self).__init__(**kwargs) + self.system_data = None + self.release_trains = None + self.cluster_types = None + self.supported_scopes = None + + +class ExtensionTypeList(msrest.serialization.Model): + """List Extension Types. + + :param value: The list of Extension Types. + :type value: list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionType] + :param next_link: The link to fetch the next page of Extension Types. + :type next_link: str + """ + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ExtensionType]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionTypeList, self).__init__(**kwargs) + self.value = kwargs.get('value', None) + self.next_link = kwargs.get('next_link', None) + + +class ExtensionVersionList(msrest.serialization.Model): + """List versions for an Extension. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param versions: Versions available for this Extension Type. + :type versions: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionVersionListVersionsItem] + :param next_link: The link to fetch the next page of Extension Types. + :type next_link: str + :ivar system_data: Metadata pertaining to creation and last modification of the resource. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SystemData + """ + + _validation = { + 'system_data': {'readonly': True}, + } + + _attribute_map = { + 'versions': {'key': 'versions', 'type': '[ExtensionVersionListVersionsItem]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionVersionList, self).__init__(**kwargs) + self.versions = kwargs.get('versions', None) + self.next_link = kwargs.get('next_link', None) + self.system_data = None + + +class ExtensionVersionListVersionsItem(msrest.serialization.Model): + """ExtensionVersionListVersionsItem. + + :param release_train: The release train for this Extension Type. + :type release_train: str + :param versions: Versions available for this Extension Type and release train. + :type versions: list[str] + """ + + _attribute_map = { + 'release_train': {'key': 'releaseTrain', 'type': 'str'}, + 'versions': {'key': 'versions', 'type': '[str]'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionVersionListVersionsItem, self).__init__(**kwargs) + self.release_train = kwargs.get('release_train', None) + self.versions = kwargs.get('versions', None) + + +class HelmOperatorProperties(msrest.serialization.Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = kwargs.get('chart_version', None) + self.chart_values = kwargs.get('chart_values', None) + + +class Identity(msrest.serialization.Model): + """Identity for the resource. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal ID of resource identity. + :vartype principal_id: str + :ivar tenant_id: The tenant ID of resource. + :vartype tenant_id: str + :param type: The identity type. The only acceptable values to pass in are None and + "SystemAssigned". The default value is None. + :type type: str + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Identity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = kwargs.get('type', None) + + +class OperationStatusList(msrest.serialization.Model): + """The async operations in progress, in the cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of async operations in progress, in the cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.OperationStatusResult] + :ivar next_link: URL to get the next set of Operation Result objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[OperationStatusResult]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(OperationStatusList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class OperationStatusResult(msrest.serialization.Model): + """The current status of an async operation. + + Variables are only populated by the server, and will be ignored when sending a request. + + All required parameters must be populated in order to send to Azure. + + :param id: Fully qualified ID for the async operation. + :type id: str + :param name: Name of the async operation. + :type name: str + :param status: Required. Operation status. + :type status: str + :param properties: Additional information, if available. + :type properties: dict[str, str] + :ivar error: If present, details of the operation error. + :vartype error: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ErrorDetail + """ + + _validation = { + 'status': {'required': True}, + 'error': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'status': {'key': 'status', 'type': 'str'}, + 'properties': {'key': 'properties', 'type': '{str}'}, + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + **kwargs + ): + super(OperationStatusResult, self).__init__(**kwargs) + self.id = kwargs.get('id', None) + self.name = kwargs.get('name', None) + self.status = kwargs['status'] + self.properties = kwargs.get('properties', None) + self.error = None + + +class ResourceProviderOperation(msrest.serialization.Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param name: Operation name, in format of {provider}/{resource}/{operation}. + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ResourceProviderOperationDisplay + :param origin: The intended executor of the operation;governs the display of the operation in + the RBAC UX and the audit logs UX. + :type origin: str + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'origin': {'key': 'origin', 'type': 'str'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = kwargs.get('name', None) + self.display = kwargs.get('display', None) + self.origin = kwargs.get('origin', None) + self.is_data_action = None + + +class ResourceProviderOperationDisplay(msrest.serialization.Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = kwargs.get('provider', None) + self.resource = kwargs.get('resource', None) + self.operation = kwargs.get('operation', None) + self.description = kwargs.get('description', None) + + +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = kwargs.get('value', None) + self.next_link = None + + +class Scope(msrest.serialization.Model): + """Scope of the extension. It can be either Cluster or Namespace; but not both. + + :param cluster: Specifies that the scope of the extension is Cluster. + :type cluster: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ScopeCluster + :param namespace: Specifies that the scope of the extension is Namespace. + :type namespace: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__( + self, + **kwargs + ): + super(Scope, self).__init__(**kwargs) + self.cluster = kwargs.get('cluster', None) + self.namespace = kwargs.get('namespace', None) + + +class ScopeCluster(msrest.serialization.Model): + """Specifies that the scope of the extension is Cluster. + + :param release_namespace: Namespace where the extension Release must be placed, for a Cluster + scoped extension. If this namespace does not exist, it will be created. + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = kwargs.get('release_namespace', None) + + +class ScopeNamespace(msrest.serialization.Model): + """Specifies that the scope of the extension is Namespace. + + :param target_namespace: Namespace where the extension will be created for an Namespace scoped + extension. If this namespace does not exist, it will be created. + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = kwargs.get('target_namespace', None) + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying the specific + configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: "Flux". + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl configuration + (either generated within the cluster or provided by the user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents containing public SSH keys + required to access private Git instances. + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. Possible values + include: "Accepted", "Deleting", "Running", "Succeeded", "Failed". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration. + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfiguration, self).__init__(**kwargs) + self.system_data = None + self.repository_url = kwargs.get('repository_url', None) + self.operator_namespace = kwargs.get('operator_namespace', "default") + self.operator_instance_name = kwargs.get('operator_instance_name', None) + self.operator_type = kwargs.get('operator_type', None) + self.operator_params = kwargs.get('operator_params', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.operator_scope = kwargs.get('operator_scope', "cluster") + self.repository_public_key = None + self.ssh_known_hosts_contents = kwargs.get('ssh_known_hosts_contents', None) + self.enable_helm_operator = kwargs.get('enable_helm_operator', None) + self.helm_operator_properties = kwargs.get('helm_operator_properties', None) + self.provisioning_state = None + self.compliance_status = None + + +class SourceControlConfigurationList(msrest.serialization.Model): + """Result of the request to list Source Control Configurations. It contains a list of SourceControlConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Source Control Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SourceControlConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SourceControlConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfigurationList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class SupportedScopes(msrest.serialization.Model): + """Extension scopes. + + :param default_scope: Default extension scopes: cluster or namespace. + :type default_scope: str + :param cluster_scope_settings: Scope settings. + :type cluster_scope_settings: + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ClusterScopeSettings + """ + + _attribute_map = { + 'default_scope': {'key': 'defaultScope', 'type': 'str'}, + 'cluster_scope_settings': {'key': 'clusterScopeSettings', 'type': 'ClusterScopeSettings'}, + } + + def __init__( + self, + **kwargs + ): + super(SupportedScopes, self).__init__(**kwargs) + self.default_scope = kwargs.get('default_scope', None) + self.cluster_scope_settings = kwargs.get('cluster_scope_settings', None) + + +class SystemData(msrest.serialization.Model): + """Metadata pertaining to creation and last modification of the resource. + + :param created_by: The identity that created the resource. + :type created_by: str + :param created_by_type: The type of identity that created the resource. Possible values + include: "User", "Application", "ManagedIdentity", "Key". + :type created_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.CreatedByType + :param created_at: The timestamp of resource creation (UTC). + :type created_at: ~datetime.datetime + :param last_modified_by: The identity that last modified the resource. + :type last_modified_by: str + :param last_modified_by_type: The type of identity that last modified the resource. Possible + values include: "User", "Application", "ManagedIdentity", "Key". + :type last_modified_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.CreatedByType + :param last_modified_at: The timestamp of resource last modification (UTC). + :type last_modified_at: ~datetime.datetime + """ + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__( + self, + **kwargs + ): + super(SystemData, self).__init__(**kwargs) + self.created_by = kwargs.get('created_by', None) + self.created_by_type = kwargs.get('created_by_type', None) + self.created_at = kwargs.get('created_at', None) + self.last_modified_by = kwargs.get('last_modified_by', None) + self.last_modified_by_type = kwargs.get('last_modified_by_type', None) + self.last_modified_at = kwargs.get('last_modified_at', None) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_models_py3.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_models_py3.py new file mode 100644 index 00000000000..50ef8c899cd --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_models_py3.py @@ -0,0 +1,1144 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import datetime +from typing import Dict, List, Optional, Union + +from azure.core.exceptions import HttpResponseError +import msrest.serialization + +from ._source_control_configuration_client_enums import * + + +class Resource(msrest.serialization.Model): + """Common fields that are returned in the response for all Azure Resource Manager resources. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class ProxyResource(Resource): + """The resource model definition for a Azure Resource Manager proxy resource. It will not have tags and a location. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ProxyResource, self).__init__(**kwargs) + + +class ClusterScopeSettings(ProxyResource): + """Extension scope settings. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :param allow_multiple_instances: Describes if multiple instances of the extension are allowed. + :type allow_multiple_instances: bool + :param default_release_namespace: Default extension release namespace. + :type default_release_namespace: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'allow_multiple_instances': {'key': 'properties.allowMultipleInstances', 'type': 'bool'}, + 'default_release_namespace': {'key': 'properties.defaultReleaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + *, + allow_multiple_instances: Optional[bool] = None, + default_release_namespace: Optional[str] = None, + **kwargs + ): + super(ClusterScopeSettings, self).__init__(**kwargs) + self.allow_multiple_instances = allow_multiple_instances + self.default_release_namespace = default_release_namespace + + +class ComplianceStatus(msrest.serialization.Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar compliance_state: The compliance state of the configuration. Possible values include: + "Pending", "Compliant", "Noncompliant", "Installed", "Failed". + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: ~datetime.datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: "Error", "Warning", + "Information". + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__( + self, + *, + last_config_applied: Optional[datetime.datetime] = None, + message: Optional[str] = None, + message_level: Optional[Union[str, "MessageLevelType"]] = None, + **kwargs + ): + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = last_config_applied + self.message = message + self.message_level = message_level + + +class ErrorAdditionalInfo(msrest.serialization.Model): + """The resource management error additional info. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar type: The additional info type. + :vartype type: str + :ivar info: The additional info. + :vartype info: any + """ + + _validation = { + 'type': {'readonly': True}, + 'info': {'readonly': True}, + } + + _attribute_map = { + 'type': {'key': 'type', 'type': 'str'}, + 'info': {'key': 'info', 'type': 'object'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorAdditionalInfo, self).__init__(**kwargs) + self.type = None + self.info = None + + +class ErrorDetail(msrest.serialization.Model): + """The error detail. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar code: The error code. + :vartype code: str + :ivar message: The error message. + :vartype message: str + :ivar target: The error target. + :vartype target: str + :ivar details: The error details. + :vartype details: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ErrorDetail] + :ivar additional_info: The error additional info. + :vartype additional_info: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ErrorAdditionalInfo] + """ + + _validation = { + 'code': {'readonly': True}, + 'message': {'readonly': True}, + 'target': {'readonly': True}, + 'details': {'readonly': True}, + 'additional_info': {'readonly': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'target': {'key': 'target', 'type': 'str'}, + 'details': {'key': 'details', 'type': '[ErrorDetail]'}, + 'additional_info': {'key': 'additionalInfo', 'type': '[ErrorAdditionalInfo]'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorDetail, self).__init__(**kwargs) + self.code = None + self.message = None + self.target = None + self.details = None + self.additional_info = None + + +class ErrorResponse(msrest.serialization.Model): + """Common error response for all Azure Resource Manager APIs to return error details for failed operations. (This also follows the OData error response format.). + + :param error: The error object. + :type error: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ErrorDetail + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + *, + error: Optional["ErrorDetail"] = None, + **kwargs + ): + super(ErrorResponse, self).__init__(**kwargs) + self.error = error + + +class Extension(ProxyResource): + """The Extension object. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :param identity: Identity of the Extension resource. + :type identity: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Identity + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SystemData + :param extension_type: Type of the Extension, of which this resource is an instance of. It + must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the + Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this extension participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension participates in for auto-upgrade (e.g. + Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension, if it is 'pinned' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param scope: Scope at which the extension is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this extension. + :type configuration_protected_settings: dict[str, str] + :ivar provisioning_state: Status of installation of this extension. Possible values include: + "Succeeded", "Failed", "Canceled", "Creating", "Updating", "Deleting". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ProvisioningState + :param statuses: Status from this extension. + :type statuses: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionStatus] + :ivar error_info: Error information from the Agent - e.g. errors during installation. + :vartype error_info: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ErrorDetail + :ivar custom_location_settings: Custom Location settings properties. + :vartype custom_location_settings: dict[str, str] + :ivar package_uri: Uri of the Helm package. + :vartype package_uri: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'error_info': {'readonly': True}, + 'custom_location_settings': {'readonly': True}, + 'package_uri': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'identity': {'key': 'identity', 'type': 'Identity'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDetail'}, + 'custom_location_settings': {'key': 'properties.customLocationSettings', 'type': '{str}'}, + 'package_uri': {'key': 'properties.packageUri', 'type': 'str'}, + } + + def __init__( + self, + *, + identity: Optional["Identity"] = None, + extension_type: Optional[str] = None, + auto_upgrade_minor_version: Optional[bool] = True, + release_train: Optional[str] = "Stable", + version: Optional[str] = None, + scope: Optional["Scope"] = None, + configuration_settings: Optional[Dict[str, str]] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + statuses: Optional[List["ExtensionStatus"]] = None, + **kwargs + ): + super(Extension, self).__init__(**kwargs) + self.identity = identity + self.system_data = None + self.extension_type = extension_type + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + self.scope = scope + self.configuration_settings = configuration_settings + self.configuration_protected_settings = configuration_protected_settings + self.provisioning_state = None + self.statuses = statuses + self.error_info = None + self.custom_location_settings = None + self.package_uri = None + + +class ExtensionsList(msrest.serialization.Model): + """Result of the request to list Extensions. It contains a list of Extension objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Extensions within a Kubernetes cluster. + :vartype value: list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Extension] + :ivar next_link: URL to get the next set of extension objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[Extension]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionsList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class ExtensionStatus(msrest.serialization.Model): + """Status from the extension. + + :param code: Status code provided by the Extension. + :type code: str + :param display_status: Short description of status of the extension. + :type display_status: str + :param level: Level of the status. Possible values include: "Error", "Warning", "Information". + Default value: "Information". + :type level: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.LevelType + :param message: Detailed message of the status from the Extension. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__( + self, + *, + code: Optional[str] = None, + display_status: Optional[str] = None, + level: Optional[Union[str, "LevelType"]] = "Information", + message: Optional[str] = None, + time: Optional[str] = None, + **kwargs + ): + super(ExtensionStatus, self).__init__(**kwargs) + self.code = code + self.display_status = display_status + self.level = level + self.message = message + self.time = time + + +class ExtensionType(msrest.serialization.Model): + """Represents an Extension Type. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar system_data: Metadata pertaining to creation and last modification of the resource. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SystemData + :ivar release_trains: Extension release train: preview or stable. + :vartype release_trains: list[str] + :ivar cluster_types: Cluster types. Possible values include: "connectedClusters", + "managedClusters". + :vartype cluster_types: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ClusterTypes + :ivar supported_scopes: Extension scopes. + :vartype supported_scopes: + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SupportedScopes + """ + + _validation = { + 'system_data': {'readonly': True}, + 'release_trains': {'readonly': True}, + 'cluster_types': {'readonly': True}, + 'supported_scopes': {'readonly': True}, + } + + _attribute_map = { + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'release_trains': {'key': 'properties.releaseTrains', 'type': '[str]'}, + 'cluster_types': {'key': 'properties.clusterTypes', 'type': 'str'}, + 'supported_scopes': {'key': 'properties.supportedScopes', 'type': 'SupportedScopes'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionType, self).__init__(**kwargs) + self.system_data = None + self.release_trains = None + self.cluster_types = None + self.supported_scopes = None + + +class ExtensionTypeList(msrest.serialization.Model): + """List Extension Types. + + :param value: The list of Extension Types. + :type value: list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionType] + :param next_link: The link to fetch the next page of Extension Types. + :type next_link: str + """ + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ExtensionType]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + *, + value: Optional[List["ExtensionType"]] = None, + next_link: Optional[str] = None, + **kwargs + ): + super(ExtensionTypeList, self).__init__(**kwargs) + self.value = value + self.next_link = next_link + + +class ExtensionVersionList(msrest.serialization.Model): + """List versions for an Extension. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param versions: Versions available for this Extension Type. + :type versions: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionVersionListVersionsItem] + :param next_link: The link to fetch the next page of Extension Types. + :type next_link: str + :ivar system_data: Metadata pertaining to creation and last modification of the resource. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SystemData + """ + + _validation = { + 'system_data': {'readonly': True}, + } + + _attribute_map = { + 'versions': {'key': 'versions', 'type': '[ExtensionVersionListVersionsItem]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + *, + versions: Optional[List["ExtensionVersionListVersionsItem"]] = None, + next_link: Optional[str] = None, + **kwargs + ): + super(ExtensionVersionList, self).__init__(**kwargs) + self.versions = versions + self.next_link = next_link + self.system_data = None + + +class ExtensionVersionListVersionsItem(msrest.serialization.Model): + """ExtensionVersionListVersionsItem. + + :param release_train: The release train for this Extension Type. + :type release_train: str + :param versions: Versions available for this Extension Type and release train. + :type versions: list[str] + """ + + _attribute_map = { + 'release_train': {'key': 'releaseTrain', 'type': 'str'}, + 'versions': {'key': 'versions', 'type': '[str]'}, + } + + def __init__( + self, + *, + release_train: Optional[str] = None, + versions: Optional[List[str]] = None, + **kwargs + ): + super(ExtensionVersionListVersionsItem, self).__init__(**kwargs) + self.release_train = release_train + self.versions = versions + + +class HelmOperatorProperties(msrest.serialization.Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__( + self, + *, + chart_version: Optional[str] = None, + chart_values: Optional[str] = None, + **kwargs + ): + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = chart_version + self.chart_values = chart_values + + +class Identity(msrest.serialization.Model): + """Identity for the resource. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal ID of resource identity. + :vartype principal_id: str + :ivar tenant_id: The tenant ID of resource. + :vartype tenant_id: str + :param type: The identity type. The only acceptable values to pass in are None and + "SystemAssigned". The default value is None. + :type type: str + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + *, + type: Optional[str] = None, + **kwargs + ): + super(Identity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = type + + +class OperationStatusList(msrest.serialization.Model): + """The async operations in progress, in the cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of async operations in progress, in the cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.OperationStatusResult] + :ivar next_link: URL to get the next set of Operation Result objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[OperationStatusResult]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(OperationStatusList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class OperationStatusResult(msrest.serialization.Model): + """The current status of an async operation. + + Variables are only populated by the server, and will be ignored when sending a request. + + All required parameters must be populated in order to send to Azure. + + :param id: Fully qualified ID for the async operation. + :type id: str + :param name: Name of the async operation. + :type name: str + :param status: Required. Operation status. + :type status: str + :param properties: Additional information, if available. + :type properties: dict[str, str] + :ivar error: If present, details of the operation error. + :vartype error: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ErrorDetail + """ + + _validation = { + 'status': {'required': True}, + 'error': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'status': {'key': 'status', 'type': 'str'}, + 'properties': {'key': 'properties', 'type': '{str}'}, + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + *, + status: str, + id: Optional[str] = None, + name: Optional[str] = None, + properties: Optional[Dict[str, str]] = None, + **kwargs + ): + super(OperationStatusResult, self).__init__(**kwargs) + self.id = id + self.name = name + self.status = status + self.properties = properties + self.error = None + + +class ResourceProviderOperation(msrest.serialization.Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param name: Operation name, in format of {provider}/{resource}/{operation}. + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ResourceProviderOperationDisplay + :param origin: The intended executor of the operation;governs the display of the operation in + the RBAC UX and the audit logs UX. + :type origin: str + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'origin': {'key': 'origin', 'type': 'str'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__( + self, + *, + name: Optional[str] = None, + display: Optional["ResourceProviderOperationDisplay"] = None, + origin: Optional[str] = None, + **kwargs + ): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = name + self.display = display + self.origin = origin + self.is_data_action = None + + +class ResourceProviderOperationDisplay(msrest.serialization.Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__( + self, + *, + provider: Optional[str] = None, + resource: Optional[str] = None, + operation: Optional[str] = None, + description: Optional[str] = None, + **kwargs + ): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = provider + self.resource = resource + self.operation = operation + self.description = description + + +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + *, + value: Optional[List["ResourceProviderOperation"]] = None, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = value + self.next_link = None + + +class Scope(msrest.serialization.Model): + """Scope of the extension. It can be either Cluster or Namespace; but not both. + + :param cluster: Specifies that the scope of the extension is Cluster. + :type cluster: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ScopeCluster + :param namespace: Specifies that the scope of the extension is Namespace. + :type namespace: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__( + self, + *, + cluster: Optional["ScopeCluster"] = None, + namespace: Optional["ScopeNamespace"] = None, + **kwargs + ): + super(Scope, self).__init__(**kwargs) + self.cluster = cluster + self.namespace = namespace + + +class ScopeCluster(msrest.serialization.Model): + """Specifies that the scope of the extension is Cluster. + + :param release_namespace: Namespace where the extension Release must be placed, for a Cluster + scoped extension. If this namespace does not exist, it will be created. + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + *, + release_namespace: Optional[str] = None, + **kwargs + ): + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = release_namespace + + +class ScopeNamespace(msrest.serialization.Model): + """Specifies that the scope of the extension is Namespace. + + :param target_namespace: Namespace where the extension will be created for an Namespace scoped + extension. If this namespace does not exist, it will be created. + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__( + self, + *, + target_namespace: Optional[str] = None, + **kwargs + ): + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = target_namespace + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying the specific + configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: "Flux". + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl configuration + (either generated within the cluster or provided by the user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents containing public SSH keys + required to access private Git instances. + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. Possible values + include: "Accepted", "Deleting", "Running", "Succeeded", "Failed". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration. + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__( + self, + *, + repository_url: Optional[str] = None, + operator_namespace: Optional[str] = "default", + operator_instance_name: Optional[str] = None, + operator_type: Optional[Union[str, "OperatorType"]] = None, + operator_params: Optional[str] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + operator_scope: Optional[Union[str, "OperatorScopeType"]] = "cluster", + ssh_known_hosts_contents: Optional[str] = None, + enable_helm_operator: Optional[bool] = None, + helm_operator_properties: Optional["HelmOperatorProperties"] = None, + **kwargs + ): + super(SourceControlConfiguration, self).__init__(**kwargs) + self.system_data = None + self.repository_url = repository_url + self.operator_namespace = operator_namespace + self.operator_instance_name = operator_instance_name + self.operator_type = operator_type + self.operator_params = operator_params + self.configuration_protected_settings = configuration_protected_settings + self.operator_scope = operator_scope + self.repository_public_key = None + self.ssh_known_hosts_contents = ssh_known_hosts_contents + self.enable_helm_operator = enable_helm_operator + self.helm_operator_properties = helm_operator_properties + self.provisioning_state = None + self.compliance_status = None + + +class SourceControlConfigurationList(msrest.serialization.Model): + """Result of the request to list Source Control Configurations. It contains a list of SourceControlConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Source Control Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SourceControlConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SourceControlConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfigurationList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class SupportedScopes(msrest.serialization.Model): + """Extension scopes. + + :param default_scope: Default extension scopes: cluster or namespace. + :type default_scope: str + :param cluster_scope_settings: Scope settings. + :type cluster_scope_settings: + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ClusterScopeSettings + """ + + _attribute_map = { + 'default_scope': {'key': 'defaultScope', 'type': 'str'}, + 'cluster_scope_settings': {'key': 'clusterScopeSettings', 'type': 'ClusterScopeSettings'}, + } + + def __init__( + self, + *, + default_scope: Optional[str] = None, + cluster_scope_settings: Optional["ClusterScopeSettings"] = None, + **kwargs + ): + super(SupportedScopes, self).__init__(**kwargs) + self.default_scope = default_scope + self.cluster_scope_settings = cluster_scope_settings + + +class SystemData(msrest.serialization.Model): + """Metadata pertaining to creation and last modification of the resource. + + :param created_by: The identity that created the resource. + :type created_by: str + :param created_by_type: The type of identity that created the resource. Possible values + include: "User", "Application", "ManagedIdentity", "Key". + :type created_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.CreatedByType + :param created_at: The timestamp of resource creation (UTC). + :type created_at: ~datetime.datetime + :param last_modified_by: The identity that last modified the resource. + :type last_modified_by: str + :param last_modified_by_type: The type of identity that last modified the resource. Possible + values include: "User", "Application", "ManagedIdentity", "Key". + :type last_modified_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.CreatedByType + :param last_modified_at: The timestamp of resource last modification (UTC). + :type last_modified_at: ~datetime.datetime + """ + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__( + self, + *, + created_by: Optional[str] = None, + created_by_type: Optional[Union[str, "CreatedByType"]] = None, + created_at: Optional[datetime.datetime] = None, + last_modified_by: Optional[str] = None, + last_modified_by_type: Optional[Union[str, "CreatedByType"]] = None, + last_modified_at: Optional[datetime.datetime] = None, + **kwargs + ): + super(SystemData, self).__init__(**kwargs) + self.created_by = created_by + self.created_by_type = created_by_type + self.created_at = created_at + self.last_modified_by = last_modified_by + self.last_modified_by_type = last_modified_by_type + self.last_modified_at = last_modified_at diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_source_control_configuration_client_enums.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_source_control_configuration_client_enums.py new file mode 100644 index 00000000000..d25cb04abdc --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/models/_source_control_configuration_client_enums.py @@ -0,0 +1,118 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from enum import Enum, EnumMeta +from six import with_metaclass + +class _CaseInsensitiveEnumMeta(EnumMeta): + def __getitem__(self, name): + return super().__getitem__(name.upper()) + + def __getattr__(cls, name): + """Return the enum member matching `name` + We use __getattr__ instead of descriptors or inserting into the enum + class' __dict__ in order to support `name` and `value` being both + properties for enum members (which live in the class' __dict__) and + enum members themselves. + """ + try: + return cls._member_map_[name.upper()] + except KeyError: + raise AttributeError(name) + + +class ClusterTypes(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Cluster types + """ + + CONNECTED_CLUSTERS = "connectedClusters" + MANAGED_CLUSTERS = "managedClusters" + +class ComplianceStateType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The compliance state of the configuration. + """ + + PENDING = "Pending" + COMPLIANT = "Compliant" + NONCOMPLIANT = "Noncompliant" + INSTALLED = "Installed" + FAILED = "Failed" + +class CreatedByType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The type of identity that created the resource. + """ + + USER = "User" + APPLICATION = "Application" + MANAGED_IDENTITY = "ManagedIdentity" + KEY = "Key" + +class Enum0(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + + MICROSOFT_CONTAINER_SERVICE = "Microsoft.ContainerService" + MICROSOFT_KUBERNETES = "Microsoft.Kubernetes" + +class Enum1(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + + MANAGED_CLUSTERS = "managedClusters" + CONNECTED_CLUSTERS = "connectedClusters" + +class Enum5(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + + MANAGED_CLUSTERS = "managedClusters" + CONNECTED_CLUSTERS = "connectedClusters" + +class LevelType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Level of the status. + """ + + ERROR = "Error" + WARNING = "Warning" + INFORMATION = "Information" + +class MessageLevelType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Level of the message. + """ + + ERROR = "Error" + WARNING = "Warning" + INFORMATION = "Information" + +class OperatorScopeType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Scope at which the operator will be installed. + """ + + CLUSTER = "cluster" + NAMESPACE = "namespace" + +class OperatorType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Type of the operator + """ + + FLUX = "Flux" + +class ProvisioningState(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The provisioning state of the extension resource. + """ + + SUCCEEDED = "Succeeded" + FAILED = "Failed" + CANCELED = "Canceled" + CREATING = "Creating" + UPDATING = "Updating" + DELETING = "Deleting" + +class ProvisioningStateType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The provisioning state of the resource provider. + """ + + ACCEPTED = "Accepted" + DELETING = "Deleting" + RUNNING = "Running" + SUCCEEDED = "Succeeded" + FAILED = "Failed" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/__init__.py new file mode 100644 index 00000000000..5f4504b206d --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/__init__.py @@ -0,0 +1,27 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._extensions_operations import ExtensionsOperations +from ._operation_status_operations import OperationStatusOperations +from ._cluster_extension_type_operations import ClusterExtensionTypeOperations +from ._cluster_extension_types_operations import ClusterExtensionTypesOperations +from ._extension_type_versions_operations import ExtensionTypeVersionsOperations +from ._location_extension_types_operations import LocationExtensionTypesOperations +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._operations import Operations + +__all__ = [ + 'ExtensionsOperations', + 'OperationStatusOperations', + 'ClusterExtensionTypeOperations', + 'ClusterExtensionTypesOperations', + 'ExtensionTypeVersionsOperations', + 'LocationExtensionTypesOperations', + 'SourceControlConfigurationsOperations', + 'Operations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_cluster_extension_type_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_cluster_extension_type_operations.py new file mode 100644 index 00000000000..f845b5d719a --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_cluster_extension_type_operations.py @@ -0,0 +1,119 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class ClusterExtensionTypeOperations(object): + """ClusterExtensionTypeOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_type, # type: Union[str, "_models.Enum5"] + cluster_name, # type: str + extension_type_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.ExtensionType" + """Get Extension Type details. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_type: The Kubernetes cluster resource name - either managedClusters (for AKS + clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_type: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum5 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_type_name: Extension type name. + :type extension_type_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: ExtensionType, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionType + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionType"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterType': self._serialize.url("cluster_type", cluster_type, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionTypeName': self._serialize.url("extension_type_name", extension_type_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('ExtensionType', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterType}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensionTypes/{extensionTypeName}'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_cluster_extension_types_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_cluster_extension_types_operations.py new file mode 100644 index 00000000000..2991257b530 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_cluster_extension_types_operations.py @@ -0,0 +1,127 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class ClusterExtensionTypesOperations(object): + """ClusterExtensionTypesOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ExtensionTypeList"] + """Get Extension Types. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionTypeList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionTypeList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionTypeList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionTypeList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/connectedClusters/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensionTypes'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_extension_type_versions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_extension_type_versions_operations.py new file mode 100644 index 00000000000..bca368e1670 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_extension_type_versions_operations.py @@ -0,0 +1,122 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionTypeVersionsOperations(object): + """ExtensionTypeVersionsOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + location, # type: str + extension_type_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ExtensionVersionList"] + """List available versions for an Extension Type. + + :param location: extension location. + :type location: str + :param extension_type_name: Extension type name. + :type extension_type_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionVersionList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionVersionList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionVersionList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'location': self._serialize.url("location", location, 'str'), + 'extensionTypeName': self._serialize.url("extension_type_name", extension_type_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionVersionList', pipeline_response) + list_of_elem = deserialized.versions + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/providers/Microsoft.KubernetesConfiguration/locations/{location}/extensionTypes/{extensionTypeName}/versions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_extensions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_extensions_operations.py new file mode 100644 index 00000000000..580a564a7cb --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_extensions_operations.py @@ -0,0 +1,505 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.core.polling import LROPoller, NoPolling, PollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.arm_polling import ARMPolling + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionsOperations(object): + """ExtensionsOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def _create_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + extension, # type: "_models.Extension" + **kwargs # type: Any + ): + # type: (...) -> "_models.Extension" + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._create_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(extension, 'Extension') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('Extension', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _create_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def begin_create( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + extension, # type: "_models.Extension" + **kwargs # type: Any + ): + # type: (...) -> LROPoller["_models.Extension"] + """Create a new Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param extension: Properties necessary to Create an Extension. + :type extension: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Extension + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either Extension or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Extension] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._create_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + extension=extension, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.Extension" + """Gets Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: Extension, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Extension + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def _delete_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + force_delete=None, # type: Optional[bool] + **kwargs # type: Any + ): + # type: (...) -> None + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + if force_delete is not None: + query_parameters['forceDelete'] = self._serialize.query("force_delete", force_delete, 'bool') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 202, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def begin_delete( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + force_delete=None, # type: Optional[bool] + **kwargs # type: Any + ): + # type: (...) -> LROPoller[None] + """Delete a Kubernetes Cluster Extension. This will cause the Agent to Uninstall the extension + from the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param force_delete: Delete the extension resource in Azure - not the normal asynchronous + delete. + :type force_delete: bool + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + force_delete=force_delete, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ExtensionsList"] + """List all Extensions in the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionsList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionsList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionsList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionsList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_location_extension_types_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_location_extension_types_operations.py new file mode 100644 index 00000000000..15282cd28e0 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_location_extension_types_operations.py @@ -0,0 +1,118 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class LocationExtensionTypesOperations(object): + """LocationExtensionTypesOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + location, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ExtensionTypeList"] + """List all Extension Types. + + :param location: extension location. + :type location: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionTypeList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ExtensionTypeList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionTypeList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'location': self._serialize.url("location", location, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionTypeList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/providers/Microsoft.KubernetesConfiguration/locations/{location}/extensionTypes'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_operation_status_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_operation_status_operations.py new file mode 100644 index 00000000000..46f3330b729 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_operation_status_operations.py @@ -0,0 +1,210 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class OperationStatusOperations(object): + """OperationStatusOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.OperationStatusList"] + """List Async Operations, currently in progress, in a cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either OperationStatusList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.OperationStatusList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('OperationStatusList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + operation_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.OperationStatusResult" + """Get Async Operation status. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param operation_id: operation Id. + :type operation_id: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: OperationStatusResult, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.OperationStatusResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusResult"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + 'operationId': self._serialize.url("operation_id", operation_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('OperationStatusResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}/operations/{operationId}'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_operations.py new file mode 100644 index 00000000000..147a262ef47 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_operations.py @@ -0,0 +1,110 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class Operations(object): + """Operations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ResourceProviderOperationList"] + """List all the available operations the KubernetesConfiguration resource provider supports. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..0a71453758b --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_05_01_preview/operations/_source_control_configurations_operations.py @@ -0,0 +1,429 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.core.polling import LROPoller, NoPolling, PollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.arm_polling import ARMPolling + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class SourceControlConfigurationsOperations(object): + """SourceControlConfigurationsOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.SourceControlConfiguration" + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def create_or_update( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + source_control_configuration, # type: "_models.SourceControlConfiguration" + **kwargs # type: Any + ): + # type: (...) -> "_models.SourceControlConfiguration" + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SourceControlConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create_or_update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def _delete_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def begin_delete( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> LROPoller[None] + """This will delete the YAML file used to set up the Source control configuration, thus stopping + future sync from the source repo. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.SourceControlConfigurationList"] + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_05_01_preview.models.SourceControlConfigurationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-05-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('SourceControlConfigurationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/__init__.py new file mode 100644 index 00000000000..f13062376d7 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +from ._version import VERSION + +__version__ = VERSION +__all__ = ['SourceControlConfigurationClient'] + +try: + from ._patch import patch_sdk # type: ignore + patch_sdk() +except ImportError: + pass diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_configuration.py new file mode 100644 index 00000000000..abc45d20646 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_configuration.py @@ -0,0 +1,71 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from ._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + + from azure.core.credentials import TokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2021-09-01" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs # type: Any + ): + # type: (...) -> None + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.BearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_source_control_configuration_client.py new file mode 100644 index 00000000000..c53deb2d4cd --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_source_control_configuration_client.py @@ -0,0 +1,99 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.mgmt.core import ARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Optional + + from azure.core.credentials import TokenCredential + from azure.core.pipeline.transport import HttpRequest, HttpResponse + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import ExtensionsOperations +from .operations import OperationStatusOperations +from .operations import Operations +from . import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar extensions: ExtensionsOperations operations + :vartype extensions: azure.mgmt.kubernetesconfiguration.v2021_09_01.operations.ExtensionsOperations + :ivar operation_status: OperationStatusOperations operations + :vartype operation_status: azure.mgmt.kubernetesconfiguration.v2021_09_01.operations.OperationStatusOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_09_01.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + base_url=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> None + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = ARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.extensions = ExtensionsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operation_status = OperationStatusOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + + def _send_request(self, http_request, **kwargs): + # type: (HttpRequest, Any) -> HttpResponse + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.HttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + def close(self): + # type: () -> None + self._client.close() + + def __enter__(self): + # type: () -> SourceControlConfigurationClient + self._client.__enter__() + return self + + def __exit__(self, *exc_details): + # type: (Any) -> None + self._client.__exit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_version.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_version.py new file mode 100644 index 00000000000..59deb8c7263 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/_version.py @@ -0,0 +1,9 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +VERSION = "1.1.0" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/__init__.py new file mode 100644 index 00000000000..ba52c91a7ba --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +__all__ = ['SourceControlConfigurationClient'] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/_configuration.py new file mode 100644 index 00000000000..3f22841a050 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/_configuration.py @@ -0,0 +1,67 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from .._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + **kwargs: Any + ) -> None: + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2021-09-01" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs: Any + ) -> None: + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.AsyncBearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/_source_control_configuration_client.py new file mode 100644 index 00000000000..4b520f9c48c --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/_source_control_configuration_client.py @@ -0,0 +1,92 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Optional, TYPE_CHECKING + +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core import AsyncARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import ExtensionsOperations +from .operations import OperationStatusOperations +from .operations import Operations +from .. import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar extensions: ExtensionsOperations operations + :vartype extensions: azure.mgmt.kubernetesconfiguration.v2021_09_01.aio.operations.ExtensionsOperations + :ivar operation_status: OperationStatusOperations operations + :vartype operation_status: azure.mgmt.kubernetesconfiguration.v2021_09_01.aio.operations.OperationStatusOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_09_01.aio.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + base_url: Optional[str] = None, + **kwargs: Any + ) -> None: + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = AsyncARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.extensions = ExtensionsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operation_status = OperationStatusOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + + async def _send_request(self, http_request: HttpRequest, **kwargs: Any) -> AsyncHttpResponse: + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.AsyncHttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = await self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "SourceControlConfigurationClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details) -> None: + await self._client.__aexit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/__init__.py new file mode 100644 index 00000000000..632ac4c1eeb --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/__init__.py @@ -0,0 +1,17 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._extensions_operations import ExtensionsOperations +from ._operation_status_operations import OperationStatusOperations +from ._operations import Operations + +__all__ = [ + 'ExtensionsOperations', + 'OperationStatusOperations', + 'Operations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_extensions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_extensions_operations.py new file mode 100644 index 00000000000..c6c3c4f9d16 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_extensions_operations.py @@ -0,0 +1,645 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionsOperations: + """ExtensionsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def _create_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + extension: "_models.Extension", + **kwargs: Any + ) -> "_models.Extension": + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._create_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(extension, 'Extension') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('Extension', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _create_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def begin_create( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + extension: "_models.Extension", + **kwargs: Any + ) -> AsyncLROPoller["_models.Extension"]: + """Create a new Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param extension: Properties necessary to Create an Extension. + :type extension: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Extension + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either Extension or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Extension] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._create_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + extension=extension, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + **kwargs: Any + ) -> "_models.Extension": + """Gets Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: Extension, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Extension + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def _delete_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + force_delete: Optional[bool] = None, + **kwargs: Any + ) -> None: + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + if force_delete is not None: + query_parameters['forceDelete'] = self._serialize.query("force_delete", force_delete, 'bool') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 202, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def begin_delete( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + force_delete: Optional[bool] = None, + **kwargs: Any + ) -> AsyncLROPoller[None]: + """Delete a Kubernetes Cluster Extension. This will cause the Agent to Uninstall the extension + from the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param force_delete: Delete the extension resource in Azure - not the normal asynchronous + delete. + :type force_delete: bool + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + force_delete=force_delete, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def _update_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + patch_extension: "_models.PatchExtension", + **kwargs: Any + ) -> "_models.Extension": + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: lambda response: ResourceExistsError(response=response, model=self._deserialize(_models.ErrorResponse, response), error_format=ARMErrorFormat), + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._update_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(patch_extension, 'PatchExtension') + body_content_kwargs['content'] = body_content + request = self._client.patch(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _update_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def begin_update( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + patch_extension: "_models.PatchExtension", + **kwargs: Any + ) -> AsyncLROPoller["_models.Extension"]: + """Patch an existing Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param patch_extension: Properties to Patch in an existing Extension. + :type patch_extension: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.PatchExtension + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either Extension or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Extension] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._update_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + patch_extension=patch_extension, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.ExtensionsList"]: + """List all Extensions in the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionsList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ExtensionsList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionsList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionsList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_operation_status_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_operation_status_operations.py new file mode 100644 index 00000000000..61fca2984db --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_operation_status_operations.py @@ -0,0 +1,204 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class OperationStatusOperations: + """OperationStatusOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.OperationStatusList"]: + """List Async Operations, currently in progress, in a cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either OperationStatusList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.OperationStatusList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('OperationStatusList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + operation_id: str, + **kwargs: Any + ) -> "_models.OperationStatusResult": + """Get Async Operation status. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param operation_id: operation Id. + :type operation_id: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: OperationStatusResult, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.OperationStatusResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusResult"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + 'operationId': self._serialize.url("operation_id", operation_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('OperationStatusResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}/operations/{operationId}'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_operations.py new file mode 100644 index 00000000000..103c895ff59 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/aio/operations/_operations.py @@ -0,0 +1,106 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class Operations: + """Operations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs: Any + ) -> AsyncIterable["_models.ResourceProviderOperationList"]: + """List all the available operations the KubernetesConfiguration resource provider supports, in + this api-version. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/__init__.py new file mode 100644 index 00000000000..2bcf3a10bde --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/__init__.py @@ -0,0 +1,86 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +try: + from ._models_py3 import ErrorAdditionalInfo + from ._models_py3 import ErrorDetail + from ._models_py3 import ErrorResponse + from ._models_py3 import Extension + from ._models_py3 import ExtensionPropertiesAksAssignedIdentity + from ._models_py3 import ExtensionStatus + from ._models_py3 import ExtensionsList + from ._models_py3 import Identity + from ._models_py3 import OperationStatusList + from ._models_py3 import OperationStatusResult + from ._models_py3 import PatchExtension + from ._models_py3 import ProxyResource + from ._models_py3 import Resource + from ._models_py3 import ResourceProviderOperation + from ._models_py3 import ResourceProviderOperationDisplay + from ._models_py3 import ResourceProviderOperationList + from ._models_py3 import Scope + from ._models_py3 import ScopeCluster + from ._models_py3 import ScopeNamespace + from ._models_py3 import SystemData +except (SyntaxError, ImportError): + from ._models import ErrorAdditionalInfo # type: ignore + from ._models import ErrorDetail # type: ignore + from ._models import ErrorResponse # type: ignore + from ._models import Extension # type: ignore + from ._models import ExtensionPropertiesAksAssignedIdentity # type: ignore + from ._models import ExtensionStatus # type: ignore + from ._models import ExtensionsList # type: ignore + from ._models import Identity # type: ignore + from ._models import OperationStatusList # type: ignore + from ._models import OperationStatusResult # type: ignore + from ._models import PatchExtension # type: ignore + from ._models import ProxyResource # type: ignore + from ._models import Resource # type: ignore + from ._models import ResourceProviderOperation # type: ignore + from ._models import ResourceProviderOperationDisplay # type: ignore + from ._models import ResourceProviderOperationList # type: ignore + from ._models import Scope # type: ignore + from ._models import ScopeCluster # type: ignore + from ._models import ScopeNamespace # type: ignore + from ._models import SystemData # type: ignore + +from ._source_control_configuration_client_enums import ( + CreatedByType, + Enum0, + Enum1, + LevelType, + ProvisioningState, +) + +__all__ = [ + 'ErrorAdditionalInfo', + 'ErrorDetail', + 'ErrorResponse', + 'Extension', + 'ExtensionPropertiesAksAssignedIdentity', + 'ExtensionStatus', + 'ExtensionsList', + 'Identity', + 'OperationStatusList', + 'OperationStatusResult', + 'PatchExtension', + 'ProxyResource', + 'Resource', + 'ResourceProviderOperation', + 'ResourceProviderOperationDisplay', + 'ResourceProviderOperationList', + 'Scope', + 'ScopeCluster', + 'ScopeNamespace', + 'SystemData', + 'CreatedByType', + 'Enum0', + 'Enum1', + 'LevelType', + 'ProvisioningState', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_models.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_models.py new file mode 100644 index 00000000000..82ac361f3a2 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_models.py @@ -0,0 +1,739 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from azure.core.exceptions import HttpResponseError +import msrest.serialization + + +class ErrorAdditionalInfo(msrest.serialization.Model): + """The resource management error additional info. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar type: The additional info type. + :vartype type: str + :ivar info: The additional info. + :vartype info: any + """ + + _validation = { + 'type': {'readonly': True}, + 'info': {'readonly': True}, + } + + _attribute_map = { + 'type': {'key': 'type', 'type': 'str'}, + 'info': {'key': 'info', 'type': 'object'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorAdditionalInfo, self).__init__(**kwargs) + self.type = None + self.info = None + + +class ErrorDetail(msrest.serialization.Model): + """The error detail. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar code: The error code. + :vartype code: str + :ivar message: The error message. + :vartype message: str + :ivar target: The error target. + :vartype target: str + :ivar details: The error details. + :vartype details: list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ErrorDetail] + :ivar additional_info: The error additional info. + :vartype additional_info: + list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ErrorAdditionalInfo] + """ + + _validation = { + 'code': {'readonly': True}, + 'message': {'readonly': True}, + 'target': {'readonly': True}, + 'details': {'readonly': True}, + 'additional_info': {'readonly': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'target': {'key': 'target', 'type': 'str'}, + 'details': {'key': 'details', 'type': '[ErrorDetail]'}, + 'additional_info': {'key': 'additionalInfo', 'type': '[ErrorAdditionalInfo]'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorDetail, self).__init__(**kwargs) + self.code = None + self.message = None + self.target = None + self.details = None + self.additional_info = None + + +class ErrorResponse(msrest.serialization.Model): + """Common error response for all Azure Resource Manager APIs to return error details for failed operations. (This also follows the OData error response format.). + + :param error: The error object. + :type error: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ErrorDetail + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorResponse, self).__init__(**kwargs) + self.error = kwargs.get('error', None) + + +class Resource(msrest.serialization.Model): + """Common fields that are returned in the response for all Azure Resource Manager resources. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class ProxyResource(Resource): + """The resource model definition for a Azure Resource Manager proxy resource. It will not have tags and a location. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ProxyResource, self).__init__(**kwargs) + + +class Extension(ProxyResource): + """The Extension object. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :param identity: Identity of the Extension resource. + :type identity: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Identity + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.SystemData + :param extension_type: Type of the Extension, of which this resource is an instance of. It + must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the + Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this extension participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension participates in for auto-upgrade (e.g. + Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension, if it is 'pinned' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param scope: Scope at which the extension is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this extension. + :type configuration_protected_settings: dict[str, str] + :ivar provisioning_state: The provisioning state of the extension resource. Possible values + include: "Succeeded", "Failed", "Canceled", "Creating", "Updating", "Deleting". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ProvisioningState + :param statuses: Status from this extension. + :type statuses: list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ExtensionStatus] + :param error_info: The error detail. + :type error_info: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ErrorDetail + :ivar custom_location_settings: Custom Location settings properties. + :vartype custom_location_settings: dict[str, str] + :ivar package_uri: Uri of the Helm package. + :vartype package_uri: str + :param aks_assigned_identity: Identity of the Extension resource in an AKS cluster. + :type aks_assigned_identity: + ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ExtensionPropertiesAksAssignedIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'custom_location_settings': {'readonly': True}, + 'package_uri': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'identity': {'key': 'identity', 'type': 'Identity'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDetail'}, + 'custom_location_settings': {'key': 'properties.customLocationSettings', 'type': '{str}'}, + 'package_uri': {'key': 'properties.packageUri', 'type': 'str'}, + 'aks_assigned_identity': {'key': 'properties.aksAssignedIdentity', 'type': 'ExtensionPropertiesAksAssignedIdentity'}, + } + + def __init__( + self, + **kwargs + ): + super(Extension, self).__init__(**kwargs) + self.identity = kwargs.get('identity', None) + self.system_data = None + self.extension_type = kwargs.get('extension_type', None) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', True) + self.release_train = kwargs.get('release_train', "Stable") + self.version = kwargs.get('version', None) + self.scope = kwargs.get('scope', None) + self.configuration_settings = kwargs.get('configuration_settings', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.provisioning_state = None + self.statuses = kwargs.get('statuses', None) + self.error_info = kwargs.get('error_info', None) + self.custom_location_settings = None + self.package_uri = None + self.aks_assigned_identity = kwargs.get('aks_assigned_identity', None) + + +class ExtensionPropertiesAksAssignedIdentity(msrest.serialization.Model): + """Identity of the Extension resource in an AKS cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal ID of resource identity. + :vartype principal_id: str + :ivar tenant_id: The tenant ID of resource. + :vartype tenant_id: str + :param type: The identity type. The only acceptable values to pass in are None and + "SystemAssigned". The default value is None. + :type type: str + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionPropertiesAksAssignedIdentity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = kwargs.get('type', None) + + +class ExtensionsList(msrest.serialization.Model): + """Result of the request to list Extensions. It contains a list of Extension objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Extensions within a Kubernetes cluster. + :vartype value: list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Extension] + :ivar next_link: URL to get the next set of extension objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[Extension]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionsList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class ExtensionStatus(msrest.serialization.Model): + """Status from the extension. + + :param code: Status code provided by the Extension. + :type code: str + :param display_status: Short description of status of the extension. + :type display_status: str + :param level: Level of the status. Possible values include: "Error", "Warning", "Information". + Default value: "Information". + :type level: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.LevelType + :param message: Detailed message of the status from the Extension. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionStatus, self).__init__(**kwargs) + self.code = kwargs.get('code', None) + self.display_status = kwargs.get('display_status', None) + self.level = kwargs.get('level', "Information") + self.message = kwargs.get('message', None) + self.time = kwargs.get('time', None) + + +class Identity(msrest.serialization.Model): + """Identity for the resource. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal ID of resource identity. + :vartype principal_id: str + :ivar tenant_id: The tenant ID of resource. + :vartype tenant_id: str + :param type: The identity type. The only acceptable values to pass in are None and + "SystemAssigned". The default value is None. + :type type: str + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Identity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = kwargs.get('type', None) + + +class OperationStatusList(msrest.serialization.Model): + """The async operations in progress, in the cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of async operations in progress, in the cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.OperationStatusResult] + :ivar next_link: URL to get the next set of Operation Result objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[OperationStatusResult]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(OperationStatusList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class OperationStatusResult(msrest.serialization.Model): + """The current status of an async operation. + + All required parameters must be populated in order to send to Azure. + + :param id: Fully qualified ID for the async operation. + :type id: str + :param name: Name of the async operation. + :type name: str + :param status: Required. Operation status. + :type status: str + :param properties: Additional information, if available. + :type properties: dict[str, str] + :param error: The error detail. + :type error: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ErrorDetail + """ + + _validation = { + 'status': {'required': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'status': {'key': 'status', 'type': 'str'}, + 'properties': {'key': 'properties', 'type': '{str}'}, + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + **kwargs + ): + super(OperationStatusResult, self).__init__(**kwargs) + self.id = kwargs.get('id', None) + self.name = kwargs.get('name', None) + self.status = kwargs['status'] + self.properties = kwargs.get('properties', None) + self.error = kwargs.get('error', None) + + +class PatchExtension(msrest.serialization.Model): + """The Extension Patch Request object. + + :param auto_upgrade_minor_version: Flag to note if this extension participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension participates in for auto-upgrade (e.g. + Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension, if it is 'pinned' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this extension. + :type configuration_protected_settings: dict[str, str] + """ + + _attribute_map = { + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + } + + def __init__( + self, + **kwargs + ): + super(PatchExtension, self).__init__(**kwargs) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', True) + self.release_train = kwargs.get('release_train', "Stable") + self.version = kwargs.get('version', None) + self.configuration_settings = kwargs.get('configuration_settings', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + + +class ResourceProviderOperation(msrest.serialization.Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param name: Operation name, in format of {provider}/{resource}/{operation}. + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. + :vartype is_data_action: bool + :ivar origin: Origin of the operation. + :vartype origin: str + """ + + _validation = { + 'is_data_action': {'readonly': True}, + 'origin': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + 'origin': {'key': 'origin', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = kwargs.get('name', None) + self.display = kwargs.get('display', None) + self.is_data_action = None + self.origin = None + + +class ResourceProviderOperationDisplay(msrest.serialization.Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = kwargs.get('provider', None) + self.resource = kwargs.get('resource', None) + self.operation = kwargs.get('operation', None) + self.description = kwargs.get('description', None) + + +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = kwargs.get('value', None) + self.next_link = None + + +class Scope(msrest.serialization.Model): + """Scope of the extension. It can be either Cluster or Namespace; but not both. + + :param cluster: Specifies that the scope of the extension is Cluster. + :type cluster: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ScopeCluster + :param namespace: Specifies that the scope of the extension is Namespace. + :type namespace: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__( + self, + **kwargs + ): + super(Scope, self).__init__(**kwargs) + self.cluster = kwargs.get('cluster', None) + self.namespace = kwargs.get('namespace', None) + + +class ScopeCluster(msrest.serialization.Model): + """Specifies that the scope of the extension is Cluster. + + :param release_namespace: Namespace where the extension Release must be placed, for a Cluster + scoped extension. If this namespace does not exist, it will be created. + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = kwargs.get('release_namespace', None) + + +class ScopeNamespace(msrest.serialization.Model): + """Specifies that the scope of the extension is Namespace. + + :param target_namespace: Namespace where the extension will be created for an Namespace scoped + extension. If this namespace does not exist, it will be created. + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = kwargs.get('target_namespace', None) + + +class SystemData(msrest.serialization.Model): + """Metadata pertaining to creation and last modification of the resource. + + :param created_by: The identity that created the resource. + :type created_by: str + :param created_by_type: The type of identity that created the resource. Possible values + include: "User", "Application", "ManagedIdentity", "Key". + :type created_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.CreatedByType + :param created_at: The timestamp of resource creation (UTC). + :type created_at: ~datetime.datetime + :param last_modified_by: The identity that last modified the resource. + :type last_modified_by: str + :param last_modified_by_type: The type of identity that last modified the resource. Possible + values include: "User", "Application", "ManagedIdentity", "Key". + :type last_modified_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.CreatedByType + :param last_modified_at: The timestamp of resource last modification (UTC). + :type last_modified_at: ~datetime.datetime + """ + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__( + self, + **kwargs + ): + super(SystemData, self).__init__(**kwargs) + self.created_by = kwargs.get('created_by', None) + self.created_by_type = kwargs.get('created_by_type', None) + self.created_at = kwargs.get('created_at', None) + self.last_modified_by = kwargs.get('last_modified_by', None) + self.last_modified_by_type = kwargs.get('last_modified_by_type', None) + self.last_modified_at = kwargs.get('last_modified_at', None) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_models_py3.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_models_py3.py new file mode 100644 index 00000000000..dfc2c01aab6 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_models_py3.py @@ -0,0 +1,804 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import datetime +from typing import Dict, List, Optional, Union + +from azure.core.exceptions import HttpResponseError +import msrest.serialization + +from ._source_control_configuration_client_enums import * + + +class ErrorAdditionalInfo(msrest.serialization.Model): + """The resource management error additional info. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar type: The additional info type. + :vartype type: str + :ivar info: The additional info. + :vartype info: any + """ + + _validation = { + 'type': {'readonly': True}, + 'info': {'readonly': True}, + } + + _attribute_map = { + 'type': {'key': 'type', 'type': 'str'}, + 'info': {'key': 'info', 'type': 'object'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorAdditionalInfo, self).__init__(**kwargs) + self.type = None + self.info = None + + +class ErrorDetail(msrest.serialization.Model): + """The error detail. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar code: The error code. + :vartype code: str + :ivar message: The error message. + :vartype message: str + :ivar target: The error target. + :vartype target: str + :ivar details: The error details. + :vartype details: list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ErrorDetail] + :ivar additional_info: The error additional info. + :vartype additional_info: + list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ErrorAdditionalInfo] + """ + + _validation = { + 'code': {'readonly': True}, + 'message': {'readonly': True}, + 'target': {'readonly': True}, + 'details': {'readonly': True}, + 'additional_info': {'readonly': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'target': {'key': 'target', 'type': 'str'}, + 'details': {'key': 'details', 'type': '[ErrorDetail]'}, + 'additional_info': {'key': 'additionalInfo', 'type': '[ErrorAdditionalInfo]'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorDetail, self).__init__(**kwargs) + self.code = None + self.message = None + self.target = None + self.details = None + self.additional_info = None + + +class ErrorResponse(msrest.serialization.Model): + """Common error response for all Azure Resource Manager APIs to return error details for failed operations. (This also follows the OData error response format.). + + :param error: The error object. + :type error: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ErrorDetail + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + *, + error: Optional["ErrorDetail"] = None, + **kwargs + ): + super(ErrorResponse, self).__init__(**kwargs) + self.error = error + + +class Resource(msrest.serialization.Model): + """Common fields that are returned in the response for all Azure Resource Manager resources. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class ProxyResource(Resource): + """The resource model definition for a Azure Resource Manager proxy resource. It will not have tags and a location. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ProxyResource, self).__init__(**kwargs) + + +class Extension(ProxyResource): + """The Extension object. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :param identity: Identity of the Extension resource. + :type identity: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Identity + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.SystemData + :param extension_type: Type of the Extension, of which this resource is an instance of. It + must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the + Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this extension participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension participates in for auto-upgrade (e.g. + Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension, if it is 'pinned' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param scope: Scope at which the extension is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this extension. + :type configuration_protected_settings: dict[str, str] + :ivar provisioning_state: The provisioning state of the extension resource. Possible values + include: "Succeeded", "Failed", "Canceled", "Creating", "Updating", "Deleting". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ProvisioningState + :param statuses: Status from this extension. + :type statuses: list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ExtensionStatus] + :param error_info: The error detail. + :type error_info: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ErrorDetail + :ivar custom_location_settings: Custom Location settings properties. + :vartype custom_location_settings: dict[str, str] + :ivar package_uri: Uri of the Helm package. + :vartype package_uri: str + :param aks_assigned_identity: Identity of the Extension resource in an AKS cluster. + :type aks_assigned_identity: + ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ExtensionPropertiesAksAssignedIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'custom_location_settings': {'readonly': True}, + 'package_uri': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'identity': {'key': 'identity', 'type': 'Identity'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDetail'}, + 'custom_location_settings': {'key': 'properties.customLocationSettings', 'type': '{str}'}, + 'package_uri': {'key': 'properties.packageUri', 'type': 'str'}, + 'aks_assigned_identity': {'key': 'properties.aksAssignedIdentity', 'type': 'ExtensionPropertiesAksAssignedIdentity'}, + } + + def __init__( + self, + *, + identity: Optional["Identity"] = None, + extension_type: Optional[str] = None, + auto_upgrade_minor_version: Optional[bool] = True, + release_train: Optional[str] = "Stable", + version: Optional[str] = None, + scope: Optional["Scope"] = None, + configuration_settings: Optional[Dict[str, str]] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + statuses: Optional[List["ExtensionStatus"]] = None, + error_info: Optional["ErrorDetail"] = None, + aks_assigned_identity: Optional["ExtensionPropertiesAksAssignedIdentity"] = None, + **kwargs + ): + super(Extension, self).__init__(**kwargs) + self.identity = identity + self.system_data = None + self.extension_type = extension_type + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + self.scope = scope + self.configuration_settings = configuration_settings + self.configuration_protected_settings = configuration_protected_settings + self.provisioning_state = None + self.statuses = statuses + self.error_info = error_info + self.custom_location_settings = None + self.package_uri = None + self.aks_assigned_identity = aks_assigned_identity + + +class ExtensionPropertiesAksAssignedIdentity(msrest.serialization.Model): + """Identity of the Extension resource in an AKS cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal ID of resource identity. + :vartype principal_id: str + :ivar tenant_id: The tenant ID of resource. + :vartype tenant_id: str + :param type: The identity type. The only acceptable values to pass in are None and + "SystemAssigned". The default value is None. + :type type: str + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + *, + type: Optional[str] = None, + **kwargs + ): + super(ExtensionPropertiesAksAssignedIdentity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = type + + +class ExtensionsList(msrest.serialization.Model): + """Result of the request to list Extensions. It contains a list of Extension objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Extensions within a Kubernetes cluster. + :vartype value: list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Extension] + :ivar next_link: URL to get the next set of extension objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[Extension]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionsList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class ExtensionStatus(msrest.serialization.Model): + """Status from the extension. + + :param code: Status code provided by the Extension. + :type code: str + :param display_status: Short description of status of the extension. + :type display_status: str + :param level: Level of the status. Possible values include: "Error", "Warning", "Information". + Default value: "Information". + :type level: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.LevelType + :param message: Detailed message of the status from the Extension. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__( + self, + *, + code: Optional[str] = None, + display_status: Optional[str] = None, + level: Optional[Union[str, "LevelType"]] = "Information", + message: Optional[str] = None, + time: Optional[str] = None, + **kwargs + ): + super(ExtensionStatus, self).__init__(**kwargs) + self.code = code + self.display_status = display_status + self.level = level + self.message = message + self.time = time + + +class Identity(msrest.serialization.Model): + """Identity for the resource. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal ID of resource identity. + :vartype principal_id: str + :ivar tenant_id: The tenant ID of resource. + :vartype tenant_id: str + :param type: The identity type. The only acceptable values to pass in are None and + "SystemAssigned". The default value is None. + :type type: str + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + *, + type: Optional[str] = None, + **kwargs + ): + super(Identity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = type + + +class OperationStatusList(msrest.serialization.Model): + """The async operations in progress, in the cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of async operations in progress, in the cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.OperationStatusResult] + :ivar next_link: URL to get the next set of Operation Result objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[OperationStatusResult]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(OperationStatusList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class OperationStatusResult(msrest.serialization.Model): + """The current status of an async operation. + + All required parameters must be populated in order to send to Azure. + + :param id: Fully qualified ID for the async operation. + :type id: str + :param name: Name of the async operation. + :type name: str + :param status: Required. Operation status. + :type status: str + :param properties: Additional information, if available. + :type properties: dict[str, str] + :param error: The error detail. + :type error: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ErrorDetail + """ + + _validation = { + 'status': {'required': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'status': {'key': 'status', 'type': 'str'}, + 'properties': {'key': 'properties', 'type': '{str}'}, + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + *, + status: str, + id: Optional[str] = None, + name: Optional[str] = None, + properties: Optional[Dict[str, str]] = None, + error: Optional["ErrorDetail"] = None, + **kwargs + ): + super(OperationStatusResult, self).__init__(**kwargs) + self.id = id + self.name = name + self.status = status + self.properties = properties + self.error = error + + +class PatchExtension(msrest.serialization.Model): + """The Extension Patch Request object. + + :param auto_upgrade_minor_version: Flag to note if this extension participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension participates in for auto-upgrade (e.g. + Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension, if it is 'pinned' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this extension. + :type configuration_protected_settings: dict[str, str] + """ + + _attribute_map = { + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + } + + def __init__( + self, + *, + auto_upgrade_minor_version: Optional[bool] = True, + release_train: Optional[str] = "Stable", + version: Optional[str] = None, + configuration_settings: Optional[Dict[str, str]] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + **kwargs + ): + super(PatchExtension, self).__init__(**kwargs) + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + self.configuration_settings = configuration_settings + self.configuration_protected_settings = configuration_protected_settings + + +class ResourceProviderOperation(msrest.serialization.Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param name: Operation name, in format of {provider}/{resource}/{operation}. + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. + :vartype is_data_action: bool + :ivar origin: Origin of the operation. + :vartype origin: str + """ + + _validation = { + 'is_data_action': {'readonly': True}, + 'origin': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + 'origin': {'key': 'origin', 'type': 'str'}, + } + + def __init__( + self, + *, + name: Optional[str] = None, + display: Optional["ResourceProviderOperationDisplay"] = None, + **kwargs + ): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = name + self.display = display + self.is_data_action = None + self.origin = None + + +class ResourceProviderOperationDisplay(msrest.serialization.Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__( + self, + *, + provider: Optional[str] = None, + resource: Optional[str] = None, + operation: Optional[str] = None, + description: Optional[str] = None, + **kwargs + ): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = provider + self.resource = resource + self.operation = operation + self.description = description + + +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + *, + value: Optional[List["ResourceProviderOperation"]] = None, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = value + self.next_link = None + + +class Scope(msrest.serialization.Model): + """Scope of the extension. It can be either Cluster or Namespace; but not both. + + :param cluster: Specifies that the scope of the extension is Cluster. + :type cluster: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ScopeCluster + :param namespace: Specifies that the scope of the extension is Namespace. + :type namespace: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__( + self, + *, + cluster: Optional["ScopeCluster"] = None, + namespace: Optional["ScopeNamespace"] = None, + **kwargs + ): + super(Scope, self).__init__(**kwargs) + self.cluster = cluster + self.namespace = namespace + + +class ScopeCluster(msrest.serialization.Model): + """Specifies that the scope of the extension is Cluster. + + :param release_namespace: Namespace where the extension Release must be placed, for a Cluster + scoped extension. If this namespace does not exist, it will be created. + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + *, + release_namespace: Optional[str] = None, + **kwargs + ): + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = release_namespace + + +class ScopeNamespace(msrest.serialization.Model): + """Specifies that the scope of the extension is Namespace. + + :param target_namespace: Namespace where the extension will be created for an Namespace scoped + extension. If this namespace does not exist, it will be created. + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__( + self, + *, + target_namespace: Optional[str] = None, + **kwargs + ): + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = target_namespace + + +class SystemData(msrest.serialization.Model): + """Metadata pertaining to creation and last modification of the resource. + + :param created_by: The identity that created the resource. + :type created_by: str + :param created_by_type: The type of identity that created the resource. Possible values + include: "User", "Application", "ManagedIdentity", "Key". + :type created_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.CreatedByType + :param created_at: The timestamp of resource creation (UTC). + :type created_at: ~datetime.datetime + :param last_modified_by: The identity that last modified the resource. + :type last_modified_by: str + :param last_modified_by_type: The type of identity that last modified the resource. Possible + values include: "User", "Application", "ManagedIdentity", "Key". + :type last_modified_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.CreatedByType + :param last_modified_at: The timestamp of resource last modification (UTC). + :type last_modified_at: ~datetime.datetime + """ + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__( + self, + *, + created_by: Optional[str] = None, + created_by_type: Optional[Union[str, "CreatedByType"]] = None, + created_at: Optional[datetime.datetime] = None, + last_modified_by: Optional[str] = None, + last_modified_by_type: Optional[Union[str, "CreatedByType"]] = None, + last_modified_at: Optional[datetime.datetime] = None, + **kwargs + ): + super(SystemData, self).__init__(**kwargs) + self.created_by = created_by + self.created_by_type = created_by_type + self.created_at = created_at + self.last_modified_by = last_modified_by + self.last_modified_by_type = last_modified_by_type + self.last_modified_at = last_modified_at diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_source_control_configuration_client_enums.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_source_control_configuration_client_enums.py new file mode 100644 index 00000000000..19b127e8cd4 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/models/_source_control_configuration_client_enums.py @@ -0,0 +1,65 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from enum import Enum, EnumMeta +from six import with_metaclass + +class _CaseInsensitiveEnumMeta(EnumMeta): + def __getitem__(self, name): + return super().__getitem__(name.upper()) + + def __getattr__(cls, name): + """Return the enum member matching `name` + We use __getattr__ instead of descriptors or inserting into the enum + class' __dict__ in order to support `name` and `value` being both + properties for enum members (which live in the class' __dict__) and + enum members themselves. + """ + try: + return cls._member_map_[name.upper()] + except KeyError: + raise AttributeError(name) + + +class CreatedByType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The type of identity that created the resource. + """ + + USER = "User" + APPLICATION = "Application" + MANAGED_IDENTITY = "ManagedIdentity" + KEY = "Key" + +class Enum0(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + + MICROSOFT_CONTAINER_SERVICE = "Microsoft.ContainerService" + MICROSOFT_KUBERNETES = "Microsoft.Kubernetes" + +class Enum1(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + + MANAGED_CLUSTERS = "managedClusters" + CONNECTED_CLUSTERS = "connectedClusters" + +class LevelType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Level of the status. + """ + + ERROR = "Error" + WARNING = "Warning" + INFORMATION = "Information" + +class ProvisioningState(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The provisioning state of the extension resource. + """ + + SUCCEEDED = "Succeeded" + FAILED = "Failed" + CANCELED = "Canceled" + CREATING = "Creating" + UPDATING = "Updating" + DELETING = "Deleting" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/__init__.py new file mode 100644 index 00000000000..632ac4c1eeb --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/__init__.py @@ -0,0 +1,17 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._extensions_operations import ExtensionsOperations +from ._operation_status_operations import OperationStatusOperations +from ._operations import Operations + +__all__ = [ + 'ExtensionsOperations', + 'OperationStatusOperations', + 'Operations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_extensions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_extensions_operations.py new file mode 100644 index 00000000000..7517bdd8cd2 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_extensions_operations.py @@ -0,0 +1,657 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.core.polling import LROPoller, NoPolling, PollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.arm_polling import ARMPolling + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionsOperations(object): + """ExtensionsOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def _create_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + extension, # type: "_models.Extension" + **kwargs # type: Any + ): + # type: (...) -> "_models.Extension" + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._create_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(extension, 'Extension') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('Extension', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _create_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def begin_create( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + extension, # type: "_models.Extension" + **kwargs # type: Any + ): + # type: (...) -> LROPoller["_models.Extension"] + """Create a new Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param extension: Properties necessary to Create an Extension. + :type extension: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Extension + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either Extension or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Extension] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._create_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + extension=extension, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.Extension" + """Gets Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: Extension, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Extension + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def _delete_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + force_delete=None, # type: Optional[bool] + **kwargs # type: Any + ): + # type: (...) -> None + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + if force_delete is not None: + query_parameters['forceDelete'] = self._serialize.query("force_delete", force_delete, 'bool') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 202, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def begin_delete( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + force_delete=None, # type: Optional[bool] + **kwargs # type: Any + ): + # type: (...) -> LROPoller[None] + """Delete a Kubernetes Cluster Extension. This will cause the Agent to Uninstall the extension + from the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param force_delete: Delete the extension resource in Azure - not the normal asynchronous + delete. + :type force_delete: bool + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + force_delete=force_delete, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def _update_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + patch_extension, # type: "_models.PatchExtension" + **kwargs # type: Any + ): + # type: (...) -> "_models.Extension" + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: lambda response: ResourceExistsError(response=response, model=self._deserialize(_models.ErrorResponse, response), error_format=ARMErrorFormat), + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._update_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(patch_extension, 'PatchExtension') + body_content_kwargs['content'] = body_content + request = self._client.patch(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _update_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def begin_update( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + patch_extension, # type: "_models.PatchExtension" + **kwargs # type: Any + ): + # type: (...) -> LROPoller["_models.Extension"] + """Patch an existing Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param patch_extension: Properties to Patch in an existing Extension. + :type patch_extension: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.PatchExtension + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either Extension or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Extension] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._update_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + patch_extension=patch_extension, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ExtensionsList"] + """List all Extensions in the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionsList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ExtensionsList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionsList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionsList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_operation_status_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_operation_status_operations.py new file mode 100644 index 00000000000..1343bf36641 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_operation_status_operations.py @@ -0,0 +1,210 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class OperationStatusOperations(object): + """OperationStatusOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.OperationStatusList"] + """List Async Operations, currently in progress, in a cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either OperationStatusList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.OperationStatusList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('OperationStatusList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + operation_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.OperationStatusResult" + """Get Async Operation status. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param operation_id: operation Id. + :type operation_id: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: OperationStatusResult, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.OperationStatusResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusResult"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + 'operationId': self._serialize.url("operation_id", operation_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('OperationStatusResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}/operations/{operationId}'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_operations.py new file mode 100644 index 00000000000..1cb21812c9b --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_09_01/operations/_operations.py @@ -0,0 +1,111 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class Operations(object): + """Operations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_09_01.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ResourceProviderOperationList"] + """List all the available operations the KubernetesConfiguration resource provider supports, in + this api-version. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_09_01.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-09-01" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/__init__.py new file mode 100644 index 00000000000..f13062376d7 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +from ._version import VERSION + +__version__ = VERSION +__all__ = ['SourceControlConfigurationClient'] + +try: + from ._patch import patch_sdk # type: ignore + patch_sdk() +except ImportError: + pass diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_configuration.py new file mode 100644 index 00000000000..bfc7dcb3271 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_configuration.py @@ -0,0 +1,71 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from ._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + + from azure.core.credentials import TokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2021-11-01-preview" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs # type: Any + ): + # type: (...) -> None + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.BearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_source_control_configuration_client.py new file mode 100644 index 00000000000..83ffa08737e --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_source_control_configuration_client.py @@ -0,0 +1,134 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.mgmt.core import ARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Optional + + from azure.core.credentials import TokenCredential + from azure.core.pipeline.transport import HttpRequest, HttpResponse + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import ExtensionsOperations +from .operations import OperationStatusOperations +from .operations import ClusterExtensionTypeOperations +from .operations import ClusterExtensionTypesOperations +from .operations import ExtensionTypeVersionsOperations +from .operations import LocationExtensionTypesOperations +from .operations import SourceControlConfigurationsOperations +from .operations import FluxConfigurationsOperations +from .operations import FluxConfigOperationStatusOperations +from .operations import Operations +from . import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar extensions: ExtensionsOperations operations + :vartype extensions: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.operations.ExtensionsOperations + :ivar operation_status: OperationStatusOperations operations + :vartype operation_status: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.operations.OperationStatusOperations + :ivar cluster_extension_type: ClusterExtensionTypeOperations operations + :vartype cluster_extension_type: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.operations.ClusterExtensionTypeOperations + :ivar cluster_extension_types: ClusterExtensionTypesOperations operations + :vartype cluster_extension_types: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.operations.ClusterExtensionTypesOperations + :ivar extension_type_versions: ExtensionTypeVersionsOperations operations + :vartype extension_type_versions: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.operations.ExtensionTypeVersionsOperations + :ivar location_extension_types: LocationExtensionTypesOperations operations + :vartype location_extension_types: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.operations.LocationExtensionTypesOperations + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.operations.SourceControlConfigurationsOperations + :ivar flux_configurations: FluxConfigurationsOperations operations + :vartype flux_configurations: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.operations.FluxConfigurationsOperations + :ivar flux_config_operation_status: FluxConfigOperationStatusOperations operations + :vartype flux_config_operation_status: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.operations.FluxConfigOperationStatusOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential, # type: "TokenCredential" + subscription_id, # type: str + base_url=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> None + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = ARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.extensions = ExtensionsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operation_status = OperationStatusOperations( + self._client, self._config, self._serialize, self._deserialize) + self.cluster_extension_type = ClusterExtensionTypeOperations( + self._client, self._config, self._serialize, self._deserialize) + self.cluster_extension_types = ClusterExtensionTypesOperations( + self._client, self._config, self._serialize, self._deserialize) + self.extension_type_versions = ExtensionTypeVersionsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.location_extension_types = LocationExtensionTypesOperations( + self._client, self._config, self._serialize, self._deserialize) + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.flux_configurations = FluxConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.flux_config_operation_status = FluxConfigOperationStatusOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + + def _send_request(self, http_request, **kwargs): + # type: (HttpRequest, Any) -> HttpResponse + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.HttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + def close(self): + # type: () -> None + self._client.close() + + def __enter__(self): + # type: () -> SourceControlConfigurationClient + self._client.__enter__() + return self + + def __exit__(self, *exc_details): + # type: (Any) -> None + self._client.__exit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_version.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_version.py new file mode 100644 index 00000000000..59deb8c7263 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/_version.py @@ -0,0 +1,9 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +VERSION = "1.1.0" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/__init__.py new file mode 100644 index 00000000000..ba52c91a7ba --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configuration_client import SourceControlConfigurationClient +__all__ = ['SourceControlConfigurationClient'] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/_configuration.py new file mode 100644 index 00000000000..bce1f6a3c16 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/_configuration.py @@ -0,0 +1,67 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies +from azure.mgmt.core.policies import ARMHttpLoggingPolicy + +from .._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + + +class SourceControlConfigurationClientConfiguration(Configuration): + """Configuration for SourceControlConfigurationClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + **kwargs: Any + ) -> None: + if credential is None: + raise ValueError("Parameter 'credential' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + super(SourceControlConfigurationClientConfiguration, self).__init__(**kwargs) + + self.credential = credential + self.subscription_id = subscription_id + self.api_version = "2021-11-01-preview" + self.credential_scopes = kwargs.pop('credential_scopes', ['https://management.azure.com/.default']) + kwargs.setdefault('sdk_moniker', 'mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs: Any + ) -> None: + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or ARMHttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') + if self.credential and not self.authentication_policy: + self.authentication_policy = policies.AsyncBearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/_source_control_configuration_client.py new file mode 100644 index 00000000000..dbc71d712f5 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/_source_control_configuration_client.py @@ -0,0 +1,127 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Optional, TYPE_CHECKING + +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core import AsyncARMPipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import ExtensionsOperations +from .operations import OperationStatusOperations +from .operations import ClusterExtensionTypeOperations +from .operations import ClusterExtensionTypesOperations +from .operations import ExtensionTypeVersionsOperations +from .operations import LocationExtensionTypesOperations +from .operations import SourceControlConfigurationsOperations +from .operations import FluxConfigurationsOperations +from .operations import FluxConfigOperationStatusOperations +from .operations import Operations +from .. import models + + +class SourceControlConfigurationClient(object): + """KubernetesConfiguration Client. + + :ivar extensions: ExtensionsOperations operations + :vartype extensions: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.aio.operations.ExtensionsOperations + :ivar operation_status: OperationStatusOperations operations + :vartype operation_status: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.aio.operations.OperationStatusOperations + :ivar cluster_extension_type: ClusterExtensionTypeOperations operations + :vartype cluster_extension_type: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.aio.operations.ClusterExtensionTypeOperations + :ivar cluster_extension_types: ClusterExtensionTypesOperations operations + :vartype cluster_extension_types: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.aio.operations.ClusterExtensionTypesOperations + :ivar extension_type_versions: ExtensionTypeVersionsOperations operations + :vartype extension_type_versions: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.aio.operations.ExtensionTypeVersionsOperations + :ivar location_extension_types: LocationExtensionTypesOperations operations + :vartype location_extension_types: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.aio.operations.LocationExtensionTypesOperations + :ivar source_control_configurations: SourceControlConfigurationsOperations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.aio.operations.SourceControlConfigurationsOperations + :ivar flux_configurations: FluxConfigurationsOperations operations + :vartype flux_configurations: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.aio.operations.FluxConfigurationsOperations + :ivar flux_config_operation_status: FluxConfigOperationStatusOperations operations + :vartype flux_config_operation_status: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.aio.operations.FluxConfigOperationStatusOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.aio.operations.Operations + :param credential: Credential needed for the client to connect to Azure. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: The ID of the target subscription. + :type subscription_id: str + :param str base_url: Service URL + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + """ + + def __init__( + self, + credential: "AsyncTokenCredential", + subscription_id: str, + base_url: Optional[str] = None, + **kwargs: Any + ) -> None: + if not base_url: + base_url = 'https://management.azure.com' + self._config = SourceControlConfigurationClientConfiguration(credential, subscription_id, **kwargs) + self._client = AsyncARMPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + self.extensions = ExtensionsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operation_status = OperationStatusOperations( + self._client, self._config, self._serialize, self._deserialize) + self.cluster_extension_type = ClusterExtensionTypeOperations( + self._client, self._config, self._serialize, self._deserialize) + self.cluster_extension_types = ClusterExtensionTypesOperations( + self._client, self._config, self._serialize, self._deserialize) + self.extension_type_versions = ExtensionTypeVersionsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.location_extension_types = LocationExtensionTypesOperations( + self._client, self._config, self._serialize, self._deserialize) + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.flux_configurations = FluxConfigurationsOperations( + self._client, self._config, self._serialize, self._deserialize) + self.flux_config_operation_status = FluxConfigOperationStatusOperations( + self._client, self._config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self._config, self._serialize, self._deserialize) + + async def _send_request(self, http_request: HttpRequest, **kwargs: Any) -> AsyncHttpResponse: + """Runs the network request through the client's chained policies. + + :param http_request: The network request you want to make. Required. + :type http_request: ~azure.core.pipeline.transport.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to True. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.pipeline.transport.AsyncHttpResponse + """ + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + } + http_request.url = self._client.format_url(http_request.url, **path_format_arguments) + stream = kwargs.pop("stream", True) + pipeline_response = await self._client._pipeline.run(http_request, stream=stream, **kwargs) + return pipeline_response.http_response + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "SourceControlConfigurationClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details) -> None: + await self._client.__aexit__(*exc_details) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/__init__.py new file mode 100644 index 00000000000..ee01fecd439 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/__init__.py @@ -0,0 +1,31 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._extensions_operations import ExtensionsOperations +from ._operation_status_operations import OperationStatusOperations +from ._cluster_extension_type_operations import ClusterExtensionTypeOperations +from ._cluster_extension_types_operations import ClusterExtensionTypesOperations +from ._extension_type_versions_operations import ExtensionTypeVersionsOperations +from ._location_extension_types_operations import LocationExtensionTypesOperations +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._flux_configurations_operations import FluxConfigurationsOperations +from ._flux_config_operation_status_operations import FluxConfigOperationStatusOperations +from ._operations import Operations + +__all__ = [ + 'ExtensionsOperations', + 'OperationStatusOperations', + 'ClusterExtensionTypeOperations', + 'ClusterExtensionTypesOperations', + 'ExtensionTypeVersionsOperations', + 'LocationExtensionTypesOperations', + 'SourceControlConfigurationsOperations', + 'FluxConfigurationsOperations', + 'FluxConfigOperationStatusOperations', + 'Operations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_cluster_extension_type_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_cluster_extension_type_operations.py new file mode 100644 index 00000000000..a18843f7071 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_cluster_extension_type_operations.py @@ -0,0 +1,114 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class ClusterExtensionTypeOperations: + """ClusterExtensionTypeOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_type_name: str, + **kwargs: Any + ) -> "_models.ExtensionType": + """Get Extension Type details. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_type_name: Extension type name. + :type extension_type_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: ExtensionType, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionType + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionType"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionTypeName': self._serialize.url("extension_type_name", extension_type_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('ExtensionType', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensionTypes/{extensionTypeName}'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_cluster_extension_types_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_cluster_extension_types_operations.py new file mode 100644 index 00000000000..3c3bf55c4ad --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_cluster_extension_types_operations.py @@ -0,0 +1,127 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class ClusterExtensionTypesOperations: + """ClusterExtensionTypesOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.ExtensionTypeList"]: + """Get Extension Types. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionTypeList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionTypeList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionTypeList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionTypeList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensionTypes'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_extension_type_versions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_extension_type_versions_operations.py new file mode 100644 index 00000000000..851eaef220c --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_extension_type_versions_operations.py @@ -0,0 +1,117 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionTypeVersionsOperations: + """ExtensionTypeVersionsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + location: str, + extension_type_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.ExtensionVersionList"]: + """List available versions for an Extension Type. + + :param location: extension location. + :type location: str + :param extension_type_name: Extension type name. + :type extension_type_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionVersionList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionVersionList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionVersionList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'location': self._serialize.url("location", location, 'str'), + 'extensionTypeName': self._serialize.url("extension_type_name", extension_type_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionVersionList', pipeline_response) + list_of_elem = deserialized.versions + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/providers/Microsoft.KubernetesConfiguration/locations/{location}/extensionTypes/{extensionTypeName}/versions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_extensions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_extensions_operations.py new file mode 100644 index 00000000000..c791c42c624 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_extensions_operations.py @@ -0,0 +1,645 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionsOperations: + """ExtensionsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def _create_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + extension: "_models.Extension", + **kwargs: Any + ) -> "_models.Extension": + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._create_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(extension, 'Extension') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('Extension', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _create_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def begin_create( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + extension: "_models.Extension", + **kwargs: Any + ) -> AsyncLROPoller["_models.Extension"]: + """Create a new Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param extension: Properties necessary to Create an Extension. + :type extension: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Extension + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either Extension or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Extension] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._create_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + extension=extension, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + **kwargs: Any + ) -> "_models.Extension": + """Gets Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: Extension, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Extension + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def _delete_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + force_delete: Optional[bool] = None, + **kwargs: Any + ) -> None: + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + if force_delete is not None: + query_parameters['forceDelete'] = self._serialize.query("force_delete", force_delete, 'bool') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 202, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def begin_delete( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + force_delete: Optional[bool] = None, + **kwargs: Any + ) -> AsyncLROPoller[None]: + """Delete a Kubernetes Cluster Extension. This will cause the Agent to Uninstall the extension + from the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param force_delete: Delete the extension resource in Azure - not the normal asynchronous + delete. + :type force_delete: bool + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + force_delete=force_delete, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def _update_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + patch_extension: "_models.PatchExtension", + **kwargs: Any + ) -> "_models.Extension": + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: lambda response: ResourceExistsError(response=response, model=self._deserialize(_models.ErrorResponse, response), error_format=ARMErrorFormat), + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._update_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(patch_extension, 'PatchExtension') + body_content_kwargs['content'] = body_content + request = self._client.patch(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _update_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + async def begin_update( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + patch_extension: "_models.PatchExtension", + **kwargs: Any + ) -> AsyncLROPoller["_models.Extension"]: + """Patch an existing Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param patch_extension: Properties to Patch in an existing Extension. + :type patch_extension: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.PatchExtension + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either Extension or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Extension] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._update_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + patch_extension=patch_extension, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.ExtensionsList"]: + """List all Extensions in the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionsList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionsList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionsList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionsList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_flux_config_operation_status_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_flux_config_operation_status_operations.py new file mode 100644 index 00000000000..bc1c6c9bc76 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_flux_config_operation_status_operations.py @@ -0,0 +1,118 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class FluxConfigOperationStatusOperations: + """FluxConfigOperationStatusOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + flux_configuration_name: str, + operation_id: str, + **kwargs: Any + ) -> "_models.OperationStatusResult": + """Get Async Operation status. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param flux_configuration_name: Name of the Flux Configuration. + :type flux_configuration_name: str + :param operation_id: operation Id. + :type operation_id: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: OperationStatusResult, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperationStatusResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusResult"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + 'operationId': self._serialize.url("operation_id", operation_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('OperationStatusResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}/operations/{operationId}'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_flux_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_flux_configurations_operations.py new file mode 100644 index 00000000000..73134513fb3 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_flux_configurations_operations.py @@ -0,0 +1,647 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class FluxConfigurationsOperations: + """FluxConfigurationsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + flux_configuration_name: str, + **kwargs: Any + ) -> "_models.FluxConfiguration": + """Gets details of the Flux Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param flux_configuration_name: Name of the Flux Configuration. + :type flux_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: FluxConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + async def _create_or_update_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + flux_configuration_name: str, + flux_configuration: "_models.FluxConfiguration", + **kwargs: Any + ) -> "_models.FluxConfiguration": + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfiguration"] + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: lambda response: ResourceExistsError(response=response, model=self._deserialize(_models.ErrorResponse, response), error_format=ARMErrorFormat), + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._create_or_update_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(flux_configuration, 'FluxConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _create_or_update_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + async def begin_create_or_update( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + flux_configuration_name: str, + flux_configuration: "_models.FluxConfiguration", + **kwargs: Any + ) -> AsyncLROPoller["_models.FluxConfiguration"]: + """Create a new Kubernetes Flux Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param flux_configuration_name: Name of the Flux Configuration. + :type flux_configuration_name: str + :param flux_configuration: Properties necessary to Create a FluxConfiguration. + :type flux_configuration: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either FluxConfiguration or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfiguration] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfiguration"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._create_or_update_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + flux_configuration_name=flux_configuration_name, + flux_configuration=flux_configuration, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + async def _update_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + flux_configuration_name: str, + flux_configuration_patch: "_models.FluxConfigurationPatch", + **kwargs: Any + ) -> "_models.FluxConfiguration": + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfiguration"] + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: lambda response: ResourceExistsError(response=response, model=self._deserialize(_models.ErrorResponse, response), error_format=ARMErrorFormat), + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._update_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(flux_configuration_patch, 'FluxConfigurationPatch') + body_content_kwargs['content'] = body_content + request = self._client.patch(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _update_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + async def begin_update( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + flux_configuration_name: str, + flux_configuration_patch: "_models.FluxConfigurationPatch", + **kwargs: Any + ) -> AsyncLROPoller["_models.FluxConfiguration"]: + """Update an existing Kubernetes Flux Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param flux_configuration_name: Name of the Flux Configuration. + :type flux_configuration_name: str + :param flux_configuration_patch: Properties to Patch in an existing Flux Configuration. + :type flux_configuration_patch: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfigurationPatch + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either FluxConfiguration or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfiguration] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfiguration"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._update_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + flux_configuration_name=flux_configuration_name, + flux_configuration_patch=flux_configuration_patch, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + async def _delete_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + flux_configuration_name: str, + force_delete: Optional[bool] = None, + **kwargs: Any + ) -> None: + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + if force_delete is not None: + query_parameters['forceDelete'] = self._serialize.query("force_delete", force_delete, 'bool') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 202, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + async def begin_delete( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + flux_configuration_name: str, + force_delete: Optional[bool] = None, + **kwargs: Any + ) -> AsyncLROPoller[None]: + """This will delete the YAML file used to set up the Flux Configuration, thus stopping future sync + from the source repo. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param flux_configuration_name: Name of the Flux Configuration. + :type flux_configuration_name: str + :param force_delete: Delete the extension resource in Azure - not the normal asynchronous + delete. + :type force_delete: bool + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + flux_configuration_name=flux_configuration_name, + force_delete=force_delete, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.FluxConfigurationsList"]: + """List all Flux Configurations. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either FluxConfigurationsList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfigurationsList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfigurationsList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('FluxConfigurationsList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_location_extension_types_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_location_extension_types_operations.py new file mode 100644 index 00000000000..a77c4936e7b --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_location_extension_types_operations.py @@ -0,0 +1,113 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class LocationExtensionTypesOperations: + """LocationExtensionTypesOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + location: str, + **kwargs: Any + ) -> AsyncIterable["_models.ExtensionTypeList"]: + """List all Extension Types. + + :param location: extension location. + :type location: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionTypeList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionTypeList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionTypeList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'location': self._serialize.url("location", location, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionTypeList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/providers/Microsoft.KubernetesConfiguration/locations/{location}/extensionTypes'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_operation_status_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_operation_status_operations.py new file mode 100644 index 00000000000..4369806defa --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_operation_status_operations.py @@ -0,0 +1,204 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class OperationStatusOperations: + """OperationStatusOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + extension_name: str, + operation_id: str, + **kwargs: Any + ) -> "_models.OperationStatusResult": + """Get Async Operation status. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param operation_id: operation Id. + :type operation_id: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: OperationStatusResult, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperationStatusResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusResult"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + 'operationId': self._serialize.url("operation_id", operation_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('OperationStatusResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}/operations/{operationId}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.OperationStatusList"]: + """List Async Operations, currently in progress, in a cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either OperationStatusList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperationStatusList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('OperationStatusList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_operations.py new file mode 100644 index 00000000000..a56f63e2787 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_operations.py @@ -0,0 +1,105 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.mgmt.core.exceptions import ARMErrorFormat + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class Operations: + """Operations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs: Any + ) -> AsyncIterable["_models.ResourceProviderOperationList"]: + """List all the available operations the KubernetesConfiguration resource provider supports. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..faf725104df --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/aio/operations/_source_control_configurations_operations.py @@ -0,0 +1,420 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +import warnings + +from azure.core.async_paging import AsyncItemPaged, AsyncList +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest +from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class SourceControlConfigurationsOperations: + """SourceControlConfigurationsOperations async operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer) -> None: + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + async def get( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def create_or_update( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + source_control_configuration: "_models.SourceControlConfiguration", + **kwargs: Any + ) -> "_models.SourceControlConfiguration": + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceControlConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create_or_update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def _delete_initial( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> None: + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + async def begin_delete( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + source_control_configuration_name: str, + **kwargs: Any + ) -> AsyncLROPoller[None]: + """This will delete the YAML file used to set up the Source control configuration, thus stopping + future sync from the source repo. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be AsyncARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of AsyncLROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, AsyncPollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + + if polling is True: polling_method = AsyncARMPolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = AsyncNoPolling() + else: polling_method = polling + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name: str, + cluster_rp: Union[str, "_models.Enum0"], + cluster_resource_name: Union[str, "_models.Enum1"], + cluster_name: str, + **kwargs: Any + ) -> AsyncIterable["_models.SourceControlConfigurationList"]: + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceControlConfigurationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + async def extract_data(pipeline_response): + deserialized = self._deserialize('SourceControlConfigurationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return AsyncItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/__init__.py new file mode 100644 index 00000000000..f69d190854a --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/__init__.py @@ -0,0 +1,169 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +try: + from ._models_py3 import ClusterScopeSettings + from ._models_py3 import ComplianceStatus + from ._models_py3 import DependsOnDefinition + from ._models_py3 import ErrorAdditionalInfo + from ._models_py3 import ErrorDetail + from ._models_py3 import ErrorResponse + from ._models_py3 import Extension + from ._models_py3 import ExtensionPropertiesAksAssignedIdentity + from ._models_py3 import ExtensionStatus + from ._models_py3 import ExtensionType + from ._models_py3 import ExtensionTypeList + from ._models_py3 import ExtensionVersionList + from ._models_py3 import ExtensionVersionListVersionsItem + from ._models_py3 import ExtensionsList + from ._models_py3 import FluxConfiguration + from ._models_py3 import FluxConfigurationPatch + from ._models_py3 import FluxConfigurationsList + from ._models_py3 import GitRepositoryDefinition + from ._models_py3 import HelmOperatorProperties + from ._models_py3 import HelmReleasePropertiesDefinition + from ._models_py3 import Identity + from ._models_py3 import KustomizationDefinition + from ._models_py3 import ObjectReferenceDefinition + from ._models_py3 import ObjectStatusConditionDefinition + from ._models_py3 import ObjectStatusDefinition + from ._models_py3 import OperationStatusList + from ._models_py3 import OperationStatusResult + from ._models_py3 import PatchExtension + from ._models_py3 import ProxyResource + from ._models_py3 import RepositoryRefDefinition + from ._models_py3 import Resource + from ._models_py3 import ResourceProviderOperation + from ._models_py3 import ResourceProviderOperationDisplay + from ._models_py3 import ResourceProviderOperationList + from ._models_py3 import Scope + from ._models_py3 import ScopeCluster + from ._models_py3 import ScopeNamespace + from ._models_py3 import SourceControlConfiguration + from ._models_py3 import SourceControlConfigurationList + from ._models_py3 import SupportedScopes + from ._models_py3 import SystemData +except (SyntaxError, ImportError): + from ._models import ClusterScopeSettings # type: ignore + from ._models import ComplianceStatus # type: ignore + from ._models import DependsOnDefinition # type: ignore + from ._models import ErrorAdditionalInfo # type: ignore + from ._models import ErrorDetail # type: ignore + from ._models import ErrorResponse # type: ignore + from ._models import Extension # type: ignore + from ._models import ExtensionPropertiesAksAssignedIdentity # type: ignore + from ._models import ExtensionStatus # type: ignore + from ._models import ExtensionType # type: ignore + from ._models import ExtensionTypeList # type: ignore + from ._models import ExtensionVersionList # type: ignore + from ._models import ExtensionVersionListVersionsItem # type: ignore + from ._models import ExtensionsList # type: ignore + from ._models import FluxConfiguration # type: ignore + from ._models import FluxConfigurationPatch # type: ignore + from ._models import FluxConfigurationsList # type: ignore + from ._models import GitRepositoryDefinition # type: ignore + from ._models import HelmOperatorProperties # type: ignore + from ._models import HelmReleasePropertiesDefinition # type: ignore + from ._models import Identity # type: ignore + from ._models import KustomizationDefinition # type: ignore + from ._models import ObjectReferenceDefinition # type: ignore + from ._models import ObjectStatusConditionDefinition # type: ignore + from ._models import ObjectStatusDefinition # type: ignore + from ._models import OperationStatusList # type: ignore + from ._models import OperationStatusResult # type: ignore + from ._models import PatchExtension # type: ignore + from ._models import ProxyResource # type: ignore + from ._models import RepositoryRefDefinition # type: ignore + from ._models import Resource # type: ignore + from ._models import ResourceProviderOperation # type: ignore + from ._models import ResourceProviderOperationDisplay # type: ignore + from ._models import ResourceProviderOperationList # type: ignore + from ._models import Scope # type: ignore + from ._models import ScopeCluster # type: ignore + from ._models import ScopeNamespace # type: ignore + from ._models import SourceControlConfiguration # type: ignore + from ._models import SourceControlConfigurationList # type: ignore + from ._models import SupportedScopes # type: ignore + from ._models import SystemData # type: ignore + +from ._source_control_configuration_client_enums import ( + ClusterTypes, + ComplianceStateType, + CreatedByType, + Enum0, + Enum1, + FluxComplianceState, + KustomizationValidationType, + LevelType, + MessageLevelType, + OperatorScopeType, + OperatorType, + ProvisioningState, + ProvisioningStateType, + ScopeType, + SourceKindType, +) + +__all__ = [ + 'ClusterScopeSettings', + 'ComplianceStatus', + 'DependsOnDefinition', + 'ErrorAdditionalInfo', + 'ErrorDetail', + 'ErrorResponse', + 'Extension', + 'ExtensionPropertiesAksAssignedIdentity', + 'ExtensionStatus', + 'ExtensionType', + 'ExtensionTypeList', + 'ExtensionVersionList', + 'ExtensionVersionListVersionsItem', + 'ExtensionsList', + 'FluxConfiguration', + 'FluxConfigurationPatch', + 'FluxConfigurationsList', + 'GitRepositoryDefinition', + 'HelmOperatorProperties', + 'HelmReleasePropertiesDefinition', + 'Identity', + 'KustomizationDefinition', + 'ObjectReferenceDefinition', + 'ObjectStatusConditionDefinition', + 'ObjectStatusDefinition', + 'OperationStatusList', + 'OperationStatusResult', + 'PatchExtension', + 'ProxyResource', + 'RepositoryRefDefinition', + 'Resource', + 'ResourceProviderOperation', + 'ResourceProviderOperationDisplay', + 'ResourceProviderOperationList', + 'Scope', + 'ScopeCluster', + 'ScopeNamespace', + 'SourceControlConfiguration', + 'SourceControlConfigurationList', + 'SupportedScopes', + 'SystemData', + 'ClusterTypes', + 'ComplianceStateType', + 'CreatedByType', + 'Enum0', + 'Enum1', + 'FluxComplianceState', + 'KustomizationValidationType', + 'LevelType', + 'MessageLevelType', + 'OperatorScopeType', + 'OperatorType', + 'ProvisioningState', + 'ProvisioningStateType', + 'ScopeType', + 'SourceKindType', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_models.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_models.py new file mode 100644 index 00000000000..da4621b7737 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_models.py @@ -0,0 +1,1637 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from azure.core.exceptions import HttpResponseError +import msrest.serialization + + +class Resource(msrest.serialization.Model): + """Common fields that are returned in the response for all Azure Resource Manager resources. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class ProxyResource(Resource): + """The resource model definition for a Azure Resource Manager proxy resource. It will not have tags and a location. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ProxyResource, self).__init__(**kwargs) + + +class ClusterScopeSettings(ProxyResource): + """Extension scope settings. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :param allow_multiple_instances: Describes if multiple instances of the extension are allowed. + :type allow_multiple_instances: bool + :param default_release_namespace: Default extension release namespace. + :type default_release_namespace: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'allow_multiple_instances': {'key': 'properties.allowMultipleInstances', 'type': 'bool'}, + 'default_release_namespace': {'key': 'properties.defaultReleaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ClusterScopeSettings, self).__init__(**kwargs) + self.allow_multiple_instances = kwargs.get('allow_multiple_instances', None) + self.default_release_namespace = kwargs.get('default_release_namespace', None) + + +class ComplianceStatus(msrest.serialization.Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar compliance_state: The compliance state of the configuration. Possible values include: + "Pending", "Compliant", "Noncompliant", "Installed", "Failed". + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: ~datetime.datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: "Error", "Warning", + "Information". + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = kwargs.get('last_config_applied', None) + self.message = kwargs.get('message', None) + self.message_level = kwargs.get('message_level', None) + + +class DependsOnDefinition(msrest.serialization.Model): + """Specify which kustomizations must succeed reconciliation on the cluster prior to reconciling this kustomization. + + :param kustomization_name: Name of the kustomization to claim dependency on. + :type kustomization_name: str + """ + + _attribute_map = { + 'kustomization_name': {'key': 'kustomizationName', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(DependsOnDefinition, self).__init__(**kwargs) + self.kustomization_name = kwargs.get('kustomization_name', None) + + +class ErrorAdditionalInfo(msrest.serialization.Model): + """The resource management error additional info. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar type: The additional info type. + :vartype type: str + :ivar info: The additional info. + :vartype info: any + """ + + _validation = { + 'type': {'readonly': True}, + 'info': {'readonly': True}, + } + + _attribute_map = { + 'type': {'key': 'type', 'type': 'str'}, + 'info': {'key': 'info', 'type': 'object'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorAdditionalInfo, self).__init__(**kwargs) + self.type = None + self.info = None + + +class ErrorDetail(msrest.serialization.Model): + """The error detail. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar code: The error code. + :vartype code: str + :ivar message: The error message. + :vartype message: str + :ivar target: The error target. + :vartype target: str + :ivar details: The error details. + :vartype details: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ErrorDetail] + :ivar additional_info: The error additional info. + :vartype additional_info: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ErrorAdditionalInfo] + """ + + _validation = { + 'code': {'readonly': True}, + 'message': {'readonly': True}, + 'target': {'readonly': True}, + 'details': {'readonly': True}, + 'additional_info': {'readonly': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'target': {'key': 'target', 'type': 'str'}, + 'details': {'key': 'details', 'type': '[ErrorDetail]'}, + 'additional_info': {'key': 'additionalInfo', 'type': '[ErrorAdditionalInfo]'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorDetail, self).__init__(**kwargs) + self.code = None + self.message = None + self.target = None + self.details = None + self.additional_info = None + + +class ErrorResponse(msrest.serialization.Model): + """Common error response for all Azure Resource Manager APIs to return error details for failed operations. (This also follows the OData error response format.). + + :param error: The error object. + :type error: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ErrorDetail + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorResponse, self).__init__(**kwargs) + self.error = kwargs.get('error', None) + + +class Extension(ProxyResource): + """The Extension object. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :param identity: Identity of the Extension resource. + :type identity: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Identity + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SystemData + :param extension_type: Type of the Extension, of which this resource is an instance of. It + must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the + Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this extension participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension participates in for auto-upgrade (e.g. + Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension, if it is 'pinned' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param scope: Scope at which the extension is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this extension. + :type configuration_protected_settings: dict[str, str] + :ivar provisioning_state: Status of installation of this extension. Possible values include: + "Succeeded", "Failed", "Canceled", "Creating", "Updating", "Deleting". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ProvisioningState + :param statuses: Status from this extension. + :type statuses: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionStatus] + :ivar error_info: Error information from the Agent - e.g. errors during installation. + :vartype error_info: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ErrorDetail + :ivar custom_location_settings: Custom Location settings properties. + :vartype custom_location_settings: dict[str, str] + :ivar package_uri: Uri of the Helm package. + :vartype package_uri: str + :param aks_assigned_identity: Identity of the Extension resource in an AKS cluster. + :type aks_assigned_identity: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionPropertiesAksAssignedIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'error_info': {'readonly': True}, + 'custom_location_settings': {'readonly': True}, + 'package_uri': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'identity': {'key': 'identity', 'type': 'Identity'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDetail'}, + 'custom_location_settings': {'key': 'properties.customLocationSettings', 'type': '{str}'}, + 'package_uri': {'key': 'properties.packageUri', 'type': 'str'}, + 'aks_assigned_identity': {'key': 'properties.aksAssignedIdentity', 'type': 'ExtensionPropertiesAksAssignedIdentity'}, + } + + def __init__( + self, + **kwargs + ): + super(Extension, self).__init__(**kwargs) + self.identity = kwargs.get('identity', None) + self.system_data = None + self.extension_type = kwargs.get('extension_type', None) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', True) + self.release_train = kwargs.get('release_train', "Stable") + self.version = kwargs.get('version', None) + self.scope = kwargs.get('scope', None) + self.configuration_settings = kwargs.get('configuration_settings', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.provisioning_state = None + self.statuses = kwargs.get('statuses', None) + self.error_info = None + self.custom_location_settings = None + self.package_uri = None + self.aks_assigned_identity = kwargs.get('aks_assigned_identity', None) + + +class ExtensionPropertiesAksAssignedIdentity(msrest.serialization.Model): + """Identity of the Extension resource in an AKS cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal ID of resource identity. + :vartype principal_id: str + :ivar tenant_id: The tenant ID of resource. + :vartype tenant_id: str + :param type: The identity type. The only acceptable values to pass in are None and + "SystemAssigned". The default value is None. + :type type: str + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionPropertiesAksAssignedIdentity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = kwargs.get('type', None) + + +class ExtensionsList(msrest.serialization.Model): + """Result of the request to list Extensions. It contains a list of Extension objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Extensions within a Kubernetes cluster. + :vartype value: list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Extension] + :ivar next_link: URL to get the next set of extension objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[Extension]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionsList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class ExtensionStatus(msrest.serialization.Model): + """Status from the extension. + + :param code: Status code provided by the Extension. + :type code: str + :param display_status: Short description of status of the extension. + :type display_status: str + :param level: Level of the status. Possible values include: "Error", "Warning", "Information". + Default value: "Information". + :type level: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.LevelType + :param message: Detailed message of the status from the Extension. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionStatus, self).__init__(**kwargs) + self.code = kwargs.get('code', None) + self.display_status = kwargs.get('display_status', None) + self.level = kwargs.get('level', "Information") + self.message = kwargs.get('message', None) + self.time = kwargs.get('time', None) + + +class ExtensionType(msrest.serialization.Model): + """Represents an Extension Type. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar system_data: Metadata pertaining to creation and last modification of the resource. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SystemData + :ivar release_trains: Extension release train: preview or stable. + :vartype release_trains: list[str] + :ivar cluster_types: Cluster types. Possible values include: "connectedClusters", + "managedClusters". + :vartype cluster_types: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ClusterTypes + :ivar supported_scopes: Extension scopes. + :vartype supported_scopes: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SupportedScopes + """ + + _validation = { + 'system_data': {'readonly': True}, + 'release_trains': {'readonly': True}, + 'cluster_types': {'readonly': True}, + 'supported_scopes': {'readonly': True}, + } + + _attribute_map = { + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'release_trains': {'key': 'properties.releaseTrains', 'type': '[str]'}, + 'cluster_types': {'key': 'properties.clusterTypes', 'type': 'str'}, + 'supported_scopes': {'key': 'properties.supportedScopes', 'type': 'SupportedScopes'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionType, self).__init__(**kwargs) + self.system_data = None + self.release_trains = None + self.cluster_types = None + self.supported_scopes = None + + +class ExtensionTypeList(msrest.serialization.Model): + """List Extension Types. + + :param value: The list of Extension Types. + :type value: list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionType] + :param next_link: The link to fetch the next page of Extension Types. + :type next_link: str + """ + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ExtensionType]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionTypeList, self).__init__(**kwargs) + self.value = kwargs.get('value', None) + self.next_link = kwargs.get('next_link', None) + + +class ExtensionVersionList(msrest.serialization.Model): + """List versions for an Extension. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param versions: Versions available for this Extension Type. + :type versions: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionVersionListVersionsItem] + :param next_link: The link to fetch the next page of Extension Types. + :type next_link: str + :ivar system_data: Metadata pertaining to creation and last modification of the resource. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SystemData + """ + + _validation = { + 'system_data': {'readonly': True}, + } + + _attribute_map = { + 'versions': {'key': 'versions', 'type': '[ExtensionVersionListVersionsItem]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionVersionList, self).__init__(**kwargs) + self.versions = kwargs.get('versions', None) + self.next_link = kwargs.get('next_link', None) + self.system_data = None + + +class ExtensionVersionListVersionsItem(msrest.serialization.Model): + """ExtensionVersionListVersionsItem. + + :param release_train: The release train for this Extension Type. + :type release_train: str + :param versions: Versions available for this Extension Type and release train. + :type versions: list[str] + """ + + _attribute_map = { + 'release_train': {'key': 'releaseTrain', 'type': 'str'}, + 'versions': {'key': 'versions', 'type': '[str]'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionVersionListVersionsItem, self).__init__(**kwargs) + self.release_train = kwargs.get('release_train', None) + self.versions = kwargs.get('versions', None) + + +class FluxConfiguration(ProxyResource): + """The Flux Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SystemData + :param scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". + :type scope: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ScopeType + :param namespace: The namespace to which this configuration is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. + :type namespace: str + :param source_kind: Source Kind to pull the configuration data from. Possible values include: + "GitRepository". + :type source_kind: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceKindType + :param suspend: Whether this configuration should suspend its reconciliation of its + kustomizations and sources. + :type suspend: bool + :param git_repository: Parameters to reconcile to the GitRepository source kind type. + :type git_repository: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.GitRepositoryDefinition + :param kustomizations: Array of kustomizations used to reconcile the artifact pulled by the + source type on the cluster. + :type kustomizations: dict[str, + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.KustomizationDefinition] + :param configuration_protected_settings: Key-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + :ivar statuses: Statuses of the Flux Kubernetes resources created by the fluxConfiguration or + created by the managed objects provisioned by the fluxConfiguration. + :vartype statuses: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ObjectStatusDefinition] + :ivar repository_public_key: Public Key associated with this fluxConfiguration (either + generated within the cluster or provided by the user). + :vartype repository_public_key: str + :ivar last_source_synced_commit_id: Branch and SHA of the last source commit synced with the + cluster. + :vartype last_source_synced_commit_id: str + :ivar last_source_synced_at: Datetime the fluxConfiguration last synced its source on the + cluster. + :vartype last_source_synced_at: ~datetime.datetime + :ivar compliance_state: Combined status of the Flux Kubernetes resources created by the + fluxConfiguration or created by the managed objects. Possible values include: "Compliant", + "Non-Compliant", "Pending", "Suspended", "Unknown". Default value: "Unknown". + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxComplianceState + :ivar provisioning_state: Status of the creation of the fluxConfiguration. Possible values + include: "Succeeded", "Failed", "Canceled", "Creating", "Updating", "Deleting". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ProvisioningState + :ivar error_message: Error message returned to the user in the case of provisioning failure. + :vartype error_message: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'statuses': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'last_source_synced_commit_id': {'readonly': True}, + 'last_source_synced_at': {'readonly': True}, + 'compliance_state': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'error_message': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'scope': {'key': 'properties.scope', 'type': 'str'}, + 'namespace': {'key': 'properties.namespace', 'type': 'str'}, + 'source_kind': {'key': 'properties.sourceKind', 'type': 'str'}, + 'suspend': {'key': 'properties.suspend', 'type': 'bool'}, + 'git_repository': {'key': 'properties.gitRepository', 'type': 'GitRepositoryDefinition'}, + 'kustomizations': {'key': 'properties.kustomizations', 'type': '{KustomizationDefinition}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ObjectStatusDefinition]'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'last_source_synced_commit_id': {'key': 'properties.lastSourceSyncedCommitId', 'type': 'str'}, + 'last_source_synced_at': {'key': 'properties.lastSourceSyncedAt', 'type': 'iso-8601'}, + 'compliance_state': {'key': 'properties.complianceState', 'type': 'str'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'error_message': {'key': 'properties.errorMessage', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(FluxConfiguration, self).__init__(**kwargs) + self.system_data = None + self.scope = kwargs.get('scope', "cluster") + self.namespace = kwargs.get('namespace', "default") + self.source_kind = kwargs.get('source_kind', None) + self.suspend = kwargs.get('suspend', False) + self.git_repository = kwargs.get('git_repository', None) + self.kustomizations = kwargs.get('kustomizations', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.statuses = None + self.repository_public_key = None + self.last_source_synced_commit_id = None + self.last_source_synced_at = None + self.compliance_state = None + self.provisioning_state = None + self.error_message = None + + +class FluxConfigurationPatch(msrest.serialization.Model): + """The Flux Configuration Patch Request object. + + :param source_kind: Source Kind to pull the configuration data from. Possible values include: + "GitRepository". + :type source_kind: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceKindType + :param suspend: Whether this configuration should suspend its reconciliation of its + kustomizations and sources. + :type suspend: bool + :param git_repository: Parameters to reconcile to the GitRepository source kind type. + :type git_repository: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.GitRepositoryDefinition + :param kustomizations: Array of kustomizations used to reconcile the artifact pulled by the + source type on the cluster. + :type kustomizations: dict[str, + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.KustomizationDefinition] + :param configuration_protected_settings: Key-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + """ + + _attribute_map = { + 'source_kind': {'key': 'properties.sourceKind', 'type': 'str'}, + 'suspend': {'key': 'properties.suspend', 'type': 'bool'}, + 'git_repository': {'key': 'properties.gitRepository', 'type': 'GitRepositoryDefinition'}, + 'kustomizations': {'key': 'properties.kustomizations', 'type': '{KustomizationDefinition}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + } + + def __init__( + self, + **kwargs + ): + super(FluxConfigurationPatch, self).__init__(**kwargs) + self.source_kind = kwargs.get('source_kind', None) + self.suspend = kwargs.get('suspend', None) + self.git_repository = kwargs.get('git_repository', None) + self.kustomizations = kwargs.get('kustomizations', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + + +class FluxConfigurationsList(msrest.serialization.Model): + """Result of the request to list Flux Configurations. It contains a list of FluxConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Flux Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[FluxConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(FluxConfigurationsList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class GitRepositoryDefinition(msrest.serialization.Model): + """Parameters to reconcile to the GitRepository source kind type. + + :param url: The URL to sync for the flux configuration git repository. + :type url: str + :param timeout_in_seconds: The maximum time to attempt to reconcile the cluster git repository + source with the remote. + :type timeout_in_seconds: long + :param sync_interval_in_seconds: The interval at which to re-reconcile the cluster git + repository source with the remote. + :type sync_interval_in_seconds: long + :param repository_ref: The source reference for the GitRepository object. + :type repository_ref: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.RepositoryRefDefinition + :param ssh_known_hosts: Base64-encoded known_hosts value containing public SSH keys required to + access private git repositories over SSH. + :type ssh_known_hosts: str + :param https_user: Base64-encoded HTTPS username used to access private git repositories over + HTTPS. + :type https_user: str + :param https_ca_file: Base64-encoded HTTPS certificate authority contents used to access git + private git repositories over HTTPS. + :type https_ca_file: str + :param local_auth_ref: Name of a local secret on the Kubernetes cluster to use as the + authentication secret rather than the managed or user-provided configuration secrets. + :type local_auth_ref: str + """ + + _attribute_map = { + 'url': {'key': 'url', 'type': 'str'}, + 'timeout_in_seconds': {'key': 'timeoutInSeconds', 'type': 'long'}, + 'sync_interval_in_seconds': {'key': 'syncIntervalInSeconds', 'type': 'long'}, + 'repository_ref': {'key': 'repositoryRef', 'type': 'RepositoryRefDefinition'}, + 'ssh_known_hosts': {'key': 'sshKnownHosts', 'type': 'str'}, + 'https_user': {'key': 'httpsUser', 'type': 'str'}, + 'https_ca_file': {'key': 'httpsCAFile', 'type': 'str'}, + 'local_auth_ref': {'key': 'localAuthRef', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(GitRepositoryDefinition, self).__init__(**kwargs) + self.url = kwargs.get('url', None) + self.timeout_in_seconds = kwargs.get('timeout_in_seconds', 600) + self.sync_interval_in_seconds = kwargs.get('sync_interval_in_seconds', 600) + self.repository_ref = kwargs.get('repository_ref', None) + self.ssh_known_hosts = kwargs.get('ssh_known_hosts', None) + self.https_user = kwargs.get('https_user', None) + self.https_ca_file = kwargs.get('https_ca_file', None) + self.local_auth_ref = kwargs.get('local_auth_ref', None) + + +class HelmOperatorProperties(msrest.serialization.Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = kwargs.get('chart_version', None) + self.chart_values = kwargs.get('chart_values', None) + + +class HelmReleasePropertiesDefinition(msrest.serialization.Model): + """HelmReleasePropertiesDefinition. + + :param last_revision_applied: The revision number of the last released object change. + :type last_revision_applied: long + :param helm_chart_ref: The reference to the HelmChart object used as the source to this + HelmRelease. + :type helm_chart_ref: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ObjectReferenceDefinition + :param failure_count: Total number of times that the HelmRelease failed to install or upgrade. + :type failure_count: long + :param install_failure_count: Number of times that the HelmRelease failed to install. + :type install_failure_count: long + :param upgrade_failure_count: Number of times that the HelmRelease failed to upgrade. + :type upgrade_failure_count: long + """ + + _attribute_map = { + 'last_revision_applied': {'key': 'lastRevisionApplied', 'type': 'long'}, + 'helm_chart_ref': {'key': 'helmChartRef', 'type': 'ObjectReferenceDefinition'}, + 'failure_count': {'key': 'failureCount', 'type': 'long'}, + 'install_failure_count': {'key': 'installFailureCount', 'type': 'long'}, + 'upgrade_failure_count': {'key': 'upgradeFailureCount', 'type': 'long'}, + } + + def __init__( + self, + **kwargs + ): + super(HelmReleasePropertiesDefinition, self).__init__(**kwargs) + self.last_revision_applied = kwargs.get('last_revision_applied', None) + self.helm_chart_ref = kwargs.get('helm_chart_ref', None) + self.failure_count = kwargs.get('failure_count', None) + self.install_failure_count = kwargs.get('install_failure_count', None) + self.upgrade_failure_count = kwargs.get('upgrade_failure_count', None) + + +class Identity(msrest.serialization.Model): + """Identity for the resource. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal ID of resource identity. + :vartype principal_id: str + :ivar tenant_id: The tenant ID of resource. + :vartype tenant_id: str + :param type: The identity type. The only acceptable values to pass in are None and + "SystemAssigned". The default value is None. + :type type: str + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Identity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = kwargs.get('type', None) + + +class KustomizationDefinition(msrest.serialization.Model): + """The Kustomization defining how to reconcile the artifact pulled by the source type on the cluster. + + :param path: The path in the source reference to reconcile on the cluster. + :type path: str + :param depends_on: Specifies other Kustomizations that this Kustomization depends on. This + Kustomization will not reconcile until all dependencies have completed their reconciliation. + :type depends_on: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.DependsOnDefinition] + :param timeout_in_seconds: The maximum time to attempt to reconcile the Kustomization on the + cluster. + :type timeout_in_seconds: long + :param sync_interval_in_seconds: The interval at which to re-reconcile the Kustomization on the + cluster. + :type sync_interval_in_seconds: long + :param retry_interval_in_seconds: The interval at which to re-reconcile the Kustomization on + the cluster in the event of failure on reconciliation. + :type retry_interval_in_seconds: long + :param prune: Enable/disable garbage collections of Kubernetes objects created by this + Kustomization. + :type prune: bool + :param validation: Specify whether to validate the Kubernetes objects referenced in the + Kustomization before applying them to the cluster. Possible values include: "none", "client", + "server". Default value: "none". + :type validation: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.KustomizationValidationType + :param force: Enable/disable re-creating Kubernetes resources on the cluster when patching + fails due to an immutable field change. + :type force: bool + """ + + _attribute_map = { + 'path': {'key': 'path', 'type': 'str'}, + 'depends_on': {'key': 'dependsOn', 'type': '[DependsOnDefinition]'}, + 'timeout_in_seconds': {'key': 'timeoutInSeconds', 'type': 'long'}, + 'sync_interval_in_seconds': {'key': 'syncIntervalInSeconds', 'type': 'long'}, + 'retry_interval_in_seconds': {'key': 'retryIntervalInSeconds', 'type': 'long'}, + 'prune': {'key': 'prune', 'type': 'bool'}, + 'force': {'key': 'force', 'type': 'bool'}, + } + + def __init__( + self, + **kwargs + ): + super(KustomizationDefinition, self).__init__(**kwargs) + self.path = kwargs.get('path', "") + self.depends_on = kwargs.get('depends_on', None) + self.timeout_in_seconds = kwargs.get('timeout_in_seconds', 600) + self.sync_interval_in_seconds = kwargs.get('sync_interval_in_seconds', 600) + self.retry_interval_in_seconds = kwargs.get('retry_interval_in_seconds', None) + self.prune = kwargs.get('prune', None) + self.force = kwargs.get('force', None) + + +class ObjectReferenceDefinition(msrest.serialization.Model): + """Object reference to a Kubernetes object on a cluster. + + :param name: Name of the object. + :type name: str + :param namespace: Namespace of the object. + :type namespace: str + """ + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'namespace': {'key': 'namespace', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ObjectReferenceDefinition, self).__init__(**kwargs) + self.name = kwargs.get('name', None) + self.namespace = kwargs.get('namespace', None) + + +class ObjectStatusConditionDefinition(msrest.serialization.Model): + """Status condition of Kubernetes object. + + :param last_transition_time: Last time this status condition has changed. + :type last_transition_time: ~datetime.datetime + :param message: A more verbose description of the object status condition. + :type message: str + :param reason: Reason for the specified status condition type status. + :type reason: str + :param status: Status of the Kubernetes object condition type. + :type status: str + :param type: Object status condition type for this object. + :type type: str + """ + + _attribute_map = { + 'last_transition_time': {'key': 'lastTransitionTime', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'reason': {'key': 'reason', 'type': 'str'}, + 'status': {'key': 'status', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ObjectStatusConditionDefinition, self).__init__(**kwargs) + self.last_transition_time = kwargs.get('last_transition_time', None) + self.message = kwargs.get('message', None) + self.reason = kwargs.get('reason', None) + self.status = kwargs.get('status', None) + self.type = kwargs.get('type', None) + + +class ObjectStatusDefinition(msrest.serialization.Model): + """Statuses of objects deployed by the user-specified kustomizations from the git repository. + + :param name: Name of the applied object. + :type name: str + :param namespace: Namespace of the applied object. + :type namespace: str + :param kind: Kind of the applied object. + :type kind: str + :param compliance_state: Compliance state of the applied object showing whether the applied + object has come into a ready state on the cluster. Possible values include: "Compliant", + "Non-Compliant", "Pending", "Suspended", "Unknown". Default value: "Unknown". + :type compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxComplianceState + :param applied_by: Object reference to the Kustomization that applied this object. + :type applied_by: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ObjectReferenceDefinition + :param status_conditions: List of Kubernetes object status conditions present on the cluster. + :type status_conditions: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ObjectStatusConditionDefinition] + :param helm_release_properties: Additional properties that are provided from objects of the + HelmRelease kind. + :type helm_release_properties: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.HelmReleasePropertiesDefinition + """ + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'namespace': {'key': 'namespace', 'type': 'str'}, + 'kind': {'key': 'kind', 'type': 'str'}, + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'applied_by': {'key': 'appliedBy', 'type': 'ObjectReferenceDefinition'}, + 'status_conditions': {'key': 'statusConditions', 'type': '[ObjectStatusConditionDefinition]'}, + 'helm_release_properties': {'key': 'helmReleaseProperties', 'type': 'HelmReleasePropertiesDefinition'}, + } + + def __init__( + self, + **kwargs + ): + super(ObjectStatusDefinition, self).__init__(**kwargs) + self.name = kwargs.get('name', None) + self.namespace = kwargs.get('namespace', None) + self.kind = kwargs.get('kind', None) + self.compliance_state = kwargs.get('compliance_state', "Unknown") + self.applied_by = kwargs.get('applied_by', None) + self.status_conditions = kwargs.get('status_conditions', None) + self.helm_release_properties = kwargs.get('helm_release_properties', None) + + +class OperationStatusList(msrest.serialization.Model): + """The async operations in progress, in the cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of async operations in progress, in the cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperationStatusResult] + :ivar next_link: URL to get the next set of Operation Result objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[OperationStatusResult]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(OperationStatusList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class OperationStatusResult(msrest.serialization.Model): + """The current status of an async operation. + + Variables are only populated by the server, and will be ignored when sending a request. + + All required parameters must be populated in order to send to Azure. + + :param id: Fully qualified ID for the async operation. + :type id: str + :param name: Name of the async operation. + :type name: str + :param status: Required. Operation status. + :type status: str + :param properties: Additional information, if available. + :type properties: dict[str, str] + :ivar error: If present, details of the operation error. + :vartype error: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ErrorDetail + """ + + _validation = { + 'status': {'required': True}, + 'error': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'status': {'key': 'status', 'type': 'str'}, + 'properties': {'key': 'properties', 'type': '{str}'}, + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + **kwargs + ): + super(OperationStatusResult, self).__init__(**kwargs) + self.id = kwargs.get('id', None) + self.name = kwargs.get('name', None) + self.status = kwargs['status'] + self.properties = kwargs.get('properties', None) + self.error = None + + +class PatchExtension(msrest.serialization.Model): + """The Extension Patch Request object. + + :param auto_upgrade_minor_version: Flag to note if this extension participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension participates in for auto-upgrade (e.g. + Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension, if it is 'pinned' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this extension. + :type configuration_protected_settings: dict[str, str] + """ + + _attribute_map = { + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + } + + def __init__( + self, + **kwargs + ): + super(PatchExtension, self).__init__(**kwargs) + self.auto_upgrade_minor_version = kwargs.get('auto_upgrade_minor_version', True) + self.release_train = kwargs.get('release_train', "Stable") + self.version = kwargs.get('version', None) + self.configuration_settings = kwargs.get('configuration_settings', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + + +class RepositoryRefDefinition(msrest.serialization.Model): + """The source reference for the GitRepository object. + + :param branch: The git repository branch name to checkout. + :type branch: str + :param tag: The git repository tag name to checkout. This takes precedence over branch. + :type tag: str + :param semver: The semver range used to match against git repository tags. This takes + precedence over tag. + :type semver: str + :param commit: The commit SHA to checkout. This value must be combined with the branch name to + be valid. This takes precedence over semver. + :type commit: str + """ + + _attribute_map = { + 'branch': {'key': 'branch', 'type': 'str'}, + 'tag': {'key': 'tag', 'type': 'str'}, + 'semver': {'key': 'semver', 'type': 'str'}, + 'commit': {'key': 'commit', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(RepositoryRefDefinition, self).__init__(**kwargs) + self.branch = kwargs.get('branch', None) + self.tag = kwargs.get('tag', None) + self.semver = kwargs.get('semver', None) + self.commit = kwargs.get('commit', None) + + +class ResourceProviderOperation(msrest.serialization.Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param name: Operation name, in format of {provider}/{resource}/{operation}. + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. + :vartype is_data_action: bool + :ivar origin: Origin of the operation. + :vartype origin: str + """ + + _validation = { + 'is_data_action': {'readonly': True}, + 'origin': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + 'origin': {'key': 'origin', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = kwargs.get('name', None) + self.display = kwargs.get('display', None) + self.is_data_action = None + self.origin = None + + +class ResourceProviderOperationDisplay(msrest.serialization.Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = kwargs.get('provider', None) + self.resource = kwargs.get('resource', None) + self.operation = kwargs.get('operation', None) + self.description = kwargs.get('description', None) + + +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = kwargs.get('value', None) + self.next_link = None + + +class Scope(msrest.serialization.Model): + """Scope of the extension. It can be either Cluster or Namespace; but not both. + + :param cluster: Specifies that the scope of the extension is Cluster. + :type cluster: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ScopeCluster + :param namespace: Specifies that the scope of the extension is Namespace. + :type namespace: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__( + self, + **kwargs + ): + super(Scope, self).__init__(**kwargs) + self.cluster = kwargs.get('cluster', None) + self.namespace = kwargs.get('namespace', None) + + +class ScopeCluster(msrest.serialization.Model): + """Specifies that the scope of the extension is Cluster. + + :param release_namespace: Namespace where the extension Release must be placed, for a Cluster + scoped extension. If this namespace does not exist, it will be created. + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = kwargs.get('release_namespace', None) + + +class ScopeNamespace(msrest.serialization.Model): + """Specifies that the scope of the extension is Namespace. + + :param target_namespace: Namespace where the extension will be created for an Namespace scoped + extension. If this namespace does not exist, it will be created. + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = kwargs.get('target_namespace', None) + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying the specific + configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: "Flux". + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl configuration + (either generated within the cluster or provided by the user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents containing public SSH keys + required to access private Git instances. + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. Possible values + include: "Accepted", "Deleting", "Running", "Succeeded", "Failed". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration. + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfiguration, self).__init__(**kwargs) + self.system_data = None + self.repository_url = kwargs.get('repository_url', None) + self.operator_namespace = kwargs.get('operator_namespace', "default") + self.operator_instance_name = kwargs.get('operator_instance_name', None) + self.operator_type = kwargs.get('operator_type', None) + self.operator_params = kwargs.get('operator_params', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.operator_scope = kwargs.get('operator_scope', "cluster") + self.repository_public_key = None + self.ssh_known_hosts_contents = kwargs.get('ssh_known_hosts_contents', None) + self.enable_helm_operator = kwargs.get('enable_helm_operator', None) + self.helm_operator_properties = kwargs.get('helm_operator_properties', None) + self.provisioning_state = None + self.compliance_status = None + + +class SourceControlConfigurationList(msrest.serialization.Model): + """Result of the request to list Source Control Configurations. It contains a list of SourceControlConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Source Control Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceControlConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SourceControlConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfigurationList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class SupportedScopes(msrest.serialization.Model): + """Extension scopes. + + :param default_scope: Default extension scopes: cluster or namespace. + :type default_scope: str + :param cluster_scope_settings: Scope settings. + :type cluster_scope_settings: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ClusterScopeSettings + """ + + _attribute_map = { + 'default_scope': {'key': 'defaultScope', 'type': 'str'}, + 'cluster_scope_settings': {'key': 'clusterScopeSettings', 'type': 'ClusterScopeSettings'}, + } + + def __init__( + self, + **kwargs + ): + super(SupportedScopes, self).__init__(**kwargs) + self.default_scope = kwargs.get('default_scope', None) + self.cluster_scope_settings = kwargs.get('cluster_scope_settings', None) + + +class SystemData(msrest.serialization.Model): + """Metadata pertaining to creation and last modification of the resource. + + :param created_by: The identity that created the resource. + :type created_by: str + :param created_by_type: The type of identity that created the resource. Possible values + include: "User", "Application", "ManagedIdentity", "Key". + :type created_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.CreatedByType + :param created_at: The timestamp of resource creation (UTC). + :type created_at: ~datetime.datetime + :param last_modified_by: The identity that last modified the resource. + :type last_modified_by: str + :param last_modified_by_type: The type of identity that last modified the resource. Possible + values include: "User", "Application", "ManagedIdentity", "Key". + :type last_modified_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.CreatedByType + :param last_modified_at: The timestamp of resource last modification (UTC). + :type last_modified_at: ~datetime.datetime + """ + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__( + self, + **kwargs + ): + super(SystemData, self).__init__(**kwargs) + self.created_by = kwargs.get('created_by', None) + self.created_by_type = kwargs.get('created_by_type', None) + self.created_at = kwargs.get('created_at', None) + self.last_modified_by = kwargs.get('last_modified_by', None) + self.last_modified_by_type = kwargs.get('last_modified_by_type', None) + self.last_modified_at = kwargs.get('last_modified_at', None) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_models_py3.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_models_py3.py new file mode 100644 index 00000000000..7ac4da66bdf --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_models_py3.py @@ -0,0 +1,1789 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import datetime +from typing import Dict, List, Optional, Union + +from azure.core.exceptions import HttpResponseError +import msrest.serialization + +from ._source_control_configuration_client_enums import * + + +class Resource(msrest.serialization.Model): + """Common fields that are returned in the response for all Azure Resource Manager resources. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class ProxyResource(Resource): + """The resource model definition for a Azure Resource Manager proxy resource. It will not have tags and a location. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ProxyResource, self).__init__(**kwargs) + + +class ClusterScopeSettings(ProxyResource): + """Extension scope settings. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :param allow_multiple_instances: Describes if multiple instances of the extension are allowed. + :type allow_multiple_instances: bool + :param default_release_namespace: Default extension release namespace. + :type default_release_namespace: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'allow_multiple_instances': {'key': 'properties.allowMultipleInstances', 'type': 'bool'}, + 'default_release_namespace': {'key': 'properties.defaultReleaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + *, + allow_multiple_instances: Optional[bool] = None, + default_release_namespace: Optional[str] = None, + **kwargs + ): + super(ClusterScopeSettings, self).__init__(**kwargs) + self.allow_multiple_instances = allow_multiple_instances + self.default_release_namespace = default_release_namespace + + +class ComplianceStatus(msrest.serialization.Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar compliance_state: The compliance state of the configuration. Possible values include: + "Pending", "Compliant", "Noncompliant", "Installed", "Failed". + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: ~datetime.datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: "Error", "Warning", + "Information". + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__( + self, + *, + last_config_applied: Optional[datetime.datetime] = None, + message: Optional[str] = None, + message_level: Optional[Union[str, "MessageLevelType"]] = None, + **kwargs + ): + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = last_config_applied + self.message = message + self.message_level = message_level + + +class DependsOnDefinition(msrest.serialization.Model): + """Specify which kustomizations must succeed reconciliation on the cluster prior to reconciling this kustomization. + + :param kustomization_name: Name of the kustomization to claim dependency on. + :type kustomization_name: str + """ + + _attribute_map = { + 'kustomization_name': {'key': 'kustomizationName', 'type': 'str'}, + } + + def __init__( + self, + *, + kustomization_name: Optional[str] = None, + **kwargs + ): + super(DependsOnDefinition, self).__init__(**kwargs) + self.kustomization_name = kustomization_name + + +class ErrorAdditionalInfo(msrest.serialization.Model): + """The resource management error additional info. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar type: The additional info type. + :vartype type: str + :ivar info: The additional info. + :vartype info: any + """ + + _validation = { + 'type': {'readonly': True}, + 'info': {'readonly': True}, + } + + _attribute_map = { + 'type': {'key': 'type', 'type': 'str'}, + 'info': {'key': 'info', 'type': 'object'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorAdditionalInfo, self).__init__(**kwargs) + self.type = None + self.info = None + + +class ErrorDetail(msrest.serialization.Model): + """The error detail. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar code: The error code. + :vartype code: str + :ivar message: The error message. + :vartype message: str + :ivar target: The error target. + :vartype target: str + :ivar details: The error details. + :vartype details: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ErrorDetail] + :ivar additional_info: The error additional info. + :vartype additional_info: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ErrorAdditionalInfo] + """ + + _validation = { + 'code': {'readonly': True}, + 'message': {'readonly': True}, + 'target': {'readonly': True}, + 'details': {'readonly': True}, + 'additional_info': {'readonly': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'target': {'key': 'target', 'type': 'str'}, + 'details': {'key': 'details', 'type': '[ErrorDetail]'}, + 'additional_info': {'key': 'additionalInfo', 'type': '[ErrorAdditionalInfo]'}, + } + + def __init__( + self, + **kwargs + ): + super(ErrorDetail, self).__init__(**kwargs) + self.code = None + self.message = None + self.target = None + self.details = None + self.additional_info = None + + +class ErrorResponse(msrest.serialization.Model): + """Common error response for all Azure Resource Manager APIs to return error details for failed operations. (This also follows the OData error response format.). + + :param error: The error object. + :type error: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ErrorDetail + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + *, + error: Optional["ErrorDetail"] = None, + **kwargs + ): + super(ErrorResponse, self).__init__(**kwargs) + self.error = error + + +class Extension(ProxyResource): + """The Extension object. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :param identity: Identity of the Extension resource. + :type identity: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Identity + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SystemData + :param extension_type: Type of the Extension, of which this resource is an instance of. It + must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the + Extension publisher. + :type extension_type: str + :param auto_upgrade_minor_version: Flag to note if this extension participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension participates in for auto-upgrade (e.g. + Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension, if it is 'pinned' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param scope: Scope at which the extension is installed. + :type scope: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Scope + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this extension. + :type configuration_protected_settings: dict[str, str] + :ivar provisioning_state: Status of installation of this extension. Possible values include: + "Succeeded", "Failed", "Canceled", "Creating", "Updating", "Deleting". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ProvisioningState + :param statuses: Status from this extension. + :type statuses: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionStatus] + :ivar error_info: Error information from the Agent - e.g. errors during installation. + :vartype error_info: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ErrorDetail + :ivar custom_location_settings: Custom Location settings properties. + :vartype custom_location_settings: dict[str, str] + :ivar package_uri: Uri of the Helm package. + :vartype package_uri: str + :param aks_assigned_identity: Identity of the Extension resource in an AKS cluster. + :type aks_assigned_identity: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionPropertiesAksAssignedIdentity + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'error_info': {'readonly': True}, + 'custom_location_settings': {'readonly': True}, + 'package_uri': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'identity': {'key': 'identity', 'type': 'Identity'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'extension_type': {'key': 'properties.extensionType', 'type': 'str'}, + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'scope': {'key': 'properties.scope', 'type': 'Scope'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ExtensionStatus]'}, + 'error_info': {'key': 'properties.errorInfo', 'type': 'ErrorDetail'}, + 'custom_location_settings': {'key': 'properties.customLocationSettings', 'type': '{str}'}, + 'package_uri': {'key': 'properties.packageUri', 'type': 'str'}, + 'aks_assigned_identity': {'key': 'properties.aksAssignedIdentity', 'type': 'ExtensionPropertiesAksAssignedIdentity'}, + } + + def __init__( + self, + *, + identity: Optional["Identity"] = None, + extension_type: Optional[str] = None, + auto_upgrade_minor_version: Optional[bool] = True, + release_train: Optional[str] = "Stable", + version: Optional[str] = None, + scope: Optional["Scope"] = None, + configuration_settings: Optional[Dict[str, str]] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + statuses: Optional[List["ExtensionStatus"]] = None, + aks_assigned_identity: Optional["ExtensionPropertiesAksAssignedIdentity"] = None, + **kwargs + ): + super(Extension, self).__init__(**kwargs) + self.identity = identity + self.system_data = None + self.extension_type = extension_type + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + self.scope = scope + self.configuration_settings = configuration_settings + self.configuration_protected_settings = configuration_protected_settings + self.provisioning_state = None + self.statuses = statuses + self.error_info = None + self.custom_location_settings = None + self.package_uri = None + self.aks_assigned_identity = aks_assigned_identity + + +class ExtensionPropertiesAksAssignedIdentity(msrest.serialization.Model): + """Identity of the Extension resource in an AKS cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal ID of resource identity. + :vartype principal_id: str + :ivar tenant_id: The tenant ID of resource. + :vartype tenant_id: str + :param type: The identity type. The only acceptable values to pass in are None and + "SystemAssigned". The default value is None. + :type type: str + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + *, + type: Optional[str] = None, + **kwargs + ): + super(ExtensionPropertiesAksAssignedIdentity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = type + + +class ExtensionsList(msrest.serialization.Model): + """Result of the request to list Extensions. It contains a list of Extension objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Extensions within a Kubernetes cluster. + :vartype value: list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Extension] + :ivar next_link: URL to get the next set of extension objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[Extension]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionsList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class ExtensionStatus(msrest.serialization.Model): + """Status from the extension. + + :param code: Status code provided by the Extension. + :type code: str + :param display_status: Short description of status of the extension. + :type display_status: str + :param level: Level of the status. Possible values include: "Error", "Warning", "Information". + Default value: "Information". + :type level: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.LevelType + :param message: Detailed message of the status from the Extension. + :type message: str + :param time: DateLiteral (per ISO8601) noting the time of installation status. + :type time: str + """ + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'display_status': {'key': 'displayStatus', 'type': 'str'}, + 'level': {'key': 'level', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'str'}, + } + + def __init__( + self, + *, + code: Optional[str] = None, + display_status: Optional[str] = None, + level: Optional[Union[str, "LevelType"]] = "Information", + message: Optional[str] = None, + time: Optional[str] = None, + **kwargs + ): + super(ExtensionStatus, self).__init__(**kwargs) + self.code = code + self.display_status = display_status + self.level = level + self.message = message + self.time = time + + +class ExtensionType(msrest.serialization.Model): + """Represents an Extension Type. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar system_data: Metadata pertaining to creation and last modification of the resource. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SystemData + :ivar release_trains: Extension release train: preview or stable. + :vartype release_trains: list[str] + :ivar cluster_types: Cluster types. Possible values include: "connectedClusters", + "managedClusters". + :vartype cluster_types: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ClusterTypes + :ivar supported_scopes: Extension scopes. + :vartype supported_scopes: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SupportedScopes + """ + + _validation = { + 'system_data': {'readonly': True}, + 'release_trains': {'readonly': True}, + 'cluster_types': {'readonly': True}, + 'supported_scopes': {'readonly': True}, + } + + _attribute_map = { + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'release_trains': {'key': 'properties.releaseTrains', 'type': '[str]'}, + 'cluster_types': {'key': 'properties.clusterTypes', 'type': 'str'}, + 'supported_scopes': {'key': 'properties.supportedScopes', 'type': 'SupportedScopes'}, + } + + def __init__( + self, + **kwargs + ): + super(ExtensionType, self).__init__(**kwargs) + self.system_data = None + self.release_trains = None + self.cluster_types = None + self.supported_scopes = None + + +class ExtensionTypeList(msrest.serialization.Model): + """List Extension Types. + + :param value: The list of Extension Types. + :type value: list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionType] + :param next_link: The link to fetch the next page of Extension Types. + :type next_link: str + """ + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ExtensionType]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + *, + value: Optional[List["ExtensionType"]] = None, + next_link: Optional[str] = None, + **kwargs + ): + super(ExtensionTypeList, self).__init__(**kwargs) + self.value = value + self.next_link = next_link + + +class ExtensionVersionList(msrest.serialization.Model): + """List versions for an Extension. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param versions: Versions available for this Extension Type. + :type versions: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionVersionListVersionsItem] + :param next_link: The link to fetch the next page of Extension Types. + :type next_link: str + :ivar system_data: Metadata pertaining to creation and last modification of the resource. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SystemData + """ + + _validation = { + 'system_data': {'readonly': True}, + } + + _attribute_map = { + 'versions': {'key': 'versions', 'type': '[ExtensionVersionListVersionsItem]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__( + self, + *, + versions: Optional[List["ExtensionVersionListVersionsItem"]] = None, + next_link: Optional[str] = None, + **kwargs + ): + super(ExtensionVersionList, self).__init__(**kwargs) + self.versions = versions + self.next_link = next_link + self.system_data = None + + +class ExtensionVersionListVersionsItem(msrest.serialization.Model): + """ExtensionVersionListVersionsItem. + + :param release_train: The release train for this Extension Type. + :type release_train: str + :param versions: Versions available for this Extension Type and release train. + :type versions: list[str] + """ + + _attribute_map = { + 'release_train': {'key': 'releaseTrain', 'type': 'str'}, + 'versions': {'key': 'versions', 'type': '[str]'}, + } + + def __init__( + self, + *, + release_train: Optional[str] = None, + versions: Optional[List[str]] = None, + **kwargs + ): + super(ExtensionVersionListVersionsItem, self).__init__(**kwargs) + self.release_train = release_train + self.versions = versions + + +class FluxConfiguration(ProxyResource): + """The Flux Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SystemData + :param scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". + :type scope: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ScopeType + :param namespace: The namespace to which this configuration is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. + :type namespace: str + :param source_kind: Source Kind to pull the configuration data from. Possible values include: + "GitRepository". + :type source_kind: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceKindType + :param suspend: Whether this configuration should suspend its reconciliation of its + kustomizations and sources. + :type suspend: bool + :param git_repository: Parameters to reconcile to the GitRepository source kind type. + :type git_repository: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.GitRepositoryDefinition + :param kustomizations: Array of kustomizations used to reconcile the artifact pulled by the + source type on the cluster. + :type kustomizations: dict[str, + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.KustomizationDefinition] + :param configuration_protected_settings: Key-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + :ivar statuses: Statuses of the Flux Kubernetes resources created by the fluxConfiguration or + created by the managed objects provisioned by the fluxConfiguration. + :vartype statuses: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ObjectStatusDefinition] + :ivar repository_public_key: Public Key associated with this fluxConfiguration (either + generated within the cluster or provided by the user). + :vartype repository_public_key: str + :ivar last_source_synced_commit_id: Branch and SHA of the last source commit synced with the + cluster. + :vartype last_source_synced_commit_id: str + :ivar last_source_synced_at: Datetime the fluxConfiguration last synced its source on the + cluster. + :vartype last_source_synced_at: ~datetime.datetime + :ivar compliance_state: Combined status of the Flux Kubernetes resources created by the + fluxConfiguration or created by the managed objects. Possible values include: "Compliant", + "Non-Compliant", "Pending", "Suspended", "Unknown". Default value: "Unknown". + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxComplianceState + :ivar provisioning_state: Status of the creation of the fluxConfiguration. Possible values + include: "Succeeded", "Failed", "Canceled", "Creating", "Updating", "Deleting". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ProvisioningState + :ivar error_message: Error message returned to the user in the case of provisioning failure. + :vartype error_message: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'statuses': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'last_source_synced_commit_id': {'readonly': True}, + 'last_source_synced_at': {'readonly': True}, + 'compliance_state': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'error_message': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'scope': {'key': 'properties.scope', 'type': 'str'}, + 'namespace': {'key': 'properties.namespace', 'type': 'str'}, + 'source_kind': {'key': 'properties.sourceKind', 'type': 'str'}, + 'suspend': {'key': 'properties.suspend', 'type': 'bool'}, + 'git_repository': {'key': 'properties.gitRepository', 'type': 'GitRepositoryDefinition'}, + 'kustomizations': {'key': 'properties.kustomizations', 'type': '{KustomizationDefinition}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'statuses': {'key': 'properties.statuses', 'type': '[ObjectStatusDefinition]'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'last_source_synced_commit_id': {'key': 'properties.lastSourceSyncedCommitId', 'type': 'str'}, + 'last_source_synced_at': {'key': 'properties.lastSourceSyncedAt', 'type': 'iso-8601'}, + 'compliance_state': {'key': 'properties.complianceState', 'type': 'str'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'error_message': {'key': 'properties.errorMessage', 'type': 'str'}, + } + + def __init__( + self, + *, + scope: Optional[Union[str, "ScopeType"]] = "cluster", + namespace: Optional[str] = "default", + source_kind: Optional[Union[str, "SourceKindType"]] = None, + suspend: Optional[bool] = False, + git_repository: Optional["GitRepositoryDefinition"] = None, + kustomizations: Optional[Dict[str, "KustomizationDefinition"]] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + **kwargs + ): + super(FluxConfiguration, self).__init__(**kwargs) + self.system_data = None + self.scope = scope + self.namespace = namespace + self.source_kind = source_kind + self.suspend = suspend + self.git_repository = git_repository + self.kustomizations = kustomizations + self.configuration_protected_settings = configuration_protected_settings + self.statuses = None + self.repository_public_key = None + self.last_source_synced_commit_id = None + self.last_source_synced_at = None + self.compliance_state = None + self.provisioning_state = None + self.error_message = None + + +class FluxConfigurationPatch(msrest.serialization.Model): + """The Flux Configuration Patch Request object. + + :param source_kind: Source Kind to pull the configuration data from. Possible values include: + "GitRepository". + :type source_kind: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceKindType + :param suspend: Whether this configuration should suspend its reconciliation of its + kustomizations and sources. + :type suspend: bool + :param git_repository: Parameters to reconcile to the GitRepository source kind type. + :type git_repository: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.GitRepositoryDefinition + :param kustomizations: Array of kustomizations used to reconcile the artifact pulled by the + source type on the cluster. + :type kustomizations: dict[str, + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.KustomizationDefinition] + :param configuration_protected_settings: Key-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + """ + + _attribute_map = { + 'source_kind': {'key': 'properties.sourceKind', 'type': 'str'}, + 'suspend': {'key': 'properties.suspend', 'type': 'bool'}, + 'git_repository': {'key': 'properties.gitRepository', 'type': 'GitRepositoryDefinition'}, + 'kustomizations': {'key': 'properties.kustomizations', 'type': '{KustomizationDefinition}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + } + + def __init__( + self, + *, + source_kind: Optional[Union[str, "SourceKindType"]] = None, + suspend: Optional[bool] = None, + git_repository: Optional["GitRepositoryDefinition"] = None, + kustomizations: Optional[Dict[str, "KustomizationDefinition"]] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + **kwargs + ): + super(FluxConfigurationPatch, self).__init__(**kwargs) + self.source_kind = source_kind + self.suspend = suspend + self.git_repository = git_repository + self.kustomizations = kustomizations + self.configuration_protected_settings = configuration_protected_settings + + +class FluxConfigurationsList(msrest.serialization.Model): + """Result of the request to list Flux Configurations. It contains a list of FluxConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Flux Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[FluxConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(FluxConfigurationsList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class GitRepositoryDefinition(msrest.serialization.Model): + """Parameters to reconcile to the GitRepository source kind type. + + :param url: The URL to sync for the flux configuration git repository. + :type url: str + :param timeout_in_seconds: The maximum time to attempt to reconcile the cluster git repository + source with the remote. + :type timeout_in_seconds: long + :param sync_interval_in_seconds: The interval at which to re-reconcile the cluster git + repository source with the remote. + :type sync_interval_in_seconds: long + :param repository_ref: The source reference for the GitRepository object. + :type repository_ref: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.RepositoryRefDefinition + :param ssh_known_hosts: Base64-encoded known_hosts value containing public SSH keys required to + access private git repositories over SSH. + :type ssh_known_hosts: str + :param https_user: Base64-encoded HTTPS username used to access private git repositories over + HTTPS. + :type https_user: str + :param https_ca_file: Base64-encoded HTTPS certificate authority contents used to access git + private git repositories over HTTPS. + :type https_ca_file: str + :param local_auth_ref: Name of a local secret on the Kubernetes cluster to use as the + authentication secret rather than the managed or user-provided configuration secrets. + :type local_auth_ref: str + """ + + _attribute_map = { + 'url': {'key': 'url', 'type': 'str'}, + 'timeout_in_seconds': {'key': 'timeoutInSeconds', 'type': 'long'}, + 'sync_interval_in_seconds': {'key': 'syncIntervalInSeconds', 'type': 'long'}, + 'repository_ref': {'key': 'repositoryRef', 'type': 'RepositoryRefDefinition'}, + 'ssh_known_hosts': {'key': 'sshKnownHosts', 'type': 'str'}, + 'https_user': {'key': 'httpsUser', 'type': 'str'}, + 'https_ca_file': {'key': 'httpsCAFile', 'type': 'str'}, + 'local_auth_ref': {'key': 'localAuthRef', 'type': 'str'}, + } + + def __init__( + self, + *, + url: Optional[str] = None, + timeout_in_seconds: Optional[int] = 600, + sync_interval_in_seconds: Optional[int] = 600, + repository_ref: Optional["RepositoryRefDefinition"] = None, + ssh_known_hosts: Optional[str] = None, + https_user: Optional[str] = None, + https_ca_file: Optional[str] = None, + local_auth_ref: Optional[str] = None, + **kwargs + ): + super(GitRepositoryDefinition, self).__init__(**kwargs) + self.url = url + self.timeout_in_seconds = timeout_in_seconds + self.sync_interval_in_seconds = sync_interval_in_seconds + self.repository_ref = repository_ref + self.ssh_known_hosts = ssh_known_hosts + self.https_user = https_user + self.https_ca_file = https_ca_file + self.local_auth_ref = local_auth_ref + + +class HelmOperatorProperties(msrest.serialization.Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__( + self, + *, + chart_version: Optional[str] = None, + chart_values: Optional[str] = None, + **kwargs + ): + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = chart_version + self.chart_values = chart_values + + +class HelmReleasePropertiesDefinition(msrest.serialization.Model): + """HelmReleasePropertiesDefinition. + + :param last_revision_applied: The revision number of the last released object change. + :type last_revision_applied: long + :param helm_chart_ref: The reference to the HelmChart object used as the source to this + HelmRelease. + :type helm_chart_ref: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ObjectReferenceDefinition + :param failure_count: Total number of times that the HelmRelease failed to install or upgrade. + :type failure_count: long + :param install_failure_count: Number of times that the HelmRelease failed to install. + :type install_failure_count: long + :param upgrade_failure_count: Number of times that the HelmRelease failed to upgrade. + :type upgrade_failure_count: long + """ + + _attribute_map = { + 'last_revision_applied': {'key': 'lastRevisionApplied', 'type': 'long'}, + 'helm_chart_ref': {'key': 'helmChartRef', 'type': 'ObjectReferenceDefinition'}, + 'failure_count': {'key': 'failureCount', 'type': 'long'}, + 'install_failure_count': {'key': 'installFailureCount', 'type': 'long'}, + 'upgrade_failure_count': {'key': 'upgradeFailureCount', 'type': 'long'}, + } + + def __init__( + self, + *, + last_revision_applied: Optional[int] = None, + helm_chart_ref: Optional["ObjectReferenceDefinition"] = None, + failure_count: Optional[int] = None, + install_failure_count: Optional[int] = None, + upgrade_failure_count: Optional[int] = None, + **kwargs + ): + super(HelmReleasePropertiesDefinition, self).__init__(**kwargs) + self.last_revision_applied = last_revision_applied + self.helm_chart_ref = helm_chart_ref + self.failure_count = failure_count + self.install_failure_count = install_failure_count + self.upgrade_failure_count = upgrade_failure_count + + +class Identity(msrest.serialization.Model): + """Identity for the resource. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar principal_id: The principal ID of resource identity. + :vartype principal_id: str + :ivar tenant_id: The tenant ID of resource. + :vartype tenant_id: str + :param type: The identity type. The only acceptable values to pass in are None and + "SystemAssigned". The default value is None. + :type type: str + """ + + _validation = { + 'principal_id': {'readonly': True}, + 'tenant_id': {'readonly': True}, + } + + _attribute_map = { + 'principal_id': {'key': 'principalId', 'type': 'str'}, + 'tenant_id': {'key': 'tenantId', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + *, + type: Optional[str] = None, + **kwargs + ): + super(Identity, self).__init__(**kwargs) + self.principal_id = None + self.tenant_id = None + self.type = type + + +class KustomizationDefinition(msrest.serialization.Model): + """The Kustomization defining how to reconcile the artifact pulled by the source type on the cluster. + + :param path: The path in the source reference to reconcile on the cluster. + :type path: str + :param depends_on: Specifies other Kustomizations that this Kustomization depends on. This + Kustomization will not reconcile until all dependencies have completed their reconciliation. + :type depends_on: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.DependsOnDefinition] + :param timeout_in_seconds: The maximum time to attempt to reconcile the Kustomization on the + cluster. + :type timeout_in_seconds: long + :param sync_interval_in_seconds: The interval at which to re-reconcile the Kustomization on the + cluster. + :type sync_interval_in_seconds: long + :param retry_interval_in_seconds: The interval at which to re-reconcile the Kustomization on + the cluster in the event of failure on reconciliation. + :type retry_interval_in_seconds: long + :param prune: Enable/disable garbage collections of Kubernetes objects created by this + Kustomization. + :type prune: bool + :param force: Enable/disable re-creating Kubernetes resources on the cluster when patching + fails due to an immutable field change. + :type force: bool + """ + + _attribute_map = { + 'path': {'key': 'path', 'type': 'str'}, + 'depends_on': {'key': 'dependsOn', 'type': '[DependsOnDefinition]'}, + 'timeout_in_seconds': {'key': 'timeoutInSeconds', 'type': 'long'}, + 'sync_interval_in_seconds': {'key': 'syncIntervalInSeconds', 'type': 'long'}, + 'retry_interval_in_seconds': {'key': 'retryIntervalInSeconds', 'type': 'long'}, + 'prune': {'key': 'prune', 'type': 'bool'}, + 'force': {'key': 'force', 'type': 'bool'}, + } + + def __init__( + self, + *, + path: Optional[str] = "", + depends_on: Optional[List["DependsOnDefinition"]] = None, + timeout_in_seconds: Optional[int] = 600, + sync_interval_in_seconds: Optional[int] = 600, + retry_interval_in_seconds: Optional[int] = None, + prune: Optional[bool] = None, + force: Optional[bool] = None, + **kwargs + ): + super(KustomizationDefinition, self).__init__(**kwargs) + self.path = path + self.depends_on = depends_on + self.timeout_in_seconds = timeout_in_seconds + self.sync_interval_in_seconds = sync_interval_in_seconds + self.retry_interval_in_seconds = retry_interval_in_seconds + self.prune = prune + self.force = force + + +class ObjectReferenceDefinition(msrest.serialization.Model): + """Object reference to a Kubernetes object on a cluster. + + :param name: Name of the object. + :type name: str + :param namespace: Namespace of the object. + :type namespace: str + """ + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'namespace': {'key': 'namespace', 'type': 'str'}, + } + + def __init__( + self, + *, + name: Optional[str] = None, + namespace: Optional[str] = None, + **kwargs + ): + super(ObjectReferenceDefinition, self).__init__(**kwargs) + self.name = name + self.namespace = namespace + + +class ObjectStatusConditionDefinition(msrest.serialization.Model): + """Status condition of Kubernetes object. + + :param last_transition_time: Last time this status condition has changed. + :type last_transition_time: ~datetime.datetime + :param message: A more verbose description of the object status condition. + :type message: str + :param reason: Reason for the specified status condition type status. + :type reason: str + :param status: Status of the Kubernetes object condition type. + :type status: str + :param type: Object status condition type for this object. + :type type: str + """ + + _attribute_map = { + 'last_transition_time': {'key': 'lastTransitionTime', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'reason': {'key': 'reason', 'type': 'str'}, + 'status': {'key': 'status', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__( + self, + *, + last_transition_time: Optional[datetime.datetime] = None, + message: Optional[str] = None, + reason: Optional[str] = None, + status: Optional[str] = None, + type: Optional[str] = None, + **kwargs + ): + super(ObjectStatusConditionDefinition, self).__init__(**kwargs) + self.last_transition_time = last_transition_time + self.message = message + self.reason = reason + self.status = status + self.type = type + + +class ObjectStatusDefinition(msrest.serialization.Model): + """Statuses of objects deployed by the user-specified kustomizations from the git repository. + + :param name: Name of the applied object. + :type name: str + :param namespace: Namespace of the applied object. + :type namespace: str + :param kind: Kind of the applied object. + :type kind: str + :param compliance_state: Compliance state of the applied object showing whether the applied + object has come into a ready state on the cluster. Possible values include: "Compliant", + "Non-Compliant", "Pending", "Suspended", "Unknown". Default value: "Unknown". + :type compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxComplianceState + :param applied_by: Object reference to the Kustomization that applied this object. + :type applied_by: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ObjectReferenceDefinition + :param status_conditions: List of Kubernetes object status conditions present on the cluster. + :type status_conditions: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ObjectStatusConditionDefinition] + :param helm_release_properties: Additional properties that are provided from objects of the + HelmRelease kind. + :type helm_release_properties: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.HelmReleasePropertiesDefinition + """ + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'namespace': {'key': 'namespace', 'type': 'str'}, + 'kind': {'key': 'kind', 'type': 'str'}, + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'applied_by': {'key': 'appliedBy', 'type': 'ObjectReferenceDefinition'}, + 'status_conditions': {'key': 'statusConditions', 'type': '[ObjectStatusConditionDefinition]'}, + 'helm_release_properties': {'key': 'helmReleaseProperties', 'type': 'HelmReleasePropertiesDefinition'}, + } + + def __init__( + self, + *, + name: Optional[str] = None, + namespace: Optional[str] = None, + kind: Optional[str] = None, + compliance_state: Optional[Union[str, "FluxComplianceState"]] = "Unknown", + applied_by: Optional["ObjectReferenceDefinition"] = None, + status_conditions: Optional[List["ObjectStatusConditionDefinition"]] = None, + helm_release_properties: Optional["HelmReleasePropertiesDefinition"] = None, + **kwargs + ): + super(ObjectStatusDefinition, self).__init__(**kwargs) + self.name = name + self.namespace = namespace + self.kind = kind + self.compliance_state = compliance_state + self.applied_by = applied_by + self.status_conditions = status_conditions + self.helm_release_properties = helm_release_properties + + +class OperationStatusList(msrest.serialization.Model): + """The async operations in progress, in the cluster. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of async operations in progress, in the cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperationStatusResult] + :ivar next_link: URL to get the next set of Operation Result objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[OperationStatusResult]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(OperationStatusList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class OperationStatusResult(msrest.serialization.Model): + """The current status of an async operation. + + Variables are only populated by the server, and will be ignored when sending a request. + + All required parameters must be populated in order to send to Azure. + + :param id: Fully qualified ID for the async operation. + :type id: str + :param name: Name of the async operation. + :type name: str + :param status: Required. Operation status. + :type status: str + :param properties: Additional information, if available. + :type properties: dict[str, str] + :ivar error: If present, details of the operation error. + :vartype error: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ErrorDetail + """ + + _validation = { + 'status': {'required': True}, + 'error': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'status': {'key': 'status', 'type': 'str'}, + 'properties': {'key': 'properties', 'type': '{str}'}, + 'error': {'key': 'error', 'type': 'ErrorDetail'}, + } + + def __init__( + self, + *, + status: str, + id: Optional[str] = None, + name: Optional[str] = None, + properties: Optional[Dict[str, str]] = None, + **kwargs + ): + super(OperationStatusResult, self).__init__(**kwargs) + self.id = id + self.name = name + self.status = status + self.properties = properties + self.error = None + + +class PatchExtension(msrest.serialization.Model): + """The Extension Patch Request object. + + :param auto_upgrade_minor_version: Flag to note if this extension participates in auto upgrade + of minor version, or not. + :type auto_upgrade_minor_version: bool + :param release_train: ReleaseTrain this extension participates in for auto-upgrade (e.g. + Stable, Preview, etc.) - only if autoUpgradeMinorVersion is 'true'. + :type release_train: str + :param version: Version of the extension for this extension, if it is 'pinned' to a specific + version. autoUpgradeMinorVersion must be 'false'. + :type version: str + :param configuration_settings: Configuration settings, as name-value pairs for configuring this + extension. + :type configuration_settings: dict[str, str] + :param configuration_protected_settings: Configuration settings that are sensitive, as + name-value pairs for configuring this extension. + :type configuration_protected_settings: dict[str, str] + """ + + _attribute_map = { + 'auto_upgrade_minor_version': {'key': 'properties.autoUpgradeMinorVersion', 'type': 'bool'}, + 'release_train': {'key': 'properties.releaseTrain', 'type': 'str'}, + 'version': {'key': 'properties.version', 'type': 'str'}, + 'configuration_settings': {'key': 'properties.configurationSettings', 'type': '{str}'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + } + + def __init__( + self, + *, + auto_upgrade_minor_version: Optional[bool] = True, + release_train: Optional[str] = "Stable", + version: Optional[str] = None, + configuration_settings: Optional[Dict[str, str]] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + **kwargs + ): + super(PatchExtension, self).__init__(**kwargs) + self.auto_upgrade_minor_version = auto_upgrade_minor_version + self.release_train = release_train + self.version = version + self.configuration_settings = configuration_settings + self.configuration_protected_settings = configuration_protected_settings + + +class RepositoryRefDefinition(msrest.serialization.Model): + """The source reference for the GitRepository object. + + :param branch: The git repository branch name to checkout. + :type branch: str + :param tag: The git repository tag name to checkout. This takes precedence over branch. + :type tag: str + :param semver: The semver range used to match against git repository tags. This takes + precedence over tag. + :type semver: str + :param commit: The commit SHA to checkout. This value must be combined with the branch name to + be valid. This takes precedence over semver. + :type commit: str + """ + + _attribute_map = { + 'branch': {'key': 'branch', 'type': 'str'}, + 'tag': {'key': 'tag', 'type': 'str'}, + 'semver': {'key': 'semver', 'type': 'str'}, + 'commit': {'key': 'commit', 'type': 'str'}, + } + + def __init__( + self, + *, + branch: Optional[str] = None, + tag: Optional[str] = None, + semver: Optional[str] = None, + commit: Optional[str] = None, + **kwargs + ): + super(RepositoryRefDefinition, self).__init__(**kwargs) + self.branch = branch + self.tag = tag + self.semver = semver + self.commit = commit + + +class ResourceProviderOperation(msrest.serialization.Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param name: Operation name, in format of {provider}/{resource}/{operation}. + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation applies to data plane. + :vartype is_data_action: bool + :ivar origin: Origin of the operation. + :vartype origin: str + """ + + _validation = { + 'is_data_action': {'readonly': True}, + 'origin': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + 'origin': {'key': 'origin', 'type': 'str'}, + } + + def __init__( + self, + *, + name: Optional[str] = None, + display: Optional["ResourceProviderOperationDisplay"] = None, + **kwargs + ): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = name + self.display = display + self.is_data_action = None + self.origin = None + + +class ResourceProviderOperationDisplay(msrest.serialization.Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__( + self, + *, + provider: Optional[str] = None, + resource: Optional[str] = None, + operation: Optional[str] = None, + description: Optional[str] = None, + **kwargs + ): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = provider + self.resource = resource + self.operation = operation + self.description = description + + +class ResourceProviderOperationList(msrest.serialization.Model): + """Result of the request to list operations. + + Variables are only populated by the server, and will be ignored when sending a request. + + :param value: List of operations supported by this resource provider. + :type value: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ResourceProviderOperation] + :ivar next_link: URL to the next set of results, if any. + :vartype next_link: str + """ + + _validation = { + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[ResourceProviderOperation]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + *, + value: Optional[List["ResourceProviderOperation"]] = None, + **kwargs + ): + super(ResourceProviderOperationList, self).__init__(**kwargs) + self.value = value + self.next_link = None + + +class Scope(msrest.serialization.Model): + """Scope of the extension. It can be either Cluster or Namespace; but not both. + + :param cluster: Specifies that the scope of the extension is Cluster. + :type cluster: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ScopeCluster + :param namespace: Specifies that the scope of the extension is Namespace. + :type namespace: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ScopeNamespace + """ + + _attribute_map = { + 'cluster': {'key': 'cluster', 'type': 'ScopeCluster'}, + 'namespace': {'key': 'namespace', 'type': 'ScopeNamespace'}, + } + + def __init__( + self, + *, + cluster: Optional["ScopeCluster"] = None, + namespace: Optional["ScopeNamespace"] = None, + **kwargs + ): + super(Scope, self).__init__(**kwargs) + self.cluster = cluster + self.namespace = namespace + + +class ScopeCluster(msrest.serialization.Model): + """Specifies that the scope of the extension is Cluster. + + :param release_namespace: Namespace where the extension Release must be placed, for a Cluster + scoped extension. If this namespace does not exist, it will be created. + :type release_namespace: str + """ + + _attribute_map = { + 'release_namespace': {'key': 'releaseNamespace', 'type': 'str'}, + } + + def __init__( + self, + *, + release_namespace: Optional[str] = None, + **kwargs + ): + super(ScopeCluster, self).__init__(**kwargs) + self.release_namespace = release_namespace + + +class ScopeNamespace(msrest.serialization.Model): + """Specifies that the scope of the extension is Namespace. + + :param target_namespace: Namespace where the extension will be created for an Namespace scoped + extension. If this namespace does not exist, it will be created. + :type target_namespace: str + """ + + _attribute_map = { + 'target_namespace': {'key': 'targetNamespace', 'type': 'str'}, + } + + def __init__( + self, + *, + target_namespace: Optional[str] = None, + **kwargs + ): + super(ScopeNamespace, self).__init__(**kwargs) + self.target_namespace = target_namespace + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. + :vartype id: str + :ivar name: The name of the resource. + :vartype name: str + :ivar type: The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or + "Microsoft.Storage/storageAccounts". + :vartype type: str + :ivar system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources. + :vartype system_data: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SystemData + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is installed to. Maximum of 253 + lower case alphanumeric characters, hyphen and period only. + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying the specific + configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: "Flux". + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected configuration settings + for the configuration. + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. Possible values include: + "cluster", "namespace". Default value: "cluster". + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl configuration + (either generated within the cluster or provided by the user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents containing public SSH keys + required to access private Git instances. + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. Possible values + include: "Accepted", "Deleting", "Running", "Succeeded", "Failed". + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration. + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ComplianceStatus + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'system_data': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + } + + def __init__( + self, + *, + repository_url: Optional[str] = None, + operator_namespace: Optional[str] = "default", + operator_instance_name: Optional[str] = None, + operator_type: Optional[Union[str, "OperatorType"]] = None, + operator_params: Optional[str] = None, + configuration_protected_settings: Optional[Dict[str, str]] = None, + operator_scope: Optional[Union[str, "OperatorScopeType"]] = "cluster", + ssh_known_hosts_contents: Optional[str] = None, + enable_helm_operator: Optional[bool] = None, + helm_operator_properties: Optional["HelmOperatorProperties"] = None, + **kwargs + ): + super(SourceControlConfiguration, self).__init__(**kwargs) + self.system_data = None + self.repository_url = repository_url + self.operator_namespace = operator_namespace + self.operator_instance_name = operator_instance_name + self.operator_type = operator_type + self.operator_params = operator_params + self.configuration_protected_settings = configuration_protected_settings + self.operator_scope = operator_scope + self.repository_public_key = None + self.ssh_known_hosts_contents = ssh_known_hosts_contents + self.enable_helm_operator = enable_helm_operator + self.helm_operator_properties = helm_operator_properties + self.provisioning_state = None + self.compliance_status = None + + +class SourceControlConfigurationList(msrest.serialization.Model): + """Result of the request to list Source Control Configurations. It contains a list of SourceControlConfiguration objects and a URL link to get the next set of results. + + Variables are only populated by the server, and will be ignored when sending a request. + + :ivar value: List of Source Control Configurations within a Kubernetes cluster. + :vartype value: + list[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceControlConfiguration] + :ivar next_link: URL to get the next set of configuration objects, if any. + :vartype next_link: str + """ + + _validation = { + 'value': {'readonly': True}, + 'next_link': {'readonly': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SourceControlConfiguration]'}, + 'next_link': {'key': 'nextLink', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SourceControlConfigurationList, self).__init__(**kwargs) + self.value = None + self.next_link = None + + +class SupportedScopes(msrest.serialization.Model): + """Extension scopes. + + :param default_scope: Default extension scopes: cluster or namespace. + :type default_scope: str + :param cluster_scope_settings: Scope settings. + :type cluster_scope_settings: + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ClusterScopeSettings + """ + + _attribute_map = { + 'default_scope': {'key': 'defaultScope', 'type': 'str'}, + 'cluster_scope_settings': {'key': 'clusterScopeSettings', 'type': 'ClusterScopeSettings'}, + } + + def __init__( + self, + *, + default_scope: Optional[str] = None, + cluster_scope_settings: Optional["ClusterScopeSettings"] = None, + **kwargs + ): + super(SupportedScopes, self).__init__(**kwargs) + self.default_scope = default_scope + self.cluster_scope_settings = cluster_scope_settings + + +class SystemData(msrest.serialization.Model): + """Metadata pertaining to creation and last modification of the resource. + + :param created_by: The identity that created the resource. + :type created_by: str + :param created_by_type: The type of identity that created the resource. Possible values + include: "User", "Application", "ManagedIdentity", "Key". + :type created_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.CreatedByType + :param created_at: The timestamp of resource creation (UTC). + :type created_at: ~datetime.datetime + :param last_modified_by: The identity that last modified the resource. + :type last_modified_by: str + :param last_modified_by_type: The type of identity that last modified the resource. Possible + values include: "User", "Application", "ManagedIdentity", "Key". + :type last_modified_by_type: str or + ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.CreatedByType + :param last_modified_at: The timestamp of resource last modification (UTC). + :type last_modified_at: ~datetime.datetime + """ + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__( + self, + *, + created_by: Optional[str] = None, + created_by_type: Optional[Union[str, "CreatedByType"]] = None, + created_at: Optional[datetime.datetime] = None, + last_modified_by: Optional[str] = None, + last_modified_by_type: Optional[Union[str, "CreatedByType"]] = None, + last_modified_at: Optional[datetime.datetime] = None, + **kwargs + ): + super(SystemData, self).__init__(**kwargs) + self.created_by = created_by + self.created_by_type = created_by_type + self.created_at = created_at + self.last_modified_by = last_modified_by + self.last_modified_by_type = last_modified_by_type + self.last_modified_at = last_modified_at diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_source_control_configuration_client_enums.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_source_control_configuration_client_enums.py new file mode 100644 index 00000000000..7b724fe947b --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/models/_source_control_configuration_client_enums.py @@ -0,0 +1,145 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from enum import Enum, EnumMeta +from six import with_metaclass + +class _CaseInsensitiveEnumMeta(EnumMeta): + def __getitem__(self, name): + return super().__getitem__(name.upper()) + + def __getattr__(cls, name): + """Return the enum member matching `name` + We use __getattr__ instead of descriptors or inserting into the enum + class' __dict__ in order to support `name` and `value` being both + properties for enum members (which live in the class' __dict__) and + enum members themselves. + """ + try: + return cls._member_map_[name.upper()] + except KeyError: + raise AttributeError(name) + + +class ClusterTypes(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Cluster types + """ + + CONNECTED_CLUSTERS = "connectedClusters" + MANAGED_CLUSTERS = "managedClusters" + +class ComplianceStateType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The compliance state of the configuration. + """ + + PENDING = "Pending" + COMPLIANT = "Compliant" + NONCOMPLIANT = "Noncompliant" + INSTALLED = "Installed" + FAILED = "Failed" + +class CreatedByType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The type of identity that created the resource. + """ + + USER = "User" + APPLICATION = "Application" + MANAGED_IDENTITY = "ManagedIdentity" + KEY = "Key" + +class Enum0(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + + MICROSOFT_CONTAINER_SERVICE = "Microsoft.ContainerService" + MICROSOFT_KUBERNETES = "Microsoft.Kubernetes" + +class Enum1(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + + MANAGED_CLUSTERS = "managedClusters" + CONNECTED_CLUSTERS = "connectedClusters" + +class FluxComplianceState(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Compliance state of the cluster object. + """ + + COMPLIANT = "Compliant" + NON_COMPLIANT = "Non-Compliant" + PENDING = "Pending" + SUSPENDED = "Suspended" + UNKNOWN = "Unknown" + +class KustomizationValidationType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Specify whether to validate the Kubernetes objects referenced in the Kustomization before + applying them to the cluster. + """ + + NONE = "none" + CLIENT = "client" + SERVER = "server" + +class LevelType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Level of the status. + """ + + ERROR = "Error" + WARNING = "Warning" + INFORMATION = "Information" + +class MessageLevelType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Level of the message. + """ + + ERROR = "Error" + WARNING = "Warning" + INFORMATION = "Information" + +class OperatorScopeType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Scope at which the operator will be installed. + """ + + CLUSTER = "cluster" + NAMESPACE = "namespace" + +class OperatorType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Type of the operator + """ + + FLUX = "Flux" + +class ProvisioningState(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The provisioning state of the resource. + """ + + SUCCEEDED = "Succeeded" + FAILED = "Failed" + CANCELED = "Canceled" + CREATING = "Creating" + UPDATING = "Updating" + DELETING = "Deleting" + +class ProvisioningStateType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The provisioning state of the resource provider. + """ + + ACCEPTED = "Accepted" + DELETING = "Deleting" + RUNNING = "Running" + SUCCEEDED = "Succeeded" + FAILED = "Failed" + +class ScopeType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Scope at which the configuration will be installed. + """ + + CLUSTER = "cluster" + NAMESPACE = "namespace" + +class SourceKindType(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """Source Kind to pull the configuration data from. + """ + + GIT_REPOSITORY = "GitRepository" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/__init__.py new file mode 100644 index 00000000000..ee01fecd439 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/__init__.py @@ -0,0 +1,31 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._extensions_operations import ExtensionsOperations +from ._operation_status_operations import OperationStatusOperations +from ._cluster_extension_type_operations import ClusterExtensionTypeOperations +from ._cluster_extension_types_operations import ClusterExtensionTypesOperations +from ._extension_type_versions_operations import ExtensionTypeVersionsOperations +from ._location_extension_types_operations import LocationExtensionTypesOperations +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._flux_configurations_operations import FluxConfigurationsOperations +from ._flux_config_operation_status_operations import FluxConfigOperationStatusOperations +from ._operations import Operations + +__all__ = [ + 'ExtensionsOperations', + 'OperationStatusOperations', + 'ClusterExtensionTypeOperations', + 'ClusterExtensionTypesOperations', + 'ExtensionTypeVersionsOperations', + 'LocationExtensionTypesOperations', + 'SourceControlConfigurationsOperations', + 'FluxConfigurationsOperations', + 'FluxConfigOperationStatusOperations', + 'Operations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_cluster_extension_type_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_cluster_extension_type_operations.py new file mode 100644 index 00000000000..116d991666f --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_cluster_extension_type_operations.py @@ -0,0 +1,119 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class ClusterExtensionTypeOperations(object): + """ClusterExtensionTypeOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_type_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.ExtensionType" + """Get Extension Type details. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_type_name: Extension type name. + :type extension_type_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: ExtensionType, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionType + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionType"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionTypeName': self._serialize.url("extension_type_name", extension_type_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('ExtensionType', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensionTypes/{extensionTypeName}'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_cluster_extension_types_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_cluster_extension_types_operations.py new file mode 100644 index 00000000000..9a59fe9f602 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_cluster_extension_types_operations.py @@ -0,0 +1,132 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class ClusterExtensionTypesOperations(object): + """ClusterExtensionTypesOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ExtensionTypeList"] + """Get Extension Types. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionTypeList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionTypeList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionTypeList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionTypeList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensionTypes'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_extension_type_versions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_extension_type_versions_operations.py new file mode 100644 index 00000000000..a9db32fce8b --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_extension_type_versions_operations.py @@ -0,0 +1,122 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionTypeVersionsOperations(object): + """ExtensionTypeVersionsOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + location, # type: str + extension_type_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ExtensionVersionList"] + """List available versions for an Extension Type. + + :param location: extension location. + :type location: str + :param extension_type_name: Extension type name. + :type extension_type_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionVersionList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionVersionList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionVersionList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'location': self._serialize.url("location", location, 'str'), + 'extensionTypeName': self._serialize.url("extension_type_name", extension_type_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionVersionList', pipeline_response) + list_of_elem = deserialized.versions + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/providers/Microsoft.KubernetesConfiguration/locations/{location}/extensionTypes/{extensionTypeName}/versions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_extensions_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_extensions_operations.py new file mode 100644 index 00000000000..b9a4aa6a917 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_extensions_operations.py @@ -0,0 +1,657 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.core.polling import LROPoller, NoPolling, PollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.arm_polling import ARMPolling + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class ExtensionsOperations(object): + """ExtensionsOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def _create_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + extension, # type: "_models.Extension" + **kwargs # type: Any + ): + # type: (...) -> "_models.Extension" + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._create_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(extension, 'Extension') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('Extension', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _create_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def begin_create( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + extension, # type: "_models.Extension" + **kwargs # type: Any + ): + # type: (...) -> LROPoller["_models.Extension"] + """Create a new Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param extension: Properties necessary to Create an Extension. + :type extension: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Extension + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either Extension or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Extension] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._create_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + extension=extension, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_create.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.Extension" + """Gets Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: Extension, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Extension + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def _delete_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + force_delete=None, # type: Optional[bool] + **kwargs # type: Any + ): + # type: (...) -> None + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + if force_delete is not None: + query_parameters['forceDelete'] = self._serialize.query("force_delete", force_delete, 'bool') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 202, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def begin_delete( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + force_delete=None, # type: Optional[bool] + **kwargs # type: Any + ): + # type: (...) -> LROPoller[None] + """Delete a Kubernetes Cluster Extension. This will cause the Agent to Uninstall the extension + from the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param force_delete: Delete the extension resource in Azure - not the normal asynchronous + delete. + :type force_delete: bool + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + force_delete=force_delete, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def _update_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + patch_extension, # type: "_models.PatchExtension" + **kwargs # type: Any + ): + # type: (...) -> "_models.Extension" + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: lambda response: ResourceExistsError(response=response, model=self._deserialize(_models.ErrorResponse, response), error_format=ARMErrorFormat), + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._update_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(patch_extension, 'PatchExtension') + body_content_kwargs['content'] = body_content + request = self._client.patch(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _update_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def begin_update( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + patch_extension, # type: "_models.PatchExtension" + **kwargs # type: Any + ): + # type: (...) -> LROPoller["_models.Extension"] + """Patch an existing Kubernetes Cluster Extension. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param patch_extension: Properties to Patch in an existing Extension. + :type patch_extension: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.PatchExtension + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either Extension or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Extension] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.Extension"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._update_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + extension_name=extension_name, + patch_extension=patch_extension, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('Extension', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}'} # type: ignore + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ExtensionsList"] + """List all Extensions in the cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionsList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionsList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionsList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionsList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_flux_config_operation_status_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_flux_config_operation_status_operations.py new file mode 100644 index 00000000000..4bd346a003f --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_flux_config_operation_status_operations.py @@ -0,0 +1,123 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class FluxConfigOperationStatusOperations(object): + """FluxConfigOperationStatusOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + flux_configuration_name, # type: str + operation_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.OperationStatusResult" + """Get Async Operation status. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param flux_configuration_name: Name of the Flux Configuration. + :type flux_configuration_name: str + :param operation_id: operation Id. + :type operation_id: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: OperationStatusResult, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperationStatusResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusResult"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + 'operationId': self._serialize.url("operation_id", operation_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('OperationStatusResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}/operations/{operationId}'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_flux_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_flux_configurations_operations.py new file mode 100644 index 00000000000..0b8e72b4573 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_flux_configurations_operations.py @@ -0,0 +1,659 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.core.polling import LROPoller, NoPolling, PollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.arm_polling import ARMPolling + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class FluxConfigurationsOperations(object): + """FluxConfigurationsOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + flux_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.FluxConfiguration" + """Gets details of the Flux Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param flux_configuration_name: Name of the Flux Configuration. + :type flux_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: FluxConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + def _create_or_update_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + flux_configuration_name, # type: str + flux_configuration, # type: "_models.FluxConfiguration" + **kwargs # type: Any + ): + # type: (...) -> "_models.FluxConfiguration" + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfiguration"] + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: lambda response: ResourceExistsError(response=response, model=self._deserialize(_models.ErrorResponse, response), error_format=ARMErrorFormat), + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._create_or_update_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(flux_configuration, 'FluxConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _create_or_update_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + def begin_create_or_update( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + flux_configuration_name, # type: str + flux_configuration, # type: "_models.FluxConfiguration" + **kwargs # type: Any + ): + # type: (...) -> LROPoller["_models.FluxConfiguration"] + """Create a new Kubernetes Flux Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param flux_configuration_name: Name of the Flux Configuration. + :type flux_configuration_name: str + :param flux_configuration: Properties necessary to Create a FluxConfiguration. + :type flux_configuration: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either FluxConfiguration or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfiguration] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfiguration"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._create_or_update_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + flux_configuration_name=flux_configuration_name, + flux_configuration=flux_configuration, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + def _update_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + flux_configuration_name, # type: str + flux_configuration_patch, # type: "_models.FluxConfigurationPatch" + **kwargs # type: Any + ): + # type: (...) -> "_models.FluxConfiguration" + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfiguration"] + error_map = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: lambda response: ResourceExistsError(response=response, model=self._deserialize(_models.ErrorResponse, response), error_format=ARMErrorFormat), + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self._update_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(flux_configuration_patch, 'FluxConfigurationPatch') + body_content_kwargs['content'] = body_content + request = self._client.patch(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + _update_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + def begin_update( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + flux_configuration_name, # type: str + flux_configuration_patch, # type: "_models.FluxConfigurationPatch" + **kwargs # type: Any + ): + # type: (...) -> LROPoller["_models.FluxConfiguration"] + """Update an existing Kubernetes Flux Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param flux_configuration_name: Name of the Flux Configuration. + :type flux_configuration_name: str + :param flux_configuration_patch: Properties to Patch in an existing Flux Configuration. + :type flux_configuration_patch: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfigurationPatch + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either FluxConfiguration or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfiguration] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfiguration"] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._update_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + flux_configuration_name=flux_configuration_name, + flux_configuration_patch=flux_configuration_patch, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + deserialized = self._deserialize('FluxConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + return deserialized + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + def _delete_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + flux_configuration_name, # type: str + force_delete=None, # type: Optional[bool] + **kwargs # type: Any + ): + # type: (...) -> None + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + if force_delete is not None: + query_parameters['forceDelete'] = self._serialize.query("force_delete", force_delete, 'bool') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 202, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + def begin_delete( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + flux_configuration_name, # type: str + force_delete=None, # type: Optional[bool] + **kwargs # type: Any + ): + # type: (...) -> LROPoller[None] + """This will delete the YAML file used to set up the Flux Configuration, thus stopping future sync + from the source repo. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param flux_configuration_name: Name of the Flux Configuration. + :type flux_configuration_name: str + :param force_delete: Delete the extension resource in Azure - not the normal asynchronous + delete. + :type force_delete: bool + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + flux_configuration_name=flux_configuration_name, + force_delete=force_delete, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'fluxConfigurationName': self._serialize.url("flux_configuration_name", flux_configuration_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, lro_options={'final-state-via': 'azure-async-operation'}, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations/{fluxConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.FluxConfigurationsList"] + """List all Flux Configurations. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either FluxConfigurationsList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.FluxConfigurationsList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.FluxConfigurationsList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('FluxConfigurationsList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/fluxConfigurations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_location_extension_types_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_location_extension_types_operations.py new file mode 100644 index 00000000000..7e4e5eb165e --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_location_extension_types_operations.py @@ -0,0 +1,118 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class LocationExtensionTypesOperations(object): + """LocationExtensionTypesOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + location, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ExtensionTypeList"] + """List all Extension Types. + + :param location: extension location. + :type location: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ExtensionTypeList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ExtensionTypeList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ExtensionTypeList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'location': self._serialize.url("location", location, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ExtensionTypeList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/providers/Microsoft.KubernetesConfiguration/locations/{location}/extensionTypes'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_operation_status_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_operation_status_operations.py new file mode 100644 index 00000000000..9cd277b30f3 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_operation_status_operations.py @@ -0,0 +1,210 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class OperationStatusOperations(object): + """OperationStatusOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + extension_name, # type: str + operation_id, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.OperationStatusResult" + """Get Async Operation status. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param extension_name: Name of the Extension. + :type extension_name: str + :param operation_id: operation Id. + :type operation_id: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: OperationStatusResult, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperationStatusResult + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusResult"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'extensionName': self._serialize.url("extension_name", extension_name, 'str'), + 'operationId': self._serialize.url("operation_id", operation_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('OperationStatusResult', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensions/{extensionName}/operations/{operationId}'} # type: ignore + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.OperationStatusList"] + """List Async Operations, currently in progress, in a cluster. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either OperationStatusList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.OperationStatusList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.OperationStatusList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('OperationStatusList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_operations.py new file mode 100644 index 00000000000..35394f50809 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_operations.py @@ -0,0 +1,110 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.mgmt.core.exceptions import ARMErrorFormat + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class Operations(object): + """Operations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def list( + self, + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.ResourceProviderOperationList"] + """List all the available operations the KubernetesConfiguration resource provider supports. + + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either ResourceProviderOperationList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.ResourceProviderOperationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.ResourceProviderOperationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('ResourceProviderOperationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} # type: ignore diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..3233f416ca0 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/v2021_11_01_preview/operations/_source_control_configurations_operations.py @@ -0,0 +1,429 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.paging import ItemPaged +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.core.polling import LROPoller, NoPolling, PollingMethod +from azure.mgmt.core.exceptions import ARMErrorFormat +from azure.mgmt.core.polling.arm_polling import ARMPolling + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class SourceControlConfigurationsOperations(object): + """SourceControlConfigurationsOperations operations. + + You should not instantiate this class directly. Instead, you should create a Client instance that + instantiates it for you and attaches it as an attribute. + + :ivar models: Alias to model classes used in this operation group. + :type models: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + """ + + models = _models + + def __init__(self, client, config, serializer, deserializer): + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self._config = config + + def get( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> "_models.SourceControlConfiguration" + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self.get.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def create_or_update( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + source_control_configuration, # type: "_models.SourceControlConfiguration" + **kwargs # type: Any + ): + # type: (...) -> "_models.SourceControlConfiguration" + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create KubernetesConfiguration. + :type source_control_configuration: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceControlConfiguration + :keyword callable cls: A custom type or function that will be passed the direct response + :return: SourceControlConfiguration, or the result of cls(response) + :rtype: ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceControlConfiguration + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfiguration"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + content_type = kwargs.pop("content_type", "application/json") + accept = "application/json" + + # Construct URL + url = self.create_or_update.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = self._serialize.header("content_type", content_type, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + body_content_kwargs = {} # type: Dict[str, Any] + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + body_content_kwargs['content'] = body_content + request = self._client.put(url, query_parameters, header_parameters, **body_content_kwargs) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, {}) + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def _delete_initial( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> None + cls = kwargs.pop('cls', None) # type: ClsType[None] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + # Construct URL + url = self._delete_initial.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.delete(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200, 204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + if cls: + return cls(pipeline_response, None, {}) + + _delete_initial.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def begin_delete( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + source_control_configuration_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> LROPoller[None] + """This will delete the YAML file used to set up the Source control configuration, thus stopping + future sync from the source repo. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control Configuration. + :type source_control_configuration_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :keyword polling: By default, your polling method will be ARMPolling. + Pass in False for this operation to not poll, or pass in your own initialized polling object for a personal polling strategy. + :paramtype polling: bool or ~azure.core.polling.PollingMethod + :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :return: An instance of LROPoller that returns either None or the result of cls(response) + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + polling = kwargs.pop('polling', True) # type: Union[bool, PollingMethod] + cls = kwargs.pop('cls', None) # type: ClsType[None] + lro_delay = kwargs.pop( + 'polling_interval', + self._config.polling_interval + ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) + + def get_long_running_output(pipeline_response): + if cls: + return cls(pipeline_response, None, {}) + + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str'), + } + + if polling is True: polling_method = ARMPolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} # type: ignore + + def list( + self, + resource_group_name, # type: str + cluster_rp, # type: Union[str, "_models.Enum0"] + cluster_resource_name, # type: Union[str, "_models.Enum1"] + cluster_name, # type: str + **kwargs # type: Any + ): + # type: (...) -> Iterable["_models.SourceControlConfigurationList"] + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. The name is case insensitive. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either Microsoft.ContainerService (for AKS + clusters) or Microsoft.Kubernetes (for OnPrem K8S clusters). + :type cluster_rp: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum0 + :param cluster_resource_name: The Kubernetes cluster resource name - either managedClusters + (for AKS clusters) or connectedClusters (for OnPrem K8S clusters). + :type cluster_resource_name: str or ~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.Enum1 + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :keyword callable cls: A custom type or function that will be passed the direct response + :return: An iterator like instance of either SourceControlConfigurationList or the result of cls(response) + :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.kubernetesconfiguration.v2021_11_01_preview.models.SourceControlConfigurationList] + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.SourceControlConfigurationList"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + api_version = "2021-11-01-preview" + accept = "application/json" + + def prepare_request(next_link=None): + # Construct headers + header_parameters = {} # type: Dict[str, Any] + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + if not next_link: + # Construct URL + url = self.list.metadata['url'] # type: ignore + path_format_arguments = { + 'subscriptionId': self._serialize.url("self._config.subscription_id", self._config.subscription_id, 'str', min_length=1), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str', max_length=90, min_length=1), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + else: + url = next_link + query_parameters = {} # type: Dict[str, Any] + request = self._client.get(url, query_parameters, header_parameters) + return request + + def extract_data(pipeline_response): + deserialized = self._deserialize('SourceControlConfigurationList', pipeline_response) + list_of_elem = deserialized.value + if cls: + list_of_elem = cls(list_of_elem) + return deserialized.next_link or None, iter(list_of_elem) + + def get_next(next_link=None): + request = prepare_request(next_link) + + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response) + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) + + return pipeline_response + + return ItemPaged( + get_next, extract_data + ) + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} # type: ignore diff --git a/src/k8s-configuration/setup.py b/src/k8s-configuration/setup.py index 6b597acaa7f..048614fdd87 100644 --- a/src/k8s-configuration/setup.py +++ b/src/k8s-configuration/setup.py @@ -14,7 +14,7 @@ from distutils import log as logger logger.warn("Wheel is not available, disabling bdist_wheel hook") -VERSION = '1.1.1' +VERSION = '1.2.0' # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers @@ -30,7 +30,6 @@ 'License :: OSI Approved :: MIT License', ] -# TODO: Add any additional SDK dependencies here DEPENDENCIES = ["pycryptodome~=3.9.8"] with open('README.rst', 'r', encoding='utf-8') as f: diff --git a/testing/Test.ps1 b/testing/Test.ps1 index 06c089f6f52..706eed01035 100644 --- a/testing/Test.ps1 +++ b/testing/Test.ps1 @@ -2,6 +2,7 @@ param ( [string] $Path, [switch] $SkipInstall, [switch] $CI, + [switch] $ParallelCI, [switch] $OnlyPublicTests, [Parameter(Mandatory=$True)] @@ -10,13 +11,20 @@ param ( ) # Disable confirm prompt for script +# Only show errors, don't show warnings az config set core.disable_confirm_prompt=true +az config set core.only_show_errors=true $ENVCONFIG = Get-Content -Path $PSScriptRoot/settings.json | ConvertFrom-Json az account set --subscription $ENVCONFIG.subscriptionId $Env:KUBECONFIG="$PSScriptRoot/tmp/KUBECONFIG" +$TestFileDirectory="$PSScriptRoot/results" + +if (-not (Test-Path -Path $TestFileDirectory)) { + New-Item -ItemType Directory -Path $TestFileDirectory +} if ($Type -eq 'k8s-extension') { $k8sExtensionVersion = $ENVCONFIG.extensionVersion.'k8s-extension' @@ -64,19 +72,62 @@ if ($Type -eq 'k8s-extension') { Write-Host "Installing k8s-configuration version $k8sConfigurationVersion..." az extension add --source ./bin/k8s_configuration-$k8sConfigurationVersion-py3-none-any.whl } - $testFilePath = "$PSScriptRoot/test/configurations" + $testFilePaths = "$PSScriptRoot/test/configurations" } -if ($CI) { +if ($ParallelCI) { + # This runs the tests in parallel during the CI pipline to speed up testing + + Write-Host "Invoking Pester to run tests from '$testFilePath'..." + $testFiles = @() + foreach ($paths in $testFilePaths) + { + $temp = Get-ChildItem $paths + $testFiles += $temp + } + $resultFileNumber = 0 + foreach ($testFile in $testFiles) + { + $resultFileNumber++ + $testName = Split-Path $testFile –leaf + Start-Job -ArgumentList $testName, $testFile, $resultFileNumber, $TestFileDirectory -Name $testName -ScriptBlock { + param($name, $testFile, $resultFileNumber, $testFileDirectory) + + Write-Host "$testFile to result file #$resultFileNumber" + $testResult = Invoke-Pester $testFile -Passthru -Output Detailed + $testResult | Export-JUnitReport -Path "$testFileDirectory/$name.xml" + } + } + + do { + Write-Host ">> Still running tests @ $(Get-Date –Format "HH:mm:ss")" –ForegroundColor Blue + Get-Job | Where-Object { $_.State -eq "Running" } | Format-Table –AutoSize + Start-Sleep –Seconds 30 + } while((Get-Job | Where-Object { $_.State -eq "Running" } | Measure-Object).Count -ge 1) + + Get-Job | Wait-Job + $failedJobs = Get-Job | Where-Object { -not ($_.State -eq "Completed")} + Get-Job | Receive-Job –AutoRemoveJob –Wait –ErrorAction 'Continue' + + if ($failedJobs.Count -gt 0) { + Write-Host "Failed Jobs" –ForegroundColor Red + $failedJobs + throw "One or more tests failed" + } +} elseif ($CI) { + if ($Path) { + $testFilePath = "$PSScriptRoot/$Path" + } Write-Host "Invoking Pester to run tests from '$testFilePath'..." $testResult = Invoke-Pester $testFilePath -Passthru -Output Detailed - $testResult | Export-JUnitReport -Path TestResults.xml + $testName = Split-Path $testFilePath –leaf + $testResult | Export-JUnitReport -Path "$testFileDirectory/$testName.xml" } else { if ($Path) { Write-Host "Invoking Pester to run tests from '$PSScriptRoot/$Path'" Invoke-Pester -Output Detailed $PSScriptRoot/$Path } else { Write-Host "Invoking Pester to run tests from '$testFilePath'..." - Invoke-Pester -Output Detailed $testFilePathc + Invoke-Pester -Output Detailed $testFilePath } -} +} \ No newline at end of file diff --git a/testing/pipeline/k8s-custom-pipelines.yml b/testing/pipeline/k8s-custom-pipelines.yml index 5db2f6d7047..f429213235c 100644 --- a/testing/pipeline/k8s-custom-pipelines.yml +++ b/testing/pipeline/k8s-custom-pipelines.yml @@ -20,120 +20,14 @@ stages: RESOURCE_GROUP: "K8sPartnerExtensionTest" BASE_CLUSTER_NAME: "k8s-configuration-cluster" jobs: - - job: K8sConfigurationTestSuite - displayName: "Run the Test Suite" - pool: - vmImage: 'ubuntu-latest' - steps: - - checkout: self - - bash: | - echo "Installing helm3" - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 - chmod 700 get_helm.sh - ./get_helm.sh --version v3.6.3 - - echo "Installing kubectl" - curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x ./kubectl - sudo mv ./kubectl /usr/local/bin/kubectl - kubectl version --client - displayName: "Setup the VM with helm3 and kubectl" - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - - # clone azure-cli - pip install --upgrade pip - pip install azdev - - ls $(CLI_REPO_PATH) - - azdev --version - azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build $(EXTENSION_NAME) with azdev" - - - bash: | - K8S_CONFIG_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) - echo "##vso[task.setvariable variable=K8S_CONFIG_VERSION]$K8S_CONFIG_VERSION" - cp * $(TEST_PATH)/bin - echo $(ls -l) - workingDirectory: $(CLI_REPO_PATH)/dist - displayName: "Copy the Built .whl to Extension Test Path" - - - bash: | - RAND_STR=$RANDOM - AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" - ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" - - JSON_STRING=$(jq -n \ - --arg SUB_ID "$SUBSCRIPTION_ID" \ - --arg RG "$RESOURCE_GROUP" \ - --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ - --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ - --arg K8S_CONFIG_VERSION "$K8S_CONFIG_VERSION" \ - '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-configuration": $K8S_CONFIG_VERSION, connectedk8s: "1.0.0"}}') - echo $JSON_STRING > settings.json - cat settings.json - workingDirectory: $(TEST_PATH) - displayName: "Generate a settings.json file" - - - bash : | - echo "Downloading the kind script" - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 - chmod +x ./kind - ./kind create cluster - displayName: "Create and Start the Kind cluster" - - - task: AzureCLI@2 - displayName: Bootstrap - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Bootstrap.ps1 -CI - workingDirectory: $(TEST_PATH) - - - task: AzureCLI@2 - displayName: Run the Test Suite - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Test.ps1 -Type k8s-configuration -CI - workingDirectory: $(TEST_PATH) - continueOnError: true - - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'JUnit' - testResultsFiles: '**/TestResults.xml' - failTaskOnFailedTests: true - condition: succeededOrFailed() - - - task: AzureCLI@2 - displayName: Cleanup - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Cleanup.ps1 -CI - workingDirectory: $(TEST_PATH) - condition: succeededOrFailed() - + - template: ./templates/run-test.yml + parameters: + jobName: SourceControlConfiguration + path: ./test/configurations/Configuration.*.Tests.ps1 + - template: ./templates/run-test.yml + parameters: + jobName: FluxConfiguration + path: ./test/configurations/Flux.*.Tests.ps1 - job: BuildPublishExtension pool: vmImage: 'ubuntu-latest' diff --git a/testing/pipeline/templates/run-test.yml b/testing/pipeline/templates/run-test.yml new file mode 100644 index 00000000000..f7943390877 --- /dev/null +++ b/testing/pipeline/templates/run-test.yml @@ -0,0 +1,112 @@ +parameters: + jobName: '' + path: '' + +jobs: +- job: ${{ parameters.jobName}} + pool: + vmImage: 'ubuntu-latest' + steps: + - bash: | + echo "Installing helm3" + curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 + chmod 700 get_helm.sh + ./get_helm.sh --version v3.6.3 + echo "Installing kubectl" + curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin/kubectl + kubectl version --client + displayName: "Setup the VM with helm3 and kubectl" + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: | + set -ev + echo "Building extension ${EXTENSION_NAME}..." + # prepare and activate virtualenv + pip install virtualenv + python3 -m venv env/ + source env/bin/activate + # clone azure-cli + git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli + pip install --upgrade pip + pip install -q azdev + ls $(CLI_REPO_PATH) + azdev --version + azdev setup -c ../azure-cli -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) + azdev extension build $(EXTENSION_NAME) + workingDirectory: $(CLI_REPO_PATH) + displayName: "Setup and Build Extension with azdev" + + - bash: | + K8S_CONFIG_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) + echo "##vso[task.setvariable variable=K8S_CONFIG_VERSION]$K8S_CONFIG_VERSION" + cp * $(TEST_PATH)/bin + workingDirectory: $(CLI_REPO_PATH)/dist + displayName: "Copy the Built .whl to Extension Test Path" + - bash: | + RAND_STR=$RANDOM + AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" + ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" + + JSON_STRING=$(jq -n \ + --arg SUB_ID "$SUBSCRIPTION_ID" \ + --arg RG "$RESOURCE_GROUP" \ + --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ + --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ + --arg K8S_CONFIG_VERSION "$K8S_CONFIG_VERSION" \ + '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-configuration": $K8S_CONFIG_VERSION, connectedk8s: "1.0.0"}}') + echo $JSON_STRING > settings.json + cat settings.json + workingDirectory: $(TEST_PATH) + displayName: "Generate a settings.json file" + - bash : | + echo "Downloading the kind script" + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 + chmod +x ./kind + ./kind create cluster + displayName: "Create and Start the Kind cluster" + + - bash: | + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + displayName: "Upgrade az to latest version" + - task: AzureCLI@2 + displayName: Bootstrap + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Bootstrap.ps1 -CI + workingDirectory: $(TEST_PATH) + + - task: AzureCLI@2 + displayName: Run the Test Suite for ${{ parameters.path }} + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Test.ps1 -CI -Path ${{ parameters.path }} -Type k8s-configuration + workingDirectory: $(TEST_PATH) + continueOnError: true + + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/testing/results/*.xml' + failTaskOnFailedTests: true + condition: succeededOrFailed() + + - task: AzureCLI@2 + displayName: Cleanup + inputs: + azureSubscription: AzureResourceConnection + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + .\Cleanup.ps1 -CI + workingDirectory: $(TEST_PATH) + condition: succeededOrFailed() \ No newline at end of file diff --git a/testing/test/configurations/Constants.ps1 b/testing/test/configurations/Constants.ps1 index f1e8c6ffdc3..8014c5446b3 100644 --- a/testing/test/configurations/Constants.ps1 +++ b/testing/test/configurations/Constants.ps1 @@ -4,5 +4,6 @@ $FAILED_MESSAGE = "Failed the install of the operator" $TMP_DIRECTORY = "$PSScriptRoot\..\..\tmp" $POD_RUNNING = "Running" +$SUCCEEDED = "Succeeded" -$MAX_RETRY_ATTEMPTS = 18 \ No newline at end of file +$MAX_RETRY_ATTEMPTS = 24 \ No newline at end of file diff --git a/testing/test/configurations/Flux.HTTPS.Tests.ps1 b/testing/test/configurations/Flux.HTTPS.Tests.ps1 new file mode 100644 index 00000000000..b5de6ab34ad --- /dev/null +++ b/testing/test/configurations/Flux.HTTPS.Tests.ps1 @@ -0,0 +1,55 @@ +Describe 'Flux Configuration (HTTPS) Testing' { + BeforeAll { + $configurationName = "https-config" + . $PSScriptRoot/Constants.ps1 + . $PSScriptRoot/Helper.ps1 + + $dummyValue = "dummyValue" + $secretName = "git-auth-$configurationName" + } + + It 'Creates a configuration with https user and https key on the cluster' { + $output = az k8s-configuration flux create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "https://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --https-user $dummyValue --https-key $dummyValue --namespace $configurationName --branch main --no-wait + $? | Should -BeTrue + + # Loop and retry until the configuration installs and helm pod comes up + $n = 0 + do + { + $output = az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $provisioningState = ($output | ConvertFrom-Json).provisioningState + Write-Host "Provisioning State: $provisioningState" + if ($provisioningState -eq $SUCCEEDED) { + break + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + + Secret-Exists $secretName -Namespace $configurationName + } + + It "Lists the configurations on the cluster" { + $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + $configExists | Should -Not -BeNullOrEmpty + } + + It "Deletes the configuration from the cluster" { + az k8s-configuration flux delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName --force + $? | Should -BeTrue + + # Configuration should be removed from the resource model + az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeFalse + } + + It "Performs another list after the delete" { + $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + $configExists | Should -BeNullOrEmpty + } +} \ No newline at end of file diff --git a/testing/test/configurations/Flux.PrivateKey.Tests.ps1 b/testing/test/configurations/Flux.PrivateKey.Tests.ps1 new file mode 100644 index 00000000000..6c1d4ecba30 --- /dev/null +++ b/testing/test/configurations/Flux.PrivateKey.Tests.ps1 @@ -0,0 +1,88 @@ +Describe 'Flux Configuration (SSH Configs) Testing' { + BeforeAll { + . $PSScriptRoot/Constants.ps1 + . $PSScriptRoot/Helper.ps1 + + $RSA_KEYPATH = "$TMP_DIRECTORY\rsa.private" + $ECDSA_KEYPATH = "$TMP_DIRECTORY\ecdsa.private" + $ED25519_KEYPATH = "$TMP_DIRECTORY\ed25519.private" + + $KEY_ARR = [System.Tuple]::Create("rsa", $RSA_KEYPATH), [System.Tuple]::Create("ecdsa", $ECDSA_KEYPATH), [System.Tuple]::Create("ed25519", $ED25519_KEYPATH) + foreach ($keyTuple in $KEY_ARR) { + # Automattically say yes to overwrite with ssh-keygen + Write-Output "y" | ssh-keygen -t $keyTuple.Item1 -f $keyTuple.Item2 -P """" + } + + $SSH_GIT_URL = "ssh://github.com/anubhav929/flux-get-started.git" + $HTTP_GIT_URL = "https://github.com/Azure/arc-k8s-demo" + + $configDataRSA = [System.Tuple]::Create("rsa-config", $RSA_KEYPATH) + $configDataECDSA = [System.Tuple]::Create("ecdsa-config", $ECDSA_KEYPATH) + $configDataED25519 = [System.Tuple]::Create("ed25519-config", $ED25519_KEYPATH) + + $CONFIG_ARR = $configDataRSA, $configDataECDSA, $configDataED25519 + } + + It 'Creates a configuration with each type of ssh private key' { + foreach($configData in $CONFIG_ARR) { + Write-Host "Creating a configuration of type $($configData.Item1)" + az k8s-configuration flux create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u $SSH_GIT_URL -n $configData.Item1 --scope cluster --namespace $configData.Item1 --ssh-private-key-file $configData.Item2 --branch main --no-wait + $? | Should -BeTrue + } + + # Loop and retry until the configuration installs and helm pod comes up + $n = 0 + do + { + $readyConfigs = 0 + foreach($configData in $CONFIG_ARR) { + $output = az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $CONFIGdATA.Item1 + $provisioningState = ($output | ConvertFrom-Json).provisioningState + Write-Host "Provisioning State: $provisioningState" + if ($provisioningState -eq $SUCCEEDED) { + $readyConfigs += 1 + } + } + Write-Host "$(kubectl get fc -A -o yaml)" + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le 30 -And $readyConfigs -ne 3) + $n | Should -BeLessOrEqual 30 + } + + It 'Fails when trying to create a configuration with ssh url and https auth values' { + az k8s-configuration flux create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u $HTTP_GIT_URL -n "config-should-fail" --scope cluster --namespace "config-should-fail" --ssh-private-key-file $RSA_KEYPATH --branch main --no-wait + $? | Should -BeFalse + } + + It "Lists the configurations on the cluster" { + $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + foreach ($configData in $CONFIG_ARR) { + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configData.Item1 } + $configExists | Should -Not -BeNullOrEmpty + } + } + + It "Deletes the configuration from the cluster" { + foreach ($configData in $CONFIG_ARR) { + az k8s-configuration flux delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configData.Item1 --force + $? | Should -BeTrue + + # Configuration should be removed from the resource model + az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configData.Item1 + $? | Should -BeFalse + } + } + + It "Performs another list after the delete" { + $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + foreach ($configData in $CONFIG_ARR) { + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configData.Item1 } + $configExists | Should -BeNullOrEmpty + } + } +} \ No newline at end of file diff --git a/testing/test/configurations/Flux.Tests.ps1 b/testing/test/configurations/Flux.Tests.ps1 new file mode 100644 index 00000000000..5d87fe7e31f --- /dev/null +++ b/testing/test/configurations/Flux.Tests.ps1 @@ -0,0 +1,61 @@ +Describe 'Basic Flux Configuration Testing' { + BeforeAll { + $configurationName = "basic-config" + . $PSScriptRoot/Constants.ps1 + . $PSScriptRoot/Helper.ps1 + } + + It 'Creates a configuration and checks that it onboards correctly' { + az k8s-configuration flux create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "https://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --namespace $configurationName --branch main --no-wait + $? | Should -BeTrue + + # Loop and retry until the configuration installs + $n = 0 + do + { + $output = az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $provisioningState = ($output | ConvertFrom-Json).provisioningState + Write-Host "Provisioning State: $provisioningState" + if ($provisioningState -eq $SUCCEEDED) { + break + } + Start-Sleep -Seconds 10 + $n += 1 + } while ($n -le $MAX_RETRY_ATTEMPTS) + $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS + } + + It "Performs a show on the configuration" { + $output = az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -n $configurationName + $? | Should -BeTrue + $output | Should -Not -BeNullOrEmpty + } + + It "Performs a re-PUT of the configuration on the cluster, with HTTPS in caps" { + az k8s-configuration flux create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "HTTPS://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --namespace $configurationName --branch main --no-wait + $? | Should -BeTrue + } + + It "Lists the configurations on the cluster" { + $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $? | Should -BeTrue + + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + $configExists | Should -Not -BeNullOrEmpty + } + + It "Deletes the configuration from the cluster" { + az k8s-configuration flux delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName --force + $? | Should -BeTrue + + # Configuration should be removed from the resource model + az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName + $? | Should -BeFalse + } + + It "Performs another list after the delete" { + $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters + $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } + $configExists | Should -BeNullOrEmpty + } +} \ No newline at end of file diff --git a/testing/test/configurations/Helper.ps1 b/testing/test/configurations/Helper.ps1 index 842e2da84aa..6a29c2b0f56 100644 --- a/testing/test/configurations/Helper.ps1 +++ b/testing/test/configurations/Helper.ps1 @@ -19,6 +19,27 @@ function Get-ConfigStatus { return $null } +function Get-FluxConfigData { + param( + [string]$configName + ) + + $output = kubectl get fc -A -o json | ConvertFrom-Json + return $output.items | Where-Object { $_.metadata.name -eq $configurationName } +} + +function Get-FluxConfigStatus { + param( + [string]$configName + ) + + $configData = Get-FluxConfigData $configName + if ($configData -ne $null) { + return $configData.status.provisioningState + } + return $null +} + function Get-PodStatus { param( [string]$podName, From 08661670de36f9a04f2054c0a42abed64169afc3 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Thu, 11 Nov 2021 22:42:58 -0800 Subject: [PATCH 78/80] Remove unneeded files --- testing/.gitignore | 9 - testing/Bootstrap.ps1 | 80 -------- testing/Cleanup.ps1 | 24 --- testing/README.md | 116 ----------- testing/Test.ps1 | 133 ------------ .../bin/connectedk8s-1.0.0-py3-none-any.whl | Bin 62802 -> 0 bytes testing/bin/connectedk8s-values.yaml | 3 - .../k8s_configuration-1.0.0-py3-none-any.whl | Bin 42351 -> 0 bytes .../bin/k8s_extension-0.3.0-py3-none-any.whl | Bin 52893 -> 0 bytes testing/docs/test_authoring.md | 142 ------------- testing/owners.txt | 2 - testing/pipeline/k8s-custom-pipelines.yml | 190 ------------------ testing/pipeline/templates/run-test.yml | 112 ----------- testing/settings.template.json | 12 -- .../Configuration.HTTPS.Tests.ps1 | 54 ----- .../Configuration.HelmOperator.Tests.ps1 | 52 ----- .../Configuration.KnownHost.Tests.ps1 | 6 - .../Configuration.PrivateKey.Tests.ps1 | 85 -------- .../configurations/Configuration.Tests.ps1 | 58 ------ testing/test/configurations/Constants.ps1 | 9 - .../test/configurations/Flux.HTTPS.Tests.ps1 | 55 ----- .../configurations/Flux.PrivateKey.Tests.ps1 | 88 -------- testing/test/configurations/Flux.Tests.ps1 | 61 ------ testing/test/configurations/Helper.ps1 | 66 ------ .../private-preview/AzurePolicy.Tests.ps1 | 95 --------- .../extensions/public/AzureDefender.Tests.ps1 | 93 --------- .../public/AzureMLKubernetes.Tests.ps1 | 94 --------- .../extensions/public/AzureMonitor.Tests.ps1 | 95 --------- testing/test/helper/Constants.ps1 | 7 - testing/test/helper/Helper.ps1 | 47 ----- 30 files changed, 1788 deletions(-) delete mode 100644 testing/.gitignore delete mode 100644 testing/Bootstrap.ps1 delete mode 100644 testing/Cleanup.ps1 delete mode 100644 testing/README.md delete mode 100644 testing/Test.ps1 delete mode 100644 testing/bin/connectedk8s-1.0.0-py3-none-any.whl delete mode 100644 testing/bin/connectedk8s-values.yaml delete mode 100644 testing/bin/k8s_configuration-1.0.0-py3-none-any.whl delete mode 100644 testing/bin/k8s_extension-0.3.0-py3-none-any.whl delete mode 100644 testing/docs/test_authoring.md delete mode 100644 testing/owners.txt delete mode 100644 testing/pipeline/k8s-custom-pipelines.yml delete mode 100644 testing/pipeline/templates/run-test.yml delete mode 100644 testing/settings.template.json delete mode 100644 testing/test/configurations/Configuration.HTTPS.Tests.ps1 delete mode 100644 testing/test/configurations/Configuration.HelmOperator.Tests.ps1 delete mode 100644 testing/test/configurations/Configuration.KnownHost.Tests.ps1 delete mode 100644 testing/test/configurations/Configuration.PrivateKey.Tests.ps1 delete mode 100644 testing/test/configurations/Configuration.Tests.ps1 delete mode 100644 testing/test/configurations/Constants.ps1 delete mode 100644 testing/test/configurations/Flux.HTTPS.Tests.ps1 delete mode 100644 testing/test/configurations/Flux.PrivateKey.Tests.ps1 delete mode 100644 testing/test/configurations/Flux.Tests.ps1 delete mode 100644 testing/test/configurations/Helper.ps1 delete mode 100644 testing/test/extensions/private-preview/AzurePolicy.Tests.ps1 delete mode 100644 testing/test/extensions/public/AzureDefender.Tests.ps1 delete mode 100644 testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 delete mode 100644 testing/test/extensions/public/AzureMonitor.Tests.ps1 delete mode 100644 testing/test/helper/Constants.ps1 delete mode 100644 testing/test/helper/Helper.ps1 diff --git a/testing/.gitignore b/testing/.gitignore deleted file mode 100644 index 083fdfb5c25..00000000000 --- a/testing/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -settings.json -tmp/ -bin/* -!bin/connectedk8s-1.0.0-py3-none-any.whl -!bin/k8s_extension-0.3.0-py3-none-any.whl -!bin/k8s_extension_private-0.1.0-py3-none-any.whl -!bin/k8s_configuration-1.0.0-py3-none-any.whl -!bin/connectedk8s-values.yaml -*.xml \ No newline at end of file diff --git a/testing/Bootstrap.ps1 b/testing/Bootstrap.ps1 deleted file mode 100644 index c9123ba6d03..00000000000 --- a/testing/Bootstrap.ps1 +++ /dev/null @@ -1,80 +0,0 @@ -param ( - [switch] $SkipInstall, - [switch] $CI -) - -# Disable confirm prompt for script -az config set core.disable_confirm_prompt=true - -# Configuring the environment -$ENVCONFIG = Get-Content -Path $PSScriptRoot/settings.json | ConvertFrom-Json - -az account set --subscription $ENVCONFIG.subscriptionId - -if (-not (Test-Path -Path $PSScriptRoot/tmp)) { - New-Item -ItemType Directory -Path $PSScriptRoot/tmp -} - -if (!$SkipInstall) { - Write-Host "Removing the old connnectedk8s extension..." - az extension remove -n connectedk8s - $connectedk8sVersion = $ENVCONFIG.extensionVersion.connectedk8s - if (!$connectedk8sVersion) { - Write-Host "connectedk8s extension version wasn't specified" -ForegroundColor Red - Exit 1 - } - Write-Host "Installing connectedk8s version $connectedk8sVersion..." - az extension add --source ./bin/connectedk8s-$connectedk8sVersion-py3-none-any.whl - if (!$?) { - Write-Host "Unable to find connectedk8s version $connectedk8sVersion, exiting..." - exit 1 - } -} - -Write-Host "Onboard cluster to Azure...starting!" - -az group show --name $envConfig.resourceGroup -if (!$?) { - Write-Host "Resource group does not exist, creating it now in region 'eastus2euap'" - az group create --name $envConfig.resourceGroup --location eastus2euap - - if (!$?) { - Write-Host "Failed to create Resource Group - exiting!" - Exit 1 - } -} - -# Skip creating the AKS Cluster if this is CI -if (!$CI) { - az aks show -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.aksClusterName - if (!$?) { - Write-Host "Cluster does not exist, creating it now" - az aks create -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.aksClusterName --generate-ssh-keys - } else { - Write-Host "Cluster already exists, no need to create it." - } - - Write-Host "Retrieving credentials for your AKS cluster..." - - az aks get-credentials -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.aksClusterName -f tmp/KUBECONFIG - if (!$?) - { - Write-Host "Cluster did not create successfully, exiting!" -ForegroundColor Red - Exit 1 - } - Write-Host "Successfully retrieved the AKS kubectl credentials" -} else { - Copy-Item $HOME/.kube/config -Destination $PSScriptRoot/tmp/KUBECONFIG -} - -az connectedk8s show -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.arcClusterName -if ($?) -{ - Write-Host "Cluster is already connected, no need to re-connect" - Exit 0 -} - -Write-Host "Connecting the cluster to Arc with connectedk8s..." -$Env:KUBECONFIG="$PSScriptRoot/tmp/KUBECONFIG" -$Env:HELMVALUESPATH="$PSScriptRoot/bin/connectedk8s-values.yaml" -az connectedk8s connect -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.arcClusterName diff --git a/testing/Cleanup.ps1 b/testing/Cleanup.ps1 deleted file mode 100644 index 9957a044241..00000000000 --- a/testing/Cleanup.ps1 +++ /dev/null @@ -1,24 +0,0 @@ -param ( - [switch] $CI -) - -# Disable confirm prompt for script -az config set core.disable_confirm_prompt=true - -$ENVCONFIG = Get-Content -Path $PSScriptRoot/settings.json | ConvertFrom-Json - -az account set --subscription $ENVCONFIG.subscriptionId - -$Env:KUBECONFIG="$PSScriptRoot/tmp/KUBECONFIG" -Write-Host "Removing the connectedk8s arc agents from the cluster..." -az connectedk8s delete -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.arcClusterName - -# Skip deleting the AKS Cluster if this is CI -if (!$CI) { - Write-Host "Deleting the AKS cluster from Azure..." - az aks delete -g $ENVCONFIG.resourceGroup -n $ENVCONFIG.aksClusterName - if (Test-Path -Path $PSScriptRoot/tmp) { - Write-Host "Deleting the tmp directory from the test directory" - Remove-Item -Path $PSScriptRoot/tmp -Force -Confirm:$false - } -} \ No newline at end of file diff --git a/testing/README.md b/testing/README.md deleted file mode 100644 index 2c2d48070bd..00000000000 --- a/testing/README.md +++ /dev/null @@ -1,116 +0,0 @@ -# K8s Partner Extension Test Suite - -This repository serves as the integration testing suite for the `k8s-extension` Azure CLI module. - -## Testing Requirements - -All partners who wish to merge their __Custom Private Preview Release__ (owner: _Partner_) into the __Official Private Preview Release__ are required to author additional integration tests for their extension to ensure that their extension will continue to function correctly as more extensions are added into the __Official Private Preview Release__. - -For more information on creating these tests, see [Authoring Tests](docs/test_authoring.md) - -## Pre-Requisites - -In order to properly test all regression tests within the test suite, you must onboard an AKS cluster which you will use to generate your Azure Arc resource to test the extensions. Ensure that you have a resource group where you can onboard this cluster. - -### Required Installations - -The following installations are required in your environment for the integration tests to run correctly: - -1. [Helm 3](https://helm.sh/docs/intro/install/) -2. [Kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) -3. [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) - -## Setup - -### Step 1: Install Pester - -This project contains [Pester](https://pester.dev/) test framework commands that are required for the integration tests to run. In an admin powershell terminal, run - -```powershell -Install-Module Pester -Force -SkipPublisherCheck -Import-Module Pester -PassThru -``` - -If you run into issues installing the framework, refer to the [Installation Guide](https://pester.dev/docs/introduction/installation) provided by the Pester docs. - -### Step 2: Get Test suite files - -You can either clone this repo (preferred option, since you will be adding your tests to this suite) or copy the files in this repo locally. Rest of the instructions here assume your working directory is k8spartner-extension-testing. - -### Step 3: Update the `k8s-extension`/`k8s-extension-private` .whl package - -This integration test suite references the .whl packages found in the `\bin` directory. After generating your `k8s-extension`/`k8s-extension-private` .whl package, copy your updated package into the `\bin` directory. - -### Step 4: Create a `settings.json` - -To onboard the AKS and Arc clusters correctly, you will need to create a `settings.json` configuration. Create a new `settings.json` file by copying the contents of the `settings.template.json` into this file. Update the subscription id, resource group, and AKS and Arc cluster name fields with your specific values. - -### Step 5: Update the extension version value in `settings.json` - -To ensure that the tests point to your `k8s-extension-private` `.whl` package, change the value of the `k8s-extension-private` to match your package versioning in the format (Major.Minor.Patch.Extension). For example, the `k8s_extension_private-0.1.0.openservicemesh_5-py3-none-any.whl` whl package would have extension versions set to -```json -{ - "k8s-extension": "0.1.0", - "k8s-extension-private": "0.1.0.openservicemesh_5", - "connectedk8s": "0.3.5" -} - -``` - -_Note: Updates to the `connectedk8s` version and `k8s-extension` version can also be made by adding a different version of the `connectedk8s` and `k8s-extension` whl packages and changing the `connectedk8s` and `k8s-extension` values to match the (Major.Minor.Patch) version format shown above_ - -### Step 6: Run the Bootstrap Command -To bootstrap the environment with AKS and Arc clusters, run -```powershell -.\Bootstrap.ps1 -``` -This script will provision the AKS and Arc clusters needed to run the integration test suite - -## Testing - -### Testing All Extension Suites -To test all extension test suites, you must call `.\Test.ps1` with the `-ExtensionType` parameter set to either `Public` or `Private`. Based on this flag, the test suite will install the extension type specified below - -| `-ExtensionType` | Installs `az extension` | -| ---------------- | --------------------- | -| `Public` | `k8s-extension` | -| `Private` | `k8s-extension-private` | - -For example, when calling -```bash -.\Test.ps1 -ExtensionType Public -``` -the script will install your `k8s-extension` whl package and run the full test suite of `*.Tests.ps1` files included in the `\test\extensions` directory - -### Testing Public Extensions Only -If you only want to run the test cases against public-preview or GA extension test cases, you can use the `-OnlyPublicTests` flag to specify this -```bash -.\Test.ps1 -ExtensionType Public -OnlyPublicTests -``` - -### Testing Specific Extension Suite - -If you only want to run the test script on your specific test file, you can do so by specifying path to your extension test suite in the execution call - -```powershell -.\Test.ps1 -Path -``` -For example to call the `AzureMonitor.Tests.ps1` test suite, we run -```powershell -.\Test.ps1 -ExtensionType Public -Path .\test\extensions\public\AzureMonitor.Tests.ps1 -``` - -### Skipping Extension Re-Install - -By default the `Test.ps1` script will uninstall any old versions of `k8s-extension`/'`k8s-extension-private` and re-install the version specified in `settings.json`. If you do not want this re-installation to occur, you can specify the `-SkipInstall` flag to skip this process. - -```powershell -.\Test.ps1 -ExtensionType Public -SkipInstall -``` - -## Cleanup -To cleanup the AKS and Arc clusters you have provisioned in testing, run -```powershell -.\Cleanup.ps1 -``` -This will remove the AKS and Arc clusters as well as the `\tmp` directory that were created by the bootstrapping script. \ No newline at end of file diff --git a/testing/Test.ps1 b/testing/Test.ps1 deleted file mode 100644 index 706eed01035..00000000000 --- a/testing/Test.ps1 +++ /dev/null @@ -1,133 +0,0 @@ -param ( - [string] $Path, - [switch] $SkipInstall, - [switch] $CI, - [switch] $ParallelCI, - [switch] $OnlyPublicTests, - - [Parameter(Mandatory=$True)] - [ValidateSet('k8s-extension','k8s-configuration', 'k8s-extension-private')] - [string]$Type -) - -# Disable confirm prompt for script -# Only show errors, don't show warnings -az config set core.disable_confirm_prompt=true -az config set core.only_show_errors=true - -$ENVCONFIG = Get-Content -Path $PSScriptRoot/settings.json | ConvertFrom-Json - -az account set --subscription $ENVCONFIG.subscriptionId - -$Env:KUBECONFIG="$PSScriptRoot/tmp/KUBECONFIG" -$TestFileDirectory="$PSScriptRoot/results" - -if (-not (Test-Path -Path $TestFileDirectory)) { - New-Item -ItemType Directory -Path $TestFileDirectory -} - -if ($Type -eq 'k8s-extension') { - $k8sExtensionVersion = $ENVCONFIG.extensionVersion.'k8s-extension' - $Env:K8sExtensionName = "k8s-extension" - - if (!$SkipInstall) { - Write-Host "Removing the old k8s-extension extension..." - az extension remove -n k8s-extension - Write-Host "Installing k8s-extension version $k8sExtensionVersion..." - az extension add --source ./bin/k8s_extension-$k8sExtensionVersion-py3-none-any.whl - if (!$?) { - Write-Host "Unable to find k8s-extension version $k8sExtensionVersion, exiting..." - exit 1 - } - } - if ($OnlyPublicTests) { - $testFilePath = "$PSScriptRoot/test/extensions/public" - } else { - $testFilePath = "$PSScriptRoot/test/extensions" - } -} elseif ($Type -eq 'k8s-extension-private') { - $k8sExtensionPrivateVersion = $ENVCONFIG.extensionVersion.'k8s-extension-private' - $Env:K8sExtensionName = "k8s-extension-private" - - if (!$SkipInstall) { - Write-Host "Removing the old k8s-extension-private extension..." - az extension remove -n k8s-extension-private - Write-Host "Installing k8s-extension-private version $k8sExtensionPrivateVersion..." - az extension add --source ./bin/k8s_extension_private-$k8sExtensionPrivateVersion-py3-none-any.whl - if (!$?) { - Write-Host "Unable to find k8s-extension-private version $k8sExtensionPrivateVersion, exiting..." - exit 1 - } - } - if ($OnlyPublicTests) { - $testFilePath = "$PSScriptRoot/test/extensions/public" - } else { - $testFilePath = "$PSScriptRoot/test/extensions" - } -} elseif ($Type -eq 'k8s-configuration') { - $k8sConfigurationVersion = $ENVCONFIG.extensionVersion.'k8s-configuration' - if (!$SkipInstall) { - Write-Host "Removing the old k8s-configuration extension..." - az extension remove -n k8s-configuration - Write-Host "Installing k8s-configuration version $k8sConfigurationVersion..." - az extension add --source ./bin/k8s_configuration-$k8sConfigurationVersion-py3-none-any.whl - } - $testFilePaths = "$PSScriptRoot/test/configurations" -} - -if ($ParallelCI) { - # This runs the tests in parallel during the CI pipline to speed up testing - - Write-Host "Invoking Pester to run tests from '$testFilePath'..." - $testFiles = @() - foreach ($paths in $testFilePaths) - { - $temp = Get-ChildItem $paths - $testFiles += $temp - } - $resultFileNumber = 0 - foreach ($testFile in $testFiles) - { - $resultFileNumber++ - $testName = Split-Path $testFile –leaf - Start-Job -ArgumentList $testName, $testFile, $resultFileNumber, $TestFileDirectory -Name $testName -ScriptBlock { - param($name, $testFile, $resultFileNumber, $testFileDirectory) - - Write-Host "$testFile to result file #$resultFileNumber" - $testResult = Invoke-Pester $testFile -Passthru -Output Detailed - $testResult | Export-JUnitReport -Path "$testFileDirectory/$name.xml" - } - } - - do { - Write-Host ">> Still running tests @ $(Get-Date –Format "HH:mm:ss")" –ForegroundColor Blue - Get-Job | Where-Object { $_.State -eq "Running" } | Format-Table –AutoSize - Start-Sleep –Seconds 30 - } while((Get-Job | Where-Object { $_.State -eq "Running" } | Measure-Object).Count -ge 1) - - Get-Job | Wait-Job - $failedJobs = Get-Job | Where-Object { -not ($_.State -eq "Completed")} - Get-Job | Receive-Job –AutoRemoveJob –Wait –ErrorAction 'Continue' - - if ($failedJobs.Count -gt 0) { - Write-Host "Failed Jobs" –ForegroundColor Red - $failedJobs - throw "One or more tests failed" - } -} elseif ($CI) { - if ($Path) { - $testFilePath = "$PSScriptRoot/$Path" - } - Write-Host "Invoking Pester to run tests from '$testFilePath'..." - $testResult = Invoke-Pester $testFilePath -Passthru -Output Detailed - $testName = Split-Path $testFilePath –leaf - $testResult | Export-JUnitReport -Path "$testFileDirectory/$testName.xml" -} else { - if ($Path) { - Write-Host "Invoking Pester to run tests from '$PSScriptRoot/$Path'" - Invoke-Pester -Output Detailed $PSScriptRoot/$Path - } else { - Write-Host "Invoking Pester to run tests from '$testFilePath'..." - Invoke-Pester -Output Detailed $testFilePath - } -} \ No newline at end of file diff --git a/testing/bin/connectedk8s-1.0.0-py3-none-any.whl b/testing/bin/connectedk8s-1.0.0-py3-none-any.whl deleted file mode 100644 index 08f34250036f455aad7e3e820c65d08d790e1201..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62802 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

YVX(toUj*0P8con1X*tXmm22nWyt~gf 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

4OLf9N*^x0^yG1@+&DtXglO();gI7nFsJg6 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 b*Hx{YBsky%^Yh?A4x|a#NYixu{O$h(4U{Xp diff --git a/testing/docs/test_authoring.md b/testing/docs/test_authoring.md deleted file mode 100644 index b41286ba66d..00000000000 --- a/testing/docs/test_authoring.md +++ /dev/null @@ -1,142 +0,0 @@ -# Test Authoring - -All partners are _required_ to author additional integration tests when merging their extension into the __Official Private Preview Release__. The information below outlines how to setup and author these additional tests. - -## Requirements - -All partners are required to cover standard CLI scenarios in your extensions testing suite. When adding these tests and preparing to merge your updated extension whl package, your tests along with the other tests in the test suite must pass at 100%. - -Standard CLI scenarios include: - -1. `az k8s-extension create` -2. `az k8s-extension show` -3. `az k8s-extension list` -4. `az k8s-extension update` -5. `az k8s-extension delete` - -In addition to these standard scenarios, if there are any rigorous parameter validation standards, these should also be included in this test suite. - -## Setup - -The setup process for test authoring is the same as setup for generic testing. See [Setup](../README.md#setup) for guidance. - -## Writing Tests - -This section outlines the common flow for creating and running additional extension integration tests for the `k8s-extension` package. - -The suite utilizes the [Pester](https://pester.dev/) framework. For more information on creating generic Pester tests, see the [Create a Pester Test](https://pester.dev/docs/quick-start#creating-a-pester-test) section in the Pester docs. - -### Step 1: Create Test File - -To create an integration test suite for your extension, create an extension test file in the format `.Tests.ps1` and place the file in one of the following directories -| Extension Type | Directory | -| ---------------------- | ----------------------------------- | -| General Availability | .\test\extensions\public | -| Public Preview | .\test\extensions\public | -| Private Preview | .\test\extensions\private-preview | - -For example, to create a test suite file for the Azure Monitor extension, I create the file `AzureMonitor.Tests.ps1` in the `\test\extensions\public` directory because Container Insights extension is in _Public Preview_. - -### Step 2: Setup Global Variables - -All test suite files must have the following structure for importing the environment config and declaring globals - -```powershell -Describe ' Testing' { - BeforeAll { - $extensionType = "" - $extensionName = "" - $extensionAgentName = "" - $extensionAgentNamespace = "" - - . $PSScriptRoot/../../helper/Constants.ps1 - . $PSScriptRoot/../../helper/Helper.ps1 - } -} -``` - -You can declare additional global variables for your tests by adding additional powershell variable to this `BeforeAll` block. - -_Note: Commonly used constants used by all extension test suites are stored in the `Constants.ps1` file_ - -### Step 3: Add Tests - -Adding tests to the test suite can now be performed by adding `It` blocks to the outer `Describe` block. For instance to test create on a extension in the case of AzureMonitor, I write the following test: - -```powershell -Describe 'Azure Monitor Testing' { - BeforeAll { - $extensionType = "microsoft.azuremonitor.containers" - $extensionName = "azuremonitor-containers" - $extensionAgentName = "omsagent" - $extensionAgentNamespace = "kube-system" - - . $PSScriptRoot/../../helper/Constants.ps1 - . $PSScriptRoot/../../helper/Helper.ps1 - } - - It 'Creates the extension and checks that it onboards correctly' { - $output = az k8s-extension create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType -n $extensionName - $? | Should -BeTrue - - $output = az k8s-extension show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeTrue - - $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion - $isAutoUpgradeMinorVersion.ToString() -eq "True" | Should -BeTrue - - # Loop and retry until the extension installs - $n = 0 - do - { - if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { - if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { - break - } - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } -} -``` - -The above test calls `az k8s-extension create` to create the `azuremonitor-containers` extension and retries checking that the extension resource was actually created on the Arc cluster and that the extension status successfully returns `$SUCCESS_MESSAGE` which is equivalent to `Successfully installed the extension`. - -## Tips/Notes - -### Accessing Extension Data - -`.\Test.ps1` assumes that the user has `kubectl` and `az` installed in their environment; therefore, tests are able to access information on the extension at the service and on the arc cluster. For instance, in the above test, we access the `extensionconfig` CRDs on the arc cluster by calling - -```powershell -kubectl get extensionconfigs -A -o json -``` - -If we want to access the extension data on the cluster with a specific `$extensionName`, we run - -```powershell -(kubectl get extensionconfigs -A -o json).items | Where-Object { $_.metadata.name -eq $extensionName } -``` - -Because some of these commands are so common, we provide the following helper commands in the `test\Helper.ps1` file - -| Command | Description | -| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -| Get-ExtensionData | Retrieves the ExtensionConfig CRD in JSON format with `.meatadata.name` matching the `extensionName` | -| Get-ExtensionStatus | Retrieves the `.status.status` from the ExtensionConfig CRD with `.meatadata.name` matching the `extensionName` | -| Get-PodStatus -Namespace | Retrieves the `status.phase` from the first pod on the cluster with `.metadata.name` matching `extensionName` | - -### Stdout for Debugging - -To print out to the Console for debugging while writing your test cases use the `Write-Host` command. If you attempt to use the `Write-Output` command, it will not show because of the way that Pester is invoked - -```powershell -Write-Host "Some example output" -``` - -### Global Constants - -Looking at the above test, we can see that we are accessing the `ENVCONFIG` to retrieve the environment variables from the `settings.json`. All variables in the `settings.json` are accessible from the `ENVCONFIG`. The most useful ones for testing will be `ENVCONFIG.arcClusterName` and `ENVCONFIG.resourceGroup`. - diff --git a/testing/owners.txt b/testing/owners.txt deleted file mode 100644 index ead6f446410..00000000000 --- a/testing/owners.txt +++ /dev/null @@ -1,2 +0,0 @@ -joinnis -nanthi \ No newline at end of file diff --git a/testing/pipeline/k8s-custom-pipelines.yml b/testing/pipeline/k8s-custom-pipelines.yml deleted file mode 100644 index f429213235c..00000000000 --- a/testing/pipeline/k8s-custom-pipelines.yml +++ /dev/null @@ -1,190 +0,0 @@ -trigger: - batch: true - branches: - include: - - k8s-configuration -pr: - branches: - include: - - k8s-configuration - -stages: -- stage: BuildTestPublishExtension - displayName: "Build, Test, and Publish Extension" - variables: - TEST_PATH: $(Agent.BuildDirectory)/s/testing - CLI_REPO_PATH: $(Agent.BuildDirectory)/s - EXTENSION_NAME: "k8s-configuration" - EXTENSION_FILE_NAME: "k8s_configuration" - SUBSCRIPTION_ID: "15c06b1b-01d6-407b-bb21-740b8617dea3" - RESOURCE_GROUP: "K8sPartnerExtensionTest" - BASE_CLUSTER_NAME: "k8s-configuration-cluster" - jobs: - - template: ./templates/run-test.yml - parameters: - jobName: SourceControlConfiguration - path: ./test/configurations/Configuration.*.Tests.ps1 - - template: ./templates/run-test.yml - parameters: - jobName: FluxConfiguration - path: ./test/configurations/Flux.*.Tests.ps1 - - job: BuildPublishExtension - pool: - vmImage: 'ubuntu-latest' - displayName: "Build and Publish the Extension Artifact" - variables: - CLI_REPO_PATH: $(Agent.BuildDirectory)/s - EXTENSION_NAME: "k8s-configuration" - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - echo "Building extension ${EXTENSION_NAME}..." - - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - - # clone azure-cli - pip install --upgrade pip - pip install azdev - - ls $(CLI_REPO_PATH) - - azdev --version - azdev setup -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build Extension with azdev" - - task: PublishBuildArtifacts@1 - inputs: - pathToPublish: $(CLI_REPO_PATH)/dist - -- stage: AzureCLIOfficial - displayName: "Azure Official CLI Code Checks" - dependsOn: [] - jobs: - - job: CheckLicenseHeader - displayName: "Check License" - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - python -m venv env/ - - chmod +x ./env/bin/activate - source ./env/bin/activate - - # clone azure-cli - git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install --upgrade pip - pip install -q azdev - - azdev setup -c ../azure-cli -r ./ - - azdev --version - az --version - - azdev verify license - - - job: StaticAnalysis - displayName: "Static Analysis" - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8==3.5.0 requests - displayName: 'Install wheel, pylint, flake8, requests' - - bash: python scripts/ci/source_code_static_analysis.py - displayName: "Static Analysis" - - - job: IndexVerify - displayName: "Verify Extensions Index" - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: 3.7 - - bash: | - #!/usr/bin/env bash - set -ev - pip install wheel==0.30.0 requests packaging - export CI="ADO" - python ./scripts/ci/test_index.py -v - displayName: "Verify Extensions Index" - - - job: SourceTests - displayName: "Integration Tests, Build Tests" - pool: - vmImage: 'ubuntu-latest' - strategy: - matrix: - Python36: - python.version: '3.6' - Python38: - python.version: '3.8' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python $(python.version)' - inputs: - versionSpec: '$(python.version)' - - bash: pip install wheel==0.30.0 - displayName: 'Install wheel==0.30.0' - - bash: ./scripts/ci/test_source.sh - displayName: 'Run integration test and build test' - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) - - - job: LintModifiedExtensions - displayName: "CLI Linter on Modified Extensions" - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - - # prepare and activate virtualenv - pip install virtualenv - python -m virtualenv venv/ - source ./venv/bin/activate - - # clone azure-cli - git clone --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - - pip install --upgrade pip - pip install azdev - - azdev --version - - azdev setup -c ../azure-cli -r ./ -e k8s-configuration - - # overwrite the default AZURE_EXTENSION_DIR set by ADO - AZURE_EXTENSION_DIR=~/.azure/cliextensions az --version - - AZURE_EXTENSION_DIR=~/.azure/cliextensions azdev linter --include-whl-extensions k8s-configuration - displayName: "CLI Linter on Modified Extension" - env: - ADO_PULL_REQUEST_LATEST_COMMIT: $(System.PullRequest.SourceCommitId) - ADO_PULL_REQUEST_TARGET_BRANCH: $(System.PullRequest.TargetBranch) diff --git a/testing/pipeline/templates/run-test.yml b/testing/pipeline/templates/run-test.yml deleted file mode 100644 index f7943390877..00000000000 --- a/testing/pipeline/templates/run-test.yml +++ /dev/null @@ -1,112 +0,0 @@ -parameters: - jobName: '' - path: '' - -jobs: -- job: ${{ parameters.jobName}} - pool: - vmImage: 'ubuntu-latest' - steps: - - bash: | - echo "Installing helm3" - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 - chmod 700 get_helm.sh - ./get_helm.sh --version v3.6.3 - echo "Installing kubectl" - curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x ./kubectl - sudo mv ./kubectl /usr/local/bin/kubectl - kubectl version --client - displayName: "Setup the VM with helm3 and kubectl" - - task: UsePythonVersion@0 - displayName: 'Use Python 3.6' - inputs: - versionSpec: 3.6 - - bash: | - set -ev - echo "Building extension ${EXTENSION_NAME}..." - # prepare and activate virtualenv - pip install virtualenv - python3 -m venv env/ - source env/bin/activate - # clone azure-cli - git clone -q --single-branch -b dev https://github.com/Azure/azure-cli.git ../azure-cli - pip install --upgrade pip - pip install -q azdev - ls $(CLI_REPO_PATH) - azdev --version - azdev setup -c ../azure-cli -r $(CLI_REPO_PATH) -e $(EXTENSION_NAME) - azdev extension build $(EXTENSION_NAME) - workingDirectory: $(CLI_REPO_PATH) - displayName: "Setup and Build Extension with azdev" - - - bash: | - K8S_CONFIG_VERSION=$(ls ${EXTENSION_FILE_NAME}* | cut -d "-" -f2) - echo "##vso[task.setvariable variable=K8S_CONFIG_VERSION]$K8S_CONFIG_VERSION" - cp * $(TEST_PATH)/bin - workingDirectory: $(CLI_REPO_PATH)/dist - displayName: "Copy the Built .whl to Extension Test Path" - - bash: | - RAND_STR=$RANDOM - AKS_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-aks" - ARC_CLUSTER_NAME="${BASE_CLUSTER_NAME}-${RAND_STR}-arc" - - JSON_STRING=$(jq -n \ - --arg SUB_ID "$SUBSCRIPTION_ID" \ - --arg RG "$RESOURCE_GROUP" \ - --arg AKS_CLUSTER_NAME "$AKS_CLUSTER_NAME" \ - --arg ARC_CLUSTER_NAME "$ARC_CLUSTER_NAME" \ - --arg K8S_CONFIG_VERSION "$K8S_CONFIG_VERSION" \ - '{subscriptionId: $SUB_ID, resourceGroup: $RG, aksClusterName: $AKS_CLUSTER_NAME, arcClusterName: $ARC_CLUSTER_NAME, extensionVersion: {"k8s-configuration": $K8S_CONFIG_VERSION, connectedk8s: "1.0.0"}}') - echo $JSON_STRING > settings.json - cat settings.json - workingDirectory: $(TEST_PATH) - displayName: "Generate a settings.json file" - - bash : | - echo "Downloading the kind script" - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 - chmod +x ./kind - ./kind create cluster - displayName: "Create and Start the Kind cluster" - - - bash: | - curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - displayName: "Upgrade az to latest version" - - task: AzureCLI@2 - displayName: Bootstrap - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Bootstrap.ps1 -CI - workingDirectory: $(TEST_PATH) - - - task: AzureCLI@2 - displayName: Run the Test Suite for ${{ parameters.path }} - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Test.ps1 -CI -Path ${{ parameters.path }} -Type k8s-configuration - workingDirectory: $(TEST_PATH) - continueOnError: true - - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'JUnit' - testResultsFiles: '**/testing/results/*.xml' - failTaskOnFailedTests: true - condition: succeededOrFailed() - - - task: AzureCLI@2 - displayName: Cleanup - inputs: - azureSubscription: AzureResourceConnection - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - .\Cleanup.ps1 -CI - workingDirectory: $(TEST_PATH) - condition: succeededOrFailed() \ No newline at end of file diff --git a/testing/settings.template.json b/testing/settings.template.json deleted file mode 100644 index 04eda8e4dfa..00000000000 --- a/testing/settings.template.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "subscriptionId": "", - "resourceGroup": "", - "aksClusterName": "", - "arcClusterName": "", - - "extensionVersion": { - "k8s-extension": "0.3.0", - "k8s-extension-private": "0.1.0", - "connectedk8s": "1.0.0" - } -} \ No newline at end of file diff --git a/testing/test/configurations/Configuration.HTTPS.Tests.ps1 b/testing/test/configurations/Configuration.HTTPS.Tests.ps1 deleted file mode 100644 index a2dee2b348f..00000000000 --- a/testing/test/configurations/Configuration.HTTPS.Tests.ps1 +++ /dev/null @@ -1,54 +0,0 @@ -Describe 'Source Control Configuration (HTTPS) Testing' { - BeforeAll { - $configurationName = "https-config" - . $PSScriptRoot/Constants.ps1 - . $PSScriptRoot/Helper.ps1 - - $dummyValue = "dummyValue" - $secretName = "git-auth-$configurationName" - } - - It 'Creates a configuration with https user and https key on the cluster' { - $output = az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "https://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --https-user $dummyValue --https-key $dummyValue --operator-namespace $configurationName - $? | Should -BeTrue - - # Loop and retry until the configuration installs and helm pod comes up - $n = 0 - do - { - if (Get-ConfigStatus $configurationName -eq $SUCCESS_MESSAGE) { - if (Get-PodStatus $configurationName -Namespace $configurationName -eq $POD_RUNNING ) { - break - } - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - - Secret-Exists $secretName -Namespace $configurationName - } - - It "Lists the configurations on the cluster" { - $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - $configExists | Should -Not -BeNullOrEmpty - } - - It "Deletes the configuration from the cluster" { - az k8s-configuration delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeTrue - - # Configuration should be removed from the resource model - az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeFalse - } - - It "Performs another list after the delete" { - $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - $configExists | Should -BeNullOrEmpty - } -} \ No newline at end of file diff --git a/testing/test/configurations/Configuration.HelmOperator.Tests.ps1 b/testing/test/configurations/Configuration.HelmOperator.Tests.ps1 deleted file mode 100644 index 2d7bbf173ea..00000000000 --- a/testing/test/configurations/Configuration.HelmOperator.Tests.ps1 +++ /dev/null @@ -1,52 +0,0 @@ -Describe 'Source Control Configuration (Helm Operator Properties) Testing' { - BeforeAll { - $configurationName = "helm-enabled-config" - . $PSScriptRoot/Constants.ps1 - . $PSScriptRoot/Helper.ps1 - - $customOperatorParams = "--set helm.versions=v3 --set mycustomhelmvalue=yay" - $customChartVersion = "0.6.0" - } - - It 'Creates a configuration with helm enabled on the cluster' { - $output = az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "https://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --enable-helm-operator --operator-namespace $configurationName --helm-operator-params "--set helm.versions=v3" - $? | Should -BeTrue - - # Loop and retry until the configuration installs and helm pod comes up - $n = 0 - do - { - if (Get-ConfigStatus $configurationName -eq $SUCCESS_MESSAGE) { - if (Get-PodStatus "$configurationName-helm" -Namespace $configurationName -eq $POD_RUNNING ) { - break - } - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Lists the configurations on the cluster" { - $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - $configExists | Should -Not -BeNullOrEmpty - } - - It "Deletes the configuration from the cluster" { - az k8s-configuration delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeTrue - - # Configuration should be removed from the resource model - az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeFalse - } - - It "Performs another list after the delete" { - $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - $configExists | Should -BeNullOrEmpty - } -} \ No newline at end of file diff --git a/testing/test/configurations/Configuration.KnownHost.Tests.ps1 b/testing/test/configurations/Configuration.KnownHost.Tests.ps1 deleted file mode 100644 index 2cb2946bc3e..00000000000 --- a/testing/test/configurations/Configuration.KnownHost.Tests.ps1 +++ /dev/null @@ -1,6 +0,0 @@ -Describe 'Source Control Configuration (SSH Configs) Testing' { - BeforeAll { - . $PSScriptRoot/Constants.ps1 - . $PSScriptRoot/Helper.ps1 - } -} \ No newline at end of file diff --git a/testing/test/configurations/Configuration.PrivateKey.Tests.ps1 b/testing/test/configurations/Configuration.PrivateKey.Tests.ps1 deleted file mode 100644 index 0ee9ee2b54c..00000000000 --- a/testing/test/configurations/Configuration.PrivateKey.Tests.ps1 +++ /dev/null @@ -1,85 +0,0 @@ -Describe 'Source Control Configuration (SSH Configs) Testing' { - BeforeAll { - . $PSScriptRoot/Constants.ps1 - . $PSScriptRoot/Helper.ps1 - - $RSA_KEYPATH = "$TMP_DIRECTORY\rsa.private" - $ECDSA_KEYPATH = "$TMP_DIRECTORY\ecdsa.private" - $ED25519_KEYPATH = "$TMP_DIRECTORY\ed25519.private" - - $KEY_ARR = [System.Tuple]::Create("rsa", $RSA_KEYPATH), [System.Tuple]::Create("ecdsa", $ECDSA_KEYPATH), [System.Tuple]::Create("ed25519", $ED25519_KEYPATH) - foreach ($keyTuple in $KEY_ARR) { - # Automattically say yes to overwrite with ssh-keygen - Write-Output "y" | ssh-keygen -t $keyTuple.Item1 -f $keyTuple.Item2 -P """" - } - - $SSH_GIT_URL = "git://github.com/anubhav929/flux-get-started.git" - $HTTP_GIT_URL = "https://github.com/Azure/arc-k8s-demo" - - $configDataRSA = [System.Tuple]::Create("rsa-config", $RSA_KEYPATH) - $configDataECDSA = [System.Tuple]::Create("ecdsa-config", $ECDSA_KEYPATH) - $configDataED25519 = [System.Tuple]::Create("ed25519-config", $ED25519_KEYPATH) - - $CONFIG_ARR = $configDataRSA, $configDataECDSA, $configDataED25519 - } - - It 'Creates a configuration with each type of ssh private key' { - foreach($configData in $CONFIG_ARR) { - Write-Host "Creating a configuration of type $($configData.Item1)" - az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u $SSH_GIT_URL -n $configData.Item1 --scope cluster --operator-namespace $configData.Item1 --ssh-private-key-file $configData.Item2 - $? | Should -BeTrue - } - - # Loop and retry until the configuration installs and helm pod comes up - $n = 0 - do - { - $readyConfigs = 0 - foreach($configData in $CONFIG_ARR) { - # TODO: Change this to checking the success message after we merge in the bugfix into the agent - if (Get-PodStatus $configData.Item1 -Namespace $configData.Item1 -eq $POD_RUNNING) { - $readyConfigs += 1 - } - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le 30 -And $readyConfigs -ne 3) - $n | Should -BeLessOrEqual 30 - } - - It 'Fails when trying to create a configuration with ssh url and https auth values' { - az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u $HTTP_GIT_URL -n "config-should-fail" --scope cluster --operator-namespace "config-should-fail" --ssh-private-key-file $RSA_KEYPATH - $? | Should -BeFalse - } - - It "Lists the configurations on the cluster" { - $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - foreach ($configData in $CONFIG_ARR) { - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configData.Item1 } - $configExists | Should -Not -BeNullOrEmpty - } - } - - It "Deletes the configuration from the cluster" { - foreach ($configData in $CONFIG_ARR) { - az k8s-configuration delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configData.Item1 - $? | Should -BeTrue - - # Configuration should be removed from the resource model - az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configData.Item1 - $? | Should -BeFalse - } - } - - It "Performs another list after the delete" { - $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - foreach ($configData in $CONFIG_ARR) { - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configData.Item1 } - $configExists | Should -BeNullOrEmpty - } - } -} \ No newline at end of file diff --git a/testing/test/configurations/Configuration.Tests.ps1 b/testing/test/configurations/Configuration.Tests.ps1 deleted file mode 100644 index 3ab06b06b1d..00000000000 --- a/testing/test/configurations/Configuration.Tests.ps1 +++ /dev/null @@ -1,58 +0,0 @@ -Describe 'Basic Source Control Configuration Testing' { - BeforeAll { - $configurationName = "basic-config" - . $PSScriptRoot/Constants.ps1 - . $PSScriptRoot/Helper.ps1 - } - - It 'Creates a configuration and checks that it onboards correctly' { - az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "https://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --enable-helm-operator=false --operator-namespace $configurationName - $? | Should -BeTrue - - # Loop and retry until the configuration installs - $n = 0 - do - { - if (Get-ConfigStatus $configurationName -Match $SUCCESS_MESSAGE) { - break - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Performs a show on the configuration" { - $output = az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -n $configurationName - $? | Should -BeTrue - $output | Should -Not -BeNullOrEmpty - } - - It "Performs a re-PUT of the configuration on the cluster, with HTTPS in caps" { - az k8s-configuration create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "HTTPS://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --enable-helm-operator=false --operator-namespace $configurationName - $? | Should -BeTrue - } - - It "Lists the configurations on the cluster" { - $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - $configExists | Should -Not -BeNullOrEmpty - } - - It "Deletes the configuration from the cluster" { - az k8s-configuration delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeTrue - - # Configuration should be removed from the resource model - az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeFalse - } - - It "Performs another list after the delete" { - $output = az k8s-configuration list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - $configExists | Should -BeNullOrEmpty - } -} \ No newline at end of file diff --git a/testing/test/configurations/Constants.ps1 b/testing/test/configurations/Constants.ps1 deleted file mode 100644 index 8014c5446b3..00000000000 --- a/testing/test/configurations/Constants.ps1 +++ /dev/null @@ -1,9 +0,0 @@ -$ENVCONFIG = Get-Content -Path $PSScriptRoot\..\..\settings.json | ConvertFrom-Json -$SUCCESS_MESSAGE = "Successfully installed the operator" -$FAILED_MESSAGE = "Failed the install of the operator" -$TMP_DIRECTORY = "$PSScriptRoot\..\..\tmp" - -$POD_RUNNING = "Running" -$SUCCEEDED = "Succeeded" - -$MAX_RETRY_ATTEMPTS = 24 \ No newline at end of file diff --git a/testing/test/configurations/Flux.HTTPS.Tests.ps1 b/testing/test/configurations/Flux.HTTPS.Tests.ps1 deleted file mode 100644 index b5de6ab34ad..00000000000 --- a/testing/test/configurations/Flux.HTTPS.Tests.ps1 +++ /dev/null @@ -1,55 +0,0 @@ -Describe 'Flux Configuration (HTTPS) Testing' { - BeforeAll { - $configurationName = "https-config" - . $PSScriptRoot/Constants.ps1 - . $PSScriptRoot/Helper.ps1 - - $dummyValue = "dummyValue" - $secretName = "git-auth-$configurationName" - } - - It 'Creates a configuration with https user and https key on the cluster' { - $output = az k8s-configuration flux create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "https://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --https-user $dummyValue --https-key $dummyValue --namespace $configurationName --branch main --no-wait - $? | Should -BeTrue - - # Loop and retry until the configuration installs and helm pod comes up - $n = 0 - do - { - $output = az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $provisioningState = ($output | ConvertFrom-Json).provisioningState - Write-Host "Provisioning State: $provisioningState" - if ($provisioningState -eq $SUCCEEDED) { - break - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - - Secret-Exists $secretName -Namespace $configurationName - } - - It "Lists the configurations on the cluster" { - $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - $configExists | Should -Not -BeNullOrEmpty - } - - It "Deletes the configuration from the cluster" { - az k8s-configuration flux delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName --force - $? | Should -BeTrue - - # Configuration should be removed from the resource model - az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeFalse - } - - It "Performs another list after the delete" { - $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - $configExists | Should -BeNullOrEmpty - } -} \ No newline at end of file diff --git a/testing/test/configurations/Flux.PrivateKey.Tests.ps1 b/testing/test/configurations/Flux.PrivateKey.Tests.ps1 deleted file mode 100644 index 6c1d4ecba30..00000000000 --- a/testing/test/configurations/Flux.PrivateKey.Tests.ps1 +++ /dev/null @@ -1,88 +0,0 @@ -Describe 'Flux Configuration (SSH Configs) Testing' { - BeforeAll { - . $PSScriptRoot/Constants.ps1 - . $PSScriptRoot/Helper.ps1 - - $RSA_KEYPATH = "$TMP_DIRECTORY\rsa.private" - $ECDSA_KEYPATH = "$TMP_DIRECTORY\ecdsa.private" - $ED25519_KEYPATH = "$TMP_DIRECTORY\ed25519.private" - - $KEY_ARR = [System.Tuple]::Create("rsa", $RSA_KEYPATH), [System.Tuple]::Create("ecdsa", $ECDSA_KEYPATH), [System.Tuple]::Create("ed25519", $ED25519_KEYPATH) - foreach ($keyTuple in $KEY_ARR) { - # Automattically say yes to overwrite with ssh-keygen - Write-Output "y" | ssh-keygen -t $keyTuple.Item1 -f $keyTuple.Item2 -P """" - } - - $SSH_GIT_URL = "ssh://github.com/anubhav929/flux-get-started.git" - $HTTP_GIT_URL = "https://github.com/Azure/arc-k8s-demo" - - $configDataRSA = [System.Tuple]::Create("rsa-config", $RSA_KEYPATH) - $configDataECDSA = [System.Tuple]::Create("ecdsa-config", $ECDSA_KEYPATH) - $configDataED25519 = [System.Tuple]::Create("ed25519-config", $ED25519_KEYPATH) - - $CONFIG_ARR = $configDataRSA, $configDataECDSA, $configDataED25519 - } - - It 'Creates a configuration with each type of ssh private key' { - foreach($configData in $CONFIG_ARR) { - Write-Host "Creating a configuration of type $($configData.Item1)" - az k8s-configuration flux create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u $SSH_GIT_URL -n $configData.Item1 --scope cluster --namespace $configData.Item1 --ssh-private-key-file $configData.Item2 --branch main --no-wait - $? | Should -BeTrue - } - - # Loop and retry until the configuration installs and helm pod comes up - $n = 0 - do - { - $readyConfigs = 0 - foreach($configData in $CONFIG_ARR) { - $output = az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $CONFIGdATA.Item1 - $provisioningState = ($output | ConvertFrom-Json).provisioningState - Write-Host "Provisioning State: $provisioningState" - if ($provisioningState -eq $SUCCEEDED) { - $readyConfigs += 1 - } - } - Write-Host "$(kubectl get fc -A -o yaml)" - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le 30 -And $readyConfigs -ne 3) - $n | Should -BeLessOrEqual 30 - } - - It 'Fails when trying to create a configuration with ssh url and https auth values' { - az k8s-configuration flux create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u $HTTP_GIT_URL -n "config-should-fail" --scope cluster --namespace "config-should-fail" --ssh-private-key-file $RSA_KEYPATH --branch main --no-wait - $? | Should -BeFalse - } - - It "Lists the configurations on the cluster" { - $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - foreach ($configData in $CONFIG_ARR) { - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configData.Item1 } - $configExists | Should -Not -BeNullOrEmpty - } - } - - It "Deletes the configuration from the cluster" { - foreach ($configData in $CONFIG_ARR) { - az k8s-configuration flux delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configData.Item1 --force - $? | Should -BeTrue - - # Configuration should be removed from the resource model - az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configData.Item1 - $? | Should -BeFalse - } - } - - It "Performs another list after the delete" { - $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - foreach ($configData in $CONFIG_ARR) { - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configData.Item1 } - $configExists | Should -BeNullOrEmpty - } - } -} \ No newline at end of file diff --git a/testing/test/configurations/Flux.Tests.ps1 b/testing/test/configurations/Flux.Tests.ps1 deleted file mode 100644 index 5d87fe7e31f..00000000000 --- a/testing/test/configurations/Flux.Tests.ps1 +++ /dev/null @@ -1,61 +0,0 @@ -Describe 'Basic Flux Configuration Testing' { - BeforeAll { - $configurationName = "basic-config" - . $PSScriptRoot/Constants.ps1 - . $PSScriptRoot/Helper.ps1 - } - - It 'Creates a configuration and checks that it onboards correctly' { - az k8s-configuration flux create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "https://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --namespace $configurationName --branch main --no-wait - $? | Should -BeTrue - - # Loop and retry until the configuration installs - $n = 0 - do - { - $output = az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $provisioningState = ($output | ConvertFrom-Json).provisioningState - Write-Host "Provisioning State: $provisioningState" - if ($provisioningState -eq $SUCCEEDED) { - break - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Performs a show on the configuration" { - $output = az k8s-configuration flux show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -n $configurationName - $? | Should -BeTrue - $output | Should -Not -BeNullOrEmpty - } - - It "Performs a re-PUT of the configuration on the cluster, with HTTPS in caps" { - az k8s-configuration flux create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type "connectedClusters" -u "HTTPS://github.com/Azure/arc-k8s-demo" -n $configurationName --scope cluster --namespace $configurationName --branch main --no-wait - $? | Should -BeTrue - } - - It "Lists the configurations on the cluster" { - $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - $configExists | Should -Not -BeNullOrEmpty - } - - It "Deletes the configuration from the cluster" { - az k8s-configuration flux delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName --force - $? | Should -BeTrue - - # Configuration should be removed from the resource model - az k8s-configuration show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $configurationName - $? | Should -BeFalse - } - - It "Performs another list after the delete" { - $output = az k8s-configuration flux list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $configExists = $output | ConvertFrom-Json | Where-Object { $_.id -Match $configurationName } - $configExists | Should -BeNullOrEmpty - } -} \ No newline at end of file diff --git a/testing/test/configurations/Helper.ps1 b/testing/test/configurations/Helper.ps1 deleted file mode 100644 index 6a29c2b0f56..00000000000 --- a/testing/test/configurations/Helper.ps1 +++ /dev/null @@ -1,66 +0,0 @@ -function Get-ConfigData { - param( - [string]$configName - ) - - $output = kubectl get gitconfigs -A -o json | ConvertFrom-Json - return $output.items | Where-Object { $_.metadata.name -eq $configurationName } -} - -function Get-ConfigStatus { - param( - [string]$configName - ) - - $configData = Get-ConfigData $configName - if ($configData -ne $null) { - return $configData.status.status - } - return $null -} - -function Get-FluxConfigData { - param( - [string]$configName - ) - - $output = kubectl get fc -A -o json | ConvertFrom-Json - return $output.items | Where-Object { $_.metadata.name -eq $configurationName } -} - -function Get-FluxConfigStatus { - param( - [string]$configName - ) - - $configData = Get-FluxConfigData $configName - if ($configData -ne $null) { - return $configData.status.provisioningState - } - return $null -} - -function Get-PodStatus { - param( - [string]$podName, - [string]$Namespace - ) - - $allPodData = kubectl get pods -n $Namespace -o json | ConvertFrom-Json - $podData = $allPodData.items | Where-Object { $_.metadata.name -Match $podName } - return $podData.status.phase -} - -function Secret-Exists { - param( - [string]$secretName, - [string]$Namespace - ) - - $allSecretData = kubectl get secrets -n $Namespace -o json | ConvertFrom-Json - $secretData = $allSecretData.items | Where-Object { $_.metadata.name -Match $secretName } - if ($secretData.Length -ge 1) { - return $true - } - return $false -} \ No newline at end of file diff --git a/testing/test/extensions/private-preview/AzurePolicy.Tests.ps1 b/testing/test/extensions/private-preview/AzurePolicy.Tests.ps1 deleted file mode 100644 index ea8c3f46cb4..00000000000 --- a/testing/test/extensions/private-preview/AzurePolicy.Tests.ps1 +++ /dev/null @@ -1,95 +0,0 @@ -Describe 'Azure Policy Testing' { - BeforeAll { - $extensionType = "microsoft.policyinsights" - $extensionName = "policy" - $extensionAgentName = "azure-policy" - $extensionAgentNamespace = "kube-system" - - . $PSScriptRoot/../../helper/Constants.ps1 - . $PSScriptRoot/../../helper/Helper.ps1 - } - - It 'Creates the extension and checks that it onboards correctly' { - $output = az $Env:K8sExtensionName create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType -n $extensionName - $? | Should -BeTrue - - $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeTrue - - $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion - $isAutoUpgradeMinorVersion.ToString() -eq "True" | Should -BeTrue - - # Loop and retry until the extension installs - $n = 0 - do - { - if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { - if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { - break - } - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Performs a show on the extension" { - $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeTrue - $output | Should -Not -BeNullOrEmpty - } - - It "Runs an update on the extension on the cluster" { - Set-ItResult -Skipped -Because "Update is not a valid scenario for now" - - # az $Env:K8sExtensionName update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName --auto-upgrade-minor-version false - # $? | Should -BeTrue - - # $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - # $? | Should -BeTrue - - # $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion - # $isAutoUpgradeMinorVersion.ToString() -eq "False" | Should -BeTrue - - # # Loop and retry until the extension config updates - # $n = 0 - # do - # { - # $isAutoUpgradeMinorVersion = (Get-ExtensionData $extensionName).spec.autoUpgradeMinorVersion - # if (!$isAutoUpgradeMinorVersion) { #autoUpgradeMinorVersion doesn't exist in ExtensionConfig CRD if false - # if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { - # if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { - # break - # } - # } - # } - # Start-Sleep -Seconds 10 - # $n += 1 - # } while ($n -le $MAX_RETRY_ATTEMPTS) - # $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Lists the extensions on the cluster" { - $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionType } - $extensionExists | Should -Not -BeNullOrEmpty - } - - It "Deletes the extension from the cluster" { - az $Env:K8sExtensionName delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeTrue - - # Extension should not be found on the cluster - az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeFalse - } - - It "Performs another list after the delete" { - $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionName } - $extensionExists | Should -BeNullOrEmpty - } -} diff --git a/testing/test/extensions/public/AzureDefender.Tests.ps1 b/testing/test/extensions/public/AzureDefender.Tests.ps1 deleted file mode 100644 index 2d199e31638..00000000000 --- a/testing/test/extensions/public/AzureDefender.Tests.ps1 +++ /dev/null @@ -1,93 +0,0 @@ -Describe 'Azure Defender Testing' { - BeforeAll { - $extensionType = "microsoft.azuredefender.kubernetes" - $extensionName = "microsoft.azuredefender.kubernetes" - $extensionAgentNamespace = "azuredefender" - - . $PSScriptRoot/../../helper/Constants.ps1 - . $PSScriptRoot/../../helper/Helper.ps1 - } - - It 'Creates the extension and checks that it onboards correctly' { - $output = az $Env:K8sExtensionName create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType -n $extensionName - $? | Should -BeTrue - - $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeTrue - - $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion - $isAutoUpgradeMinorVersion.ToString() -eq "True" | Should -BeTrue - - # Loop and retry until the extension installs - $n = 0 - do - { - # Only check the extension config, not the pod since this doesn't bring up pods - if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { - break - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Performs a show on the extension" { - $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeTrue - $output | Should -Not -BeNullOrEmpty - } - - It "Runs an update on the extension on the cluster" { - Set-ItResult -Skipped -Because "Update is not a valid scenario for now" - - # az $Env:K8sExtensionName update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName --auto-upgrade-minor-version false - # $? | Should -BeTrue - - # $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - # $? | Should -BeTrue - - # $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion - # $isAutoUpgradeMinorVersion.ToString() -eq "False" | Should -BeTrue - - # # Loop and retry until the extension config updates - # $n = 0 - # do - # { - # $isAutoUpgradeMinorVersion = (Get-ExtensionData $extensionName).spec.autoUpgradeMinorVersion - # if (!$isAutoUpgradeMinorVersion) { #autoUpgradeMinorVersion doesn't exist in ExtensionConfig CRD if false - # if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { - # if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { - # break - # } - # } - # } - # Start-Sleep -Seconds 10 - # $n += 1 - # } while ($n -le $MAX_RETRY_ATTEMPTS) - # $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Lists the extensions on the cluster" { - $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionType } - $extensionExists | Should -Not -BeNullOrEmpty - } - - It "Deletes the extension from the cluster" { - az $Env:K8sExtensionName delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeTrue - - # Extension should not be found on the cluster - az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeFalse - } - - It "Performs another list after the delete" { - $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionName } - $extensionExists | Should -BeNullOrEmpty - } -} diff --git a/testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 b/testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 deleted file mode 100644 index a434544da12..00000000000 --- a/testing/test/extensions/public/AzureMLKubernetes.Tests.ps1 +++ /dev/null @@ -1,94 +0,0 @@ -Describe 'AzureML Kubernetes Testing' { - BeforeAll { - $extensionType = "Microsoft.AzureML.Kubernetes" - $extensionName = "azureml-kubernetes-connector" - $extensionAgentNamespace = "azureml" - $relayResourceIDKey = "relayserver.hybridConnectionResourceID" - - . $PSScriptRoot/../../helper/Constants.ps1 - . $PSScriptRoot/../../helper/Helper.ps1 - } - - It 'Creates the extension and checks that it onboards correctly' { - $output = az k8s-extension create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType --name $extensionName --release-train preview --config enableTraining=true allowInsecureConnections=true - $? | Should -BeTrue - - $output = az k8s-extension show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName - $? | Should -BeTrue - - $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion - $isAutoUpgradeMinorVersion.ToString() -eq "True" | Should -BeTrue - - # Loop and retry until the extension installs - $n = 0 - do - { - if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { - break - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - - # check if relay is populated - $relayResourceID = Get-ExtensionConfigurationSettings $extensionName $relayResourceIDKey - $relayResourceID | Should -Not -BeNullOrEmpty - } - - It "Performs a show on the extension" { - $output = az k8s-extension show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName - $? | Should -BeTrue - $output | Should -Not -BeNullOrEmpty - } - - It "Runs an update on the extension on the cluster" { - Set-ItResult -Skipped -Because "Update is not a valid scenario for now" - az k8s-extension update --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName --auto-upgrade-minor-version false - $? | Should -BeTrue - - $output = az k8s-extension show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName - $? | Should -BeTrue - - $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion - $isAutoUpgradeMinorVersion.ToString() -eq "False" | Should -BeTrue - - # Loop and retry until the extension config updates - $n = 0 - do - { - $isAutoUpgradeMinorVersion = (Get-ExtensionData $extensionName).spec.autoUpgradeMinorVersion - if (!$isAutoUpgradeMinorVersion) { #autoUpgradeMinorVersion doesn't exist in ExtensionConfig CRD if false - if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { - break - } - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Lists the extensions on the cluster" { - $output = az k8s-extension list --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionType } - $extensionExists | Should -Not -BeNullOrEmpty - } - - It "Deletes the extension from the cluster" { - az k8s-extension delete --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName - $? | Should -BeTrue - - # Extension should not be found on the cluster - az k8s-extension show --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --name $extensionName - $? | Should -BeFalse - } - - It "Performs another list after the delete" { - $output = az k8s-extension list --cluster-name $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionName } - $extensionExists | Should -BeNullOrEmpty - } -} diff --git a/testing/test/extensions/public/AzureMonitor.Tests.ps1 b/testing/test/extensions/public/AzureMonitor.Tests.ps1 deleted file mode 100644 index c9baa2d0e48..00000000000 --- a/testing/test/extensions/public/AzureMonitor.Tests.ps1 +++ /dev/null @@ -1,95 +0,0 @@ -Describe 'Azure Monitor Testing' { - BeforeAll { - $extensionType = "microsoft.azuremonitor.containers" - $extensionName = "azuremonitor-containers" - $extensionAgentName = "omsagent" - $extensionAgentNamespace = "kube-system" - - . $PSScriptRoot/../../helper/Constants.ps1 - . $PSScriptRoot/../../helper/Helper.ps1 - } - - It 'Creates the extension and checks that it onboards correctly' { - $output = az $Env:K8sExtensionName create -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters --extension-type $extensionType -n $extensionName - $? | Should -BeTrue - - $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeTrue - - $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion - $isAutoUpgradeMinorVersion.ToString() -eq "True" | Should -BeTrue - - # Loop and retry until the extension installs - $n = 0 - do - { - if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { - if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { - break - } - } - Start-Sleep -Seconds 10 - $n += 1 - } while ($n -le $MAX_RETRY_ATTEMPTS) - $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Performs a show on the extension" { - $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeTrue - $output | Should -Not -BeNullOrEmpty - } - - It "Runs an update on the extension on the cluster" { - Set-ItResult -Skipped -Because "Update is not a valid scenario for now" - - # az $Env:K8sExtensionName update -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName --auto-upgrade-minor-version false - # $? | Should -BeTrue - - # $output = az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - # $? | Should -BeTrue - - # $isAutoUpgradeMinorVersion = ($output | ConvertFrom-Json).autoUpgradeMinorVersion - # $isAutoUpgradeMinorVersion.ToString() -eq "False" | Should -BeTrue - - # # Loop and retry until the extension config updates - # $n = 0 - # do - # { - # $isAutoUpgradeMinorVersion = (Get-ExtensionData $extensionName).spec.autoUpgradeMinorVersion - # if (!$isAutoUpgradeMinorVersion) { #autoUpgradeMinorVersion doesn't exist in ExtensionConfig CRD if false - # if (Get-ExtensionStatus $extensionName -eq $SUCCESS_MESSAGE) { - # if (Get-PodStatus $extensionAgentName -Namespace $extensionAgentNamespace -eq $POD_RUNNING) { - # break - # } - # } - # } - # Start-Sleep -Seconds 10 - # $n += 1 - # } while ($n -le $MAX_RETRY_ATTEMPTS) - # $n | Should -BeLessOrEqual $MAX_RETRY_ATTEMPTS - } - - It "Lists the extensions on the cluster" { - $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $? | Should -BeTrue - - $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionType } - $extensionExists | Should -Not -BeNullOrEmpty - } - - It "Deletes the extension from the cluster" { - az $Env:K8sExtensionName delete -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeTrue - - # Extension should not be found on the cluster - az $Env:K8sExtensionName show -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters -n $extensionName - $? | Should -BeFalse - } - - It "Performs another list after the delete" { - $output = az $Env:K8sExtensionName list -c $ENVCONFIG.arcClusterName -g $ENVCONFIG.resourceGroup --cluster-type connectedClusters - $extensionExists = $output | ConvertFrom-Json | Where-Object { $_.extensionType -eq $extensionName } - $extensionExists | Should -BeNullOrEmpty - } -} diff --git a/testing/test/helper/Constants.ps1 b/testing/test/helper/Constants.ps1 deleted file mode 100644 index 3ecd3621bc5..00000000000 --- a/testing/test/helper/Constants.ps1 +++ /dev/null @@ -1,7 +0,0 @@ -$ENVCONFIG = Get-Content -Path $PSScriptRoot/../../settings.json | ConvertFrom-Json -$SUCCESS_MESSAGE = "Successfully installed the extension" -$FAILED_MESSAGE = "Failed to install the extension" - -$POD_RUNNING = "Running" - -$MAX_RETRY_ATTEMPTS = 10 \ No newline at end of file diff --git a/testing/test/helper/Helper.ps1 b/testing/test/helper/Helper.ps1 deleted file mode 100644 index 362a4eedf18..00000000000 --- a/testing/test/helper/Helper.ps1 +++ /dev/null @@ -1,47 +0,0 @@ -function Get-ExtensionData { - param( - [string]$extensionName - ) - - $output = kubectl get extensionconfigs -A -o json | ConvertFrom-Json - return $output.items | Where-Object { $_.metadata.name -eq $extensionName } -} - -function Get-ExtensionStatus { - param( - [string]$extensionName - ) - - $extensionData = Get-ExtensionData $extensionName - if ($extensionData) { - return $extensionData.status.status - } - return $null -} - -function Get-PodStatus { - param( - [string]$podName, - [string]$Namespace - ) - - $allPodData = kubectl get pods -n $Namespace -o json | ConvertFrom-Json - $podData = $allPodData.items | Where-Object { $_.metadata.name -Match $podName } - if ($podData.Length -gt 1) { - return $podData[0].status.phase - } - return $podData.status.phase -} - -function Get-ExtensionConfigurationSettings { - param( - [string]$extensionName, - [string]$configKey - ) - - $extensionData = Get-ExtensionData $extensionName - if ($extensionData) { - return $extensionData.spec.parameter."$configKey" - } - return $null -} From 68a74581b699c4d43b63db27c9501c60b3771a72 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Mon, 15 Nov 2021 10:07:49 -0800 Subject: [PATCH 79/80] Fix filepath suggestion from CLI team --- .../azext_k8s_configuration/_params.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/k8s-configuration/azext_k8s_configuration/_params.py b/src/k8s-configuration/azext_k8s_configuration/_params.py index bcb72dd2d54..ed96f429ec5 100644 --- a/src/k8s-configuration/azext_k8s_configuration/_params.py +++ b/src/k8s-configuration/azext_k8s_configuration/_params.py @@ -78,7 +78,7 @@ def load_arguments(self, _): help='Base64-encoded private ssh key for private repository sync') c.argument('ssh_private_key_file', arg_group="Auth", - help='Filepath to private ssh key for private repository sync') + help='File path to private ssh key for private repository sync') c.argument('https_user', arg_group="Auth", help='HTTPS username for private repository sync') @@ -90,13 +90,13 @@ def load_arguments(self, _): help='Base64-encoded HTTPS CA certificate for TLS communication with private repository sync') c.argument('https_ca_cert_file', arg_group="Auth", - help='Filepath to HTTPS CA certificate file for TLS communication with private repository sync') + help='File path to HTTPS CA certificate file for TLS communication with private repository sync') c.argument('known_hosts', arg_group="Auth", help='Base64-encoded known_hosts data containing public SSH keys required to access private Git instances') c.argument('known_hosts_file', arg_group="Auth", - help='Filepath to known_hosts contents containing public SSH keys required to access private Git instances') + help='File path to known_hosts contents containing public SSH keys required to access private Git instances') c.argument('local_auth_ref', options_list=['--local-auth-ref', '--local-ref'], arg_group="Auth", @@ -163,7 +163,7 @@ def load_arguments(self, _): help='Specify Base64-encoded private ssh key for private repository sync') c.argument('ssh_private_key_file', arg_group="Auth", - help='Specify filepath to private ssh key for private repository sync') + help='Specify file path to private ssh key for private repository sync') c.argument('https_user', arg_group="Auth", help='Specify HTTPS username for private repository sync') @@ -175,7 +175,7 @@ def load_arguments(self, _): help='Specify Base64-encoded known_hosts contents containing public SSH keys required to access private Git instances') c.argument('ssh_known_hosts_file', arg_group="Auth", - help='Specify filepath to known_hosts contents containing public SSH keys required to access private Git instances') + help='Specify file path to known_hosts contents containing public SSH keys required to access private Git instances') with self.argument_context('k8s-configuration flux kustomization') as c: c.argument('kustomization_name', From 65a3927d6aad4aed8c411f05f94005e3098408c5 Mon Sep 17 00:00:00 2001 From: Jonathan Innis Date: Mon, 15 Nov 2021 10:09:46 -0800 Subject: [PATCH 80/80] Fix unneeded file edit --- .../azext_dataprotection/manual/version.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/dataprotection/azext_dataprotection/manual/version.py b/src/dataprotection/azext_dataprotection/manual/version.py index c8d62cb0608..7d80efbfc5b 100644 --- a/src/dataprotection/azext_dataprotection/manual/version.py +++ b/src/dataprotection/azext_dataprotection/manual/version.py @@ -1,11 +1,11 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is -# regenerated. -# -------------------------------------------------------------------------- - -VERSION = "0.2.0" +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +VERSION = "0.2.0"