Example #1
0
def delete_all(api, workflow_dict):
    """ Deletes all Wireless Design Information regardless of input from workflow_dict.

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: Not used;

    :returns: Nothing """

    _schema = None
    logger.info('wireless::delete all')
    logger.debug('schema: {}'.format(_schema))

    # SSID's to remove
    ssids = api.non_fabric_wireless.get_enterprise_ssid()

    # delete SSIDs
    if ssids:
        for ssid in ssids:
            for detail in ssid['ssidDetails']:
                logger.info('Delete Wireless::delete SSID {}'.format(detail['name']))
                result = api.non_fabric_wireless.delete_enterprise_ssid(detail['name'])
                logger.debug(result)
                common.wait_for_task_completion(api, result)
    else:
        logger.info('Delete Wireless:  No SSIDs to delete')

    # delete profiles

    try:
        profiles = api.non_fabric_wireless.get_wireless_profile()

        if profiles:

            for profile in profiles:
                no_site_profile = {'profileName': profile['profileDetails']['name'], 'sites': ""}

                # remove sites from profile
                data = common.build_json_from_template(templates.wireless_profile_j2, no_site_profile)
                result = api.non_fabric_wireless.update_wireless_profile(payload=data)
                logger.debug(result)
                common.wait_for_task_completion(api, result)

                # now good to delete profile
                logger.info('Delete Wireless::delete Profile {}'.format(profile['profileDetails']['name']))
                wireless_profile_delete_url = "/dna/intent/api/v1/wireless-profile/{}".format(
                    profile['profileDetails']['name'])
                result = api.custom_caller.call_api('DELETE', wireless_profile_delete_url)
                logger.debug(result)
                common.wait_for_task_completion(api, result)

    except:
        logger.info('delete_all::no wireless profiles found')

    # delete wireless interfaces.  Can't delete management so we have to make sure it is added
    interface = json.dumps([{"interfaceName": "management", "vlanId": 0}])
    data = common.build_json_from_template(templates.wireless_interface_j2, interface)
    result = api.custom_caller.call_api('POST', wireless_int_url, json=data)
    logger.debug(result)
    common.wait_for_task_completion(api, result['response'])
