Exemplo n.º 1
0
def main():

    # Get command line arguments
    parser = argparse.ArgumentParser(
        description=
        "Upgrade a Palo Alto Networks Firewall or Panorama to the specified version"
    )
    parser.add_argument("-v",
                        "--verbose",
                        action="count",
                        help="Verbose (-vv for extra verbose)")
    parser.add_argument("-q", "--quiet", action="store_true", help="No output")
    parser.add_argument(
        "-n",
        "--dryrun",
        action="store_true",
        help="Print what would happen, but don't perform upgrades",
    )
    # Palo Alto Networks related arguments
    fw_group = parser.add_argument_group("Palo Alto Networks Device")
    fw_group.add_argument("hostname", help="Hostname of Firewall or Panorama")
    fw_group.add_argument("username", help="Username for Firewall or Panorama")
    fw_group.add_argument("password", help="Password for Firewall or Panorama")
    fw_group.add_argument(
        "version",
        help="The target PAN-OS/Panorama version (eg. 7.0.0 or latest)")
    args = parser.parse_args()

    ### Set up logger
    # Logging Levels
    # WARNING is 30
    # INFO is 20
    # DEBUG is 10
    if args.verbose is None:
        args.verbose = 0
    if not args.quiet:
        logging_level = 20 - (args.verbose * 10)
        if logging_level <= logging.DEBUG:
            logging_format = "%(levelname)s:%(name)s:%(message)s"
        else:
            logging_format = "%(message)s"
        logging.basicConfig(format=logging_format, level=logging_level)

    # Connect to the device and determine its type (Firewall or Panorama).
    # This is important to know what version to upgrade to next.
    device = PanDevice.create_from_device(
        args.hostname,
        args.username,
        args.password,
    )

    # Perform the upgrades in sequence with reboots between each upgrade
    device.software.upgrade_to_version(args.version, args.dryrun)
Exemplo n.º 2
0
def main():

    # Get command line arguments
    parser = argparse.ArgumentParser(
        description=
        "Tag an IP address on a Palo Alto Networks Next generation Firewall")
    parser.add_argument("-v",
                        "--verbose",
                        action="count",
                        help="Verbose (-vv for extra verbose)")
    parser.add_argument("-q", "--quiet", action="store_true", help="No output")
    parser.add_argument(
        "-r",
        "--register",
        help=
        "Tags to register to an IP, for multiple tags use commas eg. linux,apache,server",
    )
    parser.add_argument(
        "-u",
        "--unregister",
        help=
        "Tags to remove from an an IP, for multiple tags use commas eg. linux,apache,server",
    )
    parser.add_argument(
        "-s",
        "--vsys",
        help=
        "Specify the vsys target in the form vsysN where N is the vsys number: vsys2, vsys4, etc.",
    )
    parser.add_argument("-l",
                        "--list",
                        action="store_true",
                        help="List all tags for an IP")
    parser.add_argument("-c",
                        "--clear",
                        action="store_true",
                        help="Clear all tags for all IP")
    # Palo Alto Networks related arguments
    fw_group = parser.add_argument_group("Palo Alto Networks Device")
    fw_group.add_argument("hostname", help="Hostname of Firewall")
    fw_group.add_argument("username", help="Username for Firewall")
    fw_group.add_argument("password", help="Password for Firewall")
    fw_group.add_argument("ip", help="The IP address to tag/untag/list")
    args = parser.parse_args()

    ### Set up logger
    # Logging Levels
    # WARNING is 30
    # INFO is 20
    # DEBUG is 10
    if args.verbose is None:
        args.verbose = 0
    if not args.quiet:
        logging_level = 20 - (args.verbose * 10)
        if logging_level <= logging.DEBUG:
            logging_format = "%(levelname)s:%(name)s:%(message)s"
        else:
            logging_format = "%(message)s"
        logging.basicConfig(format=logging_format, level=logging_level)

    # Connect to the device and determine its type (Firewall or Panorama).
    device = PanDevice.create_from_device(
        args.hostname,
        args.username,
        args.password,
    )

    # Panorama does not have a userid API, so exit.
    # You can use the userid API on a firewall with the Panorama 'target'
    # parameter by creating a Panorama object first, then create a
    # Firewall object with the 'panorama' and 'serial' variables populated.
    if issubclass(type(device), Panorama):
        logging.error(
            "Connected to a Panorama, but user-id API is not possible on Panorama.  Exiting."
        )
        sys.exit(1)

    if args.vsys is not None:
        device.vsys = args.vsys

    if args.clear:
        device.userid.clear_registered_ip()

    if args.list:
        all_tags_by_ip = device.userid.get_registered_ip()
        try:
            # Print the tags for the requested IP
            logging.info(all_tags_by_ip[args.ip])
        except KeyError:
            # There were no tags for that IP
            logging.info("No tags for IP: %s" % args.ip)

    if args.unregister:
        device.userid.unregister(args.ip, args.unregister.split(","))

    if args.register:
        device.userid.register(args.ip, args.register.split(","))
Exemplo n.º 3
0
    def get_pandevice_parent(self, module, timeout=0):
        """Builds the pandevice object tree, returning the parent object.

        If pandevice is not installed, then module.fail_json() will be
        invoked.

        Arguments:
            * module(AnsibleModule): the ansible module.
            * timeout(int): Number of seconds to retry opening the connection to PAN-OS.

        Returns:
            * The parent pandevice object based on the spec given to
              get_connection().
        """
        # Sanity check.
        if not HAS_PANDEVICE:
            module.fail_json(msg='Missing required library "pandevice".')

        pdv = tuple(int(x) for x in panos.__version__.split("."))

        # Inform people that they should upgrade to pan-os-python instead of pandevice.
        if pdv < (1, 0, 0):
            lum = [
                'Python library "pandevice" is now "pan-os-python" and is now 1.0!',
                'Please "pip install pan-os-python" at your earliest convenience.',
            ]
            module.deprecate(" ".join(lum),
                             version="3.0.0",
                             collection_name="paloaltonetworks.panos")

        # Verify pandevice minimum version.
        if self.min_pandevice_version is not None:
            if pdv < self.min_pandevice_version:
                module.fail_json(msg=_MIN_VERSION_ERROR.format(
                    "panos", panos.__version__,
                    _vstr(self.min_pandevice_version)))

        pan_device_auth, serial_number = None, None
        if module.params["provider"] and module.params["provider"][
                "ip_address"]:
            pan_device_auth = (
                module.params["provider"]["ip_address"],
                module.params["provider"]["username"],
                module.params["provider"]["password"],
                module.params["provider"]["api_key"],
                module.params["provider"]["port"],
            )
            serial_number = module.params["provider"]["serial_number"]
        elif module.params.get("ip_address", None) is not None:
            pan_device_auth = (
                module.params["ip_address"],
                module.params["username"],
                module.params["password"],
                module.params["api_key"],
                module.params["port"],
            )
            msg = 'Classic provider params are deprecated; use "provider" instead'
            module.deprecate(msg,
                             version="3.0.0",
                             collection_name="paloaltonetworks.panos")
        else:
            module.fail_json(msg="Provider params are required.")

        # Create the connection object.
        if not isinstance(timeout, int):
            raise ValueError("Timeout must be an int")
        elif timeout < 0:
            raise ValueError("Timeout must greater than or equal to 0")
        end_time = time.time() + timeout
        while True:
            try:
                self.device = PanDevice.create_from_device(*pan_device_auth)
            except PanDeviceError as e:
                if timeout == 0:
                    module.fail_json(msg="Failed connection: {0}".format(e))
                elif time.time() >= end_time:
                    module.fail_json(msg="Connection timeout: {0}".format(e))
            else:
                break

        # Verify PAN-OS minimum version.
        if self.min_panos_version is not None:
            if self.device._version_info < self.min_panos_version:
                module.fail_json(msg=_MIN_VERSION_ERROR.format(
                    "PAN-OS",
                    _vstr(self.device._version_info),
                    _vstr(self.min_panos_version),
                ))

        # Optional: Firewall via Panorama connectivity specified.
        if hasattr(self.device, "refresh_devices") and serial_number:
            fw = Firewall(serial=serial_number)
            self.device.add(fw)
            self.device = fw

        parent = self.device
        no_shared = 'Scope "shared" is not allowed'
        not_found = '{0} "{1}" is not present.'
        pano_mia_param = 'Param "{0}" is required for Panorama but not specified.'
        ts_error = "Specify either the template or the template stack{0}."
        if hasattr(self.device, "refresh_devices"):
            # Panorama connection.
            templated = False

            # Error if Panorama is not supported.
            if self.panorama_error is not None:
                module.fail_json(msg=self.panorama_error)

            # Spec: template stack.
            tmpl_required = False
            added_template = False
            if self.template_stack is not None:
                name = module.params[self.template_stack]
                if name is not None:
                    templated = True
                    stacks = TemplateStack.refreshall(parent, name_only=True)
                    for ts in stacks:
                        if ts.name == name:
                            parent = ts
                            added_template = True
                            break
                    else:
                        module.fail_json(msg=not_found.format(
                            "Template stack",
                            name,
                        ))
                elif self.template is not None:
                    tmpl_required = True
                elif not self.template_is_optional:
                    module.fail_json(
                        msg=pano_mia_param.format(self.template_stack))

            # Spec: template.
            if self.template is not None:
                name = module.params[self.template]
                if name is not None:
                    templated = True
                    if added_template:
                        module.fail_json(msg=ts_error.format(", not both"))
                    templates = Template.refreshall(parent, name_only=True)
                    for t in templates:
                        if t.name == name:
                            parent = t
                            break
                    else:
                        module.fail_json(msg=not_found.format(
                            "Template",
                            name,
                        ))
                elif self.template_is_optional:
                    pass
                elif tmpl_required:
                    module.fail_json(msg=ts_error.format(""))
                elif not added_template:
                    module.fail_json(msg=pano_mia_param.format(self.template))

            # Spec: vsys_dg or device_group.
            dg_name = self.vsys_dg or self.device_group
            if dg_name is not None:
                name = module.params[dg_name]
                if name not in (None, "shared"):
                    groups = DeviceGroup.refreshall(parent, name_only=True)
                    for dg in groups:
                        if dg.name == name:
                            parent = dg
                            break
                    else:
                        module.fail_json(msg=not_found.format(
                            "Device group",
                            name,
                        ))

            # Spec: vsys importable.
            vsys_name = self.vsys_importable or self.vsys or self.vsys_shared
            if dg_name is None and templated and vsys_name is not None:
                name = module.params[vsys_name]
                if name not in (None, "shared"):
                    vo = Vsys(name)
                    parent.add(vo)
                    parent = vo

            # Spec: rulebase.
            if self.rulebase is not None:
                if module.params[self.rulebase] in (None, "pre-rulebase"):
                    rb = PreRulebase()
                    parent.add(rb)
                    parent = rb
                elif module.params[self.rulebase] == "rulebase":
                    rb = Rulebase()
                    parent.add(rb)
                    parent = rb
                elif module.params[self.rulebase] == "post-rulebase":
                    rb = PostRulebase()
                    parent.add(rb)
                    parent = rb
                else:
                    module.fail_json(msg=not_found.format(
                        "Rulebase", module.params[self.rulebase]))
        else:
            # Firewall connection.
            # Error if firewalls are not supported.
            if self.firewall_error is not None:
                module.fail_json(msg=self.firewall_error)

            # Spec: vsys or vsys_dg or vsys_importable.
            vsys_name = (self.vsys_dg or self.vsys or self.vsys_importable
                         or self.vsys_shared)
            if vsys_name is not None:
                parent.vsys = module.params[vsys_name]
                if parent.vsys == "shared" and self.error_on_firewall_shared:
                    module.fail_json(msg=no_shared)

            # Spec: rulebase.
            if self.rulebase is not None:
                rb = Rulebase()
                parent.add(rb)
                parent = rb

        # If the module has the commit option set, show a deprecation warning.
        if module.params.get("commit"):
            module.deprecate(
                "Please use the commit modules instead of the commit option",
                version="3.0.0",
                collection_name="paloaltonetworks.panos",
            )

        # Done.
        return parent
Exemplo n.º 4
0
def main():

    # Get command line arguments
    parser = argparse.ArgumentParser(
        description="Update User-ID by adding or removing a user-to-ip mapping"
    )
    parser.add_argument(
        "-v", "--verbose", action="count", help="Verbose (-vv for extra verbose)"
    )
    parser.add_argument("-q", "--quiet", action="store_true", help="No output")
    # Palo Alto Networks related arguments
    fw_group = parser.add_argument_group("Palo Alto Networks Device")
    fw_group.add_argument("hostname", help="Hostname of Firewall")
    fw_group.add_argument("username", help="Username for Firewall")
    fw_group.add_argument("password", help="Password for Firewall")
    fw_group.add_argument(
        "action", help="The action of the user. Must be 'login' or 'logout'."
    )
    fw_group.add_argument("user", help="The username of the user")
    fw_group.add_argument("ip", help="The IP address of the user")
    args = parser.parse_args()

    ### Set up logger
    # Logging Levels
    # WARNING is 30
    # INFO is 20
    # DEBUG is 10
    if args.verbose is None:
        args.verbose = 0
    if not args.quiet:
        logging_level = 20 - (args.verbose * 10)
        if logging_level <= logging.DEBUG:
            logging_format = "%(levelname)s:%(name)s:%(message)s"
        else:
            logging_format = "%(message)s"
        logging.basicConfig(format=logging_format, level=logging_level)

    # Connect to the device and determine its type (Firewall or Panorama).
    device = PanDevice.create_from_device(args.hostname, args.username, args.password,)

    logging.debug("Detecting type of device")

    # Panorama does not have a userid API, so exit.
    # You can use the userid API on a firewall with the Panorama 'target'
    # parameter by creating a Panorama object first, then create a
    # Firewall object with the 'panorama' and 'serial' variables populated.
    if issubclass(type(device), Panorama):
        logging.error(
            "Connected to a Panorama, but user-id API is not possible on Panorama.  Exiting."
        )
        sys.exit(1)

    if args.action == "login":
        logging.debug("Login user %s at IP %s" % (args.user, args.ip))
        device.userid.login(args.user, args.ip)
    elif args.action == "logout":
        logging.debug("Logout user %s at IP %s" % (args.user, args.ip))
        device.userid.logout(args.user, args.ip)
    else:
        raise ValueError(
            "Unknown action: %s.  Must be 'login' or 'logout'." % args.action
        )

    logging.debug("Done")
Exemplo n.º 5
0
def main():
    argument_spec = dict(
        ip_address=dict(required=True),
        password=dict(no_log=True),
        username=dict(default="admin"),
        api_key=dict(no_log=True),
        operation=dict(required=True,
                       choices=["add", "update", "delete", "find"]),
        addressobject=dict(default=None),
        addressgroup=dict(default=None),
        serviceobject=dict(default=None),
        servicegroup=dict(default=None),
        address=dict(default=None),
        address_type=dict(default="ip-netmask",
                          choices=["ip-netmask", "ip-range", "fqdn"]),
        static_value=dict(type="list", elements="str", default=None),
        dynamic_value=dict(default=None),
        protocol=dict(default=None, choices=["tcp", "udp"]),
        source_port=dict(default=None),
        destination_port=dict(default=None),
        services=dict(type="list", elements="str", default=None),
        description=dict(default=None),
        tag_name=dict(default=None),
        color=dict(
            default=None,
            choices=[
                "red",
                "green",
                "blue",
                "yellow",
                "copper",
                "orange",
                "purple",
                "gray",
                "light green",
                "cyan",
                "light gray",
                "blue gray",
                "lime",
                "black",
                "gold",
                "brown",
            ],
        ),
        vsys=dict(default="vsys1"),
        devicegroup=dict(default=None),
        commit=dict(type="bool", default=False),
    )
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=False,
        required_one_of=[["api_key", "password"]],
        mutually_exclusive=[[
            "addressobject",
            "addressgroup",
            "serviceobject",
            "servicegroup",
            "tag_name",
        ]],
    )
    if not HAS_LIB:
        module.fail_json(msg="Missing required libraries.")

    ip_address = module.params["ip_address"]
    password = module.params["password"]
    username = module.params["username"]
    api_key = module.params["api_key"]
    operation = module.params["operation"]
    addressobject = module.params["addressobject"]
    addressgroup = module.params["addressgroup"]
    serviceobject = module.params["serviceobject"]
    servicegroup = module.params["servicegroup"]
    address = module.params["address"]
    address_type = module.params["address_type"]
    static_value = module.params["static_value"]
    dynamic_value = module.params["dynamic_value"]
    protocol = module.params["protocol"]
    source_port = module.params["source_port"]
    destination_port = module.params["destination_port"]
    services = module.params["services"]
    description = module.params["description"]
    tag_name = module.params["tag_name"]
    color = module.params["color"]
    vsys = module.params["vsys"]
    devicegroup = module.params["devicegroup"]
    commit = module.params["commit"]

    # Create the device with the appropriate pandevice type
    device = PanDevice.create_from_device(ip_address,
                                          username,
                                          password,
                                          api_key=api_key)

    # If Panorama, validate the devicegroup
    dev_group = None
    if hasattr(device, "refresh_devices"):
        # Panorama: set the device group.
        if devicegroup == "shared":
            # Device group of None is "shared" scope for Panorama.
            devicegroup = None
        if devicegroup is not None:
            dev_group = get_devicegroup(device, devicegroup)
            if dev_group:
                device.add(dev_group)
            else:
                module.fail_json(
                    msg=
                    "'%s' device group not found in Panorama. Is the name correct?"
                    % devicegroup)
    else:
        # Firewall: set the targetted vsys.
        device.vsys = vsys

    # What type of object are we talking about?
    if addressobject:
        obj_name = addressobject
        obj_type = objects.AddressObject
    elif addressgroup:
        obj_name = addressgroup
        obj_type = objects.AddressGroup
    elif serviceobject:
        obj_name = serviceobject
        obj_type = objects.ServiceObject
    elif servicegroup:
        obj_name = servicegroup
        obj_type = objects.ServiceGroup
    elif tag_name:
        obj_name = tag_name
        obj_type = objects.Tag
    else:
        module.fail_json(msg="No object type defined!")

    # Which operation shall we perform on the object?
    msg = None
    if operation == "find":
        # Search for the object
        match = find_object(device, dev_group, obj_name, obj_type)

        # If found, format and return the result
        if match:
            match_dict = xmltodict.parse(match.element_str())
            module.exit_json(stdout_lines=json.dumps(match_dict, indent=2),
                             msg="Object matched")
        else:
            module.fail_json(
                msg="Object '%s' not found. Is the name correct?" % obj_name)
    elif operation == "delete":
        # Search for the object
        match = find_object(device, dev_group, obj_name, obj_type)

        # If found, delete it
        if match:
            try:
                match.delete()
            except PanXapiError as e:
                module.fail_json(msg=e.message)

            msg = "Object '{0}' successfully deleted".format(obj_name)
        else:
            module.fail_json(
                msg="Object '%s' not found. Is the name correct?" % obj_name)
    elif operation == "add":
        # Search for the object. Fail if found.
        match = find_object(device, dev_group, obj_name, obj_type)
        if match:
            module.fail_json(
                msg=
                "Object '%s' already exists. Use operation: 'update' to change it."
                % obj_name)
        else:
            try:
                new_object = create_object(
                    addressobject=addressobject,
                    addressgroup=addressgroup,
                    serviceobject=serviceobject,
                    servicegroup=servicegroup,
                    address=address,
                    address_type=address_type,
                    static_value=static_value,
                    dynamic_value=dynamic_value,
                    protocol=protocol,
                    source_port=source_port,
                    destination_port=destination_port,
                    services=services,
                    description=description,
                    tag_name=tag_name,
                    color=color,
                )
                changed = add_object(device, dev_group, new_object)
            except PanXapiError as e:
                module.fail_json(msg=e.message)
        msg = "Object '{0}' successfully added".format(obj_name)
    elif operation == "update":
        # Search for the object. Update if found.
        match = find_object(device, dev_group, obj_name, obj_type)
        if match:
            try:
                new_object = create_object(
                    addressobject=addressobject,
                    addressgroup=addressgroup,
                    serviceobject=serviceobject,
                    servicegroup=servicegroup,
                    address=address,
                    address_type=address_type,
                    static_value=static_value,
                    dynamic_value=dynamic_value,
                    protocol=protocol,
                    source_port=source_port,
                    destination_port=destination_port,
                    services=services,
                    description=description,
                    tag_name=tag_name,
                    color=color,
                )
                changed = add_object(device, dev_group, new_object)
            except PanXapiError as e:
                module.fail_json(msg=e.message)
            msg = "Object '{0}' successfully updated.".format(obj_name)
        else:
            module.fail_json(
                msg=
                "Object '%s' does not exist. Use operation: 'add' to add it." %
                obj_name)

    # Optional: commit the change.
    if commit:
        try:
            device.commit(sync=True)
        except PanDeviceError as e:
            module.fail_json(msg="Failed to commit: {0}".format(e))

    # Done.
    module.exit_json(changed=True, msg=msg)
Exemplo n.º 6
0
def main():
    argument_spec = dict(
        ip_address=dict(required=True),
        password=dict(no_log=True),
        username=dict(default='admin'),
        api_key=dict(no_log=True),
        operation=dict(required=True,
                       choices=['add', 'update', 'delete', 'find']),
        addressobject=dict(default=None),
        addressgroup=dict(default=None),
        serviceobject=dict(default=None),
        servicegroup=dict(default=None),
        address=dict(default=None),
        address_type=dict(default='ip-netmask',
                          choices=['ip-netmask', 'ip-range', 'fqdn']),
        static_value=dict(type='list', elements='str', default=None),
        dynamic_value=dict(default=None),
        protocol=dict(default=None, choices=['tcp', 'udp']),
        source_port=dict(default=None),
        destination_port=dict(default=None),
        services=dict(type='list', elements='str', default=None),
        description=dict(default=None),
        tag_name=dict(default=None),
        color=dict(default=None,
                   choices=[
                       'red', 'green', 'blue', 'yellow', 'copper', 'orange',
                       'purple', 'gray', 'light green', 'cyan', 'light gray',
                       'blue gray', 'lime', 'black', 'gold', 'brown'
                   ]),
        vsys=dict(default='vsys1'),
        devicegroup=dict(default=None),
        commit=dict(type='bool', default=False),
    )
    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=False,
                           required_one_of=[['api_key', 'password']],
                           mutually_exclusive=[[
                               'addressobject', 'addressgroup',
                               'serviceobject', 'servicegroup', 'tag_name'
                           ]])
    if not HAS_LIB:
        module.fail_json(msg='Missing required libraries.')

    ip_address = module.params["ip_address"]
    password = module.params["password"]
    username = module.params['username']
    api_key = module.params['api_key']
    operation = module.params['operation']
    addressobject = module.params['addressobject']
    addressgroup = module.params['addressgroup']
    serviceobject = module.params['serviceobject']
    servicegroup = module.params['servicegroup']
    address = module.params['address']
    address_type = module.params['address_type']
    static_value = module.params['static_value']
    dynamic_value = module.params['dynamic_value']
    protocol = module.params['protocol']
    source_port = module.params['source_port']
    destination_port = module.params['destination_port']
    services = module.params['services']
    description = module.params['description']
    tag_name = module.params['tag_name']
    color = module.params['color']
    vsys = module.params['vsys']
    devicegroup = module.params['devicegroup']
    commit = module.params['commit']

    # Create the device with the appropriate pandevice type
    device = PanDevice.create_from_device(ip_address,
                                          username,
                                          password,
                                          api_key=api_key)

    # If Panorama, validate the devicegroup
    dev_group = None
    if hasattr(device, 'refresh_devices'):
        # Panorama: set the device group.
        if devicegroup == 'shared':
            # Device group of None is "shared" scope for Panorama.
            devicegroup = None
        if devicegroup is not None:
            dev_group = get_devicegroup(device, devicegroup)
            if dev_group:
                device.add(dev_group)
            else:
                module.fail_json(
                    msg=
                    '\'%s\' device group not found in Panorama. Is the name correct?'
                    % devicegroup)
    else:
        # Firewall: set the targetted vsys.
        device.vsys = vsys

    # What type of object are we talking about?
    if addressobject:
        obj_name = addressobject
        obj_type = objects.AddressObject
    elif addressgroup:
        obj_name = addressgroup
        obj_type = objects.AddressGroup
    elif serviceobject:
        obj_name = serviceobject
        obj_type = objects.ServiceObject
    elif servicegroup:
        obj_name = servicegroup
        obj_type = objects.ServiceGroup
    elif tag_name:
        obj_name = tag_name
        obj_type = objects.Tag
    else:
        module.fail_json(msg='No object type defined!')

    # Which operation shall we perform on the object?
    msg = None
    if operation == "find":
        # Search for the object
        match = find_object(device, dev_group, obj_name, obj_type)

        # If found, format and return the result
        if match:
            match_dict = xmltodict.parse(match.element_str())
            module.exit_json(stdout_lines=json.dumps(match_dict, indent=2),
                             msg='Object matched')
        else:
            module.fail_json(
                msg='Object \'%s\' not found. Is the name correct?' % obj_name)
    elif operation == "delete":
        # Search for the object
        match = find_object(device, dev_group, obj_name, obj_type)

        # If found, delete it
        if match:
            try:
                match.delete()
            except PanXapiError as e:
                module.fail_json(msg=e.message)

            msg = "Object '{0}' successfully deleted".format(obj_name)
        else:
            module.fail_json(
                msg='Object \'%s\' not found. Is the name correct?' % obj_name)
    elif operation == "add":
        # Search for the object. Fail if found.
        match = find_object(device, dev_group, obj_name, obj_type)
        if match:
            module.fail_json(
                msg=
                'Object \'%s\' already exists. Use operation: \'update\' to change it.'
                % obj_name)
        else:
            try:
                new_object = create_object(addressobject=addressobject,
                                           addressgroup=addressgroup,
                                           serviceobject=serviceobject,
                                           servicegroup=servicegroup,
                                           address=address,
                                           address_type=address_type,
                                           static_value=static_value,
                                           dynamic_value=dynamic_value,
                                           protocol=protocol,
                                           source_port=source_port,
                                           destination_port=destination_port,
                                           services=services,
                                           description=description,
                                           tag_name=tag_name,
                                           color=color)
                changed = add_object(device, dev_group, new_object)
            except PanXapiError as e:
                module.fail_json(msg=e.message)
        msg = "Object '{0}' successfully added".format(obj_name)
    elif operation == "update":
        # Search for the object. Update if found.
        match = find_object(device, dev_group, obj_name, obj_type)
        if match:
            try:
                new_object = create_object(addressobject=addressobject,
                                           addressgroup=addressgroup,
                                           serviceobject=serviceobject,
                                           servicegroup=servicegroup,
                                           address=address,
                                           address_type=address_type,
                                           static_value=static_value,
                                           dynamic_value=dynamic_value,
                                           protocol=protocol,
                                           source_port=source_port,
                                           destination_port=destination_port,
                                           services=services,
                                           description=description,
                                           tag_name=tag_name,
                                           color=color)
                changed = add_object(device, dev_group, new_object)
            except PanXapiError as e:
                module.fail_json(msg=e.message)
            msg = "Object '{0}' successfully updated.".format(obj_name)
        else:
            module.fail_json(
                msg=
                'Object \'%s\' does not exist. Use operation: \'add\' to add it.'
                % obj_name)

    # Optional: commit the change.
    if commit:
        try:
            device.commit(sync=True)
        except PanDeviceError as e:
            module.fail_json(msg='Failed to commit: {0}'.format(e))

    # Done.
    module.exit_json(changed=True, msg=msg)