|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +# Copyright (c) 2017, Palo Alto Networks |
| 4 | +# |
| 5 | +# Permission to use, copy, modify, and/or distribute this software for any |
| 6 | +# purpose with or without fee is hereby granted, provided that the above |
| 7 | +# copyright notice and this permission notice appear in all copies. |
| 8 | +# |
| 9 | +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 10 | +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 11 | +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 12 | +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 13 | +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 14 | +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 15 | +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 16 | + |
| 17 | +""" |
| 18 | +bulk_subinterfaces.py |
| 19 | +===================== |
| 20 | +
|
| 21 | +Use bulk operations to create / delete hundreds of firewall interfaces. |
| 22 | +
|
| 23 | +NOTE: Please update the hostname and auth credentials variables |
| 24 | + before running. |
| 25 | +
|
| 26 | +The purpose of this script is to use and explain both the bulk operations |
| 27 | +as it relates to subinterfaces as well as the new function that organizes |
| 28 | +objects into vsys. This script will show how the new bulk operations |
| 29 | +correctly handle when subinterface objects are in separate vsys trees. |
| 30 | +
|
| 31 | +""" |
| 32 | + |
| 33 | +import datetime |
| 34 | +import random |
| 35 | +import sys |
| 36 | + |
| 37 | +from pandevice import device |
| 38 | +from pandevice import firewall |
| 39 | +from pandevice import network |
| 40 | + |
| 41 | + |
| 42 | +HOSTNAME = '127.0.0.1' |
| 43 | +USERNAME = 'admin' |
| 44 | +PASSWORD = 'admin' |
| 45 | +INTERFACE = 'ethernet1/5' |
| 46 | + |
| 47 | + |
| 48 | +def main(): |
| 49 | + # Before we begin, you'll need to use the pandevice documentation both |
| 50 | + # for this example and for any scripts you may write for yourself. The |
| 51 | + # docs can be found here: |
| 52 | + # |
| 53 | + # http://pandevice.readthedocs.io/en/latest/reference.html |
| 54 | + # |
| 55 | + # First, let's create the firewall object that we want to modify. |
| 56 | + fw = firewall.Firewall(HOSTNAME, USERNAME, PASSWORD) |
| 57 | + print('Firewall system info: {0}'.format(fw.refresh_system_info())) |
| 58 | + |
| 59 | + print('Desired interface: {0}'.format(INTERFACE)) |
| 60 | + |
| 61 | + # Sanity Check #1: the intent here is that the interface we |
| 62 | + # specified above should not already be in use. If the interface is |
| 63 | + # already in use, then just quit out. |
| 64 | + print('Making sure interface is not currently in use...') |
| 65 | + interfaces = network.EthernetInterface.refreshall(fw, add=False) |
| 66 | + for eth in interfaces: |
| 67 | + if eth.name == INTERFACE: |
| 68 | + print('Interface {0} already in use! Please choose another'.format( |
| 69 | + INTERFACE)) |
| 70 | + return |
| 71 | + |
| 72 | + # Sanity Check #2: this has to be a multi-vsys system. So let's make |
| 73 | + # sure that we have multiple vsys to work with. If there is only one |
| 74 | + # vsys, quit out. |
| 75 | + # |
| 76 | + # Pulling the entire vsys config from each vsys is going to be large amount |
| 77 | + # of XML, so we'll specify that we only need the names of the different |
| 78 | + # vsys, not their entire subtrees. |
| 79 | + vsys_list = device.Vsys.refreshall(fw, name_only=True) |
| 80 | + print('Found the following vsys: {0}'.format(vsys_list)) |
| 81 | + if len(vsys_list) < 2: |
| 82 | + print('Only {0} vsys present, need 2 or more.'.format(len(vsys_list))) |
| 83 | + return |
| 84 | + |
| 85 | + # Let's make our base interface that we're going to make subinterfaces |
| 86 | + # out of. |
| 87 | + print('Creating base interface {0} in layer2 mode'.format(INTERFACE)) |
| 88 | + base = network.EthernetInterface(INTERFACE, 'layer2') |
| 89 | + |
| 90 | + # Like normal, after creating the object, we need to add it to the |
| 91 | + # firewall, then finally invoke "create()" to create it. |
| 92 | + fw.add(base) |
| 93 | + base.create() |
| 94 | + |
| 95 | + # Now let's go ahead and make all of our subinterfaces. |
| 96 | + eth = None |
| 97 | + for tag in range(1, 601): |
| 98 | + name = '{0}.{1}'.format(INTERFACE, tag) |
| 99 | + eth = network.Layer2Subinterface(name, tag) |
| 100 | + # Choose one of the vsys at random to put it into. |
| 101 | + vsys = random.choice(vsys_list) |
| 102 | + # Now add the subinterface to that randomly chosen vsys. |
| 103 | + vsys.add(eth) |
| 104 | + |
| 105 | + # You'll notice that we didn't invoke "create()" on the subinterfaces like |
| 106 | + # you would expect. This is because we're going to use the bulk create |
| 107 | + # function to create all of the subinterfaces in one shot, which has huge |
| 108 | + # performance gains from doing "create()" on each subinterface one-by-one. |
| 109 | + # |
| 110 | + # The function we'll use is "create_similar()". Create similar is saying, |
| 111 | + # "I want to create all objects similar to this one in my entire pandevice |
| 112 | + # object tree." In this case, since we'd be invoking it on a subinterface |
| 113 | + # of INTERFACE (our variable above), we are asking pandevice to create all |
| 114 | + # subinterfaces of INTERFACE, no matter which vsys it exists in. |
| 115 | + # |
| 116 | + # We just need any subinterface to do this. Since our last subinterface |
| 117 | + # was saved to the "eth" variable in the above loop, we can just use that |
| 118 | + # to invoke "create_similar()". |
| 119 | + print('Creating subinterfaces...') |
| 120 | + start = datetime.datetime.now() |
| 121 | + eth.create_similar() |
| 122 | + print('Creating subinterfaces took: {0}'.format( |
| 123 | + datetime.datetime.now() - start)) |
| 124 | + |
| 125 | + # Now let's explore updating them. Let's say this is a completely |
| 126 | + # different script, and we want to update all of the subinterfaces |
| 127 | + # for INTERFACE. Since this is a completely new script, we don't have any |
| 128 | + # information other than the firewall and the interface INTERFACE. So |
| 129 | + # let's start from scratch at this point, and remake the firewall object |
| 130 | + # and connect. |
| 131 | + print('\n--------\n') |
| 132 | + fw = firewall.Firewall(HOSTNAME, USERNAME, PASSWORD) |
| 133 | + print('Firewall system info: {0}'.format(fw.refresh_system_info())) |
| 134 | + |
| 135 | + print('Desired interface: {0}'.format(INTERFACE)) |
| 136 | + |
| 137 | + # Make the base interface object and connect it to our pandevice tree. |
| 138 | + base = network.EthernetInterface(INTERFACE, 'layer2') |
| 139 | + fw.add(base) |
| 140 | + |
| 141 | + # Now let's get all the subinterfaces for INTERFACE. Since our firewall's |
| 142 | + # default vsys is "None", this will get all subinterfaces of INTERFACE, |
| 143 | + # regardless of which vsys it exists in. |
| 144 | + print('Refreshing subinterfaces...') |
| 145 | + subinterfaces = network.Layer2Subinterface.refreshall(base) |
| 146 | + print('Found {0} subinterfaces'.format(len(subinterfaces))) |
| 147 | + |
| 148 | + # Now let's go ahead and update all of them. |
| 149 | + for eth in subinterfaces: |
| 150 | + eth.comment = 'Tagged {0} and in vsys {1}'.format(eth.tag, eth.vsys) |
| 151 | + |
| 152 | + # Now that we have updated all of the subinterfaces, we need to save |
| 153 | + # the changes to the firewall. But hold on a second, the vsys for these |
| 154 | + # subinterfaces is currently "None". We first need to organize these |
| 155 | + # subinterfaces into the vsys they actually exist in before we can |
| 156 | + # apply these changes to the firewall. |
| 157 | + # |
| 158 | + # This is where you can use the function "organize_into_vsys()". This |
| 159 | + # takes all objects currently attached to your pandevice object tree |
| 160 | + # and organizes them into the vsys they belong to. |
| 161 | + # |
| 162 | + # We haven't gotten the current vsys yet (this is a new script, remember), |
| 163 | + # but the function can take care of that for us. So let's just invoke it |
| 164 | + # to organize our pandevice object tree into vsys. |
| 165 | + print('Organizing subinterfaces into vsys...') |
| 166 | + fw.organize_into_vsys() |
| 167 | + |
| 168 | + # Now we're ready to save our changes. We'll use "apply_similar()", |
| 169 | + # and it behaves similarly to "create_similar()" in that you can invoke |
| 170 | + # it from any subinterface of INTERFACE and it will apply all of the |
| 171 | + # changes to subinterfaces of INTERFACE only. |
| 172 | + # |
| 173 | + # We just need one subinterface to invoke this function. Again, we'll |
| 174 | + # simply use the subinterface currently saved in the "eth" variable |
| 175 | + # from our update loop we did just above. |
| 176 | + # |
| 177 | + # NOTE: As an "apply()" function, apply does a replace of config, not |
| 178 | + # a simple update. So you must be careful that all other objects are |
| 179 | + # currently attached to your pandevice object tree when using apply |
| 180 | + # functions. In our case, we have already refreshed all layer2 |
| 181 | + # subinterfaces, and we are the only ones working with INTERFACE, so we |
| 182 | + # are safe to use this function. |
| 183 | + print('Updating all subinterfaces...') |
| 184 | + start = datetime.datetime.now() |
| 185 | + eth.apply_similar() |
| 186 | + print('Updating subinterfaces took: {0}'.format( |
| 187 | + datetime.datetime.now() - start)) |
| 188 | + |
| 189 | + # Finally, all that's left is to delete all of the subinterfaces. This |
| 190 | + # is just like you think: we first need to refresh all of the |
| 191 | + # subinterfaces of INTERFACE, organize them into their appropriate vsys, |
| 192 | + # then invoke "delete_similar()" to delete everything. |
| 193 | + print('Deleting all subinterfaces...') |
| 194 | + start = datetime.datetime.now() |
| 195 | + eth.delete_similar() |
| 196 | + print('Deleting subinterfaces took: {0}'.format( |
| 197 | + datetime.datetime.now() - start)) |
| 198 | + |
| 199 | + # Lastly, let's just delete the base interface INTERFACE. |
| 200 | + print('Deleting base interface...') |
| 201 | + base.delete() |
| 202 | + |
| 203 | + # And now we're done! If performance is a bottleneck in your automation, |
| 204 | + # or dealing with vsys is troublesome, consider using the vsys organizing |
| 205 | + # and/or bulk functions! |
| 206 | + print('Done!') |
| 207 | + |
| 208 | + |
| 209 | +if __name__ == '__main__': |
| 210 | + # This script doesn't take command line arguments. If any are passed in, |
| 211 | + # then print out the script's docstring and exit. |
| 212 | + if len(sys.argv) != 1: |
| 213 | + print __doc__ |
| 214 | + else: |
| 215 | + # No CLI args, so run the main function. |
| 216 | + main() |
0 commit comments