Example #2
0
def create_network_settings(api, workflow_dict):
    """ Creates DNA Center Global Network Settings based on input from workflow_dict.  If adding Client/Network AAA server
    settings, AAA server will need to already be configured in DNA Center.

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows Network Settings (DHCP, DNS, etc) (see schema.yaml);

    :returns: Nothing """

    _schema = 'globalSettings.schema.network_settings'
    logger.info('network_settings::create_network_settings')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        # get settings for config
        settings = {}
        # rearrange into 1 dict so it is easier to work with
        for row in table_data:
            settings[row['item']] = row['value']

        csv_fields = ['dhcpServer', 'syslogServer', 'snmpServer', 'ntpServer']

        # convert csv strings to List
        for field in csv_fields:
            if settings[field]:
                settings[field] = common.csv_string_to_list(settings[field])

        if settings:
            # proceed if site specified - if not exit
            if settings['site']:
                site_info = api.sites.get_site(name=settings['site'])
                site_id = site_info['response'][0]['id'] if site_info[
                    'response'] else None

                # build URI and create network settings
                create_network_settings_uri = "{}/{}".format(
                    network_settings_intent_uri, site_id)

                # using json builder from helper file
                data = common.build_json_from_template(
                    templates.network_settings_intent_j2, settings)
                result = api.custom_caller.call_api(
                    'POST', create_network_settings_uri, json=data)
                logger.debug(result)
                common.wait_for_task_completion(api, result)
            else:
                logger.error(
                    'network_settings::create_network_settings:: Site required to update network settings'
                )
                pass
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #3
0
def create_wireless_profile(api, workflow_dict):
    """ Creates DNA Center Wireless Profiles.  Use for creation of new wireless profiles.  If updating profile
    see "update_wireless_profile"

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows of Wireless Profiles with associated parameters. (see schema.yaml);

    :returns: Nothing """

    _schema = 'wireless_profiles.schema.wireless'
    logger.info('wireless::create_wireless_profile')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        # Intent api broken when GET for wireless profile and no current values
        # _ent_profile_db = api.non_fabric_wireless.get_wireless_profile()

        # Work around Hack

        result = api.custom_caller.call_api('GET', temp_get_wireless_profile_url)
        _ent_profile_db = result['response']

        # Get current profile names
        if _ent_profile_db:
            profile_list = [profile['name'] for profile in _ent_profile_db]
        else:
            profile_list = []

        for row in table_data:
            if 'present' in row['presence']:

                # If sites comma separated, split them up into a list
                if "," in row['sites']:
                    row['sites'] = row['sites'].split(",")
                    row['sites'] = [item.lstrip() for item in row['sites']]
                else:
                    row['sites'] = [row['sites']]

                if row['profileName'] in profile_list:
                    logger.info('Profile: {} already exists'.format(row['profileName']))
                    pass
                else:
                    logger.info('Creating Profile: {}'.format(row['profileName']))
                    data = common.build_json_from_template(templates.wireless_profile_j2, row)
                    result = api.non_fabric_wireless.create_wireless_profile(payload=data)
                    logger.debug(result)
                    common.wait_for_task_completion(api, result)
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #4
0
def update_wireless_profile(api, workflow_dict):
    """ Updates DNA Center Wireless Profiles.  Use for updating of existing wireless profiles.  If creating profile
    see "create_wireless_profile"

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows of Wireless Profiles with associated parameters. (see schema.yaml);

    :returns: Nothing """

    _schema = 'wireless_profiles.schema.wireless'
    logger.info('wireless::update_wireless_profile')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

    # API does not seem to like setting SSID info during create process so have to use update to add SSID details
        for row in table_data:
            if 'present' in row['presence']:

                # Get current profile names
                _ent_profile_db = api.non_fabric_wireless.get_wireless_profile()
                # Get Current Profiles
                profile_list = [profile['profileDetails']['name'] for profile in _ent_profile_db]

                # If sites comma separated, split them up into a list
                if "," in row['sites']:
                    row['sites'] = row['sites'].split(",")
                    row['sites'] = [item.lstrip() for item in row['sites']]
                else:
                    row['sites'] = [row['sites']]

                # filter out mapping for specific profile in row
                filtered_mappings = [mappings for mappings in workflow_dict['ssid_to_profile_mapping.schema.wireless']
                                     if mappings['profileName'] == row['profileName']
                                     and mappings['presence'] == "present"]

                row['ssidDetails'] = filtered_mappings

                if row['profileName'] in profile_list:
                    logger.info('Updating Profile: {}'.format(row['profileName']))
                    data = common.build_json_from_template(templates.wireless_profile_j2, row)
                    result = api.non_fabric_wireless.update_wireless_profile(payload=data)
                    logger.debug(result)
                    common.wait_for_task_completion(api, result)
                else:
                    logger.info('Profile: {} does not exist'.format(row['profileName']))
                    pass
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #5
0
def provision_devices(api, workflow_dict):
    _schema = 'devices.schema.devices'
    logger.info('devices::provision_devices')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        sites_db = api.sites.get_site()
        devices_db = api.devices.get_device_list()

        for device in table_data:

            if device['presence'] == 'absent' or device[
                    'provisionDevice'] == False:
                continue

            site_id = common.get_object_id(
                sites_db['response'], siteNameHierarchy=device['location'])
            device_id = common.get_object_id(devices_db['response'],
                                             hostname=device['hostname'],
                                             strict=False)
            device_name = common.get_object_id(devices_db['response'],
                                               return_param='hostname',
                                               hostname=device['hostname'],
                                               strict=False)

            logger.info('Provisioning for device: {}, at site: {}'.format(
                device['hostname'], device['location']))
            payload_data = {}
            payload_data.update({'name': device_name})
            payload_data.update({'networkDeviceId': device_id})
            payload_data.update({'siteId': site_id})
            data = common.build_json_from_template(
                templates.provision_device_j2, payload_data)
            result = api.custom_caller.call_api('POST',
                                                provision_device_url,
                                                json=data)
            status = common.wait_for_task_completion(api,
                                                     result['response'],
                                                     timeout=45,
                                                     tree=True)
            logger.debug(status)
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #6
0
def provision_wireless_device(api, workflow_dict):
    """ Provisions  Wireless LAN Controllers (WLCs) in Cisco DNA Center.  Flexconnect and OTT interface parameters (if in use) are required input
    or provision will fail

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows of Wireless WLCs with associated parameters. (see schema.yaml);

    :returns: Nothing """

    _schema = 'wireless_provisioning.schema.wireless'
    logger.info('wireless::provision_wireless_device')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        # get devices to be provisioned.
        new_provision_devices = [device for device in table_data if device['presence'] == 'present']

        if new_provision_devices:
            for device in new_provision_devices:
                # break up managed locations if csv
                if "," in device['managedAPLocations']:
                    device['managedAPLocations'] = device['managedAPLocations'].split(",")
                else:
                    device['managedAPLocations'] = [device['managedAPLocations']]
                # #get IP interface configs for specific WLC
                # Needed for centrail SSID's but not yet implemented
                wireless_int_detail = [detail for detail in workflow_dict['wireless_profisioning_interface.schema.wireless']
                                       if detail['deviceName'] == device['deviceName'] and detail['presence'] == 'present']
                if wireless_int_detail:
                    device['dynamicInterfaces'] = wireless_int_detail

                logger.info('Provisioning WLC: {}'.format(device['deviceName']))
                data = common.build_json_from_template(templates.provision_j2, device)
                result = api.non_fabric_wireless.provision(payload=data)
                logger.debug(result)
                common.wait_for_task_completion(api, result, timeout=30)
        else:
            logger.info('Provisioning WLC:  No WLCs to Provision')
            pass
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #7
0
def _create_floors(api, sites_db, table_data):
    _table_key = 'name'

    # Cycle through the rows and create entries with 'present' set
    for row in table_data:
        if 'present' in row['presence'] and 'floor' in row['type']:
            site_name_hierarchy = '{}/{}'.format(row['parentName'], row['name'])
            _id = common.get_object_id(sites_db, siteNameHierarchy=site_name_hierarchy)
            if _id is not None:
                logger.info('Floor: {}/{} already exists with id: {}'.format(row['parentName'], row[_table_key], _id))
            else:
                logger.info('Creating floor: {}/{}'.format(row['parentName'], row[_table_key]))

                data = common.build_json_from_template(templates.floor_j2, row)

                logger.debug('Building payload: {}'.format(data))
                result = api.sites.create_site(payload=data)
                status = common.wait_for_task_completion(api, result)
                logger.debug(status)
