def __init__(self, pks_ctx, tenant_auth_token): """Initialize PKS broker. :param dict pks_ctx: A dictionary with which should atleast have the following keys in it ['username', 'secret', 'host', 'port', 'uaac_port'], 'proxy' and 'pks_compute_profile_name' are optional keys. Currently all callers of this method is using ovdc cache (subject to change) to initialize PKS broker. """ self.tenant_client = None self.client_session = None self.tenant_user_name = None self.tenant_user_id = None self.tenant_org_name = None self.tenant_org_href = None # populates above attributes super().__init__(tenant_auth_token) if not pks_ctx: raise ValueError( "PKS context is required to establish connection to PKS") self.username = pks_ctx['username'] self.secret = pks_ctx['secret'] self.pks_host_uri = f"https://{pks_ctx['host']}:{pks_ctx['port']}" self.uaac_uri = f"https://{pks_ctx['host']}:{pks_ctx['uaac_port']}" self.proxy_uri = None if pks_ctx.get('proxy'): self.proxy_uri = f"http://{pks_ctx['proxy']}:80" self.compute_profile = pks_ctx.get(PKS_COMPUTE_PROFILE_KEY, None) self.nsxt_server = \ utils.get_pks_cache().get_nsxt_info(pks_ctx.get('vc')) self.nsxt_client = None if self.nsxt_server: self.nsxt_client = NSXTClient( host=self.nsxt_server.get('host'), username=self.nsxt_server.get('username'), password=self.nsxt_server.get('password'), http_proxy=self.nsxt_server.get('proxy'), https_proxy=self.nsxt_server.get('proxy'), verify_ssl=self.nsxt_server.get('verify'), log_requests=True, log_headers=True, log_body=True) # TODO() Add support in pyvcloud to send metadata values with their # types intact. verify_ssl = pks_ctx.get('verify') self.verify = True if isinstance(verify_ssl, bool): self.verify = verify_ssl elif isinstance(verify_ssl, str): self.verify = utils.str_to_bool(verify_ssl) token = self._get_token() self.client_v1 = self._get_pks_client(token, self.VERSION_V1) self.client_v1beta = self._get_pks_client(token, self.VERSION_V1BETA)
def __init__(self, pks_ctx, op_ctx: ctx.OperationContext): """Initialize PKS broker. :param dict pks_ctx: A dictionary with which should atleast have the following keys in it ['username', 'secret', 'host', 'port', 'uaac_port'], 'proxy' and 'pks_compute_profile_name' are optional keys. Currently all callers of this method is using ovdc cache (subject to change) to initialize PKS broker. """ self.context: ctx.OperationContext = None # populates above attributes super().__init__(op_ctx) if not pks_ctx: raise ValueError( "PKS context is required to establish connection to PKS") self.username = pks_ctx['username'] self.secret = pks_ctx['secret'] self.pks_host_uri = f"https://{pks_ctx['host']}:{pks_ctx['port']}" self.uaac_uri = f"https://{pks_ctx['host']}:{pks_ctx['uaac_port']}" self.proxy_uri = None if pks_ctx.get('proxy'): self.proxy_uri = f"http://{pks_ctx['proxy']}:80" self.compute_profile = pks_ctx.get(PKS_COMPUTE_PROFILE_KEY, None) self.nsxt_server = \ utils.get_pks_cache().get_nsxt_info(pks_ctx.get('vc')) self.nsxt_client = None self.pks_wire_logger = NULL_LOGGER nsxt_wire_logger = NULL_LOGGER config = utils.get_server_runtime_config() if utils.str_to_bool(config['service'].get('log_wire')): nsxt_wire_logger = SERVER_NSXT_WIRE_LOGGER self.pks_wire_logger = SERVER_PKS_WIRE_LOGGER if self.nsxt_server: self.nsxt_client = NSXTClient( host=self.nsxt_server.get('host'), username=self.nsxt_server.get('username'), password=self.nsxt_server.get('password'), logger_debug=SERVER_LOGGER, logger_wire=nsxt_wire_logger, http_proxy=self.nsxt_server.get('proxy'), https_proxy=self.nsxt_server.get('proxy'), verify_ssl=self.nsxt_server.get('verify')) # TODO() Add support in pyvcloud to send metadata values with their # types intact. verify_ssl = pks_ctx.get('verify') self.verify = True if isinstance(verify_ssl, bool): self.verify = verify_ssl elif isinstance(verify_ssl, str): self.verify = utils.str_to_bool(verify_ssl) self.pks_client = self._get_pks_client(self._get_token())
def __init__(self, request_headers, request_spec, pks_ctx): """Initialize PKS broker. :param dict pks_ctx: A dictionary with which should atleast have the following keys in it ['username', 'secret', 'host', 'port', 'uaac_port'], 'proxy' and 'pks_compute_profile_name' are optional keys. Currently all callers of this method is using ovdc cache (subject to change) to initialize PKS broker. """ super().__init__(request_headers, request_spec) if not pks_ctx: raise ValueError( "PKS context is required to establish connection to PKS") self.req_headers = request_headers self.req_spec = request_spec self.username = pks_ctx['username'] self.secret = pks_ctx['secret'] self.pks_host_uri = \ f"https://{pks_ctx['host']}:{pks_ctx['port']}" self.uaac_uri = \ f"https://{pks_ctx['host']}:{pks_ctx['uaac_port']}" self.proxy_uri = f"http://{pks_ctx['proxy']}:80" \ if pks_ctx.get('proxy') else None self.compute_profile = pks_ctx.get(PKS_COMPUTE_PROFILE_KEY, None) self.nsxt_server = \ get_pks_cache().get_nsxt_info(pks_ctx.get('vc')) if self.nsxt_server: self.nsxt_client = NSXTClient( host=self.nsxt_server.get('host'), username=self.nsxt_server.get('username'), password=self.nsxt_server.get('password'), http_proxy=self.nsxt_server.get('proxy'), https_proxy=self.nsxt_server.get('proxy'), verify_ssl=self.nsxt_server.get('verify'), log_requests=True, log_headers=True, log_body=True) # TODO() Add support in pyvcloud to send metadata values with their # types intact. verify_ssl_value_in_ctx = pks_ctx.get('verify') if isinstance(verify_ssl_value_in_ctx, bool): self.verify = verify_ssl_value_in_ctx elif isinstance(verify_ssl_value_in_ctx, str): self.verify = \ False if verify_ssl_value_in_ctx.lower() == 'false' else True else: self.verify = True token = self._get_token() self.client_v1 = self._get_pks_client(token, self.VERSION_V1) self.client_v1beta = self._get_pks_client(token, self.VERSION_V1BETA) self.client_session = None self.get_tenant_client_session()
def install_cse(config_file_name, skip_template_creation, force_update, ssh_key, retain_temp_vapp, pks_config_file_name=None, skip_config_decryption=False, decryption_password=None, 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 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 str pks_config_file_name: pks config file name. :param bool skip_config_decryption: do not decrypt the config file. :param str decryption_password: password to decrypt the config file. :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, pks_config_file_name=pks_config_file_name, skip_config_decryption=skip_config_decryption, decryption_password=decryption_password, 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: log_filename = None log_wire = str_to_bool(config['service'].get('log_wire')) if log_wire: log_filename = INSTALL_WIRELOG_FILEPATH client = Client(config['vcd']['host'], api_version=config['vcd']['api_version'], verify_ssl_certs=config['vcd']['verify'], log_file=log_filename, log_requests=log_wire, log_headers=log_wire, log_bodies=log_wire) 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) # set up cse catalog org = get_org(client, org_name=config['broker']['org']) create_and_share_catalog(org, config['broker']['catalog'], 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=msg_update_callback) remote_template_cookbook = rtm.get_remote_template_cookbook() # create all templates defined in cookbook for template in remote_template_cookbook['templates']: _install_template( client=client, remote_template_manager=rtm, template=template, org_name=config['broker']['org'], vdc_name=config['broker']['vdc'], catalog_name=config['broker']['catalog'], network_name=config['broker']['network'], ip_allocation_mode=config['broker']['ip_allocation_mode'], storage_profile=config['broker']['storage_profile'], force_update=force_update, retain_temp_vapp=retain_temp_vapp, ssh_key=ssh_key, msg_update_callback=msg_update_callback) # 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()
def install_cse(config_file_name, skip_template_creation, force_update, ssh_key, retain_temp_vapp, pks_config_file_name=None, skip_config_decryption=False, decryption_password=None, msg_update_callback=utils.NullPrinter()): """Handle logistics for CSE installation. Handles decision making for configuring AMQP exchange/settings, defined entity schema registration for vCD api version >= 35, extension registration, catalog setup and template creation. Also records telemetry data on installation details. :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 str pks_config_file_name: pks config file name. :param bool skip_config_decryption: do not decrypt the config file. :param str decryption_password: password to decrypt the config file. :param utils.ConsoleMessagePrinter msg_update_callback: Callback object. :raises cse_exception.AmqpError: if AMQP exchange could not be created. """ config = get_validated_config( config_file_name, pks_config_file_name=pks_config_file_name, skip_config_decryption=skip_config_decryption, decryption_password=decryption_password, log_wire_file=INSTALL_WIRELOG_FILEPATH, logger_debug=INSTALL_LOGGER, 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}'" msg_update_callback.info(msg) INSTALL_LOGGER.info(msg) client = None try: # Telemetry - Construct telemetry data telemetry_data = { PayloadKey.WAS_DECRYPTION_SKIPPED: bool(skip_config_decryption), # noqa: E501 PayloadKey.WAS_PKS_CONFIG_FILE_PROVIDED: bool(pks_config_file_name), # noqa: E501 PayloadKey.WERE_TEMPLATES_SKIPPED: bool(skip_template_creation), # noqa: E501 PayloadKey.WERE_TEMPLATES_FORCE_UPDATED: bool(force_update), # noqa: E501 PayloadKey.WAS_TEMP_VAPP_RETAINED: bool(retain_temp_vapp), # noqa: E501 PayloadKey.WAS_SSH_KEY_SPECIFIED: bool(ssh_key) # noqa: E501 } # Telemetry - Record detailed telemetry data on install record_user_action_details( CseOperation.SERVICE_INSTALL, telemetry_data, telemetry_settings=config['service']['telemetry']) # noqa: E501 log_filename = None log_wire = utils.str_to_bool(config['service'].get('log_wire')) if log_wire: log_filename = INSTALL_WIRELOG_FILEPATH client = Client(config['vcd']['host'], api_version=config['vcd']['api_version'], verify_ssl_certs=config['vcd']['verify'], log_file=log_filename, log_requests=log_wire, log_headers=log_wire, log_bodies=log_wire) credentials = BasicLoginCredentials(config['vcd']['username'], server_constants.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']}" msg_update_callback.general(msg) INSTALL_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 cse def schema on VCD # schema should be located at # ~/.cse-schema/api-v<API VERSION>/schema.json _register_def_schema(client, msg_update_callback=msg_update_callback, log_wire=log_wire) # Since we use CSE extension id as our telemetry instance_id, the # validated config won't have the instance_id yet. Now that CSE has # been registered as an extension, we should update the telemetry # config with the correct instance_id if config['service']['telemetry']['enable']: store_telemetry_settings(config) # register rights to vCD # TODO() should also remove rights when unregistering CSE _register_right( client, right_name=server_constants. CSE_NATIVE_DEPLOY_RIGHT_NAME, # noqa: E501 description=server_constants. CSE_NATIVE_DEPLOY_RIGHT_DESCRIPTION, # noqa: E501 category=server_constants. CSE_NATIVE_DEPLOY_RIGHT_CATEGORY, # noqa: E501 bundle_key=server_constants. CSE_NATIVE_DEPLOY_RIGHT_BUNDLE_KEY, # noqa: E501 msg_update_callback=msg_update_callback) _register_right( client, right_name=server_constants. CSE_PKS_DEPLOY_RIGHT_NAME, # noqa: E501 description=server_constants. CSE_PKS_DEPLOY_RIGHT_DESCRIPTION, # noqa: E501 category=server_constants. CSE_PKS_DEPLOY_RIGHT_CATEGORY, # noqa: E501 bundle_key=server_constants. CSE_PKS_DEPLOY_RIGHT_BUNDLE_KEY, # noqa: E501 msg_update_callback=msg_update_callback) # set up placement policies for all types of clusters _setup_placement_policies( client, policy_list=server_constants. CLUSTER_PLACEMENT_POLICIES, # noqa: E501 msg_update_callback=msg_update_callback, log_wire=log_wire) # set up cse catalog org = vcd_utils.get_org(client, org_name=config['broker']['org']) vcd_utils.create_and_share_catalog( org, config['broker']['catalog'], catalog_desc='CSE templates', logger=INSTALL_LOGGER, msg_update_callback=msg_update_callback) if skip_template_creation: msg = "Skipping creation of templates." msg_update_callback.info(msg) INSTALL_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=INSTALL_LOGGER, msg_update_callback=msg_update_callback) remote_template_cookbook = rtm.get_remote_template_cookbook() # create all templates defined in cookbook for template in remote_template_cookbook['templates']: # TODO tag created templates with placement policies _install_template( client=client, remote_template_manager=rtm, template=template, org_name=config['broker']['org'], vdc_name=config['broker']['vdc'], catalog_name=config['broker']['catalog'], network_name=config['broker']['network'], ip_allocation_mode=config['broker']['ip_allocation_mode'], storage_profile=config['broker']['storage_profile'], force_update=force_update, retain_temp_vapp=retain_temp_vapp, ssh_key=ssh_key, msg_update_callback=msg_update_callback) # if it's a PKS setup, setup NSX-T constructs if config.get('pks_config'): nsxt_servers = config['pks_config']['nsxt_servers'] wire_logger = NULL_LOGGER if log_wire: wire_logger = SERVER_NSXT_WIRE_LOGGER for nsxt_server in nsxt_servers: msg = f"Configuring NSX-T server ({nsxt_server.get('name')})" \ " for CSE. Please check install logs for details." msg_update_callback.general(msg) INSTALL_LOGGER.info(msg) nsxt_client = NSXTClient(host=nsxt_server.get('host'), username=nsxt_server.get('username'), password=nsxt_server.get('password'), logger_debug=INSTALL_LOGGER, logger_wire=wire_logger, http_proxy=nsxt_server.get('proxy'), https_proxy=nsxt_server.get('proxy'), verify_ssl=nsxt_server.get('verify')) 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 # Telemetry - Record successful install action record_user_action(CseOperation.SERVICE_INSTALL, telemetry_settings=config['service']['telemetry']) except Exception: msg_update_callback.error( "CSE Installation Error. Check CSE install logs") INSTALL_LOGGER.error("CSE Installation Error", exc_info=True) # Telemetry - Record failed install action record_user_action(CseOperation.SERVICE_INSTALL, status=OperationStatus.FAILED, telemetry_settings=config['service']['telemetry']) raise # TODO() need installation relevant exceptions for rollback finally: if client is not None: client.logout()
def _validate_pks_config_data_integrity(pks_config, msg_update_callback=NullPrinter(), logger_debug=NULL_LOGGER, logger_wire=NULL_LOGGER): all_pks_servers = \ [entry['name'] for entry in pks_config[PKS_SERVERS_SECTION_KEY]] all_pks_accounts = \ [entry['name'] for entry in pks_config[PKS_ACCOUNTS_SECTION_KEY]] # Create a cache with pks_account to Credentials mapping pks_account_info_table = {} for pks_account in pks_config[PKS_ACCOUNTS_SECTION_KEY]: pks_account_name = pks_account['pks_api_server'] credentials = Credentials(pks_account['username'], pks_account['secret']) pks_account_info_table[pks_account_name] = credentials # Check for duplicate pks api server names duplicate_pks_server_names = get_duplicate_items_in_list(all_pks_servers) if len(duplicate_pks_server_names) != 0: raise ValueError( f"Duplicate PKS api server(s) : {duplicate_pks_server_names} found" f" in Section : {PKS_SERVERS_SECTION_KEY}") # Check for duplicate pks account names duplicate_pks_account_names = get_duplicate_items_in_list(all_pks_accounts) if len(duplicate_pks_account_names) != 0: raise ValueError( f"Duplicate PKS account(s) : {duplicate_pks_account_names} found" f" in Section : {PKS_ACCOUNTS_SECTION_KEY}") # Check validity of all PKS api servers referenced in PKS accounts section for pks_account in pks_config[PKS_ACCOUNTS_SECTION_KEY]: pks_server_name = pks_account.get('pks_api_server') if pks_server_name not in all_pks_servers: raise ValueError( f"Unknown PKS api server : {pks_server_name} referenced by " f"PKS account : {pks_account.get('name')} in Section : " f"{PKS_ACCOUNTS_SECTION_KEY}") # Check validity of all PKS accounts referenced in Orgs section if PKS_ORGS_SECTION_KEY in pks_config.keys(): for org in pks_config[PKS_ORGS_SECTION_KEY]: referenced_accounts = org.get('pks_accounts') if not referenced_accounts: continue for account in referenced_accounts: if account not in all_pks_accounts: raise ValueError(f"Unknown PKS account : {account} refere" f"nced by Org : {org.get('name')} in " f"Section : {PKS_ORGS_SECTION_KEY}") # Check validity of all PKS api servers referenced in PVDC section for pvdc in pks_config[PKS_PVDCS_SECTION_KEY]: pks_server_name = pvdc.get('pks_api_server') if pks_server_name not in all_pks_servers: raise ValueError(f"Unknown PKS api server : {pks_server_name} " f"referenced by PVDC : {pvdc.get('name')} in " f"Section : {PKS_PVDCS_SECTION_KEY}") # Check validity of all PKS api servers referenced in the pks_api_servers # section for pks_server in pks_config[PKS_SERVERS_SECTION_KEY]: pks_account = pks_account_info_table.get(pks_server.get('name')) pks_configuration = Configuration() pks_configuration.proxy = f"http://{pks_server['proxy']}:80" \ if pks_server.get('proxy') else None pks_configuration.host = \ f"https://{pks_server['host']}:{pks_server['port']}/" \ f"{VERSION_V1}" pks_configuration.access_token = None pks_configuration.username = pks_account.username pks_configuration.verify_ssl = pks_server['verify'] pks_configuration.secret = pks_account.secret pks_configuration.uaac_uri = \ f"https://{pks_server['host']}:{pks_server['uaac_port']}" uaaClient = UaaClient(pks_configuration.uaac_uri, pks_configuration.username, pks_configuration.secret, proxy_uri=pks_configuration.proxy) token = uaaClient.getToken() if not token: raise ValueError( "Unable to connect to PKS server : " f"{pks_server.get('name')} ({pks_server.get('host')})") pks_configuration.token = token client = ApiClient(configuration=pks_configuration) if client: msg_update_callback.general( "Connected to PKS server (" f"{pks_server.get('name')} : {pks_server.get('host')})") # Check validity of all PKS api servers referenced in NSX-T section for nsxt_server in pks_config[PKS_NSXT_SERVERS_SECTION_KEY]: pks_server_name = nsxt_server.get('pks_api_server') if pks_server_name not in all_pks_servers: raise ValueError( f"Unknown PKS api server : {pks_server_name} referenced by " f"NSX-T server : {nsxt_server.get('name')} in Section : " f"{PKS_NSXT_SERVERS_SECTION_KEY}") # Create a NSX-T client and verify connection # server nsxt_client = NSXTClient( host=nsxt_server.get('host'), username=nsxt_server.get('username'), password=nsxt_server.get('password'), logger_debug=logger_debug, logger_wire=logger_wire, http_proxy=nsxt_server.get('proxy'), https_proxy=nsxt_server.get('proxy'), verify_ssl=nsxt_server.get('verify')) if not nsxt_client.test_connectivity(): raise ValueError( "Unable to connect to NSX-T server : " f"{nsxt_server.get('name')} ({nsxt_server.get('host')})") msg_update_callback.general( f"Connected to NSX-T server ({nsxt_server.get('host')})") ipset_manager = IPSetManager(nsxt_client) if nsxt_server.get('nodes_ip_block_ids'): block_not_found = False try: for ip_block_id in nsxt_server.get('nodes_ip_block_ids'): if not ipset_manager.get_ip_block_by_id(ip_block_id): block_not_found = True except HTTPError: block_not_found = True if block_not_found: raise ValueError( f"Unknown Node IP Block : {ip_block_id} referenced by " f"NSX-T server : {nsxt_server.get('name')}.") if nsxt_server.get('pods_ip_block_ids'): try: block_not_found = False for ip_block_id in nsxt_server.get('pods_ip_block_ids'): if not ipset_manager.get_ip_block_by_id(ip_block_id): block_not_found = True except HTTPError: block_not_found = True if block_not_found: raise ValueError( f"Unknown Pod IP Block : {ip_block_id} referenced by " f"NSX-T server : {nsxt_server.get('name')}.") dfw_manager = DFWManager(nsxt_client) fw_section_id = \ nsxt_server.get('distributed_firewall_section_anchor_id') section = dfw_manager.get_firewall_section(id=fw_section_id) if not section: raise ValueError( f"Unknown Firewall section : {fw_section_id} referenced by " f"NSX-T server : {nsxt_server.get('name')}.")
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()