Ejemplo n.º 1
0
def execute(opts, net_cmd, net_config, device_commit, use_textfsm):
    """
    This function setups up a netmiko connection and performs the different commands.
    The results are returned in a json document
    :param opts:
    :param net_cmd:
    :param net_config:
    :param device_commit: used with net_config cmds
    :param use_textfsm: used with net_cmd to specify the results should be formatted through TextFSM
    :return: json results such as:
      {
        'status': 'success'|'failure',
        'reason': xx,
        'send_command': xx,
        'send_result': xx,
        'config_command': xx,
        'config_result': xx
      }
    """
    result = {}
    connection = None
    try:
        # if secret is specified, use enable_mode
        bEnable_mode = len(opts.get('secret', '')) > 0

        connection = ConnectHandler(**opts)

        if bEnable_mode:
            connection.enable()

        # standard commands to execute
        if net_cmd:
            result['send_command'] = net_cmd
            send_result = connection.send_command(net_cmd,
                                                  use_textfsm=use_textfsm)
            result['send_result'] = send_result

        # configuration commands to execute
        if net_config:
            result['config_command'] = net_config
            config_result = connection.send_config_set(net_config.split("\n"))
            result['config_result'] = config_result
            if device_commit:
                connection.commit()

        result['status'] = 'success'
    except Exception as err:
        result['status'] = 'failure'
        result['reason'] = str(err)

    finally:
        if connection:
            if bEnable_mode:
                connection.exit_enable_mode()

            connection.disconnect()

    return result
Ejemplo n.º 2
0
def enable_netconf(net_device):
    print("{} Connecting to {}".format(time.asctime(), net_device['ip']))
    junos_device = ConnectHandler(**net_device)
    configure = junos_device.config_mode()  #eq edit or configuration mode
    print("{} Applying configuration to {}".format(time.asctime(),
                                                   net_device['ip']))
    set_netc_ssh = junos_device.send_command(
        "delete system services netconf ssh")
    print("{} Commiting config to {}".format(time.asctime(), net_device['ip']))
    junos_device.commit(comment='Enable Netconf Service', and_quit=True)
    print("{} Closing connection to {}".format(time.asctime(),
                                               net_device['ip']))
    junos_device.disconnect()
Ejemplo n.º 3
0
def enable_netconf(net_device):
    print("{} Connecting to {}".format(time.asctime(), net_device['ip']))
    junos_device = ConnectHandler(**net_device)
    configure = junos_device.config_mode()
    print("{} Applying configuration to {}".format(time.asctime(),
                                                   net_device['ip']))
    setssns = junos_device.send_command("set system services netconf ssh")
    print("{} Committing configuration to {}".format(time.asctime(),
                                                     net_device['ip']))
    junos_device.commit(comment='Enabled NETCONF service', and_quit=True)
    print("{} Closing connection to {}".format(time.asctime(),
                                               net_device['ip']))
    junos_device.disconnect()
Ejemplo n.º 4
0
Archivo: Lib.py Proyecto: ankver20/API
def ConfigP(HOSTNAME, login_details):

    print('\nDevice to be configured= ' + login_details['ip'] + '\n')
    # push config on device and create log
    # net_connect = ConnectHandler(device_type=deviceType, ip=dip, username=username, password=pw, port=port)
    net_connect = ConnectHandler(**login_details)
    #output1 = net_connect.send_config_set(config)

    # get config file from Config folder
    file_path = os.path.dirname(os.path.realpath(__file__))
    print(file_path)
    config_file = file_path + '\\Config\\' + HOSTNAME + '.cfg'

    output1 = net_connect.send_config_from_file(config_file)
    time.sleep(5)
    output2 = net_connect.commit()
    time.sleep(4)
    output3 = net_connect.exit_config_mode()
    output4 = net_connect.disconnect()

    c = ('\n----' + login_details['ip'] + '----\n' + '\n' + output1 + output2 +
         output3 + '\n' + '\n---- END ----\n')
    print(c)
    deviceLog(c)
    time.sleep(1)
Ejemplo n.º 5
0
def send_commands(devices: list, cmds: str) -> list:
    """
    Send commands to specified device.

    :param list devices: List of dictionaries representing each device
    :param str cmds: String containing the commands to send
    :return list: List containing the status of each device configured
    """
    log.info("Preparing to send onboarding commands to devices...")
    statuses = list()
    for device in devices:
        status = {"device": device['ip'], "status": "pending", "error": None}
        log.info(f"Sending commands to {device['ip']}...")
        try:
            net_connect = ConnectHandler(**device)
            net_connect.find_prompt()
            o = net_connect.send_config_set(config_commands=cmds,
                                            exit_config_mode=False)
            log_cmds.debug(f"Output for {device['ip']} config: {o}")
            o = net_connect.commit(and_quit=True)
            log_cmds.debug(f"Output for {device['ip']} commit: {o}")
            log.info(f"Successfully sent commands to {device['ip']}!")
            status['status'] = "success"
        except Exception as e:
            log.error(f"Failed sending commands to {device['ip']}!")
            log.error(f"Error sending commands: {e}")
            status['status'] = "failed"
            status['error'] = str(e)
            continue
        statuses.append(status)
    return statuses
Ejemplo n.º 6
0
def enable_netconf(net_device):
    print("{} Connecting to {}".format(time.asctime(), net_device['ip']))
    junos_device = ConnectHandler(**net_device)

    configure = junos_device.config_mode()
    print("{} Applying configuration to {}".format(time.asctime(),
                                                   net_device['ip']))

    junos_device.send_command("delete interfaces ge-0/0/2 disable")

    print("{} Committing configuration to {}".format(time.asctime(),
                                                     net_device['ip']))
    junos_device.commit(comment='delete ge0/0/2 disable', and_quit=True)

    print("{} Closing connecting to {}".format(time.asctime(),
                                               net_device['ip']))
    junos_device.disconnect()
def gethostname(device):
    dev = {
        'device_type': platform,
        'ip': device,
        'username': username,
        'secret': password,
        'password': password,
        'global_delay_factor': 4,
        'verbose': True,
    }

    device = ConnectHandler(**dev)
    device.enable()
    hostname = device.send_config_set(command)
    hostname += device.commit(confirm=True, confirm_delay=5)
    time.sleep(30)
    hostname += device.commit(check=True)
    return hostname
Ejemplo n.º 8
0
def net_connect(request):
    """
    Create the SSH connection to the remote device

    Return the netmiko connection object
    """
    device_under_test = request.config.getoption("test_device")
    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
    device = test_devices[device_under_test]
    device["verbose"] = False
    conn = ConnectHandler(**device)
    # Temporarily set the hostname
    if device_under_test == "cisco3_long_name":
        conn.send_config_set("hostname cisco3-with-a-very-long-hostname")
    elif device_under_test == "cisco_xr_long_name":
        conn.send_config_set("hostname iosxr3-with-very-long-hostname-plus")
        conn.commit()
        conn.exit_config_mode()
    return conn
Ejemplo n.º 9
0
def setup_module(module):

    module.EXPECTED_RESPONSES = {
        'enable_prompt' : 'RP/0/0/CPU0:XRv-1#',
        'base_prompt'   : 'RP/0/0/CPU0:XRv-1',
        'interface_ip'  : '169.254.254.181',
        'config_mode'   : '(config)'
    }

    show_ver_command = 'show version'
    commit_history_cmd = 'show configuration commit list'
    module.basic_command = 'show ipv4 int brief'

    net_connect = ConnectHandler(**cisco_xr)

    module.show_version = net_connect.send_command(show_ver_command)
    module.show_ip = net_connect.send_command(module.basic_command)

    net_connect.enable()
    module.enable_prompt = net_connect.find_prompt()

    current_commit_history = net_connect.send_command(commit_history_cmd)

    # get the current 10 digit commit Label ID 
    module.current_commit = current_commit_history.split('\n')[4].split()[1]
    module.config_mode = net_connect.config_mode()
    config_commands = ['logging monitor warning', 'logging buffered 30720100', 'logging console errors']
    net_connect.send_config_set(config_commands)
    net_connect.commit()

    # get the new 10 digit commit Label ID 
    new_commit_history = net_connect.send_command(commit_history_cmd)
    module.new_commit = new_commit_history.split('\n')[4].split()[1]

    module.config_commands_output = net_connect.send_command("show run | inc logging")

    net_connect.disconnect()
