Exemple #1
0
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)
Exemple #3
0
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()
Exemple #7
0
        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']
Exemple #8
0
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()
Exemple #10
0
# 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...")
Exemple #11
0
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')
Exemple #13
0
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))
Exemple #16
0
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)