def get_missing_rights_for_cluster_force_delete(client: vcd_client.Client, is_cluster_owner=False, logger=NULL_LOGGER) -> set: """ Find the missing rights for force-deleting the cluster. :param vcd_client.Client client: current client :param bool is_cluster_owner: true if the client is cluster owner :param logging.Logger logger: logger to record errors. :return: all missing rights :rtype: set :raises: OperationNotSupportedException :raises: Exception for any unexpected errors """ role_name = "" try: role_name = get_user_role_name(client) org_obj = vcd_org.Org(client, resource=client.get_org()) role_obj = vcd_role.Role( client, resource=org_obj.get_role_resource(role_name)) # noqa: E501 logger.debug(f"role_name:{role_name}") role_rights = set() for right_dict in role_obj.list_rights(): role_rights.update(right_dict.values()) logger.debug(f"rights of role:{role_name}--{role_rights}") missing_rights = set() if not server_constants.VAPP_DELETE_RIGHTS.issubset(role_rights): missing_rights.update(server_constants.VAPP_DELETE_RIGHTS) if not server_constants.DNAT_DELETE_RIGHTS.issubset(role_rights): missing_rights.update(server_constants.DNAT_DELETE_RIGHTS) if is_cluster_owner: if not server_constants.CSE_NATIVE_CLUSTER_FULL_ACCESS_RIGHTS.issubset( role_rights ) and not server_constants.CSE_NATIVE_CLUSTER_ADMINISTRATOR_FULL_ACCESS_RIGHTS.issubset( role_rights): # noqa: E501 missing_rights.update( server_constants.CSE_NATIVE_CLUSTER_FULL_ACCESS_RIGHTS ) # noqa: E501 else: if not server_constants.CSE_NATIVE_CLUSTER_ADMINISTRATOR_FULL_ACCESS_RIGHTS.issubset( role_rights): # noqa: E501 missing_rights.update( server_constants. CSE_NATIVE_CLUSTER_ADMINISTRATOR_FULL_ACCESS_RIGHTS ) # noqa: E501 except OperationNotSupportedException as err: logger.warning( f"Cannot determine the rights associated with role:{role_name} {err}" ) # noqa: E501 raise except Exception as err: logger.warning( f"Cannot determine the rights associated with role:{role_name} {err}" ) # noqa: E501 raise logger.debug(f"missing rights of role:{role_name}--{missing_rights}") return missing_rights
def vcd_login(host, user, password, org): logging.basicConfig(level=logging.DEBUG) logging.info("login called") client = Client(host, api_version="27.0", verify_ssl_certs=False, log_file='vcd.log', log_requests=True, log_headers=True, log_bodies=True) try: client.set_credentials(BasicLoginCredentials(user, org, password)) x = client._session.headers['x-vcloud-authorization'] logging.info(" ===== X VCloud ========\n \n" + x + "\n \n") logged_in_org = client.get_org() org = Org(client, resource=logged_in_org) v = org.get_vdc('OVD2') vdc = VDC(client, href=v.get('href')) vapp = vdc.get_vapp('cento_vapp11_2') nconfig_section = vapp.NetworkConfigSection nconfig = nconfig_section.findall( "{http://www.vmware.com/vcloud/v1.5}NetworkConfig") for i in range(0, len(nconfig)): print(nconfig[i].get('networkName')) ##print(etree.tostring(nconfig[0], pretty_print=True)) #pRes= catalog.isPresent(client,"c1") # res=catalog.create(client,"c44","c44",True) #logging.info(" is create ===== \n \n "+ str(res.created)+ "\n \n ") #logging.info("\n\n=====callling upload ova===\n") #catalog_item.upload_ova(client,"c44","/home/iso/tiny.ova",item_name="tiny3.ova") #logging.info("\n\n=====upload done ===\n ") #logging.info(" Delete ===== \n \n "+ str(catalog.delete(client,"c3").deleted)+ "\n \n ") #logging.info(" Delete ===== \n \n "+ str(catalog.delete(client,"c4").deleted)+ "\n \n ") #vappInfo=pyvcloudprovider_pb2.CreateVAppInfo() #vappInfo.name="vappacc2" #vappInfo.catalog_name="c1" #vappInfo.template_name="cento_tmpl1" #vapp.create(client,vappInfo) #delVappInfo=pyvcloudprovider_pb2.DeleteVAppInfo() #delVappInfo.name="vappacc2" #vapp.delete(client,delVappInfo) #ovaInfo=pyvcloudprovider_pb2.CatalogUploadOvaInfo() #ovaInfo.item_name="item1" #ovaInfo.catalog_name="testcata1" #ovaInfo.file_path="/Users/srinarayana/vmws/tiny.ova" # catalog_item.ova_check_resolved(client,ovaInfo) #vappInfo.template_name="cento_tmpl1" #vapp.create(client,vappInfo) return client except Exception as e: print('error occured', e)
def get_all_host(host, org, user, password, vdc): #Linux guest hosts linux_os_list = ['CentOS 7 (64-bit)', 'Ubuntu Linux (64-bit)', 'CentOS 8 (64-bit)'] #Windows guest hosts win_os_list = ['Microsoft Windows Server 2016 or later (64-bit)', 'Microsoft Windows Server 2019 (64-bit)'] #Host list of all Vapps host_list = {} client = Client(host, verify_ssl_certs=True,#SSL log_requests=False, log_headers=False, log_bodies=False) client.set_highest_supported_version() client.set_credentials(BasicLoginCredentials(user, org, password)) org_resource = client.get_org() org = Org(client, resource=org_resource) vdc_resource = org.get_vdc(vdc) vdc = VDC(client, resource=vdc_resource) vapps = vdc.list_resources() win_list = [] linux_list = [] other_os_list = [] hostvars = {} for vapp in vapps: if vapp["type"] == "application/vnd.vmware.vcloud.vApp+xml": currentHref = vdc.get_vapp_href(vapp["name"]) currentVapp = VApp(client, href=currentHref) for vm in currentVapp.get_all_vms(): vmName = vm.get('name') vmOs = VM(client, resource=vm) vOs = vmOs.get_operating_system_section() try: vmIp = currentVapp.get_primary_ip(vmName) except: pass if vmOs.is_powered_on(): if vOs.Description in win_os_list: win_list.append(vmName) hostvars.update({vmName:{'ansible_host':vmIp}}) elif vOs.Description in linux_os_list: linux_list.append(vmName) hostvars.update({vmName:{'ansible_host':vmIp}}) else: other_os_list.append(vmName) hostvars.update({vmName:{'ansible_host':vmIp}}) host_list.update({'windows':{'hosts':win_list}}) host_list.update({'linux':{'hosts':linux_list}}) host_list.update({'others':{'hosts':other_os_list}}) host_list.update({'_meta':{'hostvars':hostvars}}) return host_list
def login(session_id=None): log_requests = True if config['log'] == True else False log_headers = True if config['log'] == True else False log_bodies = True if config['log'] == True else False client = Client(config['host'], api_version=config['api_version'], verify_ssl_certs=config['verify_ssl_certs'], log_file=config['log_file'], log_requests=log_requests, log_headers=log_headers, log_bodies=log_bodies) if not config['verify_ssl_certs']: requests.packages.urllib3.disable_warnings() try: if session_id is not None: client.rehydrate_from_token(session_id) else: client.set_credentials( BasicLoginCredentials(config['username'], config['org'], config['password'])) logged_in_org = client.get_org() org = Org(client, resource=logged_in_org) org_url = "https://%s/cloud/org/%s" % (config['host'], logged_in_org) the_vdc = org.get_vdc(config['vdc']) # Set contextual data: ctx.client = client ctx.vdc = VDC(client, href=the_vdc.get('href')) ctx.token = client._session.headers['x-vcloud-authorization'] except Exception as e: if config['debug'] == True: print("Exception: {}\n".format(e)) return False return True
def vcd_login(host, user, password, org): logging.basicConfig(level=logging.DEBUG) logging.info("login called") client = Client( host, api_version="27.0", verify_ssl_certs=False, log_file='vcd.log', log_requests=True, log_headers=True, log_bodies=True) try: client.set_credentials(BasicLoginCredentials(user, org, password)) x = client._session.headers['x-vcloud-authorization'] logging.info(" ===== X VCloud ========\n \n" + x + "\n \n") logged_in_org = client.get_org() org = Org(client, resource=logged_in_org) v = org.get_vdc('OVD2') vdc = VDC(client, href=v.get('href')) vapp = vdc.get_vapp('cento_vapp11_2') nconfig_section = vapp.NetworkConfigSection nconfig = nconfig_section.findall( "{http://www.vmware.com/vcloud/v1.5}NetworkConfig") for i in range(0, len(nconfig)): print(nconfig[i].get('networkName')) ##print(etree.tostring(nconfig[0], pretty_print=True)) #pRes= catalog.isPresent(client,"c1") # res=catalog.create(client,"c44","c44",True) #logging.info(" is create ===== \n \n "+ str(res.created)+ "\n \n ") #logging.info("\n\n=====callling upload ova===\n") #catalog_item.upload_ova(client,"c44","/home/iso/tiny.ova",item_name="tiny3.ova") #logging.info("\n\n=====upload done ===\n ") #logging.info(" Delete ===== \n \n "+ str(catalog.delete(client,"c3").deleted)+ "\n \n ") #logging.info(" Delete ===== \n \n "+ str(catalog.delete(client,"c4").deleted)+ "\n \n ") #vappInfo=pyvcloudprovider_pb2.CreateVAppInfo() #vappInfo.name="vappacc2" #vappInfo.catalog_name="c1" #vappInfo.template_name="cento_tmpl1" #vapp.create(client,vappInfo) #delVappInfo=pyvcloudprovider_pb2.DeleteVAppInfo() #delVappInfo.name="vappacc2" #vapp.delete(client,delVappInfo) #ovaInfo=pyvcloudprovider_pb2.CatalogUploadOvaInfo() #ovaInfo.item_name="item1" #ovaInfo.catalog_name="testcata1" #ovaInfo.file_path="/Users/srinarayana/vmws/tiny.ova" # catalog_item.ova_check_resolved(client,ovaInfo) #vappInfo.template_name="cento_tmpl1" #vapp.create(client,vappInfo) return client except Exception as e: print('error occured', e)
# Disable warnings from self-signed certificates. requests.packages.urllib3.disable_warnings() # Login. SSL certificate verification is turned off to allow self-signed # certificates. You should only do this in trusted environments. print("Logging in: host={0}, org={1}, user={2}".format(host, org, user)) client = Client(host, api_version='29.0', verify_ssl_certs=False, log_file='pyvcloud.log', log_requests=True, log_headers=True, log_bodies=True) client.set_credentials(BasicLoginCredentials(user, org, password)) print("Fetching Org...") org_resource = client.get_org() org = Org(client, resource=org_resource) print("Fetching VDC...") vdc_resource = org.get_vdc(vdc) vdc = VDC(client, resource=vdc_resource) print("Fetching vApps....") vapps = vdc.list_resources(EntityType.VAPP) for vapp in vapps: print(vapp.get('name')) # Log out. print("Logging out") client.logout()
return True socket.setdefaulttimeout(10) # load config with open('config.json', 'r') as f: config = json.load(f) client = Client(config['url']) client.set_highest_supported_version() client.set_credentials( BasicLoginCredentials(config['user'], config['org'], config['password'])) print("Fetching Org...") org = Org(client, resource=client.get_org()) print("Fetching VDC...") vdc = VDC(client, resource=org.get_vdc(config['vdc'])) print("Fetching vApp...") vapp_resource = vdc.get_vapp(config['vapp']) vapp = VApp(client, resource=vapp_resource) print("Validating VMs...") vms = vapp.get_all_vms() names = map(lambda vm: vm.get('name'), vms) names = list(names) services = config['services']
def login(ctx, user, host, password, api_version, org, verify_ssl_certs, disable_warnings, vdc, session_id, use_browser_session): """Login to vCloud Director \b Login to a vCloud Director service. \b Examples vcd login mysp.com org1 usr1 Login to host 'mysp.com'. \b vcd login test.mysp.com org1 usr1 -i -w Login to a host with self-signed SSL certificate. \b vcd login mysp.com org1 usr1 --use-browser-session Login using active session from browser. \b vcd login session list chrome List active session ids from browser. \b vcd login mysp.com org1 usr1 \\ --session-id ee968665bf3412d581bbc6192508eec4 Login using active session id. \b Environment Variables VCD_PASSWORD If this environment variable is set, the command will use its value as the password to login and will not ask for one. The --password option has precedence over the environment variable. """ if not verify_ssl_certs: if disable_warnings: pass else: click.secho('InsecureRequestWarning: ' 'Unverified HTTPS request is being made. ' 'Adding certificate verification is strongly ' 'advised.', fg='yellow', err=True) requests.packages.urllib3.disable_warnings() if host == 'session' and org == 'list': sessions = [] if user == 'chrome': cookies = browsercookie.chrome() for c in cookies: if c.name == 'vcloud_session_id': sessions.append({'host': c.domain, 'session_id': c.value}) stdout(sessions, ctx) return client = Client(host, api_version=api_version, verify_ssl_certs=verify_ssl_certs, log_file='vcd.log', log_requests=True, log_headers=True, log_bodies=True ) try: if api_version is None: api_version = client.set_highest_supported_version() if session_id is not None or use_browser_session: if use_browser_session: browser_session_id = None cookies = browsercookie.chrome() for c in cookies: if c.name == 'vcloud_session_id' and \ c.domain == host: browser_session_id = c.value break if browser_session_id is None: raise Exception('Session not found in browser.') session_id = browser_session_id client.rehydrate_from_token(session_id) else: if password is None: password = click.prompt('Password', hide_input=True, type=str) client.set_credentials(BasicLoginCredentials(user, org, password)) wkep = {} for endpoint in _WellKnownEndpoint: if endpoint in client._session_endpoints: wkep[endpoint.name] = client._session_endpoints[endpoint] profiles = Profiles.load() logged_in_org = client.get_org() org_href = logged_in_org.get('href') vdc_href = '' in_use_vdc = '' if vdc is None: for v in get_links(logged_in_org, media_type=EntityType.VDC.value): in_use_vdc = v.name vdc_href = v.href break else: for v in get_links(logged_in_org, media_type=EntityType.VDC.value): if vdc == v.name: in_use_vdc = v.name vdc_href = v.href break if len(in_use_vdc) == 0: raise Exception('VDC not found') profiles.update(host, org, user, client._session.headers['x-vcloud-authorization'], api_version, wkep, verify_ssl_certs, disable_warnings, vdc=in_use_vdc, org_href=org_href, vdc_href=vdc_href, log_request=profiles.get('log_request', default=False), log_header=profiles.get('log_header', default=False), log_body=profiles.get('log_body', default=False), vapp='', vapp_href='') alt_text = '%s logged in, org: \'%s\', vdc: \'%s\'' % \ (user, org, in_use_vdc) stdout({'user': user, 'org': org, 'vdc': in_use_vdc, 'logged_in': True}, ctx, alt_text) except Exception as e: try: profiles = Profiles.load() profiles.set('token', '') except Exception: pass stderr(e, ctx)
org = sys.argv[2] user = sys.argv[3] password = sys.argv[4] # Disable warnings from self-signed certificates. requests.packages.urllib3.disable_warnings() # Login. SSL certificate verification is turned off to allow self-signed # certificates. You should only do this in trusted environments. print("Logging in: host={0}, org={1}, user={2}".format(host, org, user)) client = Client(host, verify_ssl_certs=False) client.set_highest_supported_version() client.set_credentials(BasicLoginCredentials(user, org, password)) print("Fetching Org...") org = Org(client, resource=client.get_org()) print("Fetching VDCs...") for vdc_info in org.list_vdcs(): name = vdc_info['name'] href = vdc_info['href'] print("VDC name: {0}\n href: {1}".format( vdc_info['name'], vdc_info['href'])) vdc = VDC(client, resource=org.get_vdc(vdc_info['name'])) print("{0}{1}".format("Name".ljust(40), "Type")) print("{0}{1}".format("----".ljust(40), "----")) for resource in vdc.list_resources(): print('%s%s' % (resource['name'].ljust(40), resource['type'])) # Log out. print("Logging out") client.logout()
# Login. SSL certificate verification is turned off to allow self-signed # certificates. You should only do this in trusted environments. print("Logging in: host={0}, org={1}, user={2}".format(host, org, user)) client = Client(host, api_version='27.0', verify_ssl_certs=False, log_file='pyvcloud.log', log_requests=True, log_headers=True, log_bodies=True) client.set_credentials(BasicLoginCredentials(user, org, password)) task_monitor = client.get_task_monitor() print("Fetching Org...") org_resource = client.get_org() org = Org(client, resource=org_resource) print("Fetching VDC...") vdc_resource = org.get_vdc(vdc) vdc = VDC(client, resource=vdc_resource) print("Fetching vApp...") vapp_resource = vdc.get_vapp(vapp) vapp = VApp(client, resource=vapp_resource) print("Fetching VM...") vm_resource = vapp.get_vm(vm) vm = VM(client, resource=vm_resource) print("Creating Snapshot...")
def login(ctx, user, host, password, api_version, org, verify_ssl_certs, disable_warnings, vdc, session_id, use_browser_session): """Login to vCloud Director \b Login to a vCloud Director service. \b Examples vcd login mysp.com org1 usr1 Login to host 'mysp.com'. \b vcd login test.mysp.com org1 usr1 -i -w Login to a host with self-signed SSL certificate. \b vcd login mysp.com org1 usr1 --use-browser-session Login using active session from browser. \b vcd login session list chrome List active session ids from browser. \b vcd login mysp.com org1 usr1 \\ --session-id ee968665bf3412d581bbc6192508eec4 Login using active session id. \b Environment Variables VCD_PASSWORD If this environment variable is set, the command will use its value as the password to login and will not ask for one. The --password option has precedence over the environment variable. """ if not verify_ssl_certs: if disable_warnings: pass else: click.secho( 'InsecureRequestWarning: ' 'Unverified HTTPS request is being made. ' 'Adding certificate verification is strongly ' 'advised.', fg='yellow', err=True) requests.packages.urllib3.disable_warnings() if host == 'session' and org == 'list': sessions = [] if user == 'chrome': cookies = browsercookie.chrome() for c in cookies: if c.name == 'vcloud_session_id': sessions.append({'host': c.domain, 'session_id': c.value}) stdout(sessions, ctx) return client = Client( host, api_version=api_version, verify_ssl_certs=verify_ssl_certs, log_file='vcd.log', log_requests=True, log_headers=True, log_bodies=True) try: if session_id is not None or use_browser_session: if use_browser_session: browser_session_id = None cookies = browsercookie.chrome() for c in cookies: if c.name == 'vcloud_session_id' and \ c.domain == host: browser_session_id = c.value break if browser_session_id is None: raise Exception('Session not found in browser.') session_id = browser_session_id client.rehydrate_from_token(session_id) else: if password is None: password = click.prompt('Password', hide_input=True, type=str) client.set_credentials(BasicLoginCredentials(user, org, password)) negotiated_api_version = client.get_api_version() profiles = Profiles.load() logged_in_org = client.get_org() org_href = logged_in_org.get('href') vdc_href = '' in_use_vdc = '' links = [] if float(negotiated_api_version) < float(ApiVersion.VERSION_33.value): links = get_links(logged_in_org, media_type=EntityType.VDC.value) else: if logged_in_org.get('name') != 'System': links = client.get_resource_link_from_query_object( logged_in_org, media_type=EntityType.RECORDS.value, type='vdc') if vdc is None: if len(links) > 0: in_use_vdc = links[0].name vdc_href = links[0].href else: for v in links: if vdc == v.name: in_use_vdc = v.name vdc_href = v.href break if len(in_use_vdc) == 0: raise Exception('VDC not found') token = client.get_access_token() is_jwt_token = True if not token: token = client.get_xvcloud_authorization_token() is_jwt_token = False profiles.update( host, org, user, token, negotiated_api_version, verify_ssl_certs, disable_warnings, vdc=in_use_vdc, org_href=org_href, vdc_href=vdc_href, log_request=True, log_header=True, log_body=True, vapp='', vapp_href='', is_jwt_token=is_jwt_token) alt_text = f"{user} logged in, org: '{org}', vdc: '{in_use_vdc}'" d = { 'user': user, 'org': org, 'vdc': in_use_vdc, 'logged_in': True } stdout(d, ctx, alt_text) except Exception as e: try: profiles = Profiles.load() profiles.set('token', '') except Exception: pass stderr(e, ctx)
def check_cse_installation(config, check_template='*'): """Ensures that CSE is installed on vCD according to the config file. Checks if CSE is registered to vCD, if catalog exists, and if templates exist. :param dict config: config yaml file as a dictionary :param str check_template: which template to check for. Default value of '*' means to check all templates specified in @config :raises EntityNotFoundException: if CSE is not registered to vCD as an extension, or if specified catalog does not exist, or if specified template(s) do not exist. """ click.secho(f"Validating CSE installation according to config file", fg='yellow') err_msgs = [] client = None try: client = Client(config['vcd']['host'], api_version=config['vcd']['api_version'], verify_ssl_certs=config['vcd']['verify']) credentials = BasicLoginCredentials(config['vcd']['username'], SYSTEM_ORG_NAME, config['vcd']['password']) client.set_credentials(credentials) # check that AMQP exchange exists amqp = config['amqp'] credentials = pika.PlainCredentials(amqp['username'], amqp['password']) parameters = pika.ConnectionParameters(amqp['host'], amqp['port'], amqp['vhost'], credentials, ssl=amqp['ssl'], connection_attempts=3, retry_delay=2, socket_timeout=5) connection = None try: connection = pika.BlockingConnection(parameters) channel = connection.channel() try: channel.exchange_declare(exchange=amqp['exchange'], exchange_type=EXCHANGE_TYPE, durable=True, passive=True, auto_delete=False) click.secho(f"AMQP exchange '{amqp['exchange']}' exists", fg='green') except pika.exceptions.ChannelClosed: msg = f"AMQP exchange '{amqp['exchange']}' does not exist" click.secho(msg, fg='red') err_msgs.append(msg) except Exception: # TODO replace raw exception with specific msg = f"Could not connect to AMQP exchange '{amqp['exchange']}'" click.secho(msg, fg='red') err_msgs.append(msg) finally: if connection is not None: connection.close() # check that CSE is registered to vCD ext = APIExtension(client) try: cse_info = ext.get_extension(CSE_NAME, namespace=CSE_NAMESPACE) if cse_info['enabled'] == 'true': click.secho( "CSE is registered to vCD and is currently " "enabled", fg='green') else: click.secho( "CSE is registered to vCD and is currently " "disabled", fg='yellow') except MissingRecordException: msg = "CSE is not registered to vCD" click.secho(msg, fg='red') err_msgs.append(msg) # check that catalog exists in vCD org = Org(client, resource=client.get_org()) catalog_name = config['broker']['catalog'] if catalog_exists(org, catalog_name): click.secho(f"Found catalog '{catalog_name}'", fg='green') # check that templates exist in vCD for template in config['broker']['templates']: if check_template != '*' and \ check_template != template['name']: continue catalog_item_name = template['catalog_item'] if catalog_item_exists(org, catalog_name, catalog_item_name): click.secho( f"Found template '{catalog_item_name}' in " f"catalog '{catalog_name}'", fg='green') else: msg = f"Template '{catalog_item_name}' not found in " \ f"catalog '{catalog_name}'" click.secho(msg, fg='red') err_msgs.append(msg) else: msg = f"Catalog '{catalog_name}' not found" click.secho(msg, fg='red') err_msgs.append(msg) finally: if client is not None: client.logout() if err_msgs: raise EntityNotFoundException(err_msgs) click.secho(f"CSE installation is valid", fg='green')
def login(ctx, user, host, password, api_version, org, verify_ssl_certs, disable_warnings, vdc, session_id, use_browser_session): """Login to vCloud Director \b Login to a vCloud Director service. \b Examples vcd login mysp.com org1 usr1 Login to host 'mysp.com'. \b vcd login test.mysp.com org1 usr1 -i -w Login to a host with self-signed SSL certificate. \b vcd login mysp.com org1 usr1 --use-browser-session Login using active session from browser. \b vcd login session list chrome List active session ids from browser. \b vcd login mysp.com org1 usr1 \\ --session-id ee968665bf3412d581bbc6192508eec4 Login using active session id. \b Environment Variables VCD_PASSWORD If this environment variable is set, the command will use its value as the password to login and will not ask for one. The --password option has precedence over the environment variable. """ if not verify_ssl_certs: if disable_warnings: pass else: click.secho( 'InsecureRequestWarning: ' 'Unverified HTTPS request is being made. ' 'Adding certificate verification is strongly ' 'advised.', fg='yellow', err=True) requests.packages.urllib3.disable_warnings() if host == 'session' and org == 'list': sessions = [] if user == 'chrome': cookies = browsercookie.chrome() for c in cookies: if c.name == 'vcloud_session_id': sessions.append({'host': c.domain, 'session_id': c.value}) stdout(sessions, ctx) return client = Client( host, api_version=api_version, verify_ssl_certs=verify_ssl_certs, log_file='vcd.log', log_requests=True, log_headers=True, log_bodies=True) try: if api_version is None: api_version = client.set_highest_supported_version() if session_id is not None or use_browser_session: if use_browser_session: browser_session_id = None cookies = browsercookie.chrome() for c in cookies: if c.name == 'vcloud_session_id' and \ c.domain == host: browser_session_id = c.value break if browser_session_id is None: raise Exception('Session not found in browser.') session_id = browser_session_id client.rehydrate_from_token(session_id) else: if password is None: password = click.prompt('Password', hide_input=True, type=str) client.set_credentials(BasicLoginCredentials(user, org, password)) wkep = {} for endpoint in _WellKnownEndpoint: if endpoint in client._session_endpoints: wkep[endpoint.name] = client._session_endpoints[endpoint] profiles = Profiles.load() logged_in_org = client.get_org() org_href = logged_in_org.get('href') vdc_href = '' in_use_vdc = '' if vdc is None: for v in get_links(logged_in_org, media_type=EntityType.VDC.value): in_use_vdc = v.name vdc_href = v.href break else: for v in get_links(logged_in_org, media_type=EntityType.VDC.value): if vdc == v.name: in_use_vdc = v.name vdc_href = v.href break if len(in_use_vdc) == 0: raise Exception('VDC not found') profiles.update( host, org, user, client._session.headers['x-vcloud-authorization'], api_version, wkep, verify_ssl_certs, disable_warnings, vdc=in_use_vdc, org_href=org_href, vdc_href=vdc_href, log_request=True, log_header=True, log_body=True, vapp='', vapp_href='') alt_text = '%s logged in, org: \'%s\', vdc: \'%s\'' % \ (user, org, in_use_vdc) stdout({ 'user': user, 'org': org, 'vdc': in_use_vdc, 'logged_in': True }, ctx, alt_text) except Exception as e: try: profiles = Profiles.load() profiles.set('token', '') except Exception: pass stderr(e, ctx)
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable): NAME = 'zarrenspry.vcloud_director.vcloud_director_inventory' def __init__(self): super().__init__() self.client = None self.vdc = None self.org = None self.group_keys = [] self.machines = [] self.inventory = None self.vapp_resource = None self.root_group = None self.cache_needs_update = False self.cache_key = None def _authenticate(self): _password = self.templar.template(self.get_option('password')) if not _password: raise AnsibleError(f"Password returned None. Check and try again.") try: self.client = Client( self.get_option('host'), api_version=self.get_option('api_version'), verify_ssl_certs=self.get_option('verify_ssl_certs'), log_file=None) self.client.set_credentials( BasicLoginCredentials(self.get_option('user'), self.get_option('org'), _password)) except Exception as e: raise AnsibleError(f"Failed to login to endpoint. MSG: {e}") def _get_org(self): try: self.org = Org(self.client, resource=self.client.get_org()) except Exception as e: raise AnsibleError(f"Failed to create Org object. MSG: {e}") def _get_vdc(self): self._authenticate() self._get_org() try: self.vdc = VDC(self.client, resource=self.org.get_vdc( self.get_option('target_vdc'))) except Exception as e: raise AnsibleError(f"Failed to create VDC object. MSG: {e}") def _get_vapps(self): self._get_vdc() try: return self.vdc.list_resources(EntityType.VAPP) except Exception as e: raise AnsibleError(f"Failed to get all vapp resources, MSG:: {e}") def _get_vapp_resource(self, name): try: return VApp(self.client, resource=self.vdc.get_vapp(name)) except Exception as e: raise AnsibleError(f"Failed to get vApp resource, MSG: {e}") def _get_vm_resource(self, vm): try: return VM(self.client, resource=self.vapp_resource.get_vm(vm)) except Exception as e: raise AnsibleError(f"Failed to get vm resource, MSG: {e}") def _add_host(self, machine): name, ip = machine.get('name'), machine.get('ip') self.display.vvvv(f"Adding {name}:{ip} to inventory.") self.inventory.add_host(name, self.root_group) self.inventory.set_variable(name, 'ansible_host', ip) for meta in machine.keys(): if meta not in ["metadata", "name", "ip"]: self.inventory.set_variable(name, meta, machine.get(meta)) def _add_group(self, machine, group_keys): for key in group_keys: if key in machine.get('metadata').keys(): data = machine.get('metadata').get(key) # Is this composite data ? if re.match('\[["\']\w+["\'],.*\]', data): self.display.vvvv(f"Composite data found within {key}") for group in re.findall('[a-zA-Z_]+', data): if group != self.root_group and re.match( '[\w_]', group): self.display.vvvv( f"Adding {machine.get('name')}:{machine.get('ip')} to group {group}" ) self.inventory.add_group(group) self.inventory.add_child( group, machine.get('name').lower()) else: if data != self.root_group: self.display.vvvv( f"Adding {machine.get('name')}:{machine.get('ip')} to group {data}" ) self.inventory.add_group(data) self.inventory.add_child(data, machine.get('name').lower()) def _query(self, vm): vm_name = str(vm.get('name')).lower().replace("-", "_").replace(".", "") vm_ip = None metadata = {} for network in vm.NetworkConnectionSection: for connection in network.NetworkConnection: if connection.IpAddress in [ str(i) for i in list(IPNetwork(self.get_option('cidr'))) ]: vm_ip = str(connection.IpAddress) vm_resource = self._get_vm_resource(vm.get('name')) for meta in vm_resource.get_metadata(): if hasattr(meta, "MetadataEntry"): metadata = { i.Key.pyval: i.TypedValue.Value.pyval for i in meta.MetadataEntry } if vm_ip: self.machines.append({ 'name': vm_name, 'ip': vm_ip, 'metadata': metadata, 'os_type': str(vm.VmSpecSection[0].OsType), 'power_state': VCLOUD_STATUS_MAP[int(vm.get('status'))], 'hardware_version': str(vm.VmSpecSection[0].HardwareVersion), 'vmware_tools_version': str(vm.VmSpecSection[0].VmToolsVersion), 'virtual_machine_id': str(vm.GuestCustomizationSection[0].VirtualMachineId), 'memory_hot_enabled': str(vm.VmCapabilities[0].MemoryHotAddEnabled), 'cpu_hot_enabled': str(vm.VmCapabilities[0].CpuHotAddEnabled), 'storage_profile': str(vm.StorageProfile.get("name")) }) def _populate(self, machine): group_keys = self.get_option('group_keys') filters = self.get_option('filters') if filters: for _ in machine.get('metadata').items() & filters.items(): self._add_host(machine) if group_keys: self._add_group(machine, group_keys) else: self._add_host(machine) if group_keys: self._add_group(machine, group_keys) def _config_cache(self, cache): self.load_cache_plugin() if cache: try: self.machines = self._cache[self.cache_key] except KeyError: self.cache_needs_update = True def verify_file(self, path): valid = False if super().verify_file(path): if path.endswith(('vcloud.yaml', 'vcloud.yml')): valid = True return valid def parse(self, inventory, loader, path, cache=True): super().parse(inventory, loader, path) self._read_config_data(path) self.templar = Templar(loader=loader) self.inventory = inventory self.root_group = self.get_option('root_group') self.inventory.add_group(self.root_group) self.cache_key = self.get_cache_key(path) cache = self.get_option('set_cache') self._config_cache(cache) if not cache or self.cache_needs_update: for vapp in self._get_vapps(): self.vapp_resource = self._get_vapp_resource(vapp.get('name')) vms = self.vapp_resource.get_all_vms() for vm in vms: self._query(vm) try: self._cache[self.cache_key] = self.machines except Exception as e: raise AnsibleError(f"Failed to populate data: {e}") for machine in self.machines: self._populate(machine)
class DefaultBroker(threading.Thread): def __init__(self, config): threading.Thread.__init__(self) self.config = config self.host = config['vcd']['host'] self.username = config['vcd']['username'] self.password = config['vcd']['password'] self.version = config['vcd']['api_version'] self.verify = config['vcd']['verify'] self.log = config['vcd']['log'] def _connect_sysadmin(self): if not self.verify: LOGGER.warning('InsecureRequestWarning: ' 'Unverified HTTPS request is being made. ' 'Adding certificate verification is strongly ' 'advised.') requests.packages.urllib3.disable_warnings() self.client_sysadmin = Client(uri=self.host, api_version=self.version, verify_ssl_certs=self.verify, log_headers=True, log_bodies=True) self.client_sysadmin.set_credentials( BasicLoginCredentials(self.username, 'System', self.password)) def _connect_tenant(self, headers): token = headers.get('x-vcloud-authorization') accept_header = headers.get('Accept') version = accept_header.split('version=')[1] self.client_tenant = Client(uri=self.host, api_version=version, verify_ssl_certs=self.verify, log_headers=True, log_bodies=True) session = self.client_tenant.rehydrate_from_token(token) return { 'user_name': session.get('user'), 'user_id': session.get('userId'), 'org_name': session.get('org'), 'org_href': self.client_tenant._get_wk_endpoint( _WellKnownEndpoint.LOGGED_IN_ORG) } def _to_message(self, e): if hasattr(e, 'message'): return {'message': e.message} else: return {'message': str(e)} def update_task(self, status, message=None, error_message=None): if not hasattr(self, 'task'): self.task = Task(self.client_sysadmin) if message is None: message = OP_MESSAGE[self.op] if hasattr(self, 'task_resource'): task_href = self.task_resource.get('href') else: task_href = None self.task_resource = self.task.update( status.value, 'vcloud.cse', message, self.op, '', None, 'urn:cse:cluster:%s' % self.cluster_id, self.cluster_name, 'application/vcloud.cse.cluster+xml', self.tenant_info['user_id'], self.tenant_info['user_name'], org_href=self.tenant_info['org_href'], task_href=task_href, error_message=error_message) def is_valid_name(self, name): """Validate that the cluster name against the pattern.""" if len(name) > MAX_HOST_NAME_LENGTH: return False if name[-1] == '.': name = name[:-1] allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE) return all(allowed.match(x) for x in name.split(".")) def get_template(self, name=None): if name is None: if 'template' in self.body and self.body['template'] is not None: name = self.body['template'] else: name = self.config['broker']['default_template'] for template in self.config['broker']['templates']: if template['name'] == name: return template raise Exception('Template %s not found' % name) def run(self): LOGGER.debug('thread started op=%s' % self.op) if self.op == OP_CREATE_CLUSTER: self.create_cluster_thread() elif self.op == OP_DELETE_CLUSTER: self.delete_cluster_thread() elif self.op == OP_CREATE_NODES: self.create_nodes_thread() elif self.op == OP_DELETE_NODES: self.delete_nodes_thread() def list_clusters(self, headers, body): result = {} try: result['body'] = [] result['status_code'] = OK self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant) result['body'] = clusters except Exception: LOGGER.error(traceback.format_exc()) result['body'] = [] result['status_code'] = INTERNAL_SERVER_ERROR result['message'] = traceback.format_exc() return result def get_cluster_info(self, name, headers, body): result = {} try: result['body'] = [] result['status_code'] = OK self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant, name=name) if len(clusters) == 0: raise Exception('Cluster \'%s\' not found.' % name) vapp = VApp(self.client_tenant, href=clusters[0]['vapp_href']) vms = vapp.get_all_vms() for vm in vms: node_info = { 'name': vm.get('name'), 'numberOfCpus': '', 'memoryMB': '', 'status': VCLOUD_STATUS_MAP.get(int(vm.get('status'))), 'ipAddress': '' } if hasattr(vm, 'VmSpecSection'): node_info['numberOfCpus'] = vm.VmSpecSection.NumCpus.text node_info[ 'memoryMB'] = \ vm.VmSpecSection.MemoryResourceMb.Configured.text try: node_info['ipAddress'] = vapp.get_primary_ip( vm.get('name')) except Exception: LOGGER.debug('cannot get ip address for node %s' % vm.get('name')) if vm.get('name').startswith(TYPE_MASTER): node_info['node_type'] = 'master' clusters[0].get('master_nodes').append(node_info) elif vm.get('name').startswith(TYPE_NODE): node_info['node_type'] = 'node' clusters[0].get('nodes').append(node_info) result['body'] = clusters[0] except Exception as e: LOGGER.error(traceback.format_exc()) result['body'] = [] result['status_code'] = INTERNAL_SERVER_ERROR result['message'] = str(e) return result def create_cluster(self, headers, body): result = {} result['body'] = {} cluster_name = body['name'] vdc_name = body['vdc'] node_count = body['node_count'] LOGGER.debug('about to create cluster %s on %s with %s nodes, sp=%s', cluster_name, vdc_name, node_count, body['storage_profile']) result['body'] = { 'message': 'can\'t create cluster \'%s\'' % cluster_name } result['status_code'] = INTERNAL_SERVER_ERROR try: if not self.is_valid_name(cluster_name): raise Exception('Invalid cluster name') self.tenant_info = self._connect_tenant(headers) self.headers = headers self.body = body self.cluster_name = cluster_name self.cluster_id = str(uuid.uuid4()) self.op = OP_CREATE_CLUSTER self._connect_sysadmin() self.update_task(TaskStatus.RUNNING, message='Creating cluster %s(%s)' % (cluster_name, self.cluster_id)) self.daemon = True self.start() response_body = {} response_body['name'] = self.cluster_name response_body['cluster_id'] = self.cluster_id response_body['task_href'] = self.task_resource.get('href') result['body'] = response_body result['status_code'] = ACCEPTED except Exception as e: result['body'] = self._to_message(e) LOGGER.error(traceback.format_exc()) return result def create_cluster_thread(self): network_name = self.body['network'] try: clusters = load_from_metadata(self.client_tenant, name=self.cluster_name) if len(clusters) != 0: raise Exception('Cluster already exists.') org_resource = self.client_tenant.get_org() org = Org(self.client_tenant, resource=org_resource) vdc_resource = org.get_vdc(self.body['vdc']) vdc = VDC(self.client_tenant, resource=vdc_resource) template = self.get_template() self.update_task(TaskStatus.RUNNING, message='Creating cluster vApp %s(%s)' % (self.cluster_name, self.cluster_id)) vapp_resource = vdc.create_vapp(self.cluster_name, description='cluster %s' % self.cluster_name, network=network_name, fence_mode='bridged') self.client_tenant.get_task_monitor().wait_for_status( vapp_resource.Tasks.Task[0]) tags = {} tags['cse.cluster.id'] = self.cluster_id tags['cse.version'] = pkg_resources.require( 'container-service-extension')[0].version tags['cse.template'] = template['name'] vapp = VApp(self.client_tenant, href=vapp_resource.get('href')) for k, v in tags.items(): task = vapp.set_metadata('GENERAL', 'READWRITE', k, v) self.client_tenant.get_task_monitor().wait_for_status(task) self.update_task(TaskStatus.RUNNING, message='Creating master node for %s(%s)' % (self.cluster_name, self.cluster_id)) vapp.reload() add_nodes(1, template, TYPE_MASTER, self.config, self.client_tenant, org, vdc, vapp, self.body) self.update_task(TaskStatus.RUNNING, message='Initializing cluster %s(%s)' % (self.cluster_name, self.cluster_id)) vapp.reload() init_cluster(self.config, vapp, template) master_ip = get_master_ip(self.config, vapp, template) task = vapp.set_metadata('GENERAL', 'READWRITE', 'cse.master.ip', master_ip) self.client_tenant.get_task_monitor().wait_for_status(task) if self.body['node_count'] > 0: self.update_task(TaskStatus.RUNNING, message='Creating %s node(s) for %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) add_nodes(self.body['node_count'], template, TYPE_NODE, self.config, self.client_tenant, org, vdc, vapp, self.body) self.update_task(TaskStatus.RUNNING, message='Adding %s node(s) to %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) vapp.reload() join_cluster(self.config, vapp, template) self.update_task(TaskStatus.SUCCESS, message='Created cluster %s(%s)' % (self.cluster_name, self.cluster_id)) except Exception as e: LOGGER.error(traceback.format_exc()) self.update_task(TaskStatus.ERROR, error_message=str(e)) def delete_cluster(self, headers, body): result = {} result['body'] = {} LOGGER.debug('about to delete cluster with name: %s' % body['name']) result['status_code'] = INTERNAL_SERVER_ERROR try: self.cluster_name = body['name'] self.tenant_info = self._connect_tenant(headers) self.headers = headers self.body = body self.op = OP_DELETE_CLUSTER self._connect_sysadmin() clusters = load_from_metadata(self.client_tenant, name=self.cluster_name) if len(clusters) != 1: raise Exception('Cluster %s not found.' % self.cluster_name) self.cluster = clusters[0] self.cluster_id = self.cluster['cluster_id'] self.update_task(TaskStatus.RUNNING, message='Deleting cluster %s(%s)' % (self.cluster_name, self.cluster_id)) self.daemon = True self.start() response_body = {} response_body['cluster_name'] = self.cluster_name response_body['task_href'] = self.task_resource.get('href') result['body'] = response_body result['status_code'] = ACCEPTED except Exception as e: result['body'] = self._to_message(e) LOGGER.error(traceback.format_exc()) return result def delete_cluster_thread(self): LOGGER.debug('about to delete cluster with name: %s', self.cluster_name) try: vdc = VDC(self.client_tenant, href=self.cluster['vdc_href']) task = vdc.delete_vapp(self.cluster['name'], force=True) self.client_tenant.get_task_monitor().wait_for_status(task) self.update_task(TaskStatus.SUCCESS, message='Deleted cluster %s(%s)' % (self.cluster_name, self.cluster_id)) except Exception as e: LOGGER.error(traceback.format_exc()) self.update_task(TaskStatus.ERROR, error_message=str(e)) def get_cluster_config(self, cluster_name, headers): result = {} try: self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant, name=cluster_name) if len(clusters) != 1: raise Exception('Cluster \'%s\' not found' % cluster_name) vapp = VApp(self.client_tenant, href=clusters[0]['vapp_href']) template = self.get_template(name=clusters[0]['template']) result['body'] = get_cluster_config(self.config, vapp, template['admin_password']) result['status_code'] = OK except Exception as e: result['body'] = self._to_message(e) result['status_code'] = INTERNAL_SERVER_ERROR return result def create_nodes(self, headers, body): result = {'body': {}} self.cluster_name = body['name'] LOGGER.debug('about to add %s nodes to cluster %s on VDC %s, sp=%s', body['node_count'], self.cluster_name, body['vdc'], body['storage_profile']) result['status_code'] = INTERNAL_SERVER_ERROR try: if body['node_count'] < 1: raise Exception('Invalid node count: %s.' % body['node_count']) self.tenant_info = self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant, name=self.cluster_name) if len(clusters) != 1: raise Exception('Cluster \'%s\' not found.' % self.cluster_name) self.cluster = clusters[0] self.headers = headers self.body = body self.op = OP_CREATE_NODES self._connect_sysadmin() self.cluster_id = self.cluster['cluster_id'] self.update_task( TaskStatus.RUNNING, message='Adding %s node(s) to cluster %s(%s)' % (body['node_count'], self.cluster_name, self.cluster_id)) self.daemon = True self.start() response_body = {} response_body['cluster_name'] = self.cluster_name response_body['task_href'] = self.task_resource.get('href') result['body'] = response_body result['status_code'] = ACCEPTED except Exception as e: result['body'] = self._to_message(e) LOGGER.error(traceback.format_exc()) return result def create_nodes_thread(self): LOGGER.debug('about to add nodes to cluster with name: %s', self.cluster_name) try: org_resource = self.client_tenant.get_org() org = Org(self.client_tenant, resource=org_resource) vdc = VDC(self.client_tenant, href=self.cluster['vdc_href']) vapp = VApp(self.client_tenant, href=self.cluster['vapp_href']) template = self.get_template() self.update_task( TaskStatus.RUNNING, message='Creating %s node(s) for %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) new_nodes = add_nodes(self.body['node_count'], template, TYPE_NODE, self.config, self.client_tenant, org, vdc, vapp, self.body) self.update_task( TaskStatus.RUNNING, message='Adding %s node(s) to %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) target_nodes = [] for spec in new_nodes['specs']: target_nodes.append(spec['target_vm_name']) vapp.reload() join_cluster(self.config, vapp, template, target_nodes) self.update_task( TaskStatus.SUCCESS, message='Added %s node(s) to cluster %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) except Exception as e: LOGGER.error(traceback.format_exc()) self.update_task(TaskStatus.ERROR, error_message=str(e)) def delete_nodes(self, headers, body): result = {'body': {}} self.cluster_name = body['name'] LOGGER.debug('about to delete nodes from cluster with name: %s' % body['name']) result['status_code'] = INTERNAL_SERVER_ERROR try: if len(body['nodes']) < 1: raise Exception('Invalid list of nodes: %s.' % body['nodes']) for node in body['nodes']: if node.startswith(TYPE_MASTER): raise Exception('Can\'t delete a master node: \'%s\'.' % node) self.tenant_info = self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant, name=self.cluster_name) if len(clusters) != 1: raise Exception('Cluster \'%s\' not found.' % self.cluster_name) self.cluster = clusters[0] self.headers = headers self.body = body self.op = OP_DELETE_NODES self._connect_sysadmin() self.cluster_id = self.cluster['cluster_id'] self.update_task( TaskStatus.RUNNING, message='Deleting %s node(s) from cluster %s(%s)' % (len(body['nodes']), self.cluster_name, self.cluster_id)) self.daemon = True self.start() response_body = {} response_body['cluster_name'] = self.cluster_name response_body['task_href'] = self.task_resource.get('href') result['body'] = response_body result['status_code'] = ACCEPTED except Exception as e: result['body'] = self._to_message(e) LOGGER.error(traceback.format_exc()) return result def delete_nodes_thread(self): LOGGER.debug('about to delete nodes from cluster with name: %s', self.cluster_name) try: vapp = VApp(self.client_tenant, href=self.cluster['vapp_href']) template = self.get_template() self.update_task( TaskStatus.RUNNING, message='Deleting %s node(s) from %s(%s)' % (len(self.body['nodes']), self.cluster_name, self.cluster_id)) delete_nodes_from_cluster(self.config, vapp, template, self.body['nodes'], self.body['force']) self.update_task( TaskStatus.RUNNING, message='Undeploying %s node(s) for %s(%s)' % (len(self.body['nodes']), self.cluster_name, self.cluster_id)) for vm_name in self.body['nodes']: vm = VM(self.client_tenant, resource=vapp.get_vm(vm_name)) try: task = vm.undeploy() self.client_tenant.get_task_monitor().wait_for_status(task) except Exception as e: LOGGER.warning('couldn\'t undeploy VM %s' % vm_name) self.update_task( TaskStatus.RUNNING, message='Deleting %s VM(s) for %s(%s)' % (len(self.body['nodes']), self.cluster_name, self.cluster_id)) task = vapp.delete_vms(self.body['nodes']) self.client_tenant.get_task_monitor().wait_for_status(task) self.update_task( TaskStatus.SUCCESS, message='Deleted %s node(s) to cluster %s(%s)' % (len(self.body['nodes']), self.cluster_name, self.cluster_id)) except Exception as e: LOGGER.error(traceback.format_exc()) self.update_task(TaskStatus.ERROR, error_message=str(e))
class DefaultBroker(threading.Thread): def __init__(self, config): threading.Thread.__init__(self) self.config = config self.host = config['vcd']['host'] self.username = config['vcd']['username'] self.password = config['vcd']['password'] self.version = config['vcd']['api_version'] self.verify = config['vcd']['verify'] self.log = config['vcd']['log'] def _connect_sysadmin(self): if not self.verify: LOGGER.warning('InsecureRequestWarning: ' 'Unverified HTTPS request is being made. ' 'Adding certificate verification is strongly ' 'advised.') requests.packages.urllib3.disable_warnings() self.client_sysadmin = Client(uri=self.host, api_version=self.version, verify_ssl_certs=self.verify, log_file='sysadmin.log', log_headers=True, log_bodies=True) self.client_sysadmin.set_credentials( BasicLoginCredentials(self.username, 'System', self.password)) def _connect_tenant(self, headers): token = headers.get('x-vcloud-authorization') accept_header = headers.get('Accept') version = accept_header.split('version=')[1] self.client_tenant = Client(uri=self.host, api_version=version, verify_ssl_certs=self.verify, log_file='tenant.log', log_headers=True, log_bodies=True) session = self.client_tenant.rehydrate_from_token(token) return { 'user_name': session.get('user'), 'user_id': session.get('userId'), 'org_name': session.get('org'), 'org_href': self.client_tenant._get_wk_endpoint( _WellKnownEndpoint.LOGGED_IN_ORG) } def update_task(self, status, operation, message=None, error_message=None): if not hasattr(self, 'task'): self.task = Task(self.client_sysadmin) if message is None: message = OP_MESSAGE[operation] if hasattr(self, 't'): task_href = self.t.get('href') else: task_href = None self.t = self.task.update(status.value, 'vcloud.cse', message, operation, '', None, 'urn:cse:cluster:%s' % self.cluster_id, self.cluster_name, 'application/vcloud.cse.cluster+xml', self.tenant_info['user_id'], self.tenant_info['user_name'], org_href=self.tenant_info['org_href'], task_href=task_href, error_message=error_message) def is_valid_name(self, name): """Validates that the cluster name against the pattern. """ if len(name) > MAX_HOST_NAME_LENGTH: return False if name[-1] == '.': name = name[:-1] allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE) return all(allowed.match(x) for x in name.split(".")) def get_template(self, name=None): if name is None: if 'template' in self.body and self.body['template'] is not None: name = self.body['template'] else: name = self.config['broker']['default_template'] for template in self.config['broker']['templates']: if template['name'] == name: return template raise Exception('Template %s not found' % name) def run(self): LOGGER.debug('thread started op=%s' % self.op) if self.op == OP_CREATE_CLUSTER: self.create_cluster_thread() elif self.op == OP_DELETE_CLUSTER: self.delete_cluster_thread() def list_clusters(self, headers, body): result = {} try: result['body'] = [] result['status_code'] = OK self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant, get_leader_ip=True) result['body'] = clusters except Exception: LOGGER.error(traceback.format_exc()) result['body'] = [] result['status_code'] = INTERNAL_SERVER_ERROR result['message'] = traceback.format_exc() return result def create_cluster(self, headers, body): result = {} result['body'] = {} cluster_name = body['name'] vdc_name = body['vdc'] node_count = body['node_count'] LOGGER.debug('about to create cluster %s on %s with %s nodes, sp=%s', cluster_name, vdc_name, node_count, body['storage_profile']) result['body'] = {'message': 'can\'t create cluster %s' % cluster_name} result['status_code'] = INTERNAL_SERVER_ERROR try: if not self.is_valid_name(cluster_name): raise Exception('Invalid cluster name') self.tenant_info = self._connect_tenant(headers) self.headers = headers self.body = body self.cluster_name = cluster_name self.cluster_id = str(uuid.uuid4()) self.op = OP_CREATE_CLUSTER self._connect_sysadmin() self.update_task(TaskStatus.RUNNING, self.op, message='Creating cluster %s(%s)' % (cluster_name, self.cluster_id)) self.daemon = True self.start() response_body = {} response_body['name'] = self.cluster_name response_body['cluster_id'] = self.cluster_id response_body['task_href'] = self.t.get('href') result['body'] = response_body result['status_code'] = ACCEPTED except Exception as e: result['body'] = {'message': e.message} LOGGER.error(traceback.format_exc()) return result def create_cluster_thread(self): network_name = self.body['network'] try: clusters = load_from_metadata(self.client_tenant, name=self.cluster_name) if len(clusters) != 0: raise Exception('Cluster already exists.') org_resource = self.client_tenant.get_org() org = Org(self.client_tenant, resource=org_resource) vdc_resource = org.get_vdc(self.body['vdc']) vdc = VDC(self.client_tenant, resource=vdc_resource) template = self.get_template() self.update_task(TaskStatus.RUNNING, self.op, message='Creating cluster vApp %s(%s)' % (self.cluster_name, self.cluster_id)) vapp_resource = vdc.create_vapp(self.cluster_name, description='cluster %s' % self.cluster_name, network=network_name, fence_mode='bridged') t = self.client_tenant.get_task_monitor().wait_for_status( task=vapp_resource.Tasks.Task[0], timeout=60, poll_frequency=2, fail_on_status=None, expected_target_statuses=[ TaskStatus.SUCCESS, TaskStatus.ABORTED, TaskStatus.ERROR, TaskStatus.CANCELED ], callback=None) assert t.get('status').lower() == TaskStatus.SUCCESS.value tags = {} tags['cse.cluster.id'] = self.cluster_id tags['cse.version'] = pkg_resources.require( 'container-service-extension')[0].version tags['cse.template'] = template['name'] vapp = VApp(self.client_tenant, href=vapp_resource.get('href')) for k, v in tags.items(): t = vapp.set_metadata('GENERAL', 'READWRITE', k, v) self.client_tenant.get_task_monitor().\ wait_for_status( task=t, timeout=600, poll_frequency=5, fail_on_status=None, expected_target_statuses=[TaskStatus.SUCCESS], callback=None) self.update_task(TaskStatus.RUNNING, self.op, message='Creating master node for %s(%s)' % (self.cluster_name, self.cluster_id)) vapp.reload() add_nodes(1, template, TYPE_MASTER, self.config, self.client_tenant, org, vdc, vapp, self.body, wait=True) self.update_task(TaskStatus.RUNNING, self.op, message='Initializing cluster %s(%s)' % (self.cluster_name, self.cluster_id)) vapp.reload() init_cluster(self.config, vapp, template) master_ip = get_master_ip(self.config, vapp, template) t = vapp.set_metadata('GENERAL', 'READWRITE', 'cse.master.ip', master_ip) self.client_tenant.get_task_monitor().\ wait_for_status( task=t, timeout=600, poll_frequency=5, fail_on_status=None, expected_target_statuses=[TaskStatus.SUCCESS], callback=None) if self.body['node_count'] > 0: self.update_task(TaskStatus.RUNNING, self.op, message='Creating %s node(s) for %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) add_nodes(self.body['node_count'], template, TYPE_NODE, self.config, self.client_tenant, org, vdc, vapp, self.body, wait=True) self.update_task(TaskStatus.RUNNING, self.op, message='Adding %s node(s) to %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) vapp.reload() join_cluster(self.config, vapp, template) self.update_task(TaskStatus.SUCCESS, self.op, message='Created cluster %s(%s)' % (self.cluster_name, self.cluster_id)) except Exception as e: LOGGER.error(traceback.format_exc()) self.update_task(TaskStatus.ERROR, self.op, error_message=str(e)) def delete_cluster(self, headers, body): result = {} result['body'] = {} LOGGER.debug('about to delete cluster with name: %s' % body['name']) result['status_code'] = INTERNAL_SERVER_ERROR try: self.cluster_name = body['name'] self.tenant_info = self._connect_tenant(headers) self.headers = headers self.body = body self.op = OP_DELETE_CLUSTER self._connect_sysadmin() clusters = load_from_metadata(self.client_tenant, name=self.cluster_name) if len(clusters) != 1: raise Exception('Cluster %s not found.' % self.cluster_name) self.cluster = clusters[0] self.cluster_id = self.cluster['cluster_id'] self.update_task(TaskStatus.RUNNING, self.op, message='Deleting cluster %s(%s)' % (self.cluster_name, self.cluster_id)) self.daemon = True self.start() response_body = {} response_body['cluster_name'] = self.cluster_name response_body['task_href'] = self.t.get('href') result['body'] = response_body result['status_code'] = ACCEPTED except Exception as e: if hasattr(e, 'message'): result['body'] = {'message': e.message} else: result['body'] = {'message': str(e)} LOGGER.error(traceback.format_exc()) return result def delete_cluster_thread(self): LOGGER.debug('about to delete cluster with name: %s', self.cluster_name) try: vdc = VDC(self.client_tenant, href=self.cluster['vdc_href']) delete_task = vdc.delete_vapp(self.cluster['name'], force=True) self.client_tenant.get_task_monitor().\ wait_for_status( task=delete_task, timeout=600, poll_frequency=5, fail_on_status=None, expected_target_statuses=[TaskStatus.SUCCESS], callback=None) self.update_task(TaskStatus.SUCCESS, self.op, message='Deleted cluster %s(%s)' % (self.cluster_name, self.cluster_id)) except Exception as e: LOGGER.error(traceback.format_exc()) self.update_task(self.cluster_name, self.cluster_id, TaskStatus.ERROR, self.op, error_message=str(e)) def get_cluster_config(self, cluster_name, headers): result = {} try: self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant, name=cluster_name) if len(clusters) != 1: raise Exception('Cluster \'%s\' not found' % cluster_name) vapp = VApp(self.client_tenant, href=clusters[0]['vapp_href']) template = self.get_template(name=clusters[0]['template']) result['body'] = get_cluster_config(self.config, vapp, template['admin_password']) result['status_code'] = OK except Exception as e: result['body'] = str(e) result['status_code'] = INTERNAL_SERVER_ERROR return result
class DefaultBroker(threading.Thread): def __init__(self, config): threading.Thread.__init__(self) self.config = config self.host = config['vcd']['host'] self.username = config['vcd']['username'] self.password = config['vcd']['password'] self.version = config['vcd']['api_version'] self.verify = config['vcd']['verify'] self.log = config['vcd']['log'] def _connect_sysadmin(self): if not self.verify: LOGGER.warning('InsecureRequestWarning: ' 'Unverified HTTPS request is being made. ' 'Adding certificate verification is strongly ' 'advised.') requests.packages.urllib3.disable_warnings() self.client_sysadmin = Client(uri=self.host, api_version=self.version, verify_ssl_certs=self.verify, log_headers=True, log_bodies=True) credentials = BasicLoginCredentials(self.username, SYSTEM_ORG_NAME, self.password) self.client_sysadmin.set_credentials(credentials) def _connect_tenant(self, headers): token = headers.get('x-vcloud-authorization') accept_header = headers.get('Accept') version = accept_header.split('version=')[1] self.client_tenant = Client(uri=self.host, api_version=version, verify_ssl_certs=self.verify, log_headers=True, log_bodies=True) session = self.client_tenant.rehydrate_from_token(token) return { 'user_name': session.get('user'), 'user_id': session.get('userId'), 'org_name': session.get('org'), 'org_href': self.client_tenant._get_wk_endpoint( _WellKnownEndpoint.LOGGED_IN_ORG) } def _to_message(self, e): if hasattr(e, 'message'): return {'message': e.message} else: return {'message': str(e)} def update_task(self, status, message=None, error_message=None): if not hasattr(self, 'task'): self.task = Task(self.client_sysadmin) if message is None: message = OP_MESSAGE[self.op] if hasattr(self, 'task_resource'): task_href = self.task_resource.get('href') else: task_href = None self.task_resource = self.task.update( status.value, 'vcloud.cse', message, self.op, '', None, 'urn:cse:cluster:%s' % self.cluster_id, self.cluster_name, 'application/vcloud.cse.cluster+xml', self.tenant_info['user_id'], self.tenant_info['user_name'], org_href=self.tenant_info['org_href'], task_href=task_href, error_message=error_message) def is_valid_name(self, name): """Validate that the cluster name against the pattern.""" if len(name) > MAX_HOST_NAME_LENGTH: return False if name[-1] == '.': name = name[:-1] allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE) return all(allowed.match(x) for x in name.split(".")) def get_template(self, name=None): if name is None: if 'template' in self.body and self.body['template'] is not None: name = self.body['template'] else: name = self.config['broker']['default_template'] for template in self.config['broker']['templates']: if template['name'] == name: return template raise Exception('Template %s not found' % name) def run(self): LOGGER.debug('thread started op=%s' % self.op) if self.op == OP_CREATE_CLUSTER: self.create_cluster_thread() elif self.op == OP_DELETE_CLUSTER: self.delete_cluster_thread() elif self.op == OP_CREATE_NODES: self.create_nodes_thread() elif self.op == OP_DELETE_NODES: self.delete_nodes_thread() @exception_handler def list_clusters(self, headers, body): result = {} result['body'] = [] result['status_code'] = OK self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant) result['body'] = clusters return result @exception_handler def get_cluster_info(self, name, headers, body): """Get the info of the cluster. :param cluster_name: (str): Name of the cluster :param headers: (str): Request headers :return: (dict): Info of the cluster. """ result = {} result['body'] = [] result['status_code'] = OK self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant, name=name) if len(clusters) == 0: raise CseServerError('Cluster \'%s\' not found.' % name) vapp = VApp(self.client_tenant, href=clusters[0]['vapp_href']) vms = vapp.get_all_vms() for vm in vms: node_info = {'name': vm.get('name'), 'ipAddress': ''} try: node_info['ipAddress'] = vapp.get_primary_ip(vm.get('name')) except Exception: LOGGER.debug('cannot get ip address for node %s' % vm.get('name')) if vm.get('name').startswith(TYPE_MASTER): clusters[0].get('master_nodes').append(node_info) elif vm.get('name').startswith(TYPE_NODE): clusters[0].get('nodes').append(node_info) elif vm.get('name').startswith(TYPE_NFS): clusters[0].get('nfs_nodes').append(node_info) result['body'] = clusters[0] return result @exception_handler def get_node_info(self, cluster_name, node_name, headers): """Get the info of a given node in the cluster. :param cluster_name: (str): Name of the cluster :param node_name: (str): Name of the node :param headers: (str): Request headers :return: (dict): Info of the node. """ result = {} result['body'] = [] result['status_code'] = OK self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant, name=cluster_name) if len(clusters) == 0: raise CseServerError('Cluster \'%s\' not found.' % cluster_name) vapp = VApp(self.client_tenant, href=clusters[0]['vapp_href']) vms = vapp.get_all_vms() node_info = None for vm in vms: if (node_name == vm.get('name')): node_info = { 'name': vm.get('name'), 'numberOfCpus': '', 'memoryMB': '', 'status': VCLOUD_STATUS_MAP.get(int(vm.get('status'))), 'ipAddress': '' } if hasattr(vm, 'VmSpecSection'): node_info['numberOfCpus'] = vm.VmSpecSection.NumCpus.text node_info[ 'memoryMB'] = \ vm.VmSpecSection.MemoryResourceMb.Configured.text try: node_info['ipAddress'] = vapp.get_primary_ip( vm.get('name')) except Exception: LOGGER.debug('cannot get ip address ' 'for node %s' % vm.get('name')) if vm.get('name').startswith(TYPE_MASTER): node_info['node_type'] = 'master' elif vm.get('name').startswith(TYPE_NODE): node_info['node_type'] = 'node' elif vm.get('name').startswith(TYPE_NFS): node_info['node_type'] = 'nfsd' exports = self._get_nfs_exports(node_info['ipAddress'], vapp, vm) node_info['exports'] = exports if node_info is None: raise CseServerError('Node \'%s\' not found in cluster \'%s\'' % (node_name, cluster_name)) result['body'] = node_info return result def _get_nfs_exports(self, ip, vapp, node): """Get the exports from remote NFS server (helper method). :param ip: (str): IP address of the NFS server :param vapp: (pyvcloud.vcd.vapp.VApp): The vApp or cluster to which node belongs :param node: (str): IP address of the NFS server :param node: (`lxml.objectify.StringElement`) object representing the vm resource. :return: (List): List of exports """ # TODO(right template) find a right way to retrieve # the template from which nfs node was created. template = self.config['broker']['templates'][0] script = '#!/usr/bin/env bash\nshowmount -e %s' % ip result = execute_script_in_nodes(self.config, vapp, template['admin_password'], script, nodes=[node], check_tools=False) lines = result[0][1].content.decode().split('\n') exports = [] for index in range(1, len(lines) - 1): export = lines[index].strip().split()[0] exports.append(export) return exports @exception_handler def create_cluster(self, headers, body): result = {} result['body'] = {} cluster_name = body['name'] vdc_name = body['vdc'] node_count = body['node_count'] LOGGER.debug('about to create cluster %s on %s with %s nodes, sp=%s', cluster_name, vdc_name, node_count, body['storage_profile']) result['body'] = { 'message': 'can\'t create cluster \'%s\'' % cluster_name } if not self.is_valid_name(cluster_name): raise CseServerError(f"Invalid cluster name \'{cluster_name}\'") self.tenant_info = self._connect_tenant(headers) self.headers = headers self.body = body self.cluster_name = cluster_name self.cluster_id = str(uuid.uuid4()) self.op = OP_CREATE_CLUSTER self._connect_sysadmin() self.update_task(TaskStatus.RUNNING, message='Creating cluster %s(%s)' % (cluster_name, self.cluster_id)) self.daemon = True self.start() response_body = {} response_body['name'] = self.cluster_name response_body['cluster_id'] = self.cluster_id response_body['task_href'] = self.task_resource.get('href') result['body'] = response_body result['status_code'] = ACCEPTED return result @rollback def create_cluster_thread(self): network_name = self.body['network'] try: clusters = load_from_metadata(self.client_tenant, name=self.cluster_name) if len(clusters) != 0: raise ClusterAlreadyExistsError( f'Cluster {self.cluster_name} already exists.') org_resource = self.client_tenant.get_org() org = Org(self.client_tenant, resource=org_resource) vdc_resource = org.get_vdc(self.body['vdc']) vdc = VDC(self.client_tenant, resource=vdc_resource) template = self.get_template() self.update_task(TaskStatus.RUNNING, message='Creating cluster vApp %s(%s)' % (self.cluster_name, self.cluster_id)) try: vapp_resource = vdc.create_vapp(self.cluster_name, description='cluster %s' % self.cluster_name, network=network_name, fence_mode='bridged') except Exception as e: raise ClusterOperationError('Error while creating vApp:', str(e)) self.client_tenant.get_task_monitor().wait_for_status( vapp_resource.Tasks.Task[0]) tags = {} tags['cse.cluster.id'] = self.cluster_id tags['cse.version'] = pkg_resources.require( 'container-service-extension')[0].version tags['cse.template'] = template['name'] vapp = VApp(self.client_tenant, href=vapp_resource.get('href')) for k, v in tags.items(): task = vapp.set_metadata('GENERAL', 'READWRITE', k, v) self.client_tenant.get_task_monitor().wait_for_status(task) self.update_task(TaskStatus.RUNNING, message='Creating master node for %s(%s)' % (self.cluster_name, self.cluster_id)) vapp.reload() try: add_nodes(1, template, TYPE_MASTER, self.config, self.client_tenant, org, vdc, vapp, self.body) except Exception as e: raise MasterNodeCreationError( "Error while adding master node:", str(e)) self.update_task(TaskStatus.RUNNING, message='Initializing cluster %s(%s)' % (self.cluster_name, self.cluster_id)) vapp.reload() init_cluster(self.config, vapp, template) master_ip = get_master_ip(self.config, vapp, template) task = vapp.set_metadata('GENERAL', 'READWRITE', 'cse.master.ip', master_ip) self.client_tenant.get_task_monitor().wait_for_status(task) if self.body['node_count'] > 0: self.update_task(TaskStatus.RUNNING, message='Creating %s node(s) for %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) try: add_nodes(self.body['node_count'], template, TYPE_NODE, self.config, self.client_tenant, org, vdc, vapp, self.body) except Exception as e: raise WorkerNodeCreationError( "Error while creating worker node:", str(e)) self.update_task(TaskStatus.RUNNING, message='Adding %s node(s) to %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) vapp.reload() join_cluster(self.config, vapp, template) if self.body['enable_nfs']: self.update_task(TaskStatus.RUNNING, message='Creating NFS node for %s(%s)' % (self.cluster_name, self.cluster_id)) try: add_nodes(1, template, TYPE_NFS, self.config, self.client_tenant, org, vdc, vapp, self.body) except Exception as e: raise NFSNodeCreationError( "Error while creating NFS node:", str(e)) self.update_task(TaskStatus.SUCCESS, message='Created cluster %s(%s)' % (self.cluster_name, self.cluster_id)) except (MasterNodeCreationError, WorkerNodeCreationError, NFSNodeCreationError, ClusterJoiningError, ClusterInitializationError, ClusterOperationError) as e: LOGGER.error(traceback.format_exc()) error_obj = error_to_json(e) self.update_task( TaskStatus.ERROR, error_message=error_obj[ERROR_MESSAGE][ERROR_DESCRIPTION]) raise e except Exception as e: LOGGER.error(traceback.format_exc()) error_obj = error_to_json(e) self.update_task( TaskStatus.ERROR, error_message=error_obj[ERROR_MESSAGE][ERROR_DESCRIPTION]) @exception_handler def delete_cluster(self, headers, body): result = {} result['body'] = {} LOGGER.debug('about to delete cluster with name: %s' % body['name']) result['status_code'] = INTERNAL_SERVER_ERROR self.cluster_name = body['name'] self.tenant_info = self._connect_tenant(headers) self.headers = headers self.body = body self.op = OP_DELETE_CLUSTER self._connect_sysadmin() clusters = load_from_metadata(self.client_tenant, name=self.cluster_name) if len(clusters) != 1: raise CseServerError('Cluster %s not found.' % self.cluster_name) self.cluster = clusters[0] self.cluster_id = self.cluster['cluster_id'] self.update_task(TaskStatus.RUNNING, message='Deleting cluster %s(%s)' % (self.cluster_name, self.cluster_id)) self.daemon = True self.start() response_body = {} response_body['cluster_name'] = self.cluster_name response_body['task_href'] = self.task_resource.get('href') result['body'] = response_body result['status_code'] = ACCEPTED return result def delete_cluster_thread(self): LOGGER.debug('about to delete cluster with name: %s', self.cluster_name) try: vdc = VDC(self.client_tenant, href=self.cluster['vdc_href']) task = vdc.delete_vapp(self.cluster['name'], force=True) self.client_tenant.get_task_monitor().wait_for_status(task) self.update_task(TaskStatus.SUCCESS, message='Deleted cluster %s(%s)' % (self.cluster_name, self.cluster_id)) except Exception as e: LOGGER.error(traceback.format_exc()) self.update_task(TaskStatus.ERROR, error_message=str(e)) @exception_handler def get_cluster_config(self, cluster_name, headers): result = {} self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant, name=cluster_name) if len(clusters) != 1: raise CseServerError('Cluster \'%s\' not found' % cluster_name) vapp = VApp(self.client_tenant, href=clusters[0]['vapp_href']) template = self.get_template(name=clusters[0]['template']) result['body'] = get_cluster_config(self.config, vapp, template['admin_password']) result['status_code'] = OK return result @exception_handler def create_nodes(self, headers, body): result = {'body': {}} self.cluster_name = body['name'] LOGGER.debug('about to add %s nodes to cluster %s on VDC %s, sp=%s', body['node_count'], self.cluster_name, body['vdc'], body['storage_profile']) if body['node_count'] < 1: raise CseServerError('Invalid node count: %s.' % body['node_count']) self.tenant_info = self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant, name=self.cluster_name) if len(clusters) != 1: raise CseServerError('Cluster \'%s\' not found.' % self.cluster_name) self.cluster = clusters[0] self.headers = headers self.body = body self.op = OP_CREATE_NODES self._connect_sysadmin() self.cluster_id = self.cluster['cluster_id'] self.update_task( TaskStatus.RUNNING, message='Adding %s node(s) to cluster %s(%s)' % (body['node_count'], self.cluster_name, self.cluster_id)) self.daemon = True self.start() response_body = {} response_body['cluster_name'] = self.cluster_name response_body['task_href'] = self.task_resource.get('href') result['body'] = response_body result['status_code'] = ACCEPTED return result @rollback def create_nodes_thread(self): LOGGER.debug('about to add nodes to cluster with name: %s', self.cluster_name) try: org_resource = self.client_tenant.get_org() org = Org(self.client_tenant, resource=org_resource) vdc = VDC(self.client_tenant, href=self.cluster['vdc_href']) vapp = VApp(self.client_tenant, href=self.cluster['vapp_href']) template = self.get_template() self.update_task( TaskStatus.RUNNING, message='Creating %s node(s) for %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) new_nodes = add_nodes(self.body['node_count'], template, self.body['node_type'], self.config, self.client_tenant, org, vdc, vapp, self.body) if self.body['node_type'] == TYPE_NFS: self.update_task(TaskStatus.SUCCESS, message='Created %s node(s) for %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) elif self.body['node_type'] == TYPE_NODE: self.update_task(TaskStatus.RUNNING, message='Adding %s node(s) to %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) target_nodes = [] for spec in new_nodes['specs']: target_nodes.append(spec['target_vm_name']) vapp.reload() join_cluster(self.config, vapp, template, target_nodes) self.update_task(TaskStatus.SUCCESS, message='Added %s node(s) to cluster %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) except NodeCreationError as e: error_obj = error_to_json(e) LOGGER.error(traceback.format_exc()) self.update_task( TaskStatus.ERROR, error_message=error_obj[ERROR_MESSAGE][ERROR_DESCRIPTION]) raise except Exception as e: error_obj = error_to_json(e) LOGGER.error(traceback.format_exc()) self.update_task( TaskStatus.ERROR, error_message=error_obj[ERROR_MESSAGE][ERROR_DESCRIPTION]) @exception_handler def delete_nodes(self, headers, body): result = {'body': {}} self.cluster_name = body['name'] LOGGER.debug('about to delete nodes from cluster with name: %s' % body['name']) if len(body['nodes']) < 1: raise CseServerError('Invalid list of nodes: %s.' % body['nodes']) for node in body['nodes']: if node.startswith(TYPE_MASTER): raise CseServerError('Can\'t delete a master node: \'%s\'.' % node) self.tenant_info = self._connect_tenant(headers) clusters = load_from_metadata(self.client_tenant, name=self.cluster_name) if len(clusters) != 1: raise CseServerError('Cluster \'%s\' not found.' % self.cluster_name) self.cluster = clusters[0] self.headers = headers self.body = body self.op = OP_DELETE_NODES self._connect_sysadmin() self.cluster_id = self.cluster['cluster_id'] self.update_task( TaskStatus.RUNNING, message='Deleting %s node(s) from cluster %s(%s)' % (len(body['nodes']), self.cluster_name, self.cluster_id)) self.daemon = True self.start() response_body = {} response_body['cluster_name'] = self.cluster_name response_body['task_href'] = self.task_resource.get('href') result['body'] = response_body result['status_code'] = ACCEPTED return result def delete_nodes_thread(self): LOGGER.debug('about to delete nodes from cluster with name: %s', self.cluster_name) try: vapp = VApp(self.client_tenant, href=self.cluster['vapp_href']) template = self.get_template() self.update_task( TaskStatus.RUNNING, message='Deleting %s node(s) from %s(%s)' % (len(self.body['nodes']), self.cluster_name, self.cluster_id)) try: delete_nodes_from_cluster(self.config, vapp, template, self.body['nodes'], self.body['force']) except Exception: LOGGER.error("Couldn't delete node %s from cluster:%s" % (self.body['nodes'], self.cluster_name)) self.update_task( TaskStatus.RUNNING, message='Undeploying %s node(s) for %s(%s)' % (len(self.body['nodes']), self.cluster_name, self.cluster_id)) for vm_name in self.body['nodes']: vm = VM(self.client_tenant, resource=vapp.get_vm(vm_name)) try: task = vm.undeploy() self.client_tenant.get_task_monitor().wait_for_status(task) except Exception as e: LOGGER.warning('couldn\'t undeploy VM %s' % vm_name) self.update_task( TaskStatus.RUNNING, message='Deleting %s VM(s) for %s(%s)' % (len(self.body['nodes']), self.cluster_name, self.cluster_id)) task = vapp.delete_vms(self.body['nodes']) self.client_tenant.get_task_monitor().wait_for_status(task) self.update_task( TaskStatus.SUCCESS, message='Deleted %s node(s) to cluster %s(%s)' % (len(self.body['nodes']), self.cluster_name, self.cluster_id)) except Exception as e: LOGGER.error(traceback.format_exc()) self.update_task(TaskStatus.ERROR, error_message=str(e)) def node_rollback(self, node_list): """Implements rollback for node creation failure :param list node_list: faulty nodes to be deleted """ LOGGER.info('About to rollback nodes from cluster with name: %s' % self.cluster_name) LOGGER.info('Node list to be deleted:%s' % node_list) vapp = VApp(self.client_tenant, href=self.cluster['vapp_href']) template = self.get_template() try: delete_nodes_from_cluster(self.config, vapp, template, node_list, force=True) except Exception: LOGGER.warning("Couldn't delete node %s from cluster:%s" % (node_list, self.cluster_name)) for vm_name in node_list: vm = VM(self.client_tenant, resource=vapp.get_vm(vm_name)) try: vm.undeploy() except Exception: LOGGER.warning("Couldn't undeploy VM %s" % vm_name) vapp.delete_vms(node_list) LOGGER.info('Successfully deleted nodes: %s' % node_list) def cluster_rollback(self): """Implements rollback for cluster creation failure""" LOGGER.info('About to rollback cluster with name: %s' % self.cluster_name) clusters = load_from_metadata(self.client_tenant, name=self.cluster_name) if len(clusters) != 1: LOGGER.debug('Cluster %s not found.' % self.cluster_name) return self.cluster = clusters[0] vdc = VDC(self.client_tenant, href=self.cluster['vdc_href']) vdc.delete_vapp(self.cluster['name'], force=True) LOGGER.info('Successfully deleted cluster: %s' % self.cluster_name)