|
| 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_address_objects.py |
| 19 | +========================== |
| 20 | +
|
| 21 | +Use bulk operations to create / delete hundreds of firewall Address Objects. |
| 22 | +
|
| 23 | +NOTE: Please update the hostname and auth credentials variables |
| 24 | + before running. |
| 25 | +
|
| 26 | +This script will create a large number of address objects on the firewall |
| 27 | +and then delete them. The intent is to show how to use the new bulk |
| 28 | +operations available in pandevice, both how to properly use them and what |
| 29 | +to be careful of. |
| 30 | +""" |
| 31 | + |
| 32 | +import datetime |
| 33 | +import sys |
| 34 | + |
| 35 | +import pandevice |
| 36 | +import pandevice.firewall |
| 37 | +import pandevice.objects |
| 38 | + |
| 39 | + |
| 40 | +HOSTNAME = '127.0.0.1' |
| 41 | +USERNAME = 'admin' |
| 42 | +PASSWORD = 'admin' |
| 43 | +PREFIX = 'BulkAddressObject' |
| 44 | + |
| 45 | + |
| 46 | +def num_as_ip(num, offset=0): |
| 47 | + '''Returns a number as a 192.168 IP address.''' |
| 48 | + return '192.168.{0}.{1}'.format( |
| 49 | + num // 200 + 1 + offset, |
| 50 | + num % 200 + 2) |
| 51 | + |
| 52 | + |
| 53 | +def main(): |
| 54 | + # Before we begin, you'll need to use the pandevice documentation both |
| 55 | + # for this example and for any scripts you may write for yourself. The |
| 56 | + # docs can be found here: |
| 57 | + # |
| 58 | + # http://pandevice.readthedocs.io/en/latest/reference.html |
| 59 | + # |
| 60 | + # First, let's create the firewall object that we want to modify. |
| 61 | + fw = pandevice.firewall.Firewall(HOSTNAME, USERNAME, PASSWORD) |
| 62 | + print('Firewall system info: {0}'.format(fw.refresh_system_info())) |
| 63 | + |
| 64 | + # Get the list of current address objects, as we'll need this later. We |
| 65 | + # don't want these address objects in our firewall tree yet, so let's set |
| 66 | + # the `add` flag in the refreshall method to False. |
| 67 | + original_objects = pandevice.objects.AddressObject.refreshall( |
| 68 | + fw, add=False) |
| 69 | + |
| 70 | + # As a sanity check, make sure no currently configured address objects |
| 71 | + # have the same name prefix as what this script uses. If so, quit. |
| 72 | + for x in original_objects: |
| 73 | + if x.uid.startswith(PREFIX): |
| 74 | + print('Error: prefix {0} shared with address object {1}'.format( |
| 75 | + PREFIX, x.uid)) |
| 76 | + return |
| 77 | + |
| 78 | + # Just print out how many address objects were there beforehand. |
| 79 | + print('* There are {0} address object(s) currently *'.format( |
| 80 | + len(original_objects))) |
| 81 | + |
| 82 | + # Create each address object and add it to the firewall. You'll notice |
| 83 | + # that we don't call `create()` on each object as you'd expect. This is |
| 84 | + # because we'll do a bulk create after we've finished creating everything. |
| 85 | + bulk_objects = [] |
| 86 | + for num in range(1, 601): |
| 87 | + ao = pandevice.objects.AddressObject( |
| 88 | + '{0}{1:03}'.format(PREFIX, num), |
| 89 | + num_as_ip(num)) |
| 90 | + bulk_objects.append(ao) |
| 91 | + fw.add(ao) |
| 92 | + |
| 93 | + # Now we can bulk create all the address objects. This is accomplished by |
| 94 | + # invoking `create_similar()` on any of the address objects in our tree, |
| 95 | + # turning what would have been 600 individual API calls and condensing it |
| 96 | + # into a single API call. |
| 97 | + start = datetime.datetime.now() |
| 98 | + bulk_objects[0].create_similar() |
| 99 | + print('Creating {0} address objects took: {1}'.format( |
| 100 | + len(bulk_objects), datetime.datetime.now() - start)) |
| 101 | + |
| 102 | + # We've done a bulk create, now let's look at bulk apply. |
| 103 | + # |
| 104 | + # Some care is needed when using apply with pandevice. All "apply" methods |
| 105 | + # are doing a PANOS API `type=edit` under the hood, which does a replace of |
| 106 | + # the current config with what is specified. |
| 107 | + # |
| 108 | + # So what does this mean? This means that if we wanted to do a mass |
| 109 | + # update of the address objects we just created, we need to make sure that |
| 110 | + # our object tree contains the address objects that existed before this |
| 111 | + # script started. So let's add in the pre-existing address objects to |
| 112 | + # the firewall's object tree. We'll do this first so we don't forget |
| 113 | + # later on. |
| 114 | + for x in original_objects: |
| 115 | + fw.add(x) |
| 116 | + |
| 117 | + # With that out of the way, we're ready to update or bulk address objects |
| 118 | + # by incrementing the third octet of each IP address by 10. |
| 119 | + for num, x in enumerate(bulk_objects, 1): |
| 120 | + x.value = num_as_ip(num, 10) |
| 121 | + |
| 122 | + # Now we can do our bulk apply, invoking `apply_similar()`. As before, |
| 123 | + # we invoke this on any of the related children in our pandevice |
| 124 | + # object tree. Most important of all, since our firewall object has all |
| 125 | + # the pre-existing address objects in its tree, we won't accidentally |
| 126 | + # truncate them from the firewall config. |
| 127 | + start = datetime.datetime.now() |
| 128 | + bulk_objects[0].apply_similar() |
| 129 | + print('Bulk apply {0} address objects took: {1}'.format( |
| 130 | + len(bulk_objects) + len(original_objects), |
| 131 | + datetime.datetime.now() - start)) |
| 132 | + |
| 133 | + # We've done create, we've done edit, that leaves bulk delete. We only |
| 134 | + # want to delete the bulk address objects we created in this script, so |
| 135 | + # let's remove all the pre-existing address objects from the firewall |
| 136 | + # object. |
| 137 | + for x in original_objects: |
| 138 | + fw.remove(x) |
| 139 | + |
| 140 | + # Finally, let's invoke `delete_similar()` from the firewall. As should be |
| 141 | + # expected, we invoke this from any of the objects currently in our |
| 142 | + # pandevice object tree. |
| 143 | + start = datetime.datetime.now() |
| 144 | + bulk_objects[0].delete_similar() |
| 145 | + print('Deleting {0} address objects took: {1}'.format( |
| 146 | + len(bulk_objects), datetime.datetime.now() - start)) |
| 147 | + |
| 148 | + # At this point, we've now used all the bulk operations. If performance |
| 149 | + # is a bottleneck for you, consider if any of your automation could be |
| 150 | + # refactored to use any of the bulk operations pandevice offers. |
| 151 | + print('Done!') |
| 152 | + |
| 153 | + |
| 154 | +if __name__ == '__main__': |
| 155 | + # This script doesn't take command line arguments. If any are passed in, |
| 156 | + # then print out the script's docstring and exit. |
| 157 | + if len(sys.argv) != 1: |
| 158 | + print __doc__ |
| 159 | + else: |
| 160 | + # No CLI args, so run the main function. |
| 161 | + main() |
0 commit comments