зеркало из https://github.com/Azure/ARO-RP.git
Update CLI integration test (#3898)
* change integration cli test * fix name prefix
This commit is contained in:
Родитель
96637dbc85
Коммит
53673d4857
|
@ -0,0 +1,119 @@
|
||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# Licensed under the Apache License 2.0.
|
||||||
|
|
||||||
|
from azure.cli.testsdk.preparers import RoleBasedServicePrincipalPreparer
|
||||||
|
from azure.cli.testsdk.scenario_tests.utilities import is_text_payload
|
||||||
|
from azure.cli.testsdk.utilities import GraphClientPasswordReplacer
|
||||||
|
from azure.mgmt.core.tools import resource_id
|
||||||
|
|
||||||
|
MOCK_GUID = '00000000-0000-0000-0000-000000000001'
|
||||||
|
MOCK_SECRET = 'fake-secret'
|
||||||
|
|
||||||
|
|
||||||
|
class AROClusterServicePrincipalPreparer(RoleBasedServicePrincipalPreparer):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name_prefix="clitest",
|
||||||
|
skip_assignment=True,
|
||||||
|
parameter_name="client_id",
|
||||||
|
parameter_password="client_secret",
|
||||||
|
dev_setting_sp_name="AZURE_CLI_TEST_DEV_SP_NAME",
|
||||||
|
dev_setting_sp_password="AZURE_CLI_TEST_DEV_SP_PASSWORD",
|
||||||
|
key="aro_csp",
|
||||||
|
):
|
||||||
|
super(AROClusterServicePrincipalPreparer, self).__init__(
|
||||||
|
name_prefix,
|
||||||
|
skip_assignment,
|
||||||
|
parameter_name,
|
||||||
|
parameter_password,
|
||||||
|
dev_setting_sp_name,
|
||||||
|
dev_setting_sp_password,
|
||||||
|
key,
|
||||||
|
)
|
||||||
|
self.client_id_to_replace = None
|
||||||
|
self.client_secret_to_replace = None
|
||||||
|
|
||||||
|
def create_resource(self, name, **kwargs):
|
||||||
|
client_id, client_secret = self._get_csp_credentials(name)
|
||||||
|
|
||||||
|
self.test_class_instance.kwargs[self.key] = client_id
|
||||||
|
self.test_class_instance.kwargs["{}_pass".format(self.key)] = client_secret
|
||||||
|
|
||||||
|
return {
|
||||||
|
self.parameter_name: client_id,
|
||||||
|
self.parameter_password: client_secret,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Overriden because RoleBasedServicePrincipal.remove_resource does not delete
|
||||||
|
# the underlying AAD application generated when creating the service principal
|
||||||
|
def remove_resource(self, name, **kwargs):
|
||||||
|
super().remove_resource(name, **kwargs)
|
||||||
|
|
||||||
|
if not self.dev_setting_sp_name:
|
||||||
|
self.live_only_execute(self.cli_ctx, 'az ad app delete --id {}'.format(self.result.get('appId')))
|
||||||
|
|
||||||
|
def process_request(self, request):
|
||||||
|
if self.client_id_to_replace in request.uri:
|
||||||
|
request.uri = request.uri.replace(self.client_id_to_replace, MOCK_GUID)
|
||||||
|
|
||||||
|
if is_text_payload(request) and isinstance(request.body, bytes):
|
||||||
|
request.body = self._replace_byte_keys(request.body)
|
||||||
|
elif is_text_payload(request) and isinstance(request.body, str):
|
||||||
|
request.body = self._replace_string_keys(request.body)
|
||||||
|
|
||||||
|
return request
|
||||||
|
|
||||||
|
def process_response(self, response):
|
||||||
|
if is_text_payload(response) and response['body']['string']:
|
||||||
|
response['body']['string'] = self._replace_string_keys(response['body']['string'])
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
def _get_csp_credentials(self, name):
|
||||||
|
if not self.live_test and not self.test_class_instance.in_recording:
|
||||||
|
return MOCK_GUID, MOCK_SECRET
|
||||||
|
|
||||||
|
client_id, client_secret = self._generate_csp(name)
|
||||||
|
|
||||||
|
# call AbstractPreparer.moniker to make resource counts and self.resource_moniker consistent between live
|
||||||
|
# and play-back. see SingleValueReplacer.process_request, AbstractPreparer.__call__._preparer_wrapper
|
||||||
|
# and ScenarioTest.create_random_name. This is so that when self.create_random_name is called for the
|
||||||
|
# first time during live or playback, it would have the same value.
|
||||||
|
# In short, the default sp preparer in live mode does not call moniker, which leads to inconsistent counts.
|
||||||
|
_ = self.moniker
|
||||||
|
|
||||||
|
self.client_id_to_replace = client_id
|
||||||
|
self.client_secret_to_replace = client_secret
|
||||||
|
|
||||||
|
return client_id, client_secret
|
||||||
|
|
||||||
|
def _generate_csp(self, name):
|
||||||
|
if self.dev_setting_sp_name:
|
||||||
|
client_id = self.dev_setting_sp_name
|
||||||
|
client_secret = self.dev_setting_sp_password
|
||||||
|
|
||||||
|
return client_id, client_secret
|
||||||
|
|
||||||
|
subscription = self.test_class_instance.get_subscription_id()
|
||||||
|
resource_group = self.test_class_instance.kwargs.get('rg')
|
||||||
|
command = 'az ad sp create-for-rbac -n {} --role contributor --scopes "{}"'\
|
||||||
|
.format(name, resource_id(subscription=subscription, resource_group=resource_group))
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.result = self.live_only_execute(self.cli_ctx, command).get_output_in_json()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
client_id = self.result['appId']
|
||||||
|
client_secret = self.result.get('password') or GraphClientPasswordReplacer.PWD_REPLACEMENT
|
||||||
|
|
||||||
|
return client_id, client_secret
|
||||||
|
|
||||||
|
def _replace_string_keys(self, val):
|
||||||
|
if self.client_id_to_replace is None:
|
||||||
|
return val
|
||||||
|
|
||||||
|
return val.replace(self.client_id_to_replace, MOCK_GUID).replace(self.client_secret_to_replace, MOCK_SECRET)
|
||||||
|
|
||||||
|
def _replace_byte_keys(self, val):
|
||||||
|
return self._replace_string_keys(val.decode('utf-8')).encode('utf-8')
|
|
@ -2,42 +2,93 @@
|
||||||
# Licensed under the Apache License 2.0.
|
# Licensed under the Apache License 2.0.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from random import randint
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from azure_devtools.scenario_tests import AllowLargeResponse
|
|
||||||
from azure.cli.testsdk import ResourceGroupPreparer
|
from knack.log import get_logger
|
||||||
from azure.cli.testsdk import ScenarioTest
|
from azext_aro.tests.latest.custom_preparers import AROClusterServicePrincipalPreparer
|
||||||
|
from azure.cli.testsdk import ScenarioTest, ResourceGroupPreparer
|
||||||
|
from azure.cli.testsdk.checkers import StringContainCheck
|
||||||
|
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
TEST_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '..'))
|
class AroScenarioTests(ScenarioTest):
|
||||||
|
@AllowLargeResponse()
|
||||||
|
@ResourceGroupPreparer(random_name_length=28, name_prefix='cli_test_aro', location='eastus')
|
||||||
|
@AROClusterServicePrincipalPreparer(name_prefix='cli_test_aro')
|
||||||
|
def test_aro_public_cluster(self, resource_group):
|
||||||
|
from azure.mgmt.core.tools import resource_id
|
||||||
|
|
||||||
|
subscription = self.get_subscription_id()
|
||||||
|
|
||||||
|
master_subnet = self.create_random_name('dev_master', 14)
|
||||||
|
worker_subnet = self.create_random_name('dev_worker', 14)
|
||||||
|
name = self.create_random_name('aro', 14)
|
||||||
|
|
||||||
|
temp_kubeconfig_path = self.create_random_name('kubeconfig', 24) + '.tmp'
|
||||||
|
|
||||||
class AroScenarioTest(ScenarioTest):
|
|
||||||
@ResourceGroupPreparer(name_prefix='cli_test_aro')
|
|
||||||
def test_aro(self, resource_group):
|
|
||||||
self.kwargs.update({
|
self.kwargs.update({
|
||||||
'name': 'test1'
|
'name': name,
|
||||||
|
'resource_group': resource_group,
|
||||||
|
'subscription': subscription,
|
||||||
|
'master_subnet': master_subnet,
|
||||||
|
'worker_subnet': worker_subnet,
|
||||||
|
'master_ip_range': '10.{}.{}.0/24'.format(randint(0, 127), randint(0, 255)),
|
||||||
|
'worker_ip_range': '10.{}.{}.0/24'.format(randint(0, 127), randint(0, 255)),
|
||||||
|
'master_subnet_resource': resource_id(subscription=subscription, resource_group=resource_group, namespace='Microsoft.Network', type='virtualNetworks', child_type_1='subnets', name='dev-vnet', child_name_1=master_subnet),
|
||||||
|
'worker_subnet_resource': resource_id(subscription=subscription, resource_group=resource_group, namespace='Microsoft.Network', type='virtualNetworks', child_type_1='subnets', name='dev-vnet', child_name_1=worker_subnet),
|
||||||
|
'temp_kubeconfig_path': temp_kubeconfig_path,
|
||||||
})
|
})
|
||||||
|
|
||||||
# test aro create
|
self.cmd('network vnet create -g {rg} -n dev-vnet --address-prefixes 10.0.0.0/9')
|
||||||
|
self.cmd('network vnet subnet create -g {rg} --vnet-name dev-vnet -n {master_subnet} --address-prefixes {master_ip_range} --service-endpoints Microsoft.ContainerRegistry --default-outbound false')
|
||||||
|
self.cmd('network vnet subnet create -g {rg} --vnet-name dev-vnet -n {worker_subnet} --address-prefixes {worker_ip_range} --service-endpoints Microsoft.ContainerRegistry --default-outbound false')
|
||||||
|
self.cmd('network vnet subnet update -g {rg} --vnet-name dev-vnet -n {master_subnet} --private-link-service-network-policies Disabled')
|
||||||
|
|
||||||
|
# aro validate
|
||||||
with mock.patch('azure.cli.command_modules.aro._rbac._gen_uuid', side_effect=self.create_guid):
|
with mock.patch('azure.cli.command_modules.aro._rbac._gen_uuid', side_effect=self.create_guid):
|
||||||
self.cmd('aro create -g {rg} -n {name} --tags foo=doo', checks=[
|
self.cmd('aro validate -g {rg} -n {name} --client-id {aro_csp} --client-secret {aro_csp_pass} --master-subnet {master_subnet_resource} --worker-subnet {worker_subnet_resource} --subscription {subscription}')
|
||||||
self.check('tags.foo', 'doo'),
|
|
||||||
self.check('name', '{name}')
|
# aro create
|
||||||
|
with mock.patch('azure.cli.command_modules.aro._rbac._gen_uuid', side_effect=self.create_guid):
|
||||||
|
self.cmd('aro create -g {rg} -n {name} --client-id {aro_csp} --client-secret {aro_csp_pass} --master-subnet {master_subnet_resource} --worker-subnet {worker_subnet_resource} --subscription {subscription} --tags test=create', checks=[
|
||||||
|
self.check('tags.test', 'create'),
|
||||||
|
self.check('name', '{name}'),
|
||||||
|
self.check('masterProfile.subnetId', '{master_subnet_resource}'),
|
||||||
|
self.check('workerProfiles[0].subnetId', '{worker_subnet_resource}'),
|
||||||
|
self.check('provisioningState', 'Succeeded')
|
||||||
])
|
])
|
||||||
|
|
||||||
self.cmd('aro update -g {rg} -n {name} --tags foo=boo', checks=[
|
# aro list-credentials
|
||||||
self.check('tags.foo', 'boo')
|
self.cmd('aro list-credentials -g {rg} -n {name} --subscription {subscription}', checks=[self.check('kubeadminUsername', 'kubeadmin')])
|
||||||
|
|
||||||
|
# aro get-admin-kubeconfig
|
||||||
|
try:
|
||||||
|
self.cmd('aro get-admin-kubeconfig -g {rg} -n {name} --subscription {subscription} -f {temp_kubeconfig_path}')
|
||||||
|
self.assertGreater(os.path.getsize(temp_kubeconfig_path), 0)
|
||||||
|
finally:
|
||||||
|
os.remove(temp_kubeconfig_path)
|
||||||
|
|
||||||
|
# aro show
|
||||||
|
self.cmd('aro show -g {rg} -n {name} --subscription {subscription} --output table', checks=[
|
||||||
|
StringContainCheck(name),
|
||||||
|
StringContainCheck(resource_group),
|
||||||
|
StringContainCheck('eastus'),
|
||||||
|
StringContainCheck('Succeeded'),
|
||||||
])
|
])
|
||||||
|
|
||||||
count = len(self.cmd('aro list').get_output_in_json())
|
# aro list
|
||||||
self.cmd('aro show -g {rg} -n {name}', checks=[
|
self.cmd('aro list -g {rg} --subscription {subscription}', checks=[
|
||||||
self.check('name', '{name}'),
|
self.check('[0].name', '{name}'),
|
||||||
self.check('resourceGroup', '{rg}'),
|
self.check('[0].provisioningState', 'Succeeded'),
|
||||||
self.check('tags.foo', 'boo')
|
self.check_pattern('[0].id', '.*{name}')
|
||||||
])
|
])
|
||||||
|
|
||||||
self.cmd('aro delete -g {rg} -n {name}')
|
# aro update
|
||||||
|
self.cmd('aro update -g {rg} -n {name} --subscription {subscription}', expect_failure=False)
|
||||||
|
|
||||||
final_count = len(self.cmd('aro list').get_output_in_json())
|
# aro delete
|
||||||
self.assertTrue(final_count, count - 1)
|
self.cmd('aro delete -y -g {rg} -n {name} --subscription {subscription}', expect_failure=False)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче