예제 #1
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-c',
                        '--creds',
                        help='path to file containing credentials')
    parser.add_argument('-m', '--mac', help='MAC address')
    parser.add_argument('-n', '--name', help='Device name')
    parser.add_argument('-p', '--properties', help='Properties')
    parser.add_argument(
        '-l',
        '--loglevel',
        choices=['critical', 'error', 'warning', 'info', 'debug'],
        default='critical',
        help='enable logging')
    args = parser.parse_args()

    # Handle loading of credentials
    creds = pybluecat.get_creds(args.creds)
    hostname = creds['hostname']
    username = creds['username']
    password = creds['password']

    # Enable logging if requested
    # if args.loglevel:
    #     level = getattr(logging, args.loglevel.upper())
    #     logging.basicConfig(level=level)

    # Instantiate Bluecat REST Client
    bam = pybluecat.BAM(hostname, username, password, loglevel=args.loglevel)
    r = bam.create_mac_address(args.mac, args.name, args.properties)
    print(json.dumps(r, indent=2))
예제 #2
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('hostname', help='hostname')
    parser.add_argument('-c', '--creds', help='path to file containing credentials')
    group_ME = parser.add_mutually_exclusive_group(required=True)
    group_ME.add_argument('-n', '--network', nargs=2, help='network address within desired subnet')
    group_ME.add_argument('-e', '--environment', help='environment from which to choose a network')
    parser.add_argument('-l', '--loglevel', choices=['warning', 'info', 'debug'], help='enable debugging')
    args = parser.parse_args()

    NETWORK_ENVS = {
        'lab': [u'10.168.131.0/24', u'10.168.161.0/24'],
        'dmz-vip': [u'167.73.15.0/24', u'167.73.31.0/24']
        }

    if args.loglevel:
        level = getattr(logging, args.loglevel.upper())
        logging.basicConfig(level=level)

    hostname = args.hostname.lower()
    creds = pybluecat.get_creds(args.creds)
    bam = pybluecat.BAM(creds['hostname'], creds['username'], creds['password'])

    # Get Networks List
    if args.network:
        net1 = args.network[0]
        net2 = args.network[1]
    elif args.environment:
        net1, net2 = NETWORK_ENVS[args.environment]

    # Reserve the pairs
    addresses = bam.assign_ip_address_pair(net1, net2, args.hostname)
    print(json.dumps(addresses, indent=2))
예제 #3
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('hostname', help='hostname')
    parser.add_argument('mac_addr', help='MAC Address')
    parser.add_argument(
        'ip_addr',
        help=
        'IP desired for reservation, also defines the network if "first_available" flag is set'
    )
    parser.add_argument('-c',
                        '--creds',
                        help='path to file containing credentials')
    parser.add_argument(
        '-l',
        '--loglevel',
        choices=['critical', 'error', 'warning', 'info', 'debug'],
        default='critical',
        help='enable logging')
    parser.add_argument('--location', default='', help='Location of Device')
    parser.add_argument('--notes',
                        default='',
                        help='Additional notes about the reservation')
    parser.add_argument('--owner', default='', help='Owner of the device')
    parser.add_argument('--request_num',
                        default='',
                        help='ServiceDesk Request Number')
    parser.add_argument('--no_wait',
                        action='store_true',
                        help='do NOT wait for deployment')
    parser.add_argument('--no_deploy',
                        action='store_true',
                        help='Do NOT deploy saved changes')
    args = parser.parse_args()

    # Setup console logging
    logger = logging.getLogger(__name__)
    loglevel = getattr(logging, args.loglevel.upper())
    logger.setLevel(level=loglevel)
    console_handler = logging.StreamHandler()
    logger.addHandler(console_handler)
    logger.propagate = False

    # Setup args and vars
    hostname = args.hostname
    mac = args.mac_addr.replace('.', '').replace(':', '').replace('-', '')
    ip = ip_address(unicode(args.ip_addr))
    action = 'MAKE_DHCP_RESERVED'
    creds = pybluecat.get_creds(args.creds)
    properties = {
        'Location': args.location,
        'Notes': args.notes,
        'Owner': args.owner,
        'RequestNum': args.request_num
    }
    output_object = {}

    # Initialize flow-control boolean vars
    deploy_needed = False
    ip_is_eligible = False
    mac_already_reserved = False
    desired_ip_reserved = False
    error_message = ''

    # Create instance using 'with' so cleanup of session is automatic
    with pybluecat.BAM(**creds) as bam:
        # Determine the Network of the IP Address
        try:
            logger.info('Getting Network info from ip: {}'.format(str(ip)))
            net_entity = bam.get_network(str(ip))
            net_obj = pybluecat.entity_to_json(net_entity)
            network = ip_network(unicode(net_obj['properties']['CIDR']))
            if network.prefixlen <= 24:
                dhcp_offset_ip = str(network.network_address + 31)
            else:
                dhcp_offset_ip = None
            logger.debug(json.dumps(net_obj, indent=2))
        except pybluecat.exceptions.BluecatError as e:
            logger.error(
                'Could not determine the target network or network did not exist'
            )
            exit(str(e))

        # Determine if IP eligible to be reserved, not Broadcast, Network, Gateway, etc...
        if ip == network.network_address:
            error_message = 'Cannot Update the Network Address: {}'.format(
                str(ip))
            logger.info(error_message)
        elif ip == network.broadcast_address:
            error_message = 'Cannot Update the Broadcast Address: {}'.format(
                str(ip))
            logger.info(error_message)
        elif ip == network.network_address + 1:
            error_message = 'Cannot Update the Gateway Address: {}'.format(
                str(ip))
            logger.info(error_message)
        elif ip in [network.network_address + 2, network.network_address + 3]:
            error_message = 'Cannot Update a HSRP/VRRP Address: {}'.format(
                str(ip))
            logger.info(error_message)
        elif network.prefixlen <= 24 and ip in [
                network.network_address + i for i in xrange(4, 31)
        ]:
            error_message = 'Cannot Update Address in Telecom-Reserved Space: {}'.format(
                str(ip))
            logger.info(error_message)
        else:
            ip_is_eligible = True

        # Assuming the IP is eligible, attempt the update
        if ip_is_eligible:
            try:
                logger.info('Getting current config for IP: {}'.format(
                    str(ip)))
                ip_entity = bam.get_ip_address(str(ip))
                old_reservation = pybluecat.entity_to_json(ip_entity)
                logger.debug(
                    json.dumps(old_reservation, indent=2, sort_keys=True))
                if old_reservation['properties'] is None:
                    output_object = {
                        'state': 'No Update Performed',
                        'message': 'Target IP is not a DHCP_RESERVATION',
                        'existing_reservation': old_reservation
                    }
                elif old_reservation['properties']['state'] != 'DHCP_RESERVED':
                    output_object = {
                        'state': 'No Update Performed',
                        'message': 'Target IP is not a DHCP_RESERVATION',
                        'existing_reservation': old_reservation
                    }
                else:
                    response = bam.update_dhcp_reservation(
                        old_reservation, hostname, mac, properties)
                    new_reservation = bam.get_ip_address(str(ip))
                    new_reservation = pybluecat.entity_to_json(new_reservation)
                    logger.debug(
                        json.dumps(old_reservation, indent=2, sort_keys=True))
                    output_object = {
                        'status': 'Reservation Updated Successfully',
                        'message': 'Target IP was updated',
                        'old_reservation': old_reservation,
                        'new_reservation': new_reservation
                    }
                    deploy_needed = True
            except pybluecat.exceptions.BluecatError as e:
                output_object = {
                    'status': 'Error Occurred during Update',
                    'message': e.message
                }
        else:
            output_object = {
                'status': 'No Update Performed',
                'message': error_message
            }

        # Deploy DHCP changes if no_deploy flag isn't set
        if deploy_needed and not args.no_deploy:
            logger.info('Deploying Config changes')
            server_set = bam.queue_servers(net_obj['id'])
            for server in server_set:
                logger.info('Deploying changes to server: {}'.format(
                    str(server)))
                bam.deploy_server_services(server, 'DHCP')
            # Monitor the deployment through completion unless no_wait flag is set
            if not args.no_wait:
                logger.info('Waiting for deployment to finish')
                bam.monitor_server_deployment(server_set)
                logger.info('Deployment finished')
            else:
                logger.info('Monitoring of deployment is being skipped')

    # Finally output the IP info
    #print_ip_info(ip_obj)
    print(json.dumps(output_object, indent=2, sort_keys=True))
예제 #4
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('hostname', help='hostname')
    parser.add_argument('mac_addr', help='MAC Address')
    parser.add_argument(
        'ip_addr',
        help=
        'IP desired for reservation, also defines the network if "first_available" flag is set'
    )
    parser.add_argument('-c',
                        '--creds',
                        help='path to file containing credentials')
    parser.add_argument(
        '-l',
        '--loglevel',
        choices=['critical', 'error', 'warning', 'info', 'debug'],
        default='critical',
        help='enable logging')
    parser.add_argument('--location', default='', help='Location of Device')
    parser.add_argument('--notes',
                        default='',
                        help='Additional notes about the reservation')
    parser.add_argument('--owner', default='', help='Owner of the device')
    parser.add_argument('--request_num',
                        default='',
                        help='ServiceDesk Request Number')
    parser.add_argument('--first_available',
                        action='store_true',
                        help='Use first available IP as fallback option')
    parser.add_argument('--no_wait',
                        action='store_true',
                        help='do NOT wait for deployment')
    parser.add_argument('--no_deploy',
                        action='store_true',
                        help='Do NOT deploy saved changes')
    args = parser.parse_args()

    # Setup console logging
    logger = logging.getLogger(__name__)
    loglevel = getattr(logging, args.loglevel.upper())
    logger.setLevel(level=loglevel)
    console_handler = logging.StreamHandler()
    logger.addHandler(console_handler)
    logger.propagate = False

    # Setup args and vars
    hostname = args.hostname
    mac = args.mac_addr.replace('.', '').replace(':', '').replace('-', '')
    ip = ip_address(unicode(args.ip_addr))
    action = 'MAKE_DHCP_RESERVED'
    creds = pybluecat.get_creds(args.creds)
    properties = {
        'Location': args.location,
        'Notes': args.notes,
        'Owner': args.owner,
        'RequestNum': args.request_num
    }
    output_object = {}

    # Initialize flow-control boolean vars
    deploy_needed = False
    ip_is_eligible = False
    mac_already_reserved = False
    desired_ip_reserved = False
    error_message = ''

    # Create instance using 'with' so cleanup of session is automatic
    with pybluecat.BAM(**creds) as bam:
        # Determine the Network of the IP Address
        try:
            logger.info('Getting Network info from ip: {}'.format(str(ip)))
            net_entity = bam.get_network(str(ip))
            net_obj = pybluecat.entity_to_json(net_entity)
            network = ip_network(unicode(net_obj['properties']['CIDR']))
            if network.prefixlen <= 24:
                dhcp_offset_ip = str(network.network_address + 31)
            else:
                dhcp_offset_ip = None
            logger.debug(json.dumps(net_obj, indent=2))
        except pybluecat.exceptions.BluecatError as e:
            logger.error(
                'Could not determine the target network or network did not exist'
            )
            exit(str(e))

        # Determine if IP eligible to be reserved, not Broadcast, Network, Gateway, etc...
        if ip == network.network_address:
            error_message = 'Cannot reserve the Network Address: {}'.format(
                str(ip))
            logger.info(error_message)
        elif ip == network.broadcast_address:
            error_message = 'Cannot reserve the Broadcast Address: {}'.format(
                str(ip))
            logger.info(error_message)
        elif ip == network.network_address + 1:
            error_message = 'Cannot reserve the Gateway Address: {}'.format(
                str(ip))
            logger.info(error_message)
        elif ip in [network.network_address + 2, network.network_address + 3]:
            error_message = 'Cannot reserve a GSLB/VRRP Address: {}'.format(
                str(ip))
            logger.info(error_message)
        elif network.prefixlen <= 24 and ip in [
                network.network_address + i for i in xrange(4, 31)
        ]:
            error_message = 'Cannot reserve Address in Telecom-Reserved Space: {}'.format(
                str(ip))
            logger.info(error_message)
        else:
            ip_is_eligible = True

        # Determine if MAC is already associated with a reservation in target network
        logger.info(
            'Searching for existing reservations for MAC: {}'.format(mac))
        try:
            linked_entities = search_mac(bam, mac)
            for entity in linked_entities:
                if entity['type'] == 'IP4Address':
                    ip_obj = pybluecat.entity_to_json(entity)
                    logger.debug(json.dumps(ip_obj, indent=2, sort_keys=True))
                    ip_obj_address = ip_address(
                        unicode(ip_obj['properties']['address']))
                    # Break loop as soon as match is found, return the matched reservation
                    if ip_obj_address in network and ip_obj['properties'][
                            'state'] == 'DHCP_RESERVED':
                        logger.info(
                            'Found existing reservation in target network')
                        mac_already_reserved = True
                        output_object = {
                            'status': 'Found existing reservation',
                            'message':
                            'MAC Address has existing reservation in current network.',
                            'reservation': ip_obj
                        }
                        break
        # If MAC not found handle the error, otherwise exit script with error code 1
        except pybluecat.exceptions.BluecatError as e:
            if 'Object was not found' in e.message:
                logger.info('MAC address does not currently exist in Bluecat')
            else:
                logger.error('Failed searching for MAC')
                exit(str(e))

        # If we didn't find an existing reservation, try to get a new one
        if not mac_already_reserved:
            logger.info(
                'MAC address has no current reservations in target network')
            # Try to create the Reservation using the literal IP given as arg
            if ip_is_eligible:
                logger.info(
                    'Sending reservation request to Bluecat for IP: {}'.format(
                        str(ip)))
                try:
                    ip_id = bam.assign_ip_address(hostname, str(ip), mac,
                                                  action, properties)
                    ip_entity = bam.get_entity_by_id(ip_id)
                    ip_obj = pybluecat.entity_to_json(ip_entity)
                    desired_ip_reserved = True
                    deploy_needed = True
                    output_object = {
                        'status': 'New Reservation Create',
                        'message':
                        'Desired IP Address was Available and Assigned',
                        'reservation': ip_obj
                    }
                # Handle Bluecat errors, shouldn't see anything other than Dupes at this point
                except pybluecat.exceptions.BluecatError as e:
                    if 'Duplicate' in e.message:
                        error_message = 'Desired IP is already in Use'
                        logger.info(error_message)
                        ip_entity = bam.get_ip_address(str(ip))
                        conflicting_ip = pybluecat.entity_to_json(ip_entity)
                    elif 'already used by another IP within the same network' in e.message:
                        # Should've been caught earlier
                        error_message = e.message
                        logger.error(error_message)
                    else:
                        # Probably a system failure :(
                        logger.error(e.message)

            # If we were not able to reserve the desired IP for whatever reason...
            if not desired_ip_reserved:
                # Get next available IP if flag is set
                if args.first_available:
                    try:
                        logger.info(
                            'Sending request to Bluecat to assign next available address in network: {}'
                            .format(str(network)))
                        ip_entity = bam.assign_next_ip_address(
                            net_obj['id'], hostname, mac, action, properties,
                            dhcp_offset_ip)
                        ip_obj = pybluecat.entity_to_json(ip_entity)
                        logger.debug(
                            json.dumps(ip_obj, indent=2, sort_keys=True))
                        output_object = {
                            'status':
                            'New Reservation Created',
                            'message': [
                                error_message,
                                'First Available IP Address was assigned'
                            ],
                            'reservation':
                            ip_obj
                        }
                        deploy_needed = True
                    # Expected errors here would be network out of addresses
                    except pybluecat.exceptions.BluecatError as e:
                        output_object = {
                            'status': 'Reservation could not be completed',
                            'message': [error_message, e.message]
                        }
                        logger.error(
                            'Unable to assign next available IP address')
                # Should hit this only when target IP in ineligible and __first_available is not set
                else:
                    output_object = {
                        'status':
                        'Reservation could not be completed',
                        'message': [
                            error_message,
                            'Try using the --first_available flag or choose a different IP Address'
                        ],
                        'conflicting_ip':
                        conflicting_ip
                    }

        # Deploy DHCP changes if no_deploy flag isn't set
        if deploy_needed and not args.no_deploy:
            logger.info('Deploying Config changes')
            server_set = bam.queue_servers(net_obj['id'])
            for server in server_set:
                logger.info('Deploying changes to server: {}'.format(
                    str(server)))
                bam.deploy_server_services(server, 'DHCP')
            # Monitor the deployment through completion unless no_wait flag is set
            if not args.no_wait:
                logger.info('Waiting for deployment to finish')
                bam.monitor_server_deployment(server_set)
                logger.info('Deployment finished')
            else:
                logger.info('Monitoring of deployment is being skipped')

    # Finally output the IP info
    #print_ip_info(ip_obj)
    print(json.dumps(output_object, indent=2, sort_keys=True))
예제 #5
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-c',
                        '--creds',
                        help='path to file containing credentials')
    parser.add_argument('-i', '--ip', help='IP address')
    parser.add_argument('-m', '--mac', help='MAC address')
    parser.add_argument('-n', '--name', help='Device name')
    parser.add_argument(
        '-l',
        '--loglevel',
        default='critical',
        help='enable logging',
        choices=['critical', 'error', 'warning', 'info', 'debug'])
    match_group = parser.add_mutually_exclusive_group()
    match_group.add_argument('--match_all', action='store_true')
    match_group.add_argument('--match_any', action='store_true')
    args = parser.parse_args()

    # Setup console logging
    logger = logging.getLogger(__name__)
    loglevel = getattr(logging, args.loglevel.upper())
    logger.setLevel(level=loglevel)
    console_handler = logging.StreamHandler()
    logger.addHandler(console_handler)
    logger.propagate = False

    # Handle loading of credentials
    creds = pybluecat.get_creds(args.creds)
    hostname = creds['hostname']
    username = creds['username']
    password = creds['password']

    # Instantiate Bluecat REST Client
    bam = pybluecat.BAM(hostname, username,
                        password)  # , loglevel=args.loglevel)

    # Normalizing Arguments due to Rundeck requirements
    if args.ip == '':
        ip = None
    else:
        ip = args.ip
    if args.mac == '':
        mac = None
    else:
        mac = args.mac
    if args.name == '':
        name = None
    else:
        name = args.name

    # Use provided fields to search Bluecat Objects
    results = []
    if ip is not None:
        results += search_ip(bam, ip)
    if mac is not None:
        results += search_mac(bam, mac)
    if name is not None:
        results += search_name(bam, name)

    # Eliminate Dupes and conflicting filters
    matches = []
    for result in results:
        ip_obj = bam.entity_to_json(result)
        # Skip NULL objects
        if ip_obj['properties'] is None:
            continue
        # Skip Duplicates
        if ip_obj in matches:
            continue
        # Gather details about the ip_object
        res_name = ip_obj['name']
        res_ip = ip_obj['properties']['address']
        if 'macAddress' in ip_obj['properties']:
            res_mac = ip_obj['properties']['macAddress']
        else:
            res_mac = ''
        logger.info('NAME: {}, IP: {}, MAC: {}'.format(res_name, res_ip,
                                                       res_mac))
        # If IP Object state is not "DHCP_RESERVED" DO NOT DELETE
        if ip_obj['properties']['state'] != 'DHCP_RESERVED':
            logger.info(
                'IP Object is NOT a DHCP Reservation, ignoring objects with state: {}'
                .format(ip_obj['properties']['state']))
            continue
        # If --match_all is set, ensure ALL set fields match the reservation
        if args.match_all:
            # If --hostname is set and doesn't match, skip to next reservation
            if name is not None and res_name.lower() != name.lower():
                logger.info(
                    'Reservation doesn\'t match --hostname filter with --match_all set, ignoring'
                )
                continue
            # If --ip_addr is set and doesn't match, skip to next reservation
            if ip is not None and res_ip != str(ip):
                logger.info(
                    'Reservation doesn\'t match --ip_addr filter with --match_all set, ignoring'
                )
                continue
            # If --mac_addr is set and doesn't match, skip to next reservation
            if mac is not None and format_mac(res_mac) != mac:
                logger.info(
                    'Reservation doesn\'t match --mac_addr filter with --match_all set, ignoring'
                )
                continue
        matches.append(ip_obj)

    # Output the remaining matched ip objects
    print(json.dumps(matches, indent=2, sort_keys=True))
예제 #6
0
def main():
    parser = argparse.ArgumentParser()
    field_group = parser.add_argument_group(
        'Matchable Fields',
        'Provide at least one of the following fields to delete a reservation')
    parser.add_argument('--hostname',
                        help='hostname of reservation(s) to delete')
    parser.add_argument('--mac_addr',
                        help='MAC Address of reservation(s) to delete')
    parser.add_argument('--ip_addr',
                        help='IP Address of reservation to delete')
    match_group = parser.add_mutually_exclusive_group(required=True)
    match_group.add_argument(
        '--match_all',
        action='store_true',
        help='Delete only objects that match ALL conditions')
    match_group.add_argument(
        '--match_any',
        action='store_true',
        help='Delete any object that matches ANY condition')
    parser.add_argument('-c',
                        '--creds',
                        help='path to file containing credentials')
    parser.add_argument(
        '-l',
        '--loglevel',
        choices=['critical', 'error', 'warning', 'info', 'debug'],
        default='critical',
        help='enable logging')
    parser.add_argument('--no_wait',
                        action='store_true',
                        help='do NOT wait for deployment')
    parser.add_argument('--no_deploy',
                        action='store_true',
                        help='Do NOT deploy saved changes')
    args = parser.parse_args()

    # Setup console logging
    logger = logging.getLogger(__name__)
    loglevel = getattr(logging, args.loglevel.upper())
    logger.setLevel(level=loglevel)
    console_handler = logging.StreamHandler()
    logger.addHandler(console_handler)
    logger.propagate = False

    # Setup args and vars
    # None values are passed along to be ignored later
    # Rundeck passes in empty strings instead, so translate those to None
    if args.hostname is not None:
        if args.hostname.strip() == '':
            hostname = None
        else:
            hostname = args.hostname
    else:
        hostname = None
    if args.mac_addr is not None:
        if args.mac_addr.strip() == '':
            mac = None
        else:
            mac = format_mac(args.mac_addr)
    else:
        mac = None
    if args.ip_addr is not None:
        if args.ip_addr.strip() == '':
            ip = None
        else:
            ip = ip_address(unicode(args.ip_addr))
    else:
        ip = None
    creds = pybluecat.get_creds(args.creds)
    output_object = {'status': '', 'message': [], 'deleted_reservations': []}

    # Exit Immediately if no fields were provided
    if all(field is None for field in [hostname, mac, ip]):
        output_object['status'] = 'No Reservations were Deleted'
        output_object['message'].append('No Fields were populated')
        output_object['message'].append(
            'Please provided at least a Hostname, MAC_Address, or IP_Address')
        print(json.dumps(output_object, indent=2, sort_keys=True))
        exit()

    # Initialize flow-control boolean vars
    deploy_needed = False
    ip_is_eligible = False
    error_message = ''
    ips_seen_so_far = []
    candidate_reservations = []
    reservations_to_delete = []
    deleted_reservations = []

    # Create instance using 'with' so cleanup of session is automatic
    with pybluecat.BAM(**creds) as bam:
        # Get reservation matching the hostname, if given
        if hostname is not None:
            logger.info(
                'Hostname provided ({}), searching for reservations'.format(
                    hostname))
            results = bam.search_ip_by_name(hostname)
            logger.debug(json.dumps(results, indent=2, sort_keys=True))
            candidate_reservations += results
        # Get reservations matching the IP Address, if given
        if ip is not None:
            logger.info(
                'IP Address provided ({}), searching for reservations'.format(
                    str(ip)))
            result = bam.get_ip_address(str(ip))
            logger.debug(json.dumps(result, indent=2, sort_keys=True))
            candidate_reservations.append(result)
        # Get reservations matching the MAC Address, if given
        if mac is not None:
            logger.info(
                'MAC Address provided ({}), searching for reservations'.format(
                    args.mac_addr))
            results = search_mac(bam, mac)
            logger.debug(json.dumps(results, indent=2, sort_keys=True))
            candidate_reservations += results

        # Determine which of the matched reservations qualify for deletion
        logger.info(
            'Checking all gathered reservations for deletion eligibility')
        for reservation in candidate_reservations:
            reservation = pybluecat.entity_to_json(reservation)
            # Skip NULL objects, can happen when MAC searches turn up nothing
            if reservation['properties'] is None:
                logger.info('Ignoring NULL object')
                continue
            # Gather details about the ip_object
            res_name = reservation['name']
            res_ip = reservation['properties']['address']
            if 'macAddress' in reservation['properties']:
                res_mac = reservation['properties']['macAddress']
            else:
                res_mac = ''
            logger.info('NAME: {}, IP: {}, MAC: {}'.format(
                res_name, res_ip, res_mac))
            # If IP Object state is not "DHCP_RESERVED" DO NOT DELETE
            if reservation['properties']['state'] != 'DHCP_RESERVED':
                logger.info(
                    'Reservation ineligible for deletion, ignoring objects with state: {}'
                    .format(reservation['properties']['state']))
                continue
            # Ignore duplicate objects from the multiple searches
            if res_ip in ips_seen_so_far:
                logger.info(
                    'Duplicate entry for IP {}, skipping'.format(res_ip))
                continue
            # If --match_all is set, ensure ALL set fields match the reservation
            if args.match_all:
                # If --hostname is set and doesn't match, skip to next reservation
                if hostname is not None and res_name.lower() != hostname.lower(
                ):
                    logger.info(
                        'Reservation doesn\'t match --hostname filter with --match_all set, ineligible for deletion'
                    )
                    continue
                # If --ip_addr is set and doesn't match, skip to next reservation
                if ip is not None and res_ip != str(ip):
                    logger.info(
                        'Reservation doesn\'t match --ip_addr filter with --match_all set, ineligible for deletion'
                    )
                    continue
                # If --mac_addr is set and doesn't match, skip to next reservation
                if mac is not None and format_mac(res_mac) != mac:
                    logger.info(
                        'Reservation doesn\'t match --mac_addr filter with --match_all set, ineligible for deletion'
                    )
                    continue
            # Determine the Network of the IP Address
            try:
                logger.info('Getting Network info from ip: {}'.format(res_ip))
                net_entity = bam.get_network(res_ip)
                net_obj = pybluecat.entity_to_json(net_entity)
                network = ip_network(unicode(net_obj['properties']['CIDR']))
                logger.debug(json.dumps(net_obj, indent=2))
            except pybluecat.exceptions.BluecatError as e:
                # This would be really odd... But try to continue with the other reservations
                logger.error(
                    'Could not determine the target network or network did not exist'
                )
                logger.error(e.message)
                continue
            # Continue on with either all reservations (if --match_any) or whatever is left from the --match_all block
            off_limits, error_message = is_ip_off_limits(res_ip, network)
            if off_limits:
                logger.info('Reservation ineligible for deletion: {}'.format(
                    error_message))
                continue
            # Finally, mark the reservation for deletion
            reservations_to_delete.append((reservation, net_obj))
            ips_seen_so_far.append(res_ip)

        # Start deleting!
        for reservation, net_obj in reservations_to_delete:
            logger.info('Deleting DHCP Reservation: {}'.format(
                json.dumps(reservation, indent=2, sort_keys=True)))
            response = bam.delete(reservation['id'])
            output_object['deleted_reservations'].append(reservation)
            output_object['message'].append('DELETED: {}, {}'.format(
                reservation['properties']['address'], reservation['name']))
            deleted_reservations.append((reservation, net_obj))
        if len(deleted_reservations) > 0:
            deploy_needed = True
            output_object[
                'status'] = 'Reservations have been deleted, config NOT deployed'
        else:
            output_object['status'] = 'No Reservations were Deleted'

        server_set = set()
        # Deploy DHCP changes if no_deploy flag isn't set
        if deploy_needed and not args.no_deploy:
            # Build unique set of DHCP servers
            logger.info(
                'Gathering list of BAM servers to push updated configs to')
            for reservation, net_obj in deleted_reservations:
                server_set = server_set | bam.queue_servers(net_obj['id'])
            # Deploy changes to all servers in set
            logger.info('Deploying Config changes')
            for server in server_set:
                logger.info('Deploying changes to server: {}'.format(
                    str(server)))
                bam.deploy_server_services(server, 'DHCP')
                output_object['message'].append(
                    'Server {} queued for deployment'.format(str(server)))
            # Monitor the deployment through completion unless no_wait flag is set
            if not args.no_wait:
                logger.info('Waiting for deployment to finish')
                bam.monitor_server_deployment(server_set)
                output_object[
                    'status'] = 'Reservations have been deleted, configs have been deployed'
                logger.info('Deployment finished')
            else:
                output_object[
                    'status'] = 'Reservations have been deleted, configs queued for deployment'
                logger.info('Monitoring of deployment is being skipped')

    # Finally output the IP info
    print(json.dumps(output_object, indent=2, sort_keys=True))
예제 #7
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('hostname', help='hostname')
    parser.add_argument('-c',
                        '--creds',
                        help='path to file containing credentials')
    group_ME = parser.add_mutually_exclusive_group(required=True)
    group_ME.add_argument('-n',
                          '--network',
                          help='network address within desired subnet')
    group_ME.add_argument('-e',
                          '--environment',
                          help='environment from which to choose a network')
    parser.add_argument('-l',
                        '--loglevel',
                        choices=['warning', 'info', 'debug'],
                        help='enable debugging')
    args = parser.parse_args()

    NETWORK_ENVS = {
        'lab':
        [ip_network(u'10.168.131.0/24'),
         ip_network(u'10.168.161.0/24')],
        'dev': [ip_network(u'10.57.128.0/23')],
        'test': [ip_network(u'10.57.144.0/23')],
        'stage': [ip_network(u'10.57.160.0/23')],
        'prod-ctis':
        [ip_network(u'10.7.96.0/23'),
         ip_network(u'10.7.98.0/23')],
        'prod-brad':
        [ip_network(u'10.107.96.0/23'),
         ip_network(u'10.107.98.0/23')],
        'prod-both':
        [ip_network(u'10.200.112.0/24'),
         ip_network(u'10.200.113.0/24')],
        'fmt': [ip_network(u'10.57.136.0/30'),
                ip_network(u'10.57.136.4/30')]
    }

    if args.loglevel:
        level = getattr(logging, args.loglevel.upper())
        logging.basicConfig(level=level)

    hostname = args.hostname.lower()
    creds = pybluecat.get_creds(args.creds)
    c = pybluecat.BAM(creds['hostname'], creds['username'], creds['password'])

    # Get Networks List
    if args.network:
        netAddr = args.network.split('/')[0]
        netObj = c.get_network(netAddr)
        netObj = c.entity_to_json(netObj)
        networks = [ip_network(netObj['properties']['CIDR'])]
    elif args.environment:
        import requests
        base_url = 'http://infradevapi.spectrum-health.org/infrastructure/'
        env = args.environment.lower()
        url = base_url + env
        proxy = {'http': None, 'https': None}
        if 'dmz' in args.environment:
            dhcp_offset = 0
        try:
            r = requests.get(url, proxies=proxy)
            logging.info(r.request.url)
            logging.info(r.status_code)
            logging.info(r.content)
        except:
            print('Environment Not Found. No Network Available.')
            exit()
        networks = [
            ip_network(net['netaddr'] + '/' + net['netmask'], strict=False)
            for net in json.loads(r.text)[env]
        ]
    logging.info('Networks: {}'.format(str(networks)))

    foundIP = False
    # Check for existing IP reservations in target networks
    results = c.search_by_object_types(hostname, 'IP4Address', 0, 1000)
    logging.info(str(results))
    for result in results:
        temp = c.entity_to_json(result)
        for net in networks:
            if ip_address(temp['properties']['address']) in net:
                foundIP = True
                ipObj = temp
                networks = [net]
                logging.info('Found IP already in existence: {}'.format(
                    json.dumps(ipObj, indent=2)))
                break
    for network in networks:
        logging.info('Working through network: {}'.format(str(network)))
        # Get Network Object and set dhcp_offset based on CIDR
        netObj = c.get_network(str(network.network_address))
        netObj = c.entity_to_json(netObj)
        if network.prefixlen > 24:
            dhcp_offset = 0
        else:
            dhcp_offset = 30
        logging.info('DHCP-Offsest: {}'.format(str(dhcp_offset)))
        # Ensure IPs in the offset are 'reserved'
        while not foundIP:
            logging.info('Checking Status of Offset Addreses')
            ip = c.get_next_ip_address(netObj['id'])
            logging.info('Address {}'.format(str(ip)))
            if ip is None or ip == '':
                break
            elif network.network_address + dhcp_offset >= ip_address(
                    unicode(ip)):
                c.assign_ip_address('', ip, '', 'MAKE_RESERVED', '')
                logging.info('Setting IP Address as RESERVED: {}'.format(ip))
            else:
                break
        # If an existing IP has not been found yet, start working through
        # every free IP in the BAM Network until one is assigned or net is
        # exhausted
        if not foundIP:
            logging.info('Determining next available IP Address')
            while True:
                ipObj = c.assign_next_ip_address(netObj['id'], hostname)
                # None as a result indicates network has no next IP, end loop
                if ipObj['id'] == 0:
                    break
                ipObj = c.entity_to_json(ipObj)
                logging.info('IP Address free in BAM: {}'.format(
                    ipObj['properties']['address']))
                # Check if IP has existing PTR record, if True, write it to BAM, try next IP
                ptr = dns_PTR_exists(ipObj['properties']['address'])
                if ptr:
                    logging.info(
                        'PTR Record found for Address: {}'.format(ptr))
                    ipObj['name'] = ptr.split('.')[0]
                    ipObj = c.json_to_entity(ipObj)
                    c.update(ipObj)
                # Try to Ping the IP address, if response, log in BAM, try next IP
                elif ping(ipObj['properties']['address']):
                    logging.info('Address responded to ping')
                    ipObj['name'] = 'IN-USE: something pinged'
                    ipObj = c.json_to_entity(ipObj)
                    c.update(ipObj)
                # Finally, reserve the IP in BAM for the hostname
                else:
                    logging.info('Address doesn\'t ping or have PTR record')
                    foundIP = True
                    break
        # If an IP has been found, either new or existing, return results and exit
        if foundIP:
            network = ip_network(unicode(netObj['properties']['CIDR']))
            output = {
                'ip_addr': ipObj['properties']['address'],
                'gateway': str(network.network_address + 1),
                'net_mask': str(network.netmask),
                'net_name': netObj['name'],
                '_ipobj': ipObj,
                '_netobj': netObj
            }
            print(json.dumps(output, sort_keys=True, indent=4))
            c.logout()
            exit()
    if not foundIP:
        print('No Addresses Available.')
        exit(1)