Example #8
0
def add_device_role(api, workflow_dict):
    _schema = 'devices.schema.devices'
    logger.info('devices::delete_devices')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        device_role_changes = [row for row in table_data if row['role']]
        _device_db = api.devices.get_device_list()['response']
        device_name_list = [(device['hostname'], device['id'])
                            for device in _device_db]
        device_uuid_list = []

        # get device id for names without domain name attached
        if device_role_changes:
            for device in device_name_list:
                for change_device in device_role_changes:
                    if device[0].split(
                            '.')[0] == change_device['hostname'].split('.')[0]:
                        device_uuid_list.append({
                            'hostname':
                            change_device['hostname'],
                            'id':
                            device[1],
                            'role':
                            change_device['role']
                        })

        # now push the role changes
        if device_uuid_list:
            for device in device_uuid_list:
                data = common.build_json_from_template(
                    templates.device_role_j2, device)
                result = api.devices.update_device_role(payload=data)
                status = common.wait_for_task_completion(
                    api, result['response'])
                logger.debug(status)

        else:
            logger.error("Device does not exist.  Role not updated")
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #9
0
def add_aaa(api, workflow_dict):
    """ Creates DNA Center Global AAA Server based on input from workflow_dict.

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows with AAA server settings required (see schema.yaml);

    :returns: Nothing """

    _schema = 'aaa.schema.system_settings'
    logger.info('system_settings::add_aaa')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        # get Current AAA Servers and get a name list
        _aaa_db = api.custom_caller.call_api('GET', aaa_uri)['response']
        if _aaa_db:
            aaa_ips = [aaa['ipAddress'] for aaa in _aaa_db]
        else:
            aaa_ips = []

        # process each row
        for row in table_data:

            # if present marked and ise not already added to dnac
            if row['presence'] == 'present':
                if row['ipAddress'] not in aaa_ips:
                    logger.info('Adding AAA: {}.  This may take some time...'.format(row['ipAddress']))
                    data = common.build_json_from_template(templates.aaa_j2, row)
                    result = api.custom_caller.call_api('POST', aaa_uri, json=data)
                    status = common.wait_for_task_completion(api, result.response, timeout=60)
                    logger.debug(status)

                    # if added successfully, wait until ise process is completed
                    if not status['response']['isError']:
                        logger.info('Waiting on AAA to move from INPROGRESS to ACTIVE')
                        _wait_on_ise_completion(api, row)

                    else:
                        logger.error(status['response']['failureReason'])
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #10
0
def create_enterprise_ssid(api, workflow_dict):
    """ Creates DNA Center Enterprise SSIDs.

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows of Enterprise SSID definitions (see schema.yaml);

    :returns: Nothing """

    _schema = 'ssids.schema.wireless'
    logger.info('wireless::create_enterprise_ssid')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        _ent_ssid_db = api.non_fabric_wireless.get_enterprise_ssid()

        # Get existing SSID List
        ssid_list = []
        for item in _ent_ssid_db,:

            if item:
                for wlan_profile in item:
                    for ssid in wlan_profile['ssidDetails']:
                        ssid_list.append(ssid['name'])
            else:
                ssid_list = []

        for row in table_data:
            if 'present' in row['presence']:
                if row['name'] in ssid_list:
                    logger.info('SSID: {} already exists'.format(row['name']))
                    pass
                else:
                    logger.info('Creating Enterprise SSID: {}'.format(row['name']))
                    data = common.build_json_from_template(templates.ssid_j2, row)
                    result = api.non_fabric_wireless.create_enterprise_ssid(payload=data)
                    logger.debug(result)
                    common.wait_for_task_completion(api, result)
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #11
0
def deploy_templates(api, workflow_dict):
    """ Deploys Templates

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows of devices and templates to be pushed (see schema.py);

    :returns: Nothing """

    _schema = 'deploy.schema.templates'
    logger.info('templates::deploy_templates')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        deployment_details = [
            device for device in table_data if device['presence'] == 'present'
        ]

        for deployment in deployment_details:

            # get template id
            response = api.template_programmer.gets_the_templates_available()
            template_data = common.get_object_by_attribute(
                response, name=deployment['templateName'])

            # if template exists go ahead and deploy
            if template_data['templateId'] is not None:
                deployment['templateId'] = template_data['templateId']
                data = common.build_json_from_template(
                    json_templates.deploy_template_j2, deployment)
                response = api.template_programmer.deploy_template(
                    payload=data)
                # api response is broken for deployment api response.  just printing the response for now
                # common.wait_for_task_completion(response)

                return response
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #12
0
def _create_buildings(api, sites_db, table_data):
    _table_key = 'name'

    # Cycle through the rows and create entries with 'present' set
    for row in table_data:
        if 'present' in row['presence'] and 'building' in row['type']:
            site_name_hierarchy = '{}/{}'.format(row['parentName'], row['name'])
            _id = common.get_object_id(sites_db, siteNameHierarchy=site_name_hierarchy)
            if _id is not None:
                logger.info('Building: {}/{} already exists with id: {}'.format(row['parentName'], row[_table_key], _id))
            else:
                logger.info('Creating building: {}/{}'.format(row['parentName'], row[_table_key]))

                data = common.build_json_from_template(templates.building_j2, row)

                data['site']['building']['address'] = '{}, {}, {}'.format(
                    row['street'],
                    row['city'],
                    row['country']
                )

                # If lat and lon are defined, they are used instead of _address_lookup
                if row['latitude'] is not None and row['longitude'] is not None:
                    data['site']['building']['longitude'] = float(row['longitude'])
                    data['site']['building']['latitude'] = float(row['latitude'])
                else:
                    location = _address_lookup(row['street'], row['city'], row['country'])
                    if location is not None:
                        logger.info('Address lookup: SUCCESS')
                        data['site']['building']['address'] = location['address']
                        data['site']['building']['longitude'] = float(location['lon'])
                        data['site']['building']['latitude'] = float(location['lat'])
                    else:
                        logger.info('Address lookup: FAILURE')

                logger.debug('Building payload: {}'.format(data))
                result = api.sites.create_site(payload=data)
                status = common.wait_for_task_completion(api, result)
                logger.debug(status)
Example #13
0
def delete_wireless(api, workflow_dict):
    """ Deletes wireless SSID's, profiles, and interfaces specified in workflow_dict.

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows of wireless information (see schema.yaml);

    :returns: Nothing """

    _schema = 'ssids.schema.wireless'
    logger.info('wireless::delete_wireless::ssids')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        # SSID's to remove
        ssids = [ssid['name'] for ssid in table_data if ssid['presence'] == "absent"]

        # delete new SSIDs
        if ssids:
            for ssid in ssids:
                logger.info('Delete Wireless::delete SSID {}'.format(ssid))
                result = api.non_fabric_wireless.delete_enterprise_ssid(ssid)
                logger.debug(result)
                common.wait_for_task_completion(api, result)
        else:
            logger.info('Delete Wireless:  No SSIDs to delete')
    else:
        logger.error('schema not found: {}'.format(_schema))

    _schema = 'wireless_profiles.schema.wireless'
    logger.info('wireless::delete_wireless::wireless_profiles')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        profiles = [profile['profileName'] for profile in table_data if profile['presence'] == "absent"]

        # remove wireless Profiles
        if profiles:

            for profile in profiles:
                no_site_profile = {'profileName': profile, 'sites': ""}

                # remove sites from profile
                data = common.build_json_from_template(templates.wireless_profile_j2, no_site_profile)
                result = api.non_fabric_wireless.update_wireless_profile(payload=data)
                logger.debug(result)
                common.wait_for_task_completion(api, result)

                # now good to delete profile
                logger.info('Delete Wireless::delete Profile {}'.format(profile))
                wireless_profile_delete_url = "/dna/intent/api/v1/wireless-profile/{}".format(profile)
                result = api.custom_caller.call_api('DELETE', wireless_profile_delete_url)
                logger.debug(result)
                common.wait_for_task_completion(api, result)
        else:
            logger.info('Delete Wireless:  No Profiles to delete')
    else:
        logger.error('schema not found: {}'.format(_schema))

    _schema = 'ssid_to_profile_mapping.schema.wireless'
    logger.info('wireless::delete_wireless::ssid_to_profile_mapping')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]
        # delete wireless interfaces
        # Get current interface list
        result = api.custom_caller.call_api('GET', wireless_int_url)
        current_wireless_interfaces = result['response'][0]['value']
        # Get interfaces to remove
        interfaces_to_remove = [interface['interfaceNameOTT'] for interface in table_data
                                if interface['interfaceNameOTT'] is not None and interface['presence'] == "absent"]

        # create remove targeted interfaces from list and post new list
        if interfaces_to_remove:
            interfaces = json.dumps([interface for interface in current_wireless_interfaces
                                     if interface['interfaceName'] not in interfaces_to_remove])
            logger.info('Deleting Wireless Interfaces ')
            data = common.build_json_from_template(templates.wireless_interface_j2, interfaces)
            result = api.custom_caller.call_api('POST', wireless_int_url, json=data)
            logger.debug(result)
            common.wait_for_task_completion(api, result['response'])
        else:
            logger.info('Delete Wireless:  No Wireless Interfaces to delete')
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #14
0
def run_discovery(api, workflow_dict):
    """ Initiates DNA Center Device Discovery based on input from workflow_dict.

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows of discovery job definitions (see schema.yaml);

    :returns: Nothing """

    _schema = 'discovery.schema.discovery'
    logger.info('discovery::run_discovery')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        get_discoveries_url = '{}/1/99'.format(discovery_url)

        # Cycle through the rows and create entries with 'present' set
        for row in table_data:
            if row['presence'] and 'present' in row['presence']:

                # URI: GET to discover ID of existing discoveries so that we can delete/update
                _discovery = api.custom_caller.call_api('GET', get_discoveries_url)
                _id = common.get_object_id(_discovery['response'], name=row['name'])

                if _id is not None:
                    data = { 'id': _id, 'discoveryStatus': 'Active'}
                    # URI: PUT to start/rerun an existing discovery
                    # discovery_url = 'api/v1/discovery'
                    result = api.custom_caller.call_api('PUT', discovery_url, json=data)
                    logger.info('Waiting a few seconds for discovery to start ...')
                    time.sleep(5)
                    status = common.wait_for_task_completion(api, result['response'], timeout=30)
                    logger.debug(status)
                    _wait_for_discovery_to_complete(api, _id)

                else:

                    _creds = []

                    _cli = api.network_discovery.get_global_credentials('CLI')
                    _id = common.get_object_id(_cli['response'], description=row['cli'])
                    _creds.append(_id)

                    _cli = api.network_discovery.get_global_credentials('SNMPV2_READ_COMMUNITY')
                    _id = common.get_object_id(_cli['response'], description=row['snmp_ro'])
                    _creds.append(_id)

                    _cli = api.network_discovery.get_global_credentials('SNMPV2_WRITE_COMMUNITY')
                    _id = common.get_object_id(_cli['response'], description=row['snmp_rw'])
                    _creds.append(_id)

                    _discovery_range = '{}-{}'.format(row['startIp'], row['endIp'])
                    row.update({'discovery_range': _discovery_range})

                    data = common.build_json_from_template(templates.discovery_j2, row)
                    data['globalCredentialIdList'] = _creds
                    logger.info('Adding discovery ... ')
                    result = api.network_discovery.start_discovery(payload=data)
                    status = common.wait_for_task_completion(api, result['response'])
                    logger.debug(status)

                    _discovery = api.custom_caller.call_api('GET', get_discoveries_url)
                    _id = common.get_object_id(_discovery['response'], name=row['name'])
                    _wait_for_discovery_to_complete(api, _id)
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #15
0
def assign_to_site(api, workflow_dict):
    _schema = 'devices.schema.devices'
    logger.info('devices::assign_to_site')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        # Hack until we figure out how to check device inventory status correctly
        # logger.info('devices::Sleep for 5 minutes ...')
        # time.sleep(300)

        sites_db = api.sites.get_site()

        for device in table_data:

            if 'absent' == device['presence']:
                continue

            site_id = common.get_object_id(
                sites_db['response'], siteNameHierarchy=device['location'])
            topology_db = api.custom_caller.call_api('GET', topology_db_uri)
            device_ip = common.get_object_id(topology_db['response']['nodes'],
                                             return_param='ip',
                                             label=device['hostname'],
                                             strict=False)

            if device_ip is None:
                logger.info('Device {} not found in topology database'.format(
                    device['hostname']))
                logger.info('Entering wait loop for maximum 60 seconds')
                topology_db = _wait_for_device_presence(api,
                                                        device['hostname'],
                                                        timeout=60)
                device_ip = common.get_object_id(
                    topology_db['response']['nodes'],
                    return_param='ip',
                    label=device['hostname'],
                    strict=False)

            if site_id is not None:
                # TODO Can this be converted to native SDK call?
                # URI: GET used to discover discover site membership
                site_member_uri = site_member_uri_pattern.format(site_id)
                site_membership = api.custom_caller.call_api(
                    'GET', site_member_uri)
                device_provisioned = 0
                for members_response in site_membership['device']:
                    # Check if device already provisioned under this site
                    # This is suboptimal since the device could be provisioned under a different site already
                    if len(members_response['response']):
                        device_id = common.get_object_id(
                            members_response['response'],
                            return_param='instanceUuid',
                            hostname=device['hostname'],
                            strict=False)
                        if device_id is not None:
                            logger.info(
                                'Device {} already allocated to site {}'.
                                format(device['hostname'], device['location']))
                            logger.debug(
                                'Hostname: {} instanceUuid: {}'.format(
                                    device['hostname'], device_id))
                            device_provisioned = 1
                        else:
                            logger.info('Adding device {} to site {}'.format(
                                device['hostname'], device['location']))
                            data = common.build_json_from_template(
                                templates.device_to_site_j2,
                                {'device_ip': device_ip})
                            result = api.sites.assign_device_to_site(
                                site_id, payload=data)
                            status = common.wait_for_task_completion(
                                api, result)
                            logger.debug(status)
                            device_provisioned = 1

                if not device_provisioned:
                    # If we didn't find a device under this site, try and assign the device to site
                    # Again, not optimal as the device may exist under a different site
                    logger.info(
                        'Device {} not found under target site {}'.format(
                            device['hostname'], device['location']))
                    logger.info('Trying to add device {} to site {}'.format(
                        device['hostname'], device['location']))
                    data = common.build_json_from_template(
                        templates.device_to_site_j2, {'device_ip': device_ip})
                    result = api.sites.assign_device_to_site(site_id,
                                                             payload=data)
                    status = common.wait_for_task_completion(api, result)
                    logger.debug(status)
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #16
0
def create_network_profile(api, workflow_dict):
    """ Creates switching Network Profiles.  Wireless profile creation is handled
    in wireless module.

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows of network profiles (see schema.py);

    :returns: Nothing """

    _schema = 'network_profiles.schema.network_profiles'
    logger.info('network_profiles::create_network_profiles')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        # get profiles to be created
        new_profiles = [profile for profile in table_data if profile['presence'] == 'present']

        if new_profiles:
            # check for dupe profile names
            result = api.custom_caller.call_api('GET', network_profile_base_url, params={"namespace": "switching"})
            current_profiles = result['response']
            current_profile_names = [profile['name'] for profile in current_profiles]

            # get site ids
            sites = api.sites.get_site()

            # now create it
            for profile in new_profiles:
                if profile['name'] in current_profile_names:
                    logger.info('network_profiles:: {} already exists'.format(profile['name']))
                    pass

                else:
                    logger.info('network profiles: Creating {}'.format(profile['name']))
                    data = common.build_json_from_template(templates.add_profile_j2, profile)
                    result = api.custom_caller.call_api('POST', network_profile_base_url, json=data)
                    logger.debug(result)
                    create_result = common.wait_for_task_completion(api, result['response'])

                    # if successful creation lets move on to adding sites
                    if create_result['response']['isError'] == False:
                        data = api.custom_caller.call_api('GET', network_profile_base_url, params={"name": profile['name']})
                        profile['id'] = data['response'][0]['siteProfileUuid']
                        # if location then assign it to profile
                        # split up sites if csv
                        if profile['sites']:
                            logger.info('network_profiles::update_site')
                            profile['sites'] = common.csv_string_to_list(profile['sites'])

                            # get site id and add it to profile
                            for new_site in profile['sites']:
                                site_id = common.get_object_id(sites['response'], siteNameHierarchy=new_site)
                                site_add_url = "{}/{}/site/{}".format(network_profile_base_url, profile['id'], site_id)
                                result = api.custom_caller.call_api('POST', site_add_url)
                                logger.debug(result)
                                common.wait_for_task_completion(api, result['response'])

                        # Assign templates to profile
                        # first build out objects needed starting with day0
                        if profile['day0Template'] or profile['cliTemplate']:
                            if profile['day0Template']:
                                day0_list = common.csv_string_to_list(profile['day0Template'])
                                day0_obj = []
                                if profile['product_series']:
                                    template_db = api.template_programmer.gets_the_templates_available(
                                        product_family="Switches and Hubs",
                                        product_series=profile['product_series']
                                    )
                                else:
                                    template_db = api.template_programmer.gets_the_templates_available(
                                        productFamily="Switches and Hubs")

                                # build object with names/ids
                                for template in day0_list:

                                    for item in template_db:

                                        if item['name'] == template:
                                            # Get latest version
                                            version_list = [version['version'] for version in item['versionsInfo']]
                                            version = max(version_list)
                                            # Update Object
                                            day0_obj.append(
                                                {"name": item['name'], "id": item['templateId'], "version": version})
                                profile['day0Template'] = day0_obj

                            # now build day 1 objects
                            if profile['cliTemplate']:
                                day1_list = common.csv_string_to_list(profile['cliTemplate'])
                                day1_obj = []

                                if profile['product_series']:
                                    template_db = api.template_programmer.gets_the_templates_available(
                                        product_family="Switches and Hubs",
                                        product_series=profile['product_series']
                                    )
                                else:
                                    template_db = api.template_programmer.gets_the_templates_available(
                                        product_family="Switches and Hubs")

                                # build object with names/ids
                                for template in day1_list:

                                    for item in template_db:

                                        if item['name'] == template:
                                            # Get latest version
                                            version_list = [version['version'] for version in item['versionsInfo']]
                                            version = max(version_list)
                                            # Update Object
                                            day1_obj.append(
                                                {"name": item['name'], "id": item['templateId'], "version": version})

                                # update profile with additional info needed (id,version #)
                                profile['cliTemplate'] = day1_obj

                            logger.info('network profiles::adding templates')
                            data = common.build_json_from_template(templates.add_templates_to_profile_j2, profile)
                            add_template_profile_url = "{}/{}".format(network_profile_base_url, profile['id'])
                            result = api.custom_caller.call_api('PUT', add_template_profile_url, json=data)
                            logger.debug(result)
                            common.wait_for_task_completion(api, result['response'])

                        else:
                            logger.info('network profiles:: No Templates to add')
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #17
0
def create_wireless_interface(api, workflow_dict):
    # consider moving this as a child function

    """ Creates DNA Center Wireless Over The Top (OTT) Interfaces.  If using OTT, wireless interfaces will need to be created
    before assigning them to a wireless profile

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows of Wireless info with associated parameters. (see schema.yaml);

    :returns: Nothing """

    _schema = 'ssid_to_profile_mapping.schema.wireless'
    logger.info('wireless::create_wireless_interface')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        # create list of to be added interface mappings if they do not exist in current mappings
        new_interface_mappings = [
            {
                "interfaceName": interface['interfaceNameOTT'],
                "vlanId": interface['ottVlan']
             }
            for interface in table_data if interface['interfaceNameOTT'] is not None and interface['presence'] == "present"
        ]

        # if new interfaces proceed to adding new interfaces
        if new_interface_mappings:

            # get current wireless interfaces as PUT is not supported so we need to post all interfaces when adding a
            # new one
            result = api.custom_caller.call_api('GET', wireless_int_url)
            current_wireless_interfaces = result['response'][0]['value']

            # create list of current interface mappings
            current_interface_mappings = [
                {
                    "interfaceName": interface['interfaceName'],
                    "vlanId": interface['vlanId']
                }
                for interface in current_wireless_interfaces if interface['interfaceName'] is not None
            ]
            current_int_names = [current_interface['interfaceName'] for current_interface in current_interface_mappings]

            # add new interfaces to current list
            for interface in new_interface_mappings:
                if interface["interfaceName"] not in current_int_names:
                    current_interface_mappings.append(
                        {"interfaceName": interface['interfaceName'], "vlanId": interface['vlanId']})

            # format list and send create request
            current_interface_mappings = json.dumps(current_interface_mappings)
            logger.info('Creating Wireless Interfaces ')
            data = common.build_json_from_template(templates.wireless_interface_j2, current_interface_mappings)
            result = api.custom_caller.call_api('POST', wireless_int_url, json=data)
            logger.debug(result)
            common.wait_for_task_completion(api, result['response'])
        else:
            logger.info('Creating Wireless Interfaces: No Wireless interfaces to Create')
            pass
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #18
0
def create_templates(api, workflow_dict):
    """ Creates Templates.  Template content can either be added to template content field or templates can be added to sample templates
    directory under templates module.  If using templates json file, templateName field will need to match the name of template json identified in
    the __TEMPLATE_CONTENTS__ global variable.  New template json files will need to be added to the __TEMPLATE_CONTENTS__.


    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows of templates (see schema.py);

    :returns: Nothing """
    _logInfo(inspect.currentframe().f_code.co_name)
    _schema = 'templates.schema.templates'
    logger.info('templates::create_templates')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        projects = _listTemplateProjects(api)

        for row in table_data:
            if _PRESENT_ in row[_PRESENCE_ROW_]:
                templateName = row[_TEMPLATES_TABLE_TEMPLATE_NAME_COLUMN_]
                templateDescription = row[
                    _TEMPLATES_TABLE_TEMPLATE_DESCRIPTION_COLUMN_]
                projectName = row[_TEMPLATES_TABLE_PROJECT_NAME_COLUMN_]

                _logDebug(("ProjectName: {}; TemplateName: {}").format(
                    projectName, templateName))

                projectID = _getProjectID(api, projectName)
                existing_template = _getTemplateInProjectId(
                    api, templateName, projectID)
                _logDebug(("ProjectID: {}; Existing TemplateID:{}").format(
                    projectID, existing_template))

                #                         pprint.pprint(existing_template)
                if templateName not in _TEMPLATE_CONTENTS_.keys():
                    # if project exists create template
                    if projectID:
                        row['projectId'] = projectID

                        # row['parentTemplateId'] = existing_template.id
                        row['deviceTypes'] = []
                        row['deviceTypes'].append(
                            {"productFamily": row['productFamily']})
                        row['deviceTypes'] = json.dumps(row['deviceTypes'])

                        # check if template already exists if... if it does then use update
                        if existing_template is not None:
                            row['templateId'] = existing_template.id
                            logger.info(
                                "templates::create templates {} template exists, updating"
                                .format(row['templateName']))
                            data = common.build_json_from_template(
                                json_templates.blank_template_j2, row)
                            response = api.template_programmer.update_template(
                                projectID, payload=data)
                            logger.debug(response)
                            template_data = common.wait_for_task_completion(
                                api, response['response'])

                            # commit template to new version if template was created correctly
                            if template_data['response']['data']:
                                templateID = template_data['response']['data']
                                response = api.template_programmer.version_template(
                                    templateId=template_data['response']
                                    ['data'])
                                common.wait_for_task_completion(
                                    api, response['response'])
                                logger.info(
                                    "border_handoff::{} template update successful"
                                    .format(row['templateName']))

                                return {
                                    "response": {
                                        "description":
                                        "Template Created Successfully",
                                        "isError": False,
                                        "templateId": templateID
                                    }
                                }
                            else:
                                logger.error(
                                    "templates:: create {} template failed".
                                    format(row['templateName']))

                        # Otherwise create a new one
                        else:
                            logger.info(
                                "templates::create templates:: create {} template"
                                .format(row['templateName']))
                            data = common.build_json_from_template(
                                json_templates.blank_template_j2, row)
                            response = api.template_programmer.create_template(
                                projectID, payload=data)
                            logger.debug(response)
                            template_data = common.wait_for_task_completion(
                                api, response['response'])

                            # commit template to version 1 if template was created correctly
                            if template_data['response']['data']:
                                templateId = template_data['response']['data']
                                response = api.template_programmer.version_template(
                                    templateId=templateId)
                                common.wait_for_task_completion(
                                    api, response['response'])

                                return {
                                    "response": {
                                        "description":
                                        "Template Created Successfully",
                                        "isError": False,
                                        "templateId": templateId
                                    }
                                }
                            else:
                                return {
                                    "response": {
                                        "description": "Template Not Created",
                                        "isError": True
                                    }
                                }

                # if existing template files exist generate template from json file
                else:
                    template_content = _getTemplateContent(templateName)
                    template_content["description"] = templateDescription

                    if projectID is not None:
                        if existing_template is None:
                            # Create a new template
                            _logDebug("Creating new template: " + templateName)
                            response = api.template_programmer.create_template(
                                **template_content, project_id=projectID)
                            templateID = common.wait_on_task(
                                api, response,
                                "Create template: " + templateName)
                            _logDebug(templateID)

                            response = api.template_programmer.version_template(
                                templateId=templateID)
                            _logDebug(str(response))

                            return {
                                "response": {
                                    "description":
                                    "Template Created Successfully",
                                    "isError": False,
                                    "templateId": templateID
                                }
                            }
                        else:
                            # Update existing template
                            _logDebug("Updating existing template: " +
                                      existing_template.name)
                            template_content['projectId'] = projectID
                            template_content['id'] = existing_template.id
                            template_content[
                                'parentTemplateId'] = existing_template.id

                            #                                 pprint.pprint(template_content)
                            response = api.template_programmer.update_template(
                                **template_content)

                            templateID = common.wait_on_task(
                                api, response,
                                "Update template: " + existing_template.name)
                            return {
                                "response": {
                                    "description":
                                    "Template Updated Successfully",
                                    "isError": False,
                                    "templateId": templateID
                                }
                            }
                    else:
                        _logInfo(templateName + " -> Project does not exist.")
    else:
        logger.error('schema not found: {}'.format(_schema))
Example #19
0
def add_port_assignment(api, workflow_dict):
    """ FIXME.

    :param api: An instance of the dnacentersdk.DNACenterAPI class
    :param workflow_dict: A dictionary containing rows of discovery job definitions (see schema.yaml);

    :returns: Nothing """

    _schema = 'ports.schema.host_onboarding'
    logger.info('host onboarding::add port assignment')
    logger.debug('schema: {}'.format(_schema))

    if _schema in workflow_dict.keys():
        table_data = workflow_dict[_schema]

        # get info from db
        port_assignments = [
            assignment for assignment in table_data
            if assignment['presence'] == 'present'
        ]

        if port_assignments:
            for assignment in port_assignments:
                # provision AP Port
                if assignment['portType'] and assignment['portType'] == "ap":
                    # check to make sure pool is of AP Provisioning
                    segment_db = api.custom_caller.call_api(
                        'GET', base_sda_segment_uri)['response']
                    ap_provision_segments = [
                        segment['name'] for segment in segment_db
                        if segment['isApProvisioning'] == True
                    ]

                    # if true assign the port
                    if assignment['dataPoolName'] in ap_provision_segments:
                        logger.info(
                            'host onboarding: Assigning {} to AP Port on Switch {}'
                            .format(assignment['interfaceName'],
                                    assignment['deviceIP']))
                        ap_port_uri = "{}/{}".format(add_port_uri_base,
                                                     "access-point")
                        data = common.build_json_from_template(
                            templates.port_template_j2, assignment)
                        result = api.custom_caller.call_api('POST',
                                                            ap_port_uri,
                                                            json=data)
                        common.wait_for_task_completion(api, result)

                        # rate limited after 5 calls so need to sleep temporarily
                        if len(port_assignments) > 5:
                            time.sleep(12)

                # provision User port
                elif assignment['portType'] and assignment[
                        'portType'] == "user":
                    logger.info(
                        'host onboarding: Assigning {} to User Port on Switch {}'
                        .format(assignment['interfaceName'],
                                assignment['deviceIP']))
                    user_port_uri = "{}/{}".format(add_port_uri_base,
                                                   "user-device")
                    data = common.build_json_from_template(
                        templates.port_template_j2, assignment)
                    result = api.custom_caller.call_api('POST',
                                                        user_port_uri,
                                                        json=data)
                    common.wait_for_task_completion(api, result)

                    # rate limited after 5 calls so need to sleep temporarily
                    if len(port_assignments) > 5:
                        time.sleep(12)
    else:
        logger.error('schema not found: {}'.format(_schema))