Open russellpope opened 8 years ago
Just a quick update. I'm going over this function and I see that based on how the conditional is written I never actually get a True result because some of the things it's comparing are uppercase to lowercase. Also my parent object appears to not always be the tenant the contract/filter was defined in so it doesn't find the filterentries in the query_url.
Here's what I've hacked up so far. Debating adding logic to check the common tenant if the parent.name tenant value comes up empty.
@classmethod
def get(cls, session, parent, tenant):
"""
To get all of acitoolkit style Filter Entries APIC class.
:param session: the instance of Session used for APIC communication
:param parent: Object to assign as the parent to the created objects.
:param tenant: Tenant object to assign the created objects.
"""
apic_class = 'vzRsSubjFiltAtt'
if isinstance(tenant, str):
raise TypeError
logging.debug('%s.get called', cls.__name__)
if tenant is None:
tenant_url = ''
else:
tenant_url = '/tn-%s' % tenant.name
if parent is not None:
tenant_url = tenant_url + parent._get_url_extension()
query_url = ('/api/mo/uni%s.json?query-target=subtree&'
'target-subtree-class=%s' % (tenant_url, apic_class))
ret = session.get(query_url)
data = ret.json()['imdata']
logging.debug('response returned %s', data)
resp = []
for object_data in data:
dn = object_data['vzRsSubjFiltAtt']['attributes']['dn']
tDn = object_data['vzRsSubjFiltAtt']['attributes']['tDn']
tRn = object_data['vzRsSubjFiltAtt']['attributes']['tRn']
if dn.split('/')[2][4:].upper() == parent.name.upper() and \
dn.split('/')[4][len(apic_class) - 1:].upper() == dn.split('/')[3][5:].upper() and \
dn.split('/')[3][5:].upper() == tDn.split('/')[2][4:].upper() and \
tDn.split('/')[2][4:].upper() == tRn[4:].upper():
filter_name = str(object_data[apic_class]['attributes']['tRn'][4:])
contract_name = filter_name[:len(parent.name)]
entry_name = filter_name[:len(parent.name)]
if contract_name.upper() == parent.name.upper() and entry_name != '':
query_url = ('/api/mo/uni%s/flt-%s.json?query-target=subtree&'
'target-subtree-class=vzEntry&'
'query-target-filter=eq(vzEntry.name,"%s")' % (tenant_url, filter_name, entry_name))
ret = session.get(query_url)
filter_data = ret.json()['imdata']
if len(filter_data) == 0:
continue
logging.debug('response returned %s', filter_data)
resp = []
obj = cls(entry_name, parent)
attribute_data = filter_data[0]['vzEntry']['attributes']
obj._populate_from_attributes(attribute_data)
resp.append(obj)
return resp
Any thoughts? Has anyone else seen this behavior?
The APIC object model uses vzBrCP, vzSubj, vzRsSubjFiltAtt, vzFilter, vzEntry classes to define the contract and filter entries. Originally, the ACI toolkit simplified this to only Contract and FilterEntry. These are mapped directly to vzBrCP and vzEntry respectively. The intermediate objects (vzSubj, vzRsSubjFiltAtt, vzFilter) were automatically created and named using a mashup of the FilterEntry name. The current FilterEntry.get() will only collect the FilterEntry objects that were created in this manner i.e. it only collects FilterEntry objects that were created by the ACI toolkit. This is likely the reason you are not seeing the entries.
Since then, the ACI toolkit has added the ContractSubject and Filter classes to map to vzSubj and vzFilter. It also continues to support placing the FilterEntry directly within the Contract in the previous manner. The FilterEntry.get() needs to be updated to support this and provide the ability to collect all of the filter entries in the APIC. We should also update the sample script so that it can collect all of the filter entries.
Awesome, thanks for the update. I'm glad I'm not totally insane. I'll see what I can sort out based on your guidance. Looking forward to your next update. I'm actually enjoying working with the toolkit otherwise.
Another way is to use the get_deep() function. I've added a new sample file to the repo showing how this can be done. https://github.com/datacenter/acitoolkit/blob/master/samples/aci-show-all-filter-entries.py
Hrmm, I get an error:
Traceback (most recent call last):
File "/Users/ldh/github.kovarus/aci-applications/aci-show-all-filter-entries.py", line 68, in <module>
for aci_filter in tenant.get_children(ACI.Filter):
AttributeError: 'module' object has no attribute 'Filter'
I tried swapping it to ACI.FilterEntry and it still returns nothing. Going to try in a new clean venv in case I broke something.
I just pulled a new clone on Ubuntu and the script is working in a fresh install. Is it possible you need to re-run "python setup.py install" ? Filter was added to the init.py file in February 2016. If your install was run before that, it will need to be re-run.
Oops yeap I was just being dopey. New venv and a re-install sorted me.
I just meet the same issue as yours,then I make a little change to the Filter.get() function,an it worked...Here is the script: ` def get(cls, session, parent, tenant): """ To get all of acitoolkit style Filter Entries APIC class.
:param session: the instance of Session used for APIC communication
:param parent: Object to assign as the parent to the created objects.
:param tenant: Tenant object to assign the created objects.
"""
apic_class = 'vzRsSubjFiltAtt'
if isinstance(tenant, str):
raise TypeError
logging.debug('%s.get called', cls.__name__)
if tenant is None:
tenant_url = ''
else:
tenant_url = '/tn-%s' % tenant.name
if parent is not None:
tenant_url = tenant_url + parent._get_url_extension()
query_url = ('/api/mo/uni%s.json?query-target=subtree&'
'target-subtree-class=%s' % (tenant_url, apic_class))
ret = session.get(query_url)
data = ret.json()['imdata']
logging.debug('response returned %s', data)
resp = []
for object_data in data:
dn = object_data['vzRsSubjFiltAtt']['attributes']['dn']
tDn = object_data['vzRsSubjFiltAtt']['attributes']['tDn']
tRn = object_data['vzRsSubjFiltAtt']['attributes']['tRn']
if dn.split('/')[2][4:] == parent.name:
filter_name = str(object_data[apic_class]['attributes']['tRn'][4:])
contract_name = dn.split('/')[2][4:]
if tDn.split('/')[1]=='tn-common':
query_url=('/api/mo/uni/tn-common/flt-%s.json?query-target=subtree&'
'target-subtree-class=vzEntry' % filter_name)
else:
query_url = ('/api/mo/uni%s/flt-%s.json?query-target=subtree&'
'target-subtree-class=vzEntry' % (tenant_url, filter_name))
ret = session.get(query_url)
filter_data = ret.json()['imdata']
logging.debug('response returned %s', filter_data)
entry_name=filter_data[0]['vzEntry']['attributes']['name']
obj = cls(entry_name, parent)
attribute_data = filter_data[0]['vzEntry']['attributes']
obj._populate_from_attributes(attribute_data)
resp.append(obj)
return resp`
Hey there,
I'm trying to get the filter entries via FilterEntry.get(session, parent=contract, tenant=tenant) but it seems to return empty lists.
Assuming I was doing something wrong I tried your sample her: samples/aci-show-filter-entries.py and I get the same empty output: Filter Entries Contract Tenant
Process finished with exit code 0
I'm logging in with the admin account on the APIC. When I use the API browser I see one that I expect: url: https://10.1.2.201/api/node/mo/uni/tn-kpsc/flt-https_inbound.json?query-target=children&target-subtree-class=vzEntry&subscription=yes response:
{"totalCount":"1","subscriptionId":"72058006372483231","imdata":[{"vzEntry":{"attributes":{"applyToFrag":"no","arpOpc":"unspecified","childAction":"","dFromPort":"https","dToPort":"https","descr":"","dn":"uni/tn-kpsc/flt-https_inbound/e-https_in","etherT":"ip","icmpv4T":"unspecified","icmpv6T":"unspecified","lcOwn":"local","matchDscp":"unspecified","modTs":"2016-06-08T17:04:21.134+00:00","name":"https_in","prot":"tcp","sFromPort":"unspecified","sToPort":"unspecified","stateful":"no","status":"","tcpRules":"","uid":"15374"}}}]}
I'm certain I'm doing something wrong here but I can't seem to sort it out.
Any help would be appreciated!
editing to add information.
I debugged it and I see when I hit this URL with a REST client like postman I get: 'https://10.1.2.201/api/mo/uni/tn-kpsc.json?query-target=subtree&target-subtree-class=vzRsSubjFiltAtt'
It returns this JSON (I've truncated it for brevity):
Which does include the filters I'd expect to see so I think my configuration on the device is fine.