'@inherits: :class:`NodeDriver.list_nodes`
:keyword    project: Limit nodes returned to those configured under
the defined project.
:type       project: :class:`.CloudStackProject`
:keyword    location: Limit nodes returned to those in the defined
location.
:type       location: :class:`.NodeLocation`
:rtype: ``list`` of :class:`CloudStackNode`'

def list_nodes(self, project=None, location=None):

    args = {}
    if project:
        args['projectid'] = project.id
    if (location is not None):
        args['zoneid'] = location.id
    vms = self._sync_request('listVirtualMachines', params=args)
    addrs = self._sync_request('listPublicIpAddresses', params=args)
    port_forwarding_rules = self._sync_request('listPortForwardingRules')
    ip_forwarding_rules = self._sync_request('listIpForwardingRules')
    public_ips_map = {}
    for addr in addrs.get('publicipaddress', []):
        if ('virtualmachineid' not in addr):
            continue
        vm_id = str(addr['virtualmachineid'])
        if (vm_id not in public_ips_map):
            public_ips_map[vm_id] = {}
        public_ips_map[vm_id][addr['ipaddress']] = addr['id']
    nodes = []
    for vm in vms.get('virtualmachine', []):
        public_ips = public_ips_map.get(str(vm['id']), {}).keys()
        public_ips = list(public_ips)
        node = self._to_node(data=vm, public_ips=public_ips)
        addresses = public_ips_map.get(str(vm['id']), {}).items()
        addresses = [CloudStackAddress(id=address_id, address=address, driver=node.driver) for (address, address_id) in addresses]
        node.extra['ip_addresses'] = addresses
        rules = []
        for addr in addresses:
            for r in ip_forwarding_rules.get('ipforwardingrule', []):
                if (str(r['virtualmachineid']) == node.id):
                    rule = CloudStackIPForwardingRule(node, r['id'], addr, r['protocol'].upper(), r['startport'], r['endport'])
                    rules.append(rule)
        node.extra['ip_forwarding_rules'] = rules
        rules = []
        for r in port_forwarding_rules.get('portforwardingrule', []):
            if (str(r['virtualmachineid']) == node.id):
                addr = [CloudStackAddress(id=a['id'], address=a['ipaddress'], driver=node.driver) for a in addrs.get('publicipaddress', []) if (a['ipaddress'] == r['ipaddress'])]
                rule = CloudStackPortForwardingRule(node, r['id'], addr[0], r['protocol'].upper(), r['publicport'], r['privateport'], r['publicendport'], r['privateendport'])
                if (not (addr[0].address in node.public_ips)):
                    node.public_ips.append(addr[0].address)
                rules.append(rule)
        node.extra['port_forwarding_rules'] = rules
        nodes.append(node)
    return nodes
