def _remove_cse_artifacts(): for template in env.TEMPLATE_DEFINITIONS: env.delete_catalog_item(template['source_ova_name']) catalog_item_name = get_revisioned_template_name( template['name'], template['revision']) env.delete_catalog_item(catalog_item_name) temp_vapp_name = testutils.get_temp_vapp_name(template['name']) env.delete_vapp(temp_vapp_name) env.delete_catalog() env.unregister_cse()
def _install_template(client, remote_template_manager, template, org_name, vdc_name, catalog_name, network_name, ip_allocation_mode, storage_profile, force_update, retain_temp_vapp, ssh_key, msg_update_callback): remote_template_manager.download_template_scripts( template_name=template[RemoteTemplateKey.NAME], revision=template[RemoteTemplateKey.REVISION], force_overwrite=force_update) catalog_item_name = get_revisioned_template_name( template[RemoteTemplateKey.NAME], template[RemoteTemplateKey.REVISION]) # remote template data is a super set of local template data, barring # the key 'catalog_item_name' template_data = dict(template) template_data[LocalTemplateKey.CATALOG_ITEM_NAME] = catalog_item_name missing_keys = [k for k in LocalTemplateKey if k not in template_data] if len(missing_keys) > 0: raise ValueError(f"Invalid template data. Missing keys: {missing_keys}" ) # noqa: E501 build_params = { 'template_name': template[RemoteTemplateKey.NAME], 'template_revision': template[RemoteTemplateKey.REVISION], 'source_ova_name': template[RemoteTemplateKey.SOURCE_OVA_NAME], # noqa: E501 'source_ova_href': template[RemoteTemplateKey.SOURCE_OVA_HREF], # noqa: E501 'source_ova_sha256': template[RemoteTemplateKey.SOURCE_OVA_SHA256], # noqa: E501 'org_name': org_name, 'vdc_name': vdc_name, 'catalog_name': catalog_name, 'catalog_item_name': catalog_item_name, 'catalog_item_description': template[RemoteTemplateKey.DESCRIPTION], # noqa: E501 'temp_vapp_name': template[RemoteTemplateKey.NAME] + '_temp', # noqa: E501 'cpu': template[RemoteTemplateKey.CPU], 'memory': template[RemoteTemplateKey.MEMORY], 'network_name': network_name, 'ip_allocation_mode': ip_allocation_mode, # noqa: E501 'storage_profile': storage_profile } builder = TemplateBuilder(client, client, build_params, ssh_key=ssh_key, logger=LOGGER, msg_update_callback=msg_update_callback) builder.build(force_recreate=force_update, retain_temp_vapp=retain_temp_vapp) ltm.save_metadata(client, org_name, catalog_name, catalog_item_name, template_data)
def _install_template(client, remote_template_manager, template, org_name, vdc_name, catalog_name, network_name, ip_allocation_mode, storage_profile, force_update, retain_temp_vapp, ssh_key, msg_update_callback): remote_template_manager.download_template_scripts( template_name=template[RemoteTemplateKey.NAME], revision=template[RemoteTemplateKey.REVISION], force_overwrite=force_update) catalog_item_name = get_revisioned_template_name( template[RemoteTemplateKey.NAME], template[RemoteTemplateKey.REVISION]) build_params = { 'template_name': template[RemoteTemplateKey.NAME], 'template_revision': template[RemoteTemplateKey.REVISION], 'source_ova_name': template[RemoteTemplateKey.SOURCE_OVA_NAME], # noqa: E501 'source_ova_href': template[RemoteTemplateKey.SOURCE_OVA_HREF], # noqa: E501 'source_ova_sha256': template[RemoteTemplateKey.SOURCE_OVA_SHA256], # noqa: E501 'org_name': org_name, 'vdc_name': vdc_name, 'catalog_name': catalog_name, 'catalog_item_name': catalog_item_name, 'catalog_item_description': template[RemoteTemplateKey.DESCRIPTION], # noqa: E501 'temp_vapp_name': template[RemoteTemplateKey.NAME] + '_temp', # noqa: E501 'cpu': template[RemoteTemplateKey.CPU], 'memory': template[RemoteTemplateKey.MEMORY], 'network_name': network_name, 'ip_allocation_mode': ip_allocation_mode, # noqa: E501 'storage_profile': storage_profile } builder = TemplateBuilder(client, client, build_params, ssh_key=ssh_key, logger=LOGGER, msg_update_callback=msg_update_callback) builder.build(force_recreate=force_update, retain_temp_vapp=retain_temp_vapp) # remote definition is a super set of local definition, barring # the key 'catalog_item_name' template_definition = dict(template) template_definition['catalog_item_name'] = catalog_item_name save_k8s_local_template_definition_as_metadata( client=client, catalog_name=catalog_name, catalog_item_name=catalog_item_name, template_definition=template_definition, org_name=org_name)
def test_0090_install_retain_temp_vapp(config, unregister_cse_before_test): """Test install. Installation options: '--template', '--ssh-key', '--retain-temp-vapp', '--skip-config-decryption'. Tests that installation: - downloads/uploads ova file, - creates photon temp vapp, - creates k8s templates - skips deleting the temp vapp - checks that proper packages are installed in the vm in temp vApp command: cse install cse_test_config.yaml --retain-temp-vapp --skip-config-decryption # noqa: E501 --ssh-key ~/.ssh/id_rsa.pub required files: ~/.ssh/id_rsa.pub, cse_test_config.yaml expected: cse registered, catalog exists, source ovas exist, temp vapps exist, k8s templates exist. """ cmd = f"install {env.ACTIVE_CONFIG_FILEPATH} --ssh-key " \ f"{env.SSH_KEY_FILEPATH} --retain-temp-vapp --skip-config-decryption" result = env.CLI_RUNNER.invoke(cli, cmd.split(), catch_exceptions=False) assert result.exit_code == 0,\ testutils.format_command_info('cse', cmd, result.exit_code, result.output) # check that cse was registered correctly env.check_cse_registration(config['amqp']['routing_key'], config['amqp']['exchange']) vdc = VDC(env.CLIENT, href=env.VDC_HREF) for template_config in env.TEMPLATE_DEFINITIONS: # check that source ova file exists in catalog assert env.catalog_item_exists( template_config['source_ova_name']), \ 'Source ova file does not exist when it should.' # check that k8s templates exist catalog_item_name = get_revisioned_template_name( template_config['name'], template_config['revision']) assert env.catalog_item_exists(catalog_item_name), \ 'k8s template does not exist when it should.' # check that temp vapp exists temp_vapp_name = testutils.get_temp_vapp_name(template_config['name']) try: vdc.reload() vdc.get_vapp(temp_vapp_name) except EntityNotFoundException: assert False, 'vApp does not exist when it should.'
def test_0080_install_skip_template_creation(config, unregister_cse_before_test): """Test install. Installation options: '--ssh-key', '--skip-create-templates', '--skip-config-decryption' Tests that installation: - registers CSE, without installing the templates command: cse install cse_test_config.yaml --ssh-key ~/.ssh/id_rsa.pub --skip-config-decryption --skip-create-templates # noqa: E501 required files: ~/.ssh/id_rsa.pub, cse_test_config.yaml, expected: cse registered, catalog exists, source ovas do not exist, temp vapps do not exist, k8s templates do not exist. """ cmd = f"install {env.ACTIVE_CONFIG_FILEPATH} --ssh-key " \ f"{env.SSH_KEY_FILEPATH} --skip-template-creation --skip-config-decryption" # noqa: E501 result = env.CLI_RUNNER.invoke(cli, cmd.split(), catch_exceptions=False) assert result.exit_code == 0,\ testutils.format_command_info('cse', cmd, result.exit_code, result.output) # check that cse was registered correctly env.check_cse_registration(config['amqp']['routing_key'], config['amqp']['exchange']) for template_config in env.TEMPLATE_DEFINITIONS: # check that source ova file does not exist in catalog assert not env.catalog_item_exists( template_config['source_ova_name']), \ 'Source ova file exists when it should not.' # check that k8s templates does not exist catalog_item_name = get_revisioned_template_name( template_config['name'], template_config['revision']) assert not env.catalog_item_exists(catalog_item_name), \ 'k8s templates exist when they should not.' # check that temp vapp does not exists temp_vapp_name = testutils.get_temp_vapp_name(template_config['name']) assert not env.vapp_exists(temp_vapp_name), \ 'vApp exists when it should not.'
def test_0100_install_force_update(config, unregister_cse_before_test): """Tests installation option: '--force-update'. Tests that installation: - creates all templates correctly, - customizes temp vapps correctly. command: cse install cse_test_config.yaml --ssh-key ~/.ssh/id_rsa.pub --force-update --skip-config-decryption required files: cse_test_config.yaml, ~/.ssh/id_rsa.pub, ubuntu/photon init/cust scripts expected: cse registered, source ovas exist, k8s templates exist and temp vapps don't exist. """ cmd = f"install {env.ACTIVE_CONFIG_FILEPATH} --ssh-key " \ f"{env.SSH_KEY_FILEPATH} --force-update --skip-config-decryption" result = env.CLI_RUNNER.invoke(cli, cmd.split(), catch_exceptions=False) assert result.exit_code == 0,\ testutils.format_command_info('cse', cmd, result.exit_code, result.output) # check that cse was registered correctly env.check_cse_registration(config['amqp']['routing_key'], config['amqp']['exchange']) for template_config in env.TEMPLATE_DEFINITIONS: # check that source ova file exists in catalog assert env.catalog_item_exists( template_config['source_ova_name']), \ 'Source ova file does not exists when it should.' # check that k8s templates exist catalog_item_name = get_revisioned_template_name( template_config['name'], template_config['revision']) assert env.catalog_item_exists(catalog_item_name), \ 'k8s template does not exist when it should.' # check that temp vapp does not exists temp_vapp_name = testutils.get_temp_vapp_name(template_config['name']) assert not env.vapp_exists(temp_vapp_name), \ 'vApp exists when it should not.'
def test_0090_install_retain_temp_vapp(config, unregister_cse_before_test): """Test install. Installation options: '--config', '--template', '--ssh-key', '--retain-temp-vapp'. Tests that installation: - downloads/uploads ova file, - creates photon temp vapp, - creates k8s templates - skips deleting the temp vapp - checks that proper packages are installed in the vm in temp vApp command: cse install --config cse_test_config.yaml --retain-temp-vapp --ssh-key ~/.ssh/id_rsa.pub required files: ~/.ssh/id_rsa.pub, cse_test_config.yaml expected: cse registered, catalog exists, source ovas exist, temp vapps exist, k8s templates exist. """ cmd = f"install --config {env.ACTIVE_CONFIG_FILEPATH} --ssh-key " \ f"{env.SSH_KEY_FILEPATH} --retain-temp-vapp" result = env.CLI_RUNNER.invoke(cli, cmd.split(), catch_exceptions=False) assert result.exit_code == 0,\ testutils.format_command_info('cse', cmd, result.exit_code, result.output) # check that cse was registered correctly env.check_cse_registration(config['amqp']['routing_key'], config['amqp']['exchange']) vdc = VDC(env.CLIENT, href=env.VDC_HREF) ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) for template_config in env.TEMPLATE_DEFINITIONS: # check that source ova file exists in catalog assert env.catalog_item_exists( template_config['source_ova_name']), \ 'Source ova file does not existswhen it should.' # check that k8s templates exist catalog_item_name = get_revisioned_template_name( template_config['name'], template_config['revision']) assert env.catalog_item_exists(catalog_item_name), \ 'k8s template does not exist when it should.' # check that temp vapp exists temp_vapp_name = testutils.get_temp_vapp_name(template_config['name']) try: vdc.reload() vapp_resource = vdc.get_vapp(temp_vapp_name) except EntityNotFoundException: assert False, 'vApp does not exist when it should.' # ssh into vms to check for installed software vapp = VApp(env.CLIENT, resource=vapp_resource) # The temp vapp is shutdown before the template is captured, it # needs to be powered on before trying to ssh into it. task = vapp.power_on() env.CLIENT.get_task_monitor().wait_for_success(task) # HACK! let the ssh daemon come up time.sleep(env.WAIT_INTERVAL) # 30 seconds ip = vapp.get_primary_ip(TEMP_VAPP_VM_NAME) try: ssh_client.connect(ip, username='******') # run different commands depending on OS if 'photon' in temp_vapp_name: script_filepath = get_local_script_filepath( template_config['name'], template_config['revision'], ScriptFile.CUST) script = read_data_file(script_filepath) pattern = r'(kubernetes\S*)' packages = re.findall(pattern, script) stdin, stdout, stderr = ssh_client.exec_command("rpm -qa") installed = [line.strip('.x86_64\n') for line in stdout] for package in packages: assert package in installed, \ f"{package} not found in Photon VM" elif 'ubuntu' in temp_vapp_name: script_filepath = get_local_script_filepath( template_config['name'], template_config['revision'], ScriptFile.CUST) script = read_data_file(script_filepath) pattern = r'((kubernetes|docker\S*|kubelet|kubeadm|kubectl)\S*=\S*)' # noqa: E501 packages = [tup[0] for tup in re.findall(pattern, script)] cmd = "dpkg -l | awk '{print $2\"=\"$3}'" stdin, stdout, stderr = ssh_client.exec_command(cmd) installed = [line.strip() for line in stdout] for package in packages: assert package in installed, \ f"{package} not found in Ubuntu VM" finally: if ssh_client: ssh_client.close()
def install_cse(ctx, config_file_name='config.yaml', skip_template_creation=True, force_update=False, ssh_key=None, retain_temp_vapp=False, msg_update_callback=None): """Handle logistics for CSE installation. Handles decision making for configuring AMQP exchange/settings, extension registration, catalog setup, and template creation. :param click.core.Context ctx: :param str config_file_name: config file name. :param bool skip_template_creation: If True, skip creating the templates. :param bool force_update: if True and templates already exist in vCD, overwrites existing templates. :param str ssh_key: public ssh key to place into template vApp(s). :param bool retain_temp_vapp: if True, temporary vApp will not destroyed, so the user can ssh into and debug the vm. :param utils.ConsoleMessagePrinter msg_update_callback: Callback object that writes messages onto console. :raises AmqpError: if AMQP exchange could not be created. """ configure_install_logger() config = get_validated_config(config_file_name, msg_update_callback=msg_update_callback) populate_vsphere_list(config['vcs']) msg = f"Installing CSE on vCloud Director using config file " \ f"'{config_file_name}'" if msg_update_callback: msg_update_callback.info(msg) LOGGER.info(msg) client = None try: client = Client(config['vcd']['host'], api_version=config['vcd']['api_version'], verify_ssl_certs=config['vcd']['verify'], log_file=INSTALL_WIRELOG_FILEPATH, log_requests=True, log_headers=True, log_bodies=True) credentials = BasicLoginCredentials(config['vcd']['username'], SYSTEM_ORG_NAME, config['vcd']['password']) client.set_credentials(credentials) msg = f"Connected to vCD as system administrator: " \ f"{config['vcd']['host']}:{config['vcd']['port']}" if msg_update_callback: msg_update_callback.general(msg) LOGGER.info(msg) # create amqp exchange if it doesn't exist amqp = config['amqp'] _create_amqp_exchange(amqp['exchange'], amqp['host'], amqp['port'], amqp['vhost'], amqp['ssl'], amqp['username'], amqp['password'], msg_update_callback=msg_update_callback) # register or update cse on vCD _register_cse(client, amqp['routing_key'], amqp['exchange'], msg_update_callback=msg_update_callback) # register rights to vCD # TODO() should also remove rights when unregistering CSE _register_right(client, right_name=CSE_NATIVE_DEPLOY_RIGHT_NAME, description=CSE_NATIVE_DEPLOY_RIGHT_DESCRIPTION, category=CSE_NATIVE_DEPLOY_RIGHT_CATEGORY, bundle_key=CSE_NATIVE_DEPLOY_RIGHT_BUNDLE_KEY, msg_update_callback=msg_update_callback) _register_right(client, right_name=CSE_PKS_DEPLOY_RIGHT_NAME, description=CSE_PKS_DEPLOY_RIGHT_DESCRIPTION, category=CSE_PKS_DEPLOY_RIGHT_CATEGORY, bundle_key=CSE_PKS_DEPLOY_RIGHT_BUNDLE_KEY, msg_update_callback=msg_update_callback) org_name = config['broker']['org'] catalog_name = config['broker']['catalog'] # set up cse catalog org = get_org(client, org_name=org_name) create_and_share_catalog(org, catalog_name, catalog_desc='CSE templates', msg_update_callback=msg_update_callback) if skip_template_creation: msg = "Skipping creation of templates." if msg_update_callback: msg_update_callback.info(msg) LOGGER.warning(msg) else: # read remote template cookbook, download all scripts rtm = RemoteTemplateManager( remote_template_cookbook_url=config['broker'] ['remote_template_cookbook_url'], # noqa: E501 logger=LOGGER, msg_update_callback=ConsoleMessagePrinter()) remote_template_cookbook = rtm.get_remote_template_cookbook() # create all templates defined in cookbook for template in remote_template_cookbook['templates']: rtm.download_template_scripts( template_name=template[RemoteTemplateKey.NAME], revision=template[RemoteTemplateKey.REVISION], force_overwrite=force_update) catalog_item_name = get_revisioned_template_name( template[RemoteTemplateKey.NAME], template[RemoteTemplateKey.REVISION]) build_params = { 'template_name': template[RemoteTemplateKey.NAME], 'template_revision': template[RemoteTemplateKey.REVISION], 'source_ova_name': template[RemoteTemplateKey.SOURCE_OVA_NAME], # noqa: E501 'source_ova_href': template[RemoteTemplateKey.SOURCE_OVA_HREF], # noqa: E501 'source_ova_sha256': template[ RemoteTemplateKey.SOURCE_OVA_SHA256], # noqa: E501 'org_name': org_name, 'vdc_name': config['broker']['vdc'], 'catalog_name': catalog_name, 'catalog_item_name': catalog_item_name, 'catalog_item_description': template[RemoteTemplateKey.DESCRIPTION], # noqa: E501 'temp_vapp_name': template[RemoteTemplateKey.NAME] + '_temp', # noqa: E501 'cpu': template[RemoteTemplateKey.CPU], 'memory': template[RemoteTemplateKey.MEMORY], 'network_name': config['broker']['network'], 'ip_allocation_mode': config['broker']['ip_allocation_mode'], # noqa: E501 'storage_profile': config['broker']['storage_profile'] } builder = TemplateBuilder( client, client, build_params, ssh_key=ssh_key, logger=LOGGER, msg_update_callback=ConsoleMessagePrinter()) builder.build(force_recreate=force_update, retain_temp_vapp=retain_temp_vapp) # remote definition is a super set of local definition, barring # the key 'catalog_item_name' template_definition = dict(template) template_definition['catalog_item_name'] = catalog_item_name save_k8s_local_template_definition_as_metadata( client=client, catalog_name=catalog_name, catalog_item_name=catalog_item_name, template_definition=template_definition, org_name=org_name) # if it's a PKS setup, setup NSX-T constructs if config.get('pks_config'): nsxt_servers = config.get('pks_config')['nsxt_servers'] for nsxt_server in nsxt_servers: msg = f"Configuring NSX-T server ({nsxt_server.get('name')})" \ " for CSE. Please check install logs for details." if msg_update_callback: msg_update_callback.general(msg) LOGGER.info(msg) nsxt_client = NSXTClient(host=nsxt_server.get('host'), username=nsxt_server.get('username'), password=nsxt_server.get('password'), http_proxy=nsxt_server.get('proxy'), https_proxy=nsxt_server.get('proxy'), verify_ssl=nsxt_server.get('verify'), logger_instance=LOGGER, log_requests=True, log_headers=True, log_body=True) setup_nsxt_constructs( nsxt_client=nsxt_client, nodes_ip_block_id=nsxt_server.get('nodes_ip_block_ids'), pods_ip_block_id=nsxt_server.get('pods_ip_block_ids'), ncp_boundary_firewall_section_anchor_id=nsxt_server.get( 'distributed_firewall_section_anchor_id') ) # noqa: E501 except Exception: if msg_update_callback: msg_update_callback.error( "CSE Installation Error. Check CSE install logs") LOGGER.error("CSE Installation Error", exc_info=True) raise # TODO() need installation relevant exceptions for rollback finally: if client is not None: client.logout()