Ejemplo n.º 10
0
def main():
    nc = ConnectHandler(**cros)

    output = nc.send_command("show interface configuration brief")
    print(output)

    output = nc.send_config_set([
        "interface physical 7/1/3",
        "admin-status up",
        "ipv4 address 1.1.1.1 prefix 24",
    ])
    print(output)

    output = nc.commit()
    print(output)

    output = nc.send_command("show interface configuration brief")
    print(output)
Ejemplo n.º 11
0
    connect = ConnectHandler(device_type='juniper',
                             ip=devices,
                             username=username,
                             password=password,
                             port=22,
                             global_delay_factor=2)
    connect.find_prompt()
    time.sleep(1)
    print('Connect Successfully')
    connect.config_mode()
    print(connect.send_config_set('rollback 0'))
    connect.send_config_from_file(config)
    print(connect.send_config_set('show | compare'))
    print(connect.send_config_set('commit check'))
    x = raw_input(str('Proceed to commit(Y or N) : '))
    if x == 'Y':
        print('Commiting')
        connect.commit()  #connect.send_config_set('commit')
        print('Below configuration hasbeen modified to device')
        print('==================')
        print(connect.send_config_set('show | compare rollback 1'))
        connect.exit_config_mode()
        connect.disconnect()
    else:
        connect.send_config_set('rollback 0')
        connect.commit()
        connect.disconnect()
end_time = datetime.now()
print("Total time: {}".format(end_time - start_time))
print('Completed Successfully!!')
Ejemplo n.º 12
0
def create_ospf(n: str) -> list:
    return [
        f"set interfaces ge-0/0/1 unit 0 family inet address 192.168.0.{n}/30",
        f"set interfaces lo0 unit 0 family inet address 10.0.0.{n}/32",
        f"set routing-options router-id 10.0.0.{n}",
        "set protocols ospf area 0.0.0.0 interface lo0.0 passive",
        "set protocols ospf area 0.0.0.0 interface ge-0/0/1.0"
    ]


if __name__ == "__main__":
    vsrx1 = create_conn("2201")
    vsrx2 = create_conn("2202")
    vsrx1_conn = ConnectHandler(**vsrx1)
    vsrx2_conn = ConnectHandler(**vsrx2)
    vsrx1_conn.send_config_set(create_ospf("1"))
    vsrx2_conn.send_config_set(create_ospf("2"))
    vsrx1_conn.commit()
    vsrx2_conn.commit()
    vsrx1_conn.disconnect()
    vsrx2_conn.disconnect()

    vsrx1 = create_conn("2201")
    vsrx2 = create_conn("2202")
    vsrx1_conn = ConnectHandler(**vsrx1)
    vsrx2_conn = ConnectHandler(**vsrx2)
    print(vsrx1_conn.send_command(SHOW_OSPF))
    print(vsrx2_conn.send_command(SHOW_OSPF))
    vsrx1_conn.disconnect()
    vsrx2_conn.disconnect()
Ejemplo n.º 13
0
class BaseNode(object):
    def __init__(self, ip, hostname, username, password, platform, type):
        self.ip = ip
        self.hostname = hostname
        self.username = username
        self.password = password
        self.platform = platform
        self.type = type
        self.password_decrypt = base64.b64decode(self.password)

    def connect(self):
        if (self.type == 'switch'):
            self.net_connect = ConnectHandler(self.ip,
                                              self.hostname,
                                              self.username,
                                              self.password_decrypt,
                                              self.get_secret(),
                                              device_type=self.get_device())
        elif (self.type == 'vfirewall'):
            self.net_connect = ConnectHandler(self.ip,
                                              self.hostname,
                                              self.username,
                                              self.password_decrypt,
                                              self.get_secret(),
                                              port=22,
                                              device_type=self.get_device())
        else:
            self.net_connect = ConnectHandler(self.ip,
                                              self.hostname,
                                              self.username,
                                              self.password_decrypt,
                                              self.get_secret(),
                                              device_type=self.get_device())

    def get_secret(self):
        enable_get_secret = ''
        if (self.location() == 'wdstk'):
            enable_get_secret = base64.b64decode(self.password)
        elif (self.location() == 'ktch'):
            enable_get_secret = base64.b64decode(self.password)

        return enable_get_secret

    def location(self):
        datacenter_location = ''
        if (self.type == 'firewall'):
            location_list = self.hostname.split('-')
            datacenter_location = location_list[3]

        elif (self.type == 'switch' or self.type == 'router'):
            location_list = self.hostname.split('.')
            datacenter_location = location_list[3]

        return datacenter_location

    def get_device(self):
        device_attribute = ''
        if (self.type == 'router' or self.type == 'switch'):
            device_attribute = 'cisco_ios'

        elif (self.type == 'firewall'):
            device_attribute = 'cisco_asa'

        elif (self.type == 'vfirewall'):
            device_attribute = 'juniper'

        return device_attribute

    def push_cfgs(self, commands):

        self.connect()
        output = self.net_connect.enable()
        if (self.platform == 'cisco'):
            output = self.net_connect.send_config_set(commands)
            print output
        if (self.platform == 'juniper'):
            output = self.net_connect.send_config_set(commands,
                                                      exit_config_mode=False)
            self.net_connect.commit(and_quit=True)
            print output
        self.net_connect.disconnect()

    def exec_command(self, command):

        self.connect()
        output = self.net_connect.send_command(command)
        output = output.replace('\n', '\n{}: '.format(self.hostname))
        output = re.sub(r'^', '{}: '.format(self.hostname), output)
        print("{}".format(output))
        print("")
        self.net_connect.disconnect()

    def get_config(self, command):

        command = 'show running-config'
        f = open("/backup-configs/{}".format(self.hostname) + ".conf", "w")
        self.connect()
        output = self.net_connect.send_command_expect("show running-config")
        f.write(output)
        f.close()
        self.net_connect.disconnect()

    def get_diff(self, commands):

        f = open("/diff-configs/{}".format(self.hostname) + ".conf", "w")
        self.connect()
        output = self.net_connect.send_config_set(commands)
        #		print output
        f.write(output)
        f.close()
        self.net_connect.disconnect()
Ejemplo n.º 14
0
class BaseNode(object):

	def __init__(self,created_at,created_by,domain_name,hardware_vendor,lifecycle_status,location_name,mgmt_ip4,mgmt_con_ip4,mgmt_oob_ip4,mgmt_snmp_community4,name,platform_name,oncall_team,opersys,software_image,software_version,type,role_name,serial_num,status,updated_at,updated_by):

		self.created_at = created_at
		self.created_by = created_by
		self.domain_name = domain_name
		self.hardware_vendor = hardware_vendor 
		self.lifecycle_status = lifecycle_status
		self.location_name = location_name
		self.mgmt_con_ip4 = mgmt_con_ip4
		self.mgmt_ip4 = mgmt_ip4
		self.mgmt_oob_ip4 = mgmt_oob_ip4
		self.mgmt_snmp_community4 = mgmt_snmp_community4
		self.name = name
		self.password = os.environ.get('PASSWORD')
		self.platform_name = platform_name
		self.oncall_team = oncall_team
		self.opersys = opersys
		self.role_name = role_name 
		self.serial_num = serial_num
		self.software_image = software_image
		self.software_version = software_version
		self.status = status
		self.type = type
		self.updated_at = updated_at
		self.updated_by = updated_by
		self.username = os.environ.get('USERNAME')

	def connect(self):
		self.net_connect = ConnectHandler(self.mgmt_ip4,self.name,self.username,self.password,self.password,device_type=self.get_device_type())
			
	def scpconnect(self):
		self.connect()
		self.scp_connect = SCPConn(self.net_connect)
		
	def location(self):
		datacenter_location = ''
		if (self.type == 'firewall'):
			location_list = self.name.split('-')	
			datacenter_location = location_list[3]

		elif (self.type == 'switch' or self.type == 'router'):
			location_list = self.name.split('.')	
			datacenter_location = location_list[3]

		return datacenter_location

	def get_device_type(self):

		device_type = {
				'ASA5510' : 'cisco_asa',
				'WS-C3750G-24TS-1U' : 'cisco_ios',
				'f5linux' : 'f5_linux',
				'ltm' : 'f5_ltm',
				'tmsh' : 'f5_tmsh',
				'firefly-perimeter' : 'juniper',
				'juniper_junos' : 'juniper_junos',
				'vyattavyos' : 'vyatta_vyos',
				'vyos' : 'vyos'
		}
	
		return device_type['{}'.format(self.platform_name)]

	def push_cfgs(self,commands):
		self.connect()
		output = self.net_connect.enable()
		if self.hardware_vendor == 'cisco' and self.opersys == 'ios':
			output = self.net_connect.send_config_set(commands, exit_config_mode=True)
			save = self.net_connect.send_command('write memory')
#			print(output)
#			print(save)
		elif self.hardware_vendor == 'cisco' and self.opersys == 'asa':
			output = self.net_connect.send_config_set(commands, exit_config_mode=True)
			save = self.net_connect.send_command('write memory')
#			print(output)
#			print(save)
		elif self.hardware_vendor == 'cisco' and self.opersys == 'nxos':
			output = self.net_connect.send_config_set(commands, exit_config_mode=True)
			save = self.net_connect.send_command('copy running-config startup-config')
#			print(output)
#			print(save)
		elif self.hardware_vendor == 'juniper':
			output = self.net_connect.send_config_set(commands, exit_config_mode=False)
			self.net_connect.commit(and_quit=True)
#			print(output)
		elif self.hardware_vendor == 'vyatta':
			output = self.net_connect.send_config_set(commands, exit_config_mode=False)
			self.net_connect.commit()
#			print(output)
		elif self.hardware_vendor == 'f5':
			output = self.net_connect.send_config_set(commands,enter_config_mode=False,exit_config_mode=False)
			save = self.net_connect.send_command('save sys config')
#			print(output)
#			print(save)
		self.net_connect.disconnect()

	def pull_cfgs(self,command):
		scp_flag = False
		method = 'pull_cfgs'
		if self.hardware_vendor == 'cisco' and self.opersys == 'ios':
			command = 'show running-config | exclude ntp clock-period'
		elif self.hardware_vendor == 'cisco' and self.opersys == 'nxos':
			command = 'show running-config | exclude Time'
		elif self.hardware_vendor == 'cisco' and self.opersys == 'asa':
			command = 'show running-config'
		elif self.hardware_vendor == 'juniper':
			command = 'show configuration'
		elif(self.hardware_vendor == 'vyatta'):
			command = 'show configuration commands'
		elif self.hardware_vendor == 'f5':
			command = 'list ltm one-line'
			self.scpconnect()
			self.write_to_file(command)
			scp_flag = True
			self.scp_connect.scp_get_file('/var/local/ucs/config.ucs', '{}/backup-configs/{}'.format(self.get_home_directory(),self.name))
			self.scp_connect.close()
			self.net_connect.disconnect()
		if self.hardware_vendor != 'juniper' or self.hardware_vendor != 'f5':
			self.connect()
			self.write_to_file(command,scp_flag,method)
			self.net_connect.disconnect()

	def exec_cmd(self,command):
		self.connect()
		output = self.net_connect.send_command(command)
		output = output.replace('\n','\n{}: '.format(self.name))
		output = re.sub(r'^','{}: '.format(self.name),output)
		print ('{}'.format(output))
		print('')
		self.net_connect.disconnect()

	def get_home_directory(self):
		home_directory = os.getenv('HOME')

		return home_directory

	def get_config(self,command):
		scp_flag = False
		method = 'get_config'
		if self.hardware_vendor == 'cisco':
			command = 'show running-config'
		elif self.hardware_vendor == 'f5':
			command = 'list one-line'
		self.connect()
		self.write_to_file(command,scp_flag,method)
		self.net_connect.disconnect()

	def get_diff(self,commands):
		scp_flag = False
		method = 'get_diff'
		self.connect()
		self.write_to_file(commands,scp_flag,method)
		self.net_connect.disconnect()

	def get_subdir(self,scp_flag):
		if self.hardware_vendor == 'f5' and scp_flag:
			sub_dir = 'ucs'
		else:
			sub_dir = 'configs'
		return sub_dir

	def write_to_file(self,command,scp_flag,method):
		if method == 'pull_cfgs':
			extention = ''
			if self.hardware_vendor == 'juniper' and 'display set' in command:
				extention = '.set'
			else:
				extention = '.conf'
			self.check_and_mkdir(scp_flag,method)
			with open('{}/backup-configs/{}/{}{}'.format(self.get_home_directory(),self.get_subdir(scp_flag),self.name,extention), "w") as file:
				output = self.net_connect.send_command(command)
				file.write(output)
				file.close()
		elif method == 'get_config':
			self.check_and_mkdir(scp_flag,method)
			with open('{}/backup-configs/{}'.format(self.get_home_directory(),self.name) + ".conf", "w") as file:
				output = self.net_connect.send_command(command)
				file.write(output)
				file.close()
		elif method == 'get_diff':
			self.check_and_mkdir(scp_flag,method)
			with open('{}/diff-configs/{}'.format(self.get_home_directory(),self.name) + ".conf", "w") as file:
				output = self.net_connect.send_config_set(command)
				file.write(output)
				file.close()

	def check_and_mkdir(self,scp_flag,method):
		if method == 'pull_cfgs':
			os.makedirs('{}/backup-configs/{}/'.format(self.get_home_directory(),self.get_subdir(scp_flag)),exist_ok=True)
		elif method == 'get_config':
			os.makedirs('{}/backup-configs/{}'.format(self.get_home_directory(),self.name),exist_ok=True)	
		elif method == 'get_diff':
			os.makedirs('{}/diff-configs/{}'.format(self.get_home_directory(),self.name),exist_ok=True)
Ejemplo n.º 15
0
Pynet2ExitConfig = Pynet2Connect.exit_config_mode()
JuniperExitConfig = JuniperConnect.exit_config_mode()
print "\n", Pynet1ExitConfig, "\n", Pynet2ExitConfig, "\n", JuniperExitConfig, "\n"


print "Checking interfaces' IPs..."
time.sleep(2)
Pynet1IpInt = Pynet1Connect.send_command('show ip int brief')
Pynet2IpInt = Pynet2Connect.send_command('show ip int brief')
JuniperIpInt = JuniperConnect.send_command('show interfaces terse | match "up    up"')
print "\n", Pynet1IpInt, "\n\n", Pynet2IpInt, "\n\n", JuniperIpInt, "\n"


print "Sending a few config commands to the Juniper..."
time.sleep(2)
JuniperConfig = JuniperConnect.config_mode()
JuniperConfigCommands = ['set interfaces vlan unit 0 description "Management Vlan 0"',
                            'set system host-name pynet-juniper-srx1']
JuniperConfigChange = JuniperConnect.send_config_set(JuniperConfigCommands)

JuniperConfigCheckCommand = ['show | compare']
JuniperConfigChangeCheck = JuniperConnect.send_config_set(JuniperConfigCheckCommand)
print "Displaying the change below...\n"
print JuniperConfigChangeCheck
time.sleep(1)

print "\nCommiting the change..."
JuniperConnect.commit()

time.sleep(60)
    'device_type': 'juniper',
    'ip': '127.0.0.1',
    'username': '******',
    'password': '******',
    'port': 2222,
    'verbose': False
}

routers = [rtr1, rtr2]

for dev in routers:
    net_connect = ConnectHandler(**dev)
    print("************Show commands*************")
    output1 = net_connect.send_command("show config| display set")
    output2 = net_connect.send_command(
        "show system information | match Hostname:")
    print(output1)
    print(output2)
    print("*******" * 10)
    print("***********Config mode********")
    net_connect.config_mode()
    config_output1 = net_connect.send_command(
        "set interfaces et-0/0/0 description netmiko_juniper_test_script")
    print(config_output1)
    #Commit commands
    commit = net_connect.commit(and_quit=True)
    print(commit)
    print("************Show command*************")
    output3 = net_connect.send_command("show interfaces description")
    print(output3)
Ejemplo n.º 17
0
class PANOSDriver(NetworkDriver):

    def __init__(self, hostname, username, password, timeout=60, optional_args=None):
        self.hostname = hostname
        self.username = username
        self.password = password
        self.timeout = timeout
        self.loaded = False
        self.changed = False
        self.device = None
        self.ssh_device = None
        self.ssh_connection = False
        self.merge_config = False

        if optional_args is None:
            optional_args = {}

        netmiko_argument_map = {
            'port': None,
            'verbose': False,
            'use_keys': False,
            'key_file': None,
            'ssh_strict': False,
            'system_host_keys': False,
            'alt_host_keys': False,
            'alt_key_file': '',
            'ssh_config_file': None,
        }

        fields = netmiko_version.split('.')
        fields = [int(x) for x in fields]
        maj_ver, min_ver, bug_fix = fields
        if maj_ver >= 2:
            netmiko_argument_map['allow_agent'] = False
        elif maj_ver == 1 and min_ver >= 1:
            netmiko_argument_map['allow_agent'] = False

        # Build dict of any optional Netmiko args
        self.netmiko_optional_args = {}
        for k, v in netmiko_argument_map.items():
            try:
                self.netmiko_optional_args[k] = optional_args[k]
            except KeyError:
                pass
        self.api_key = optional_args.get('api_key', '')

    def open(self):
        try:
            if self.api_key:
                self.device = pan.xapi.PanXapi(hostname=self.hostname,
                                               api_key=self.api_key)
            else:
                self.device = pan.xapi.PanXapi(hostname=self.hostname,
                                               api_username=self.username,
                                               api_password=self.password)
        except ConnectionException as e:
            raise ConnectionException(str(e))

    def _open_ssh(self):
        try:
            self.ssh_device = ConnectHandler(device_type='paloalto_panos',
                                             ip=self.hostname,
                                             username=self.username,
                                             password=self.password,
                                             **self.netmiko_optional_args)
        except ConnectionException as e:
            raise ConnectionException(str(e))

        self.ssh_connection = True

    def close(self):
        self.device = None
        if self.ssh_connection:
            self.ssh_device.disconnect()
            self.ssh_connection = False
            self.ssh_device = None

    def _import_file(self, filename):
        if not self.api_key:
            key = self.device.keygen()
        else:
            key = self.api_key

        params = {
            'type': 'import',
            'category': 'configuration',
            'key': key
        }

        path = os.path.basename(filename)

        mef = requests_toolbelt.MultipartEncoder(
            fields={
                'file': (path, open(filename, 'rb'), 'application/octet-stream')
            }
        )

        requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
        url = 'https://{0}/api/'.format(self.hostname)
        request = requests.post(
            url,
            verify=False,
            params=params,
            headers={'Content-Type': mef.content_type},
            data=mef
        )

        # if something goes wrong just raise an exception
        request.raise_for_status()
        response = xml.etree.ElementTree.fromstring(request.content)

        if response.attrib['status'] == 'error':
            return False
        else:
            return path

    def is_alive(self):
        if self.device:
            if self.ssh_connection:
                is_alive = self.ssh_device.remote_conn.transport.is_active()
            else:
                is_alive = True
        else:
            is_alive = False
        return {'is_alive': is_alive}

    def load_replace_candidate(self, filename=None, config=None):
        if config:
            raise ReplaceConfigException("This method requires a config file.")

        elif filename:
            if self.loaded is False:
                if self._save_backup() is False:
                    raise ReplaceConfigException('Error while storing backup config')

            path = self._import_file(filename)
            if path is False:
                msg = "Error while trying to move the config file to the device."
                raise ReplaceConfigException(msg)

            # Let's load the config.
            cmd = '<load><config><from>{0}</from></config></load>'.format(path)
            self.device.op(cmd=cmd)

            if self.device.status == 'success':
                self.loaded = True
            else:
                raise ReplaceConfigException('Error while loading config from {0}').format(path)

        else:
            raise ReplaceConfigException("This method requires a config file.")

    def _get_file_content(self, filename):
        try:
            with open(filename, 'r') as f:
                content = f.read()
        except IOError:
            raise MergeConfigException('Error while opening {0}. Make sure '
                                       'filename is correct.'.format(filename))
        return content

    def _send_merge_commands(self, config, file_config):
        """
        Netmiko is being used to push set commands.
        """
        if self.loaded is False:
            if self._save_backup() is False:
                raise MergeConfigException('Error while storing backup '
                                           'config.')
        if self.ssh_connection is False:
            self._open_ssh()

        if file_config:
            if isinstance(config, str):
                config = config.splitlines()
        else:
            if isinstance(config, str):
                config = str(config).split()

        self.ssh_device.send_config_set(config)
        self.loaded = True
        self.merge_config = True

    def _get_candidate(self):
        candidate_command = '<show><config><candidate></candidate></config></show>'
        self.device.op(cmd=candidate_command)
        candidate = str(self.device.xml_root())
        return candidate

    def _get_running(self):
        self.device.show()
        running = str(self.device.xml_root())
        return running

    def get_config(self, retrieve='all'):
        configs = {}
        running = py23_compat.text_type('')
        candidate = py23_compat.text_type('')
        startup = py23_compat.text_type('')

        if retrieve == 'all':
            running = py23_compat.text_type(self._get_running())
            candidate = py23_compat.text_type(self._get_candidate())
        elif retrieve == 'running':
            running = py23_compat.text_type(self._get_running())
        elif retrieve == 'candidate':
            candidate = py23_compat.text_type(self._get_candidate())

        configs['running'] = running
        configs['candidate'] = candidate
        configs['startup'] = startup

        return configs

    def load_merge_candidate(self, filename=None, config=None):
        if filename:
            file_config = True
            content = self._get_file_content(filename)
            config = content.splitlines()
            self._send_merge_commands(config, file_config)

        elif config:
            file_config = False
            self._send_merge_commands(config, file_config)

        else:
            raise MergeConfigException('You must provide either a file '
                                       'or a set-format string')

    def compare_config(self):
        """
        Netmiko is being used to obtain config diffs because pan-python
        doesn't support the needed command.
        """
        if self.ssh_connection is False:
            self._open_ssh()

        self.ssh_device.exit_config_mode()
        diff = self.ssh_device.send_command("show config diff")
        return diff.strip()

    def _save_backup(self):
        self.backup_file = 'config_{0}.xml'.format(str(datetime.now().date()).replace(' ', '_'))
        backup_command = '<save><config><to>{0}</to></config></save>'.format(self.backup_file)

        self.device.op(cmd=backup_command)
        if self.device.status == 'success':
            return True
        else:
            return False

    def commit_config(self):
        """
        Netmiko is being used to commit the configuration because it takes
        a better care of results compared to pan-python.
        """
        if self.loaded:
            if self.ssh_connection is False:
                self._open_ssh()
            try:
                self.ssh_device.commit()
                time.sleep(3)
                self.loaded = False
                self.changed = True
            except:   # noqa
                if self.merge_config:
                    raise MergeConfigException('Error while commiting config')
                else:
                    raise ReplaceConfigException('Error while commiting config')
        else:
            raise ReplaceConfigException('No config loaded.')

    def discard_config(self):
        if self.loaded:
            discard_cmd = '<load><config><from>{0}</from></config></load>'.format(self.backup_file)
            self.device.op(cmd=discard_cmd)

            if self.device.status == 'success':
                self.loaded = False
                self.merge_config = False
            else:
                raise ReplaceConfigException("Error while loading backup config.")

    def rollback(self):
        """
        Netmiko is being used to commit the rollback configuration because
        it takes a better care of results compared to pan-python.
        """
        if self.changed:
            rollback_cmd = '<load><config><from>{0}</from></config></load>'.format(self.backup_file)
            self.device.op(cmd=rollback_cmd)
            time.sleep(5)

            if self.ssh_connection is False:
                self._open_ssh()
            try:
                self.ssh_device.commit()
                self.loaded = False
                self.changed = False
                self.merge_config = False
            except:    # noqa
                ReplaceConfigException("Error while loading backup config")

    def _extract_interface_list(self):
        self.device.op(cmd='<show><interface>all</interface></show>')
        interfaces_xml = xmltodict.parse(self.device.xml_root())
        interfaces_json = json.dumps(interfaces_xml['response']['result'])
        interfaces = json.loads(interfaces_json)

        interface_set = set()

        for entry in interfaces.values():
            for entry_contents in entry.values():
                if isinstance(entry_contents, dict):
                    # If only 1 interface is listed, xmltodict returns a dictionary, otherwise
                    # it returns a list of dictionaries.
                    entry_contents = [entry_contents]
                for intf in entry_contents:
                    interface_set.add(intf['name'])

        return list(interface_set)

    def get_facts(self):
        facts = {}

        try:
            self.device.op(cmd='<show><system><info></info></system></show>')
            system_info_xml = xmltodict.parse(self.device.xml_root())
            system_info_json = json.dumps(system_info_xml['response']['result']['system'])
            system_info = json.loads(system_info_json)
        except AttributeError:
            system_info = {}

        if system_info:
            facts['hostname'] = system_info['hostname']
            facts['vendor'] = py23_compat.text_type('Palo Alto Networks')
            facts['uptime'] = int(convert_uptime_string_seconds(system_info['uptime']))
            facts['os_version'] = system_info['sw-version']
            facts['serial_number'] = system_info['serial']
            facts['model'] = system_info['model']
            facts['fqdn'] = py23_compat.text_type('N/A')
            facts['interface_list'] = self._extract_interface_list()

            facts['interface_list'].sort()

        return facts

    def get_lldp_neighbors(self):
        """Return LLDP neighbors details."""

        neighbors = {}

        cmd = '<show><lldp><neighbors>all</neighbors></lldp></show>'
        try:
            self.device.op(cmd=cmd)
            lldp_table_xml = xmltodict.parse(self.device.xml_root())
            lldp_table_json = json.dumps(lldp_table_xml['response']['result']['entry'])
            lldp_table = json.loads(lldp_table_json)
        except AttributeError:
            lldp_table = []

        for lldp_item in lldp_table:

            local_int = lldp_item['@name']

            if local_int not in neighbors.keys():
                neighbors[local_int] = []
            try:
                lldp_neighs = lldp_item.get('neighbors').get('entry')
            except AttributeError:
                lldp_neighs = ''
            if isinstance(lldp_neighs, dict):
                lldp_neighs = [lldp_neighs]

            for neighbor in lldp_neighs:
                n = {}
                n['hostname'] = neighbor['system-name']
                n['port'] = neighbor['port-id']
                neighbors[local_int].append(n)
        return neighbors

    def get_route_to(self, destination='', protocol=''):
        """Return route details to a specific destination, learned from a certain protocol."""

        # Note, it should be possible to query the FIB:
        # "<show><routing><fib></fib></routing></show>"
        # To add informations to this getter
        routes = {}

        if destination:
            destination = "<destination>{0}</destination>".format(destination)
        if protocol:
            protocol = "<type>{0}</type>".format(protocol)

        cmd = "<show><routing><route>{0}{1}</route></routing></show>".format(protocol, destination)
        try:
            self.device.op(cmd=cmd)
            routes_table_xml = xmltodict.parse(self.device.xml_root())
            routes_table_json = json.dumps(routes_table_xml['response']['result']['entry'])
            routes_table = json.loads(routes_table_json)
        except (AttributeError, KeyError):
            routes_table = []

        if isinstance(routes_table, dict):
            routes_table = [routes_table]

        for route in routes_table:
            d = {
                'current_active': False,
                'last_active': False,
                'age': -1,
                'next_hop': u'',
                'protocol': u'',
                'outgoing_interface': u'',
                'preference': -1,
                'inactive_reason': u'',
                'routing_table': u'default',
                'selected_next_hop': False,
                'protocol_attributes': {}
            }
            destination = route['destination']
            flags = route['flags']

            if 'A' in flags:
                d['current_active'] = True
            else:
                d['current_active'] = False
            if 'C' in flags:
                d['protocol'] = "connect"
            if 'S' in flags:
                d['protocol'] = "static"
            if 'R' in flags:
                d['protocol'] = "rip"
            if 'R' in flags:
                d['protocol'] = "rip"
            if 'O' in flags:
                d['protocol'] = "ospf"
            if 'B' in flags:
                d['protocol'] = "bgp"
            if 'H' in flags:
                d['protocol'] = "host"
            if route['age'] is not None:
                d['age'] = int(route['age'])
            if route['nexthop'] is not None:
                d['next_hop'] = route['nexthop']
            if route['interface'] is not None:
                d['outgoing_interface'] = route['interface']
            if route['metric'] is not None:
                d['preference'] = int(route['metric'])
            if route['virtual-router'] is not None:
                d['routing_table'] = route['virtual-router']

            if destination not in routes.keys():
                routes[destination] = []
            routes[destination].append(d)

        return routes

    def get_interfaces(self):
        LOOPBACK_SUBIF_DEFAULTS = {
            'is_up': True,
            'is_enabled': True,
            'speed': 0,
            'last_flapped': -1.0,
            'mac_address': '',
            'description': 'N/A'
        }
        interface_dict = {}
        interface_list = self._extract_interface_list()

        for intf in interface_list:
            interface = {}
            cmd = "<show><interface>{0}</interface></show>".format(intf)

            try:
                self.device.op(cmd=cmd)
                interface_info_xml = xmltodict.parse(self.device.xml_root())
                interface_info_json = json.dumps(interface_info_xml['response']['result']['hw'])
                interface_info = json.loads(interface_info_json)
            except KeyError as err:
                if 'loopback.' in intf and 'hw' in str(err):
                    # loopback sub-ifs don't return a 'hw' key
                    interface_dict[intf] = LOOPBACK_SUBIF_DEFAULTS
                    continue
                raise

            interface['is_up'] = interface_info.get('state') == 'up'

            conf_state = interface_info.get('state_c')
            if conf_state == 'down':
                interface['is_enabled'] = False
            elif conf_state in ('up', 'auto'):
                interface['is_enabled'] = True
            else:
                msg = 'Unknown configured state {} for interface {}'.format(conf_state, intf)
                raise RuntimeError(msg)

            interface['last_flapped'] = -1.0
            interface['speed'] = interface_info.get('speed')
            # Loopback and down interfaces
            if interface['speed'] in ('[n/a]', 'unknown'):
                interface['speed'] = 0
            else:
                interface['speed'] = int(interface['speed'])
            interface['mac_address'] = standardize_mac(interface_info.get('mac'))
            interface['description'] = py23_compat.text_type('N/A')
            interface_dict[intf] = interface

        return interface_dict

    def get_interfaces_ip(self):
        '''Return IP interface data.'''

        def extract_ip_info(parsed_intf_dict):
            '''
            IPv4:
              - Primary IP is in the '<ip>' tag. If no v4 is configured the return value is 'N/A'.
              - Secondary IP's are in '<addr>'. If no secondaries, this field is not returned by
                the xmltodict.parse() method.

            IPv6:
              - All addresses are returned in '<addr6>'. If no v6 configured, this is not returned
                either by xmltodict.parse().

            Example of XML response for an intf with multiple IPv4 and IPv6 addresses:

            <response status="success">
              <result>
                <ifnet>
                  <entry>
                    <name>ethernet1/5</name>
                    <zone/>
                    <fwd>N/A</fwd>
                    <vsys>1</vsys>
                    <dyn-addr/>
                    <addr6>
                      <member>fe80::d61d:71ff:fed8:fe14/64</member>
                      <member>2001::1234/120</member>
                    </addr6>
                    <tag>0</tag>
                    <ip>169.254.0.1/30</ip>
                    <id>20</id>
                    <addr>
                      <member>1.1.1.1/28</member>
                    </addr>
                  </entry>
                  {...}
                </ifnet>
                <hw>
                  {...}
                </hw>
              </result>
            </response>
            '''
            intf = parsed_intf_dict['name']
            _ip_info = {intf: {}}

            v4_ip = parsed_intf_dict.get('ip')
            secondary_v4_ip = parsed_intf_dict.get('addr')
            v6_ip = parsed_intf_dict.get('addr6')

            if v4_ip != 'N/A':
                address, pref = v4_ip.split('/')
                _ip_info[intf].setdefault('ipv4', {})[address] = {'prefix_length': int(pref)}

            if secondary_v4_ip is not None:
                members = secondary_v4_ip['member']
                if not isinstance(members, list):
                    # If only 1 secondary IP is present, xmltodict converts field to a string, else
                    # it converts it to a list of strings.
                    members = [members]
                for address in members:
                    address, pref = address.split('/')
                    _ip_info[intf].setdefault('ipv4', {})[address] = {'prefix_length': int(pref)}

            if v6_ip is not None:
                members = v6_ip['member']
                if not isinstance(members, list):
                    # Same "1 vs many -> string vs list of strings" comment.
                    members = [members]
                for address in members:
                    address, pref = address.split('/')
                    _ip_info[intf].setdefault('ipv6', {})[address] = {'prefix_length': int(pref)}

            # Reset dictionary if no addresses were found.
            if _ip_info == {intf: {}}:
                _ip_info = {}

            return _ip_info

        ip_interfaces = {}
        cmd = "<show><interface>all</interface></show>"

        self.device.op(cmd=cmd)
        interface_info_xml = xmltodict.parse(self.device.xml_root())
        interface_info_json = json.dumps(
            interface_info_xml['response']['result']['ifnet']['entry']
        )
        interface_info = json.loads(interface_info_json)

        if isinstance(interface_info, dict):
            # Same "1 vs many -> dict vs list of dicts" comment.
            interface_info = [interface_info]

        for interface_dict in interface_info:
            ip_info = extract_ip_info(interface_dict)
            if ip_info:
                ip_interfaces.update(ip_info)

        return ip_interfaces
Ejemplo n.º 18
0
f = open('vars.yml', 'r')
vars = load(f.read(), Loader=FullLoader)
f.close()

print("generating and loading configuration")
for item in vars:
    host_vars = vars[item]
    device = host_vars['netmiko']
    dev = ConnectHandler(**device)
    f = open(host_vars['netmiko']['host'] + '.txt', 'w')
    f.write(junos_template.render(host_vars))
    f.close()
    load = dev.send_config_from_file(config_file=host_vars['netmiko']['host'] +
                                     '.txt')
    commit = dev.commit(confirm=False,
                        check=False,
                        comment='commited from netmiko')
    dev.disconnect()

print("waiting 15 seconds before validating BGP sessions state")
time.sleep(15)
for item in vars:
    host_vars = vars[item]
    device = host_vars['netmiko']
    dev = ConnectHandler(**device)
    command = "show bgp neighbor"
    command_output = dev.send_command(command + "| display json")
    data_json = json.loads(command_output)
    print("Device " + host_vars['netmiko']['host'])
    for neighbor in data_json["bgp-information"][0]["bgp-peer"]:
        print("session with " + neighbor["peer-address"][0]['data'] + " is " +
Ejemplo n.º 19
0
class Connection(object):
    '''Netmiko Based Connection

    Sample implementation of NetmikoConnection connection to devices
    allowing devices to ssh or telnet to end routers
    '''
    def __init__(self, protocol, ip, port, username, enable_password,
                 tacacs_password, line_passwd, os, *args, **kwargs):
        # instantiate device information
        self.protocol = protocol
        self.ip = ip
        self.port = port
        self.username = username
        self.enable_password = enable_password
        self.tacacs_password = tacacs_password
        self.line_passwd = line_passwd
        self.os = os
        self._is_connected = False

    def connect(self):
        #self.net_connect = ConnectHandler(device_type='a10', ip='192.168.100.96', username='******', password='******',secret='admin')
        connect_params = self._connect_params_dict()
        try:
            self.net_connect = ConnectHandler(**connect_params)
        except ValueError:
            extends = 'netconnect.extends.' + str(
                self.os) + '.' + 'ConnectHandler'
            self.net_connect = utils.import_object(extends, **connect_params)
            self._is_connected = True
        except Exception as ex:
            log.info(ex)
            self._is_connected = False
        else:
            self._is_connected = True

    @property
    def connected(self):
        return self._is_connected

    def execute(self, command, timeout=500):
        if not self._is_connected:
            log.error("Error: device not connected")
            return False

        if isinstance(command, str):  ## if string is given, transfer to list
            command = command.splitlines()

        if self.os not in [
                'linux', 'nso'
        ]:  ## some devices like linux don't need enable operation
            self.net_connect.enable()

        expect_string = None
        if self.os in ['linux']:  ## add Linux prompt pattern
            expect_string = r'(.*?([>\$~%]|[^#\s]#))\s?$'

        output = ""
        for cmd in command:
            log.debug('To be executed command: %s', cmd)
            result = self.net_connect.send_command_expect(
                cmd, expect_string=expect_string, max_loops=int(timeout))
            output = output + result

        return output

    def send(self, command):
        result = self.net_connect.send_command_timing(command)

        return result

    def configure(self, cmd):
        if not self._is_connected:
            log.error("Error: device not connected")
            return False

        log.debug('To be configured command: %s', cmd)
        result = self.net_connect.send_config_set(cmd)
        if self.os in ['cisco_xr', 'nso'
                       ]:  ## some devices like cisco_xr need commit operation
            self.net_connect.commit()
            self.net_connect.exit_config_mode()

        return result

    def disconnect(self):
        self.net_connect.disconnect()
        self._is_connected = False

    def cli_style(self, style):
        if self.os != 'nso':
            log.error("Error: Only nso supported cli")
            return False

        if style == 'cisco' and self.current_cli_style != 'cisco':
            self.net_connect.send_command_timing("switch cli")
        elif style == 'juniper' and self.current_cli_style != 'juniper':
            self.net_connect.send_command_timing("switch cli")
        else:
            log.error("Please input right cli style!")

        return self.current_cli_style

    @property
    def current_cli_style(self):
        if self.os != 'nso':
            log.error("Error: Only nso supported cli")
            return False

        prompt = self.net_connect.find_prompt()
        if prompt.endswith('#'): self._current_cli_style = 'cisco'
        elif prompt.endswith('>'): self._current_cli_style = 'juniper'
        else: self._current_cli_style = 'unknow'

        log.debug('Current cli style: %s', self._current_cli_style)
        return self._current_cli_style

    def _connect_params_dict(self):
        """Generate dictionary of Paramiko connection parameters."""
        conn_dict = {
            'device_type': self.os,
            'ip': self.ip,
            'port': self.port,
            'username': self.username,
            'password': self.tacacs_password,
            'secret': self.enable_password
        }

        log.debug('The connection info dict: %s', conn_dict)
        return conn_dict
Ejemplo n.º 20
0
class PANOSDriver(NetworkDriver):

    def __init__(self, hostname, username, password, timeout=60, optional_args=None):
        self.hostname = hostname
        self.username = username
        self.password = password
        self.timeout = timeout
        self.loaded = False
        self.changed = False
        self.device = None
        self.ssh_device = None
        self.ssh_connection = False
        self.merge_config = False

        if optional_args is None:
            optional_args = {}

        netmiko_argument_map = {
            'port': None,
            'verbose': False,
            'use_keys': False,
            'key_file': None,
            'ssh_strict': False,
            'system_host_keys': False,
            'alt_host_keys': False,
            'alt_key_file': '',
            'ssh_config_file': None,
        }

        fields = netmiko_version.split('.')
        fields = [int(x) for x in fields]
        maj_ver, min_ver, bug_fix = fields
        if maj_ver >= 2:
            netmiko_argument_map['allow_agent'] = False
        elif maj_ver == 1 and min_ver >= 1:
            netmiko_argument_map['allow_agent'] = False

        # Build dict of any optional Netmiko args
        self.netmiko_optional_args = {}
        for k, v in netmiko_argument_map.items():
            try:
                self.netmiko_optional_args[k] = optional_args[k]
            except KeyError:
                pass
        self.api_key = optional_args.get('api_key', '')

    def open(self):
        try:
            if self.api_key:
                self.device = pan.xapi.PanXapi(hostname=self.hostname,
                                               api_key=self.api_key)
            else:
                self.device = pan.xapi.PanXapi(hostname=self.hostname,
                                               api_username=self.username,
                                               api_password=self.password)
        except ConnectionException as e:
            raise ConnectionException(str(e))

    def _open_ssh(self):
        try:
            self.ssh_device = ConnectHandler(device_type='paloalto_panos',
                                             ip=self.hostname,
                                             username=self.username,
                                             password=self.password,
                                             **self.netmiko_optional_args)
        except ConnectionException as e:
            raise ConnectionException(str(e))

        self.ssh_connection = True

    def close(self):
        self.device = None
        if self.ssh_connection:
            self.ssh_device.disconnect()
            self.ssh_connection = False
            self.ssh_device = None

    def _import_file(self, filename):
        if not self.api_key:
            key = self.device.keygen()
        else:
            key = self.api_key

        params = {
            'type': 'import',
            'category': 'configuration',
            'key': key
        }

        path = os.path.basename(filename)

        mef = requests_toolbelt.MultipartEncoder(
            fields={
                'file': (path, open(filename, 'rb'), 'application/octet-stream')
            }
        )

        requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
        url = 'https://{0}/api/'.format(self.hostname)
        request = requests.post(
            url,
            verify=False,
            params=params,
            headers={'Content-Type': mef.content_type},
            data=mef
        )

        # if something goes wrong just raise an exception
        request.raise_for_status()
        response = xml.etree.ElementTree.fromstring(request.content)

        if response.attrib['status'] == 'error':
            return False
        else:
            return path

    def is_alive(self):
        if self.device:
            if self.ssh_connection:
                is_alive = self.ssh_device.remote_conn.transport.is_active()
            else:
                is_alive = True
        else:
            is_alive = False
        return {'is_alive': is_alive}

    def load_replace_candidate(self, filename=None, config=None):
        if config:
            raise ReplaceConfigException("This method requires a config file.")

        elif filename:
            if self.loaded is False:
                if self._save_backup() is False:
                    raise ReplaceConfigException('Error while storing backup config')

            path = self._import_file(filename)
            if path is False:
                msg = "Error while trying to move the config file to the device."
                raise ReplaceConfigException(msg)

            # Let's load the config.
            cmd = '<load><config><from>{0}</from></config></load>'.format(path)
            self.device.op(cmd=cmd)

            if self.device.status == 'success':
                self.loaded = True
            else:
                raise ReplaceConfigException('Error while loading config from {0}').format(path)

        else:
            raise ReplaceConfigException("This method requires a config file.")

    def _get_file_content(self, filename):
        try:
            with open(filename, 'r') as f:
                content = f.read()
        except IOError:
            raise MergeConfigException('Error while opening {0}. Make sure '
                                       'filename is correct.'.format(filename))
        return content

    def _send_merge_commands(self, config, file_config):
        """
        Netmiko is being used to push set commands.
        """
        if self.loaded is False:
            if self._save_backup() is False:
                raise MergeConfigException('Error while storing backup '
                                           'config.')
        if self.ssh_connection is False:
            self._open_ssh()

        if file_config:
            if isinstance(config, str):
                config = config.splitlines()
        else:
            if isinstance(config, str):
                config = str(config).split()

        self.ssh_device.send_config_set(config)
        self.loaded = True
        self.merge_config = True

    def _get_candidate(self):
        candidate_command = '<show><config><candidate></candidate></config></show>'
        self.device.op(cmd=candidate_command)
        candidate = str(self.device.xml_root())
        return candidate

    def _get_running(self):
        self.device.show()
        running = str(self.device.xml_root())
        return running

    def get_config(self, retrieve='all'):
        configs = {}
        running = py23_compat.text_type('')
        candidate = py23_compat.text_type('')
        startup = py23_compat.text_type('')

        if retrieve == 'all':
            running = py23_compat.text_type(self._get_running())
            candidate = py23_compat.text_type(self._get_candidate())
        elif retrieve == 'running':
            running = py23_compat.text_type(self._get_running())
        elif retrieve == 'candidate':
            candidate = py23_compat.text_type(self._get_candidate())

        configs['running'] = running
        configs['candidate'] = candidate
        configs['startup'] = startup

        return configs

    def load_merge_candidate(self, filename=None, config=None):
        if filename:
            file_config = True
            content = self._get_file_content(filename)
            config = content.splitlines()
            self._send_merge_commands(config, file_config)

        elif config:
            file_config = False
            self._send_merge_commands(config, file_config)

        else:
            raise MergeConfigException('You must provide either a file '
                                       'or a set-format string')

    def compare_config(self):
        """
        Netmiko is being used to obtain config diffs because pan-python
        doesn't support the needed command.
        """
        if self.ssh_connection is False:
            self._open_ssh()

        self.ssh_device.exit_config_mode()
        diff = self.ssh_device.send_command("show config diff")
        return diff.strip()

    def _save_backup(self):
        self.backup_file = 'config_{0}.xml'.format(str(datetime.now().date()).replace(' ', '_'))
        backup_command = '<save><config><to>{0}</to></config></save>'.format(self.backup_file)

        self.device.op(cmd=backup_command)
        if self.device.status == 'success':
            return True
        else:
            return False

    def commit_config(self):
        """
        Netmiko is being used to commit the configuration because it takes
        a better care of results compared to pan-python.
        """
        if self.loaded:
            if self.ssh_connection is False:
                self._open_ssh()
            try:
                self.ssh_device.commit()
                time.sleep(3)
                self.loaded = False
                self.changed = True
            except:
                if self.merge_config:
                    raise MergeConfigException('Error while commiting config')
                else:
                    raise ReplaceConfigException('Error while commiting config')
        else:
            raise ReplaceConfigException('No config loaded.')

    def discard_config(self):
        if self.loaded:
            discard_cmd = '<load><config><from>{0}</from></config></load>'.format(self.backup_file)
            self.device.op(cmd=discard_cmd)

            if self.device.status == 'success':
                self.loaded = False
                self.merge_config = False
            else:
                raise ReplaceConfigException("Error while loading backup config.")

    def rollback(self):
        """
        Netmiko is being used to commit the rollback configuration because
        it takes a better care of results compared to pan-python.
        """
        if self.changed:
            rollback_cmd = '<load><config><from>{0}</from></config></load>'.format(self.backup_file)
            self.device.op(cmd=rollback_cmd)
            time.sleep(5)

            if self.ssh_connection is False:
                self._open_ssh()
            try:
                self.ssh_device.commit()
                self.loaded = False
                self.changed = False
                self.merge_config = False
            except:
                ReplaceConfigException("Error while loading backup config")

    def get_facts(self):
        facts = {}

        try:
            self.device.op(cmd='<show><system><info></info></system></show>')
            system_info_xml = xmltodict.parse(self.device.xml_root())
            system_info_json = json.dumps(system_info_xml['response']['result']['system'])
            system_info = json.loads(system_info_json)
        except AttributeError:
            system_info = {}

        try:
            self.device.op(cmd='<show><interface>all</interface></show>')
            interfaces_xml = xmltodict.parse(self.device.xml_root())
            interfaces_json = json.dumps(interfaces_xml['response']['result'])
            interfaces = json.loads(interfaces_json)
        except AttributeError:
            interfaces = {}

        if system_info:
            facts['hostname'] = system_info['hostname']
            facts['vendor'] = py23_compat.text_type('Palo Alto Networks')
            facts['uptime'] = int(convert_uptime_string_seconds(system_info['uptime']))
            facts['os_version'] = system_info['sw-version']
            facts['serial_number'] = system_info['serial']
            facts['model'] = system_info['model']
            facts['fqdn'] = py23_compat.text_type('N/A')
            facts['interface_list'] = []

        for element in interfaces:
            for entry in interfaces[element]:
                for intf in interfaces[element][entry]:
                    if intf['name'] not in facts['interface_list']:
                        facts['interface_list'].append(intf['name'])
        facts['interface_list'].sort()
        return facts

    def get_lldp_neighbors(self):
        """Return LLDP neighbors details."""

        neighbors = {}

        cmd = '<show><lldp><neighbors>all</neighbors></lldp></show>'
        try:
            self.device.op(cmd=cmd)
            lldp_table_xml = xmltodict.parse(self.device.xml_root())
            lldp_table_json = json.dumps(lldp_table_xml['response']['result']['entry'])
            lldp_table = json.loads(lldp_table_json)
        except AttributeError:
            lldp_table = []

        for lldp_item in lldp_table:

            local_int = lldp_item['@name']

            if local_int not in neighbors.keys():
                neighbors[local_int] = []

            lldp_neighs = lldp_item['neighbors']['entry']
            if isinstance(lldp_neighs, dict):
                lldp_neighs = [lldp_neighs]

            for neighbor in lldp_neighs:
                n = {}
                n['hostname'] = neighbor['system-name']
                n['port'] = neighbor['port-id']
                neighbors[local_int].append(n)
        return neighbors

    def get_route_to(self, destination='', protocol=''):
        """Return route details to a specific destination, learned from a certain protocol."""

        # Note, it should be possible to query the FIB:
        # "<show><routing><fib></fib></routing></show>"
        # To add informations to this getter
        routes = {}

        if destination:
            destination = "<destination>{0}</destination>".format(destination)
        if protocol:
            protocol = "<type>{0}</type>".format(protocol)

        cmd = "<show><routing><route>{0}{1}</route></routing></show>".format(protocol, destination)
        try:
            self.device.op(cmd=cmd)
            routes_table_xml = xmltodict.parse(self.device.xml_root())
            routes_table_json = json.dumps(routes_table_xml['response']['result']['entry'])
            routes_table = json.loads(routes_table_json)
        except AttributeError:
            routes_table = []

        if isinstance(routes_table, dict):
            routes_table = [routes_table]

        for route in routes_table:
            d = {
                'current_active': False,
                'last_active': False,
                'age': -1,
                'next_hop': u'',
                'protocol': u'',
                'outgoing_interface': u'',
                'preference': -1,
                'inactive_reason': u'',
                'routing_table': u'default',
                'selected_next_hop': False,
                'protocol_attributes': {}
            }
            destination = route['destination']
            flags = route['flags']

            if 'A' in flags:
                d['current_active'] = True
            else:
                d['current_active'] = False
            if 'C' in flags:
                d['protocol'] = "connect"
            if 'S' in flags:
                d['protocol'] = "static"
            if 'R' in flags:
                d['protocol'] = "rip"
            if 'R' in flags:
                d['protocol'] = "rip"
            if 'O' in flags:
                d['protocol'] = "ospf"
            if 'B' in flags:
                d['protocol'] = "bgp"
            if 'H' in flags:
                d['protocol'] = "host"
            if route['age'] is not None:
                d['age'] = int(route['age'])
            if route['nexthop'] is not None:
                d['next_hop'] = route['nexthop']
            if route['interface'] is not None:
                d['outgoing_interface'] = route['interface']
            if route['metric'] is not None:
                d['preference'] = int(route['metric'])
            if route['virtual-router'] is not None:
                d['routing_table'] = route['virtual-router']

            if destination not in routes.keys():
                routes[destination] = []
            routes[destination].append(d)

        return routes

    def get_interfaces(self):
        interface_dict = {}
        interface_list = self.get_facts()['interface_list']

        for intf in interface_list:
            interface = {}
            cmd = "<show><interface>{0}</interface></show>".format(intf)

            try:
                self.device.op(cmd=cmd)
                interface_info_xml = xmltodict.parse(self.device.xml_root())
                interface_info_json = json.dumps(interface_info_xml['response']['result']['hw'])
                interface_info = json.loads(interface_info_json)
            except AttributeError:
                interface_info = {}

            name = interface_info.get('name')
            state = interface_info.get('state')

            if state == 'up':
                interface['is_up'] = True
                interface['is_enabled'] = True
            else:
                interface['is_up'] = False
                interface['is_enabled'] = False

            interface['last_flapped'] = -1.0
            interface['speed'] = interface_info.get('speed')
            # Quick fix for loopback interfaces
            if interface['speed'] == '[n/a]':
                interface['speed'] = 0
            else:
                interface['speed'] = int(interface['speed'])
            interface['mac_address'] = interface_info.get('mac')
            interface['description'] = py23_compat.text_type('N/A')
            interface_dict[name] = interface

        return interface_dict