예제 #8
0
def main():
    # Get and Parse all CLI arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('cidr',
                        nargs='+',
                        help='CIDR(s) to act as root for enumeration')
    parser.add_argument('-a',
                        '--append',
                        help='omit header for appending to previous output',
                        action='store_true')
    parser.add_argument('-c',
                        '--creds',
                        help='path to file containing credentials')
    parser.add_argument('--minimum',
                        type=int,
                        default=32,
                        help='Minimum size (inclusive) of subnets, e.g. "24"')
    parser.add_argument('--maximum',
                        type=int,
                        default=0,
                        help='Maximum size (inclusive) of subnets, e.g. "24"')
    parser.add_argument('--ignore_blocks',
                        action='store_true',
                        help='omits IP4Blocks from output')
    parser.add_argument(
        '--cidr_blacklist',
        help='filepath to list of network blocks to not enumerate')
    kw_group = parser.add_mutually_exclusive_group()
    kw_group.add_argument(
        '--keyword_blacklist',
        help='filepath to list of name keywords to not enumerate')
    kw_group.add_argument(
        '--keyword_whitelist',
        help='filepath to list of name keywords to not enumerate')
    args = parser.parse_args()

    # Initialize the Global Ignore Blocks flag
    global IGNORE_BLOCKS
    IGNORE_BLOCKS = args.ignore_blocks
    # Initialize the Global CIDR Minimum size
    global MINIMUM
    MINIMUM = args.minimum
    # Initialize the Global CIDR Maximum size
    global MAXIMUM
    MAXIMUM = args.maximum
    # Initialize the Global CIDR Blacklist
    global CIDR_BLACKLIST
    if args.cidr_blacklist is not None:
        try:
            with open(args.cidr_blacklist) as f:
                CIDR_BLACKLIST = [
                    line.strip().split()[0] for line in f.readlines()
                    if line.strip() != ''
                ]
        except Exception:
            sys.exit('blacklist {} could not be parsed'.format(
                args.cidr_blacklist))
    else:
        CIDR_BLACKLIST = []
    # Initialize the Global Keyword Blacklist
    global KW_BLACKLIST
    if args.keyword_blacklist is not None:
        try:
            with open(args.keyword_blacklist) as f:
                KW_BLACKLIST = [
                    line.strip().split()[0].lower() for line in f.readlines()
                    if line.strip() != ''
                ]
        except Exception:
            sys.exit('blacklist {} could not be parsed'.format(
                args.keyword_blacklist))
    else:
        KW_BLACKLIST = []
    # Initialize the Global Keyword Whitelist
    global KW_WHITELIST
    if args.keyword_whitelist is not None:
        try:
            with open(args.keyword_whitelist) as f:
                KW_WHITELIST = [
                    line.strip().split()[0].lower() for line in f.readlines()
                    if line.strip() != ''
                ]
        except Exception:
            sys.exit('whitelist {} could not be parsed'.format(
                args.keyword_blacklist))
    else:
        KW_WHITELIST = ['']

    # Get Credentials
    creds = pybluecat.get_creds(args.creds)
    # Create the Bluecat sessions
    with pybluecat.BAM(creds['hostname'], creds['username'],
                       creds['password']) as c:
        config = c.get_entity_by_name(0, 'Spectrum Health', 'Configuration')
        # Output headers if append flag not set
        if not args.append:
            print('Network,Name,Type,VLAN,Location')
        # Walk Bluecat from each starting block
        for cidr in args.cidr:
            startBlock = find_start_block(c, cidr, config['id'])
            if not IGNORE_BLOCKS:
                print(get_line(c, startBlock))
            walk_networks(c, startBlock)