зеркало из https://github.com/Azure/Avere.git
Moving to OO model.
This commit is contained in:
Родитель
16c08b400f
Коммит
50abd47cab
|
@ -24,7 +24,7 @@ steps:
|
|||
AZURE_CLIENT_ID: $(SPAPPID)
|
||||
AZURE_CLIENT_SECRET: $(SPPW)
|
||||
- script: |
|
||||
python3 test/avere_template_deploy.py --skip-az-ops
|
||||
python3 test/test_avere_template_deploy.py --skip-az-ops
|
||||
displayName: 'Test Avere vFXT template-based deployment'
|
||||
env:
|
||||
AVERE_ADMIN_PW: $(controllerpassword)
|
||||
|
|
|
@ -1,228 +1,110 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
"""
|
||||
Test template-based Avere vFXT deployment.
|
||||
Class used for testing template-based deployment of the Avere vFXT product.
|
||||
|
||||
Assumptions:
|
||||
1. The caller/script is able to write to the current working directory.
|
||||
2. Azure secrets are stored in the following environment variables:
|
||||
* AVERE_ADMIN_PW
|
||||
* AVERE_CONTROLLER_PW
|
||||
* AZURE_CLIENT_ID
|
||||
* AZURE_CLIENT_SECRET
|
||||
* AZURE_TENANT_ID
|
||||
* AZURE_SUBSCRIPTION_ID
|
||||
Objects require the following environment variables at instantiation:
|
||||
* AVERE_ADMIN_PW
|
||||
* AVERE_CONTROLLER_PW
|
||||
* AZURE_CLIENT_ID
|
||||
* AZURE_CLIENT_SECRET
|
||||
* AZURE_TENANT_ID
|
||||
* AZURE_SUBSCRIPTION_ID
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
from pprint import pformat
|
||||
from random import choice
|
||||
from string import ascii_lowercase, digits
|
||||
from urllib.request import urlretrieve
|
||||
|
||||
import requests
|
||||
from azure.common.credentials import ServicePrincipalCredentials
|
||||
from azure.mgmt.resource import ResourceManagementClient
|
||||
from azure.mgmt.resource.resources.models import DeploymentMode
|
||||
|
||||
# GLOBAL VARIABLES ############################################################
|
||||
|
||||
DEFAULT_LOCATION = 'eastus2'
|
||||
DEPLOY_PARAMS = {}
|
||||
RESOURCE_GROUP_CREATED = False
|
||||
SCRIPT_ARGS = None
|
||||
TEMPLATE_URL = 'https://raw.githubusercontent.com/Azure/Avere/master/src/vfxt/azuredeploy-auto.json'
|
||||
TEMPLATE_LOCAL_FILE = os.path.basename(TEMPLATE_URL)
|
||||
class AvereTemplateDeploy:
|
||||
def __init__(self, deploy_params={}, resource_group=None,
|
||||
location='eastus2', debug=True):
|
||||
"""Initialize, authenticate to Azure, generate deploy params."""
|
||||
self._template_url = 'https://raw.githubusercontent.com/Azure/Avere/master/src/vfxt/azuredeploy-auto.json'
|
||||
self.debug = debug
|
||||
|
||||
# FUNCTIONS ###################################################################
|
||||
self.deploy_params = deploy_params
|
||||
self.resource_group = self.deploy_params.pop('resourceGroup',
|
||||
resource_group)
|
||||
self.location = self.deploy_params.pop('location', location)
|
||||
|
||||
def load_credentials():
|
||||
"""Loads Azure credentials from environment variables."""
|
||||
print('> Load Azure credentials.')
|
||||
return ResourceManagementClient(
|
||||
credentials=ServicePrincipalCredentials(
|
||||
client_id=os.environ['AZURE_CLIENT_ID'],
|
||||
secret=os.environ['AZURE_CLIENT_SECRET'],
|
||||
tenant=os.environ['AZURE_TENANT_ID']
|
||||
),
|
||||
subscription_id=os.environ['AZURE_SUBSCRIPTION_ID']
|
||||
)
|
||||
self._debug('> Loading Azure credentials')
|
||||
self.rm_client = ResourceManagementClient(
|
||||
credentials=ServicePrincipalCredentials(
|
||||
client_id=os.environ['AZURE_CLIENT_ID'],
|
||||
secret=os.environ['AZURE_CLIENT_SECRET'],
|
||||
tenant=os.environ['AZURE_TENANT_ID']
|
||||
),
|
||||
subscription_id=os.environ['AZURE_SUBSCRIPTION_ID']
|
||||
)
|
||||
|
||||
def load_params():
|
||||
"""
|
||||
Loads the parameters needed in this script (e.g., resource group name).
|
||||
|
||||
If the user specified a parameters file, load those values into
|
||||
DEPLOY_PARAMS. Otherwise, generate the parameter values and store those
|
||||
values for re-use. The generated parameter values are stored in the current
|
||||
working directory as <resource-group-name>.params.json.
|
||||
"""
|
||||
global DEPLOY_PARAMS
|
||||
if SCRIPT_ARGS.param_file: # Open user-specified params file.
|
||||
with open(SCRIPT_ARGS.param_file) as config_file:
|
||||
DEPLOY_PARAMS = json.load(config_file)
|
||||
else: # Generate and store params.
|
||||
random_id = 'av' + \
|
||||
''.join(random.choice(ascii_lowercase + digits) for _ in range(6))
|
||||
rg_name = 'aapipe-' + random_id + '-rg'
|
||||
DEPLOY_PARAMS = {
|
||||
'resource-group': rg_name,
|
||||
'parameters': {
|
||||
'virtualNetworkResourceGroup': rg_name,
|
||||
if not self.deploy_params:
|
||||
random_id = 'av' + \
|
||||
''.join(choice(ascii_lowercase + digits) for _ in range(6))
|
||||
self.resource_group = 'aapipe-' + random_id + '-rg'
|
||||
self.deploy_params = {
|
||||
'virtualNetworkResourceGroup': self.resource_group,
|
||||
'virtualNetworkName': random_id + '-vnet',
|
||||
'virtualNetworkSubnetName': random_id + '-subnet',
|
||||
'avereBackedStorageAccountName': random_id + 'sa',
|
||||
'controllerName': random_id + '-con',
|
||||
'controllerAuthenticationType': 'password'
|
||||
}
|
||||
}
|
||||
with open(DEPLOY_PARAMS['resource-group'] + '.params.json', 'w') as pf:
|
||||
json.dump(DEPLOY_PARAMS, pf)
|
||||
self._debug('> Generated deploy parameters: \n{}'.format(
|
||||
json.dumps(self.deploy_params, indent=4)))
|
||||
|
||||
# Set location/region. Precedence: command-line > params file > default
|
||||
if not SCRIPT_ARGS.location:
|
||||
SCRIPT_ARGS.location = DEPLOY_PARAMS.pop('location', DEFAULT_LOCATION)
|
||||
_debug('SCRIPT_ARGS.location = {}'.format(SCRIPT_ARGS.location))
|
||||
_debug('DEPLOY_PARAMS (before secrets): \n{}'.format(
|
||||
json.dumps(DEPLOY_PARAMS, indent=4)))
|
||||
|
||||
# Add secrets to the parameters for template deployment.
|
||||
secrets = {
|
||||
'adminPassword': os.environ['AVERE_ADMIN_PW'],
|
||||
'controllerPassword': os.environ['AVERE_CONTROLLER_PW'],
|
||||
'servicePrincipalAppId': os.environ['AZURE_CLIENT_ID'],
|
||||
'servicePrincipalPassword': os.environ['AZURE_CLIENT_SECRET'],
|
||||
'servicePrincipalTenant': os.environ['AZURE_TENANT_ID']
|
||||
}
|
||||
DEPLOY_PARAMS['parameters'] = {**DEPLOY_PARAMS['parameters'], **secrets}
|
||||
|
||||
def create_resource_group(rm_client):
|
||||
"""Creates an Azure resource group."""
|
||||
global RESOURCE_GROUP_CREATED
|
||||
print('> Creating resource group: ' + DEPLOY_PARAMS['resource-group'])
|
||||
if not SCRIPT_ARGS.skip_az_ops:
|
||||
rg = rm_client.resource_groups.create_or_update(
|
||||
DEPLOY_PARAMS['resource-group'],
|
||||
{'location': SCRIPT_ARGS.location}
|
||||
def create_resource_group(self):
|
||||
"""Creates the Azure resource group for this deployment."""
|
||||
self._debug('> Creating resource group: ' + self.resource_group)
|
||||
return self.rm_client.resource_groups.create_or_update(
|
||||
self.resource_group,
|
||||
{'location': self.location}
|
||||
)
|
||||
_debug('Resource Group = {}'.format(rg))
|
||||
RESOURCE_GROUP_CREATED = True
|
||||
|
||||
def deploy_template(rm_client):
|
||||
"""Deploys the Avere vFXT template."""
|
||||
print('> Deploying template')
|
||||
def delete_resource_group(self):
|
||||
"""Deletes the Azure resource group for this deployment."""
|
||||
self._debug('> Deleting resource group: ' + self.resource_group)
|
||||
return self.rm_client.resource_groups.delete(self.resource_group)
|
||||
|
||||
# Prepare parameters.
|
||||
parameters = {k: {'value': v} for k, v in DEPLOY_PARAMS['parameters'].items()}
|
||||
def deploy(self):
|
||||
"""Deploys the Avere vFXT template."""
|
||||
self._debug('> Deploying template')
|
||||
|
||||
if not SCRIPT_ARGS.skip_az_ops:
|
||||
op = rm_client.deployments.create_or_update(
|
||||
resource_group_name=DEPLOY_PARAMS['resource-group'],
|
||||
deploy_secrets = {
|
||||
'adminPassword': os.environ['AVERE_ADMIN_PW'],
|
||||
'controllerPassword': os.environ['AVERE_CONTROLLER_PW'],
|
||||
'servicePrincipalAppId': os.environ['AZURE_CLIENT_ID'],
|
||||
'servicePrincipalPassword': os.environ['AZURE_CLIENT_SECRET'],
|
||||
'servicePrincipalTenant': os.environ['AZURE_TENANT_ID']
|
||||
}
|
||||
params = {**self.deploy_params, **deploy_secrets}
|
||||
|
||||
return self.rm_client.deployments.create_or_update(
|
||||
resource_group_name=self.resource_group,
|
||||
deployment_name='azuredeploy-auto',
|
||||
properties={
|
||||
'mode': DeploymentMode.incremental,
|
||||
'template': _load_template(),
|
||||
'parameters': parameters
|
||||
'parameters': {k: {'value': v} for k, v in params.items()},
|
||||
'template': requests.get(self._template_url).json()
|
||||
}
|
||||
)
|
||||
_wait_for_op(op)
|
||||
|
||||
def delete_resource_group(rm_client):
|
||||
"""Deletes the resource group."""
|
||||
print('> Deleting resource group: ' + DEPLOY_PARAMS['resource-group'])
|
||||
if not SCRIPT_ARGS.skip_az_ops:
|
||||
op = rm_client.resource_groups.delete(DEPLOY_PARAMS['resource-group'])
|
||||
_wait_for_op(op)
|
||||
def _debug(self, s):
|
||||
"""Prints the passed string, with a DEBUG header, if debug is on."""
|
||||
if self.debug:
|
||||
print('[DEBUG]: {}'.format(s))
|
||||
|
||||
def cleanup(rm_client):
|
||||
"""
|
||||
Performs multiple cleanup activities.
|
||||
1. Deletes the downloaded template file.
|
||||
2. Deletes the resource group.
|
||||
"""
|
||||
print('> Cleaning up')
|
||||
if os.path.isfile(TEMPLATE_LOCAL_FILE):
|
||||
os.remove(TEMPLATE_LOCAL_FILE)
|
||||
|
||||
if not SCRIPT_ARGS.skip_rg_cleanup and RESOURCE_GROUP_CREATED:
|
||||
delete_resource_group(rm_client)
|
||||
|
||||
# HELPER FUNCTIONS ############################################################
|
||||
|
||||
def _load_template():
|
||||
"""Downloads the Avere vFXT deployment template."""
|
||||
_debug('Downloading template: ' + TEMPLATE_URL)
|
||||
urlretrieve(TEMPLATE_URL, filename=TEMPLATE_LOCAL_FILE)
|
||||
with open(TEMPLATE_LOCAL_FILE, 'r') as template_file_fd:
|
||||
template = json.load(template_file_fd)
|
||||
return template
|
||||
|
||||
def _wait_for_op(op, timeout_sec=60):
|
||||
"""
|
||||
Wait for a long-running operation (op) for timeout_sec seconds.
|
||||
|
||||
op is an AzureOperationPoller object.
|
||||
"""
|
||||
time_start = time.time()
|
||||
while not op.done():
|
||||
op.wait(timeout=timeout_sec)
|
||||
print('>> operation status: {0} ({1} sec)'.format(
|
||||
op.status(), int(time.time() - time_start)))
|
||||
result = op.result()
|
||||
if result:
|
||||
print('>> operation result: {}'.format(result))
|
||||
|
||||
def _debug(s):
|
||||
"""Prints the passed string, with a DEBUG header, if debug is on."""
|
||||
if SCRIPT_ARGS.debug:
|
||||
print('[DEBUG]: {}'.format(s))
|
||||
|
||||
# MAIN ########################################################################
|
||||
|
||||
def main():
|
||||
"""Main script driver."""
|
||||
rm_client = load_credentials()
|
||||
load_params()
|
||||
retcode = 0 # PASS
|
||||
try:
|
||||
create_resource_group(rm_client)
|
||||
deploy_template(rm_client)
|
||||
except Exception as ex:
|
||||
print('\n' + ('><' * 40))
|
||||
print('> TEST FAILED')
|
||||
print('> EXCEPTION TEXT: {}'.format(ex))
|
||||
print(('><' * 40) + '\n')
|
||||
retcode = 1 # FAIL
|
||||
raise
|
||||
except:
|
||||
retcode = 2 # FAIL
|
||||
raise
|
||||
finally:
|
||||
cleanup(rm_client)
|
||||
print('> SCRIPT COMPLETE. Resource Group: {} (region: {})'.format(
|
||||
DEPLOY_PARAMS['resource-group'], SCRIPT_ARGS.location))
|
||||
print('> RESULT: ' + ('FAIL' if retcode else 'PASS'))
|
||||
sys.exit(retcode)
|
||||
def __str__(self):
|
||||
return pformat(vars(self), indent=4)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
arg_parser = argparse.ArgumentParser(
|
||||
description='Test template-based Avere vFXT deployment.')
|
||||
|
||||
arg_parser.add_argument('-p', '--param-file', default=None,
|
||||
help='Full path to JSON params file. ' +
|
||||
'Default: None (generate new params)')
|
||||
arg_parser.add_argument('-l', '--location', default=None,
|
||||
help='Azure location (region short name) to use for deployment. ' +
|
||||
'Default: ' + DEFAULT_LOCATION)
|
||||
arg_parser.add_argument('-xc', '--skip-rg-cleanup', action='store_true',
|
||||
help='Do NOT delete the resource group during cleanup.')
|
||||
arg_parser.add_argument('-xo', '--skip-az-ops', action='store_true',
|
||||
help='Do NOT actually run any of the Azure operations.')
|
||||
arg_parser.add_argument('-d', '--debug', action='store_true',
|
||||
help='Turn on script debugging.')
|
||||
SCRIPT_ARGS = arg_parser.parse_args()
|
||||
|
||||
main()
|
||||
pass
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
azure.mgmt.resource
|
||||
requests
|
|
@ -0,0 +1,114 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
"""
|
||||
Driver for testing template-based deployment of the Avere vFXT product.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
|
||||
from avere_template_deploy import AvereTemplateDeploy
|
||||
|
||||
|
||||
# HELPER FUNCTIONS ############################################################
|
||||
|
||||
def wait_for_op(op, timeout_sec=60):
|
||||
"""
|
||||
Wait for a long-running operation (op) for timeout_sec seconds.
|
||||
|
||||
op is an AzureOperationPoller object.
|
||||
"""
|
||||
time_start = time.time()
|
||||
while not op.done():
|
||||
op.wait(timeout=timeout_sec)
|
||||
print('>> operation status: {0} ({1} sec)'.format(
|
||||
op.status(), int(time.time() - time_start)))
|
||||
result = op.result()
|
||||
if result:
|
||||
print('>> operation result: {}'.format(result))
|
||||
|
||||
|
||||
# MAIN ########################################################################
|
||||
|
||||
def main(script_args):
|
||||
def debug(s):
|
||||
"""Prints the passed string, with a DEBUG header, if debug is on."""
|
||||
if script_args.debug:
|
||||
print('[DEBUG]: {}'.format(s))
|
||||
|
||||
"""Main script driver."""
|
||||
retcode = 0 # PASS
|
||||
try:
|
||||
deploy_params = {}
|
||||
if script_args.param_file: # Open user-specified params file.
|
||||
with open(script_args.param_file) as pfile:
|
||||
deploy_params = json.load(pfile)
|
||||
|
||||
atd = AvereTemplateDeploy(
|
||||
debug=script_args.debug,
|
||||
location=script_args.location,
|
||||
deploy_params=deploy_params
|
||||
)
|
||||
debug('atd = \n{}'.format(atd))
|
||||
|
||||
if not script_args.param_file:
|
||||
dparams = {
|
||||
**atd.deploy_params,
|
||||
'resourceGroup': atd.resource_group
|
||||
}
|
||||
with open(atd.resource_group + '.params.json', 'w') as pfile:
|
||||
json.dump(dparams, pfile)
|
||||
|
||||
print('> Creating resource group: ' + atd.resource_group)
|
||||
if not script_args.skip_az_ops:
|
||||
rg = atd.create_resource_group()
|
||||
debug('Resource Group = {}'.format(rg))
|
||||
|
||||
print('> Deploying template')
|
||||
if not script_args.skip_az_ops:
|
||||
wait_for_op(atd.deploy())
|
||||
except Exception as ex:
|
||||
print('\n' + ('><' * 40))
|
||||
print('> TEST FAILED')
|
||||
print('> EXCEPTION TEXT: {}'.format(ex))
|
||||
print(('><' * 40) + '\n')
|
||||
retcode = 1 # FAIL
|
||||
raise
|
||||
except:
|
||||
retcode = 2 # FAIL
|
||||
raise
|
||||
finally:
|
||||
if not script_args.skip_rg_cleanup:
|
||||
print('> Deleting resource group: ' + atd.resource_group)
|
||||
if not script_args.skip_az_ops:
|
||||
wait_for_op(atd.delete_resource_group())
|
||||
|
||||
print('> SCRIPT COMPLETE. Resource Group: {} (region: {})'.format(
|
||||
atd.resource_group, atd.location))
|
||||
print('> RESULT: ' + ('FAIL' if retcode else 'PASS'))
|
||||
sys.exit(retcode)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
default_location = 'eastus2'
|
||||
|
||||
arg_parser = argparse.ArgumentParser(
|
||||
description='Test template-based Avere vFXT deployment.')
|
||||
|
||||
arg_parser.add_argument('-p', '--param-file', default=None,
|
||||
help='Full path to JSON params file. ' +
|
||||
'Default: None (generate new params)')
|
||||
arg_parser.add_argument('-l', '--location', default=default_location,
|
||||
help='Azure location (region short name) to use for deployment. ' +
|
||||
'Default: ' + default_location)
|
||||
arg_parser.add_argument('-xc', '--skip-rg-cleanup', action='store_true',
|
||||
help='Do NOT delete the resource group during cleanup.')
|
||||
arg_parser.add_argument('-xo', '--skip-az-ops', action='store_true',
|
||||
help='Do NOT actually run any of the Azure operations.')
|
||||
arg_parser.add_argument('-d', '--debug', action='store_true',
|
||||
help='Turn on script debugging.')
|
||||
script_args = arg_parser.parse_args()
|
||||
|
||||
main(script_args)
|
Загрузка…
Ссылка в новой задаче