<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 ciscoconfparse
ciscoconfparse is a Python library for querying Cisco-style configurations. 
The purpose of this workbook is to examine some features that are, in my view, not very well presented in the official documentation.
Step2:  I am going to use a very stripped down version of the Secure IOS Template by Team Cymru. This is not a fully functional IOS configuration!
Step3:  First, he configuration must be parsed by creating an instance of ciscoconfparse.CiscoConfParse(). The class expects either a file object or a list of configuration lines.
Step4:  When CiscoConfParse() reads a configuration, it stores parent-child relationships as a special IOSCfgLine object. IOSCfgLine instances are returned when one queries the parsed configuration.
Finding lines matching a regular expression
Step5:  IOSCfgLine instances have several useful attributes.
Step6:  Finding sections with children
The next example finds interfaces that have NTP disabled.
Step7:  The .text attribute only returns the matching line whereas the .ioscfg attributes includes all children lines as a list.
Step8:  Finding sections without children
The next example finds interfaces that have NTP not disabled.
Step9:  Finding sections with all children
The next example finds interfaces that have IP-Unreachables and MOP disabled.
Step10:  Finding lines with parents
The .find_objects_w_parents() methods returns children and not their parents.
Step11:  Deleting lines
This can be handy in combination with the IOSCfgLine.delete() method which I haven't covered yet. 
IOSCfgLine objects provide several methods for changing an existing configuration. Let's delete all no mop enable lines.
Step12:  The no mop enable lines are now missing.
Step13:  Adding lines
Let's ensure that the configuration uses an NTP server.
Step14:  Adding lines to sections
Let's ensure that all Ethernet interfaces have an explicit MTU of 1500 configured. This is a two-step process were first any existing MTU lines are deleted and then the correct ones are added.
<ASSISTANT_TASK:>
Python Code:
# The line below can be ignored but I didn't set up my environment properly 
import sys ; sys.path.append('/home/mjuenemann/.virtualenvs/ciscoconfparse/lib/python3.6/site-packages')
import ciscoconfparse
Explanation: ciscoconfparse
ciscoconfparse is a Python library for querying Cisco-style configurations. 
The purpose of this workbook is to examine some features that are, in my view, not very well presented in the official documentation.
End of explanation
CONFIG = 
!
hostname router01
!
tacacs-server host 192.0.2.34
tacacs-server key cheezit
!
interface Ethernet2/0
 description Unprotected interface, facing towards Internet
 ip address 192.0.2.14 255.255.255.240
 no ip unreachables
 ntp disable
 no mop enable
 mtu 900
!
interface Ethernet2/1
 description Protected interface, facing towards DMZ
 ip address 192.0.2.17 255.255.255.240
 no mop enable
Explanation: I am going to use a very stripped down version of the Secure IOS Template by Team Cymru. This is not a fully functional IOS configuration!
End of explanation
config = ciscoconfparse.CiscoConfParse(CONFIG.split('\n'))
config
Explanation: First, he configuration must be parsed by creating an instance of ciscoconfparse.CiscoConfParse(). The class expects either a file object or a list of configuration lines.
End of explanation
tacacs_lines = config.find_objects(r'^tacacs')
tacacs_lines
first_tacacs_line = tacacs_lines[0]
type(first_tacacs_line)
Explanation: When CiscoConfParse() reads a configuration, it stores parent-child relationships as a special IOSCfgLine object. IOSCfgLine instances are returned when one queries the parsed configuration.
Finding lines matching a regular expression
End of explanation
first_tacacs_line.linenum
first_tacacs_line.indent
 first_tacacs_line.text
Explanation: IOSCfgLine instances have several useful attributes.
End of explanation
interfaces_with_ntp_disabled = config.find_objects_w_child(r'^interface', r'ntp disable')
interfaces_with_ntp_disabled
Explanation: Finding sections with children
The next example finds interfaces that have NTP disabled.
End of explanation
interfaces_with_ntp_disabled[0].text
interfaces_with_ntp_disabled[0].ioscfg
Explanation: The .text attribute only returns the matching line whereas the .ioscfg attributes includes all children lines as a list.
End of explanation
interfaces_with_ntp_not_disabled = config.find_objects_wo_child(r'^interface', r'ntp disable')
interfaces_with_ntp_not_disabled
interfaces_with_ntp_not_disabled[0].ioscfg
Explanation: Finding sections without children
The next example finds interfaces that have NTP not disabled.
End of explanation
results = config.find_objects_w_all_children(r'interface', [r'no ip unreachables', r'no mop enable'])
results
results[0].ioscfg
Explanation: Finding sections with all children
The next example finds interfaces that have IP-Unreachables and MOP disabled.
End of explanation
results = config.find_objects_w_parents(r'^interface', 'no mop enable')
results
Explanation: Finding lines with parents
The .find_objects_w_parents() methods returns children and not their parents.
End of explanation
for result in results:
    result.delete()
# Call .commit() after changing the configuration
config.commit()
Explanation: Deleting lines
This can be handy in combination with the IOSCfgLine.delete() method which I haven't covered yet. 
IOSCfgLine objects provide several methods for changing an existing configuration. Let's delete all no mop enable lines.
End of explanation
config.ioscfg
Explanation: The no mop enable lines are now missing.
End of explanation
config.append_line('ntp server 192.168.1.1')
# Call .commit() before searching again!!!
config.commit()
config.ioscfg
Explanation: Adding lines
Let's ensure that the configuration uses an NTP server.
End of explanation
# Delete all existing MTU lines.
for interface in config.find_objects(r'^interface.+Ethernet'):
    interface.delete_children_matching('mtu \d+')
config.commit()
# Add the correct MTU. Note the use of the correct indentation value for children.
for interface in config.find_objects(r'^interface.+Ethernet'):
    interface.append_to_family('mtu 1500', indent=interface.child_indent)
config.commit()
config.ioscfg
Explanation: Adding lines to sections
Let's ensure that all Ethernet interfaces have an explicit MTU of 1500 configured. This is a two-step process were first any existing MTU lines are deleted and then the correct ones are added.
End of explanation
<END_TASK>