Topics Map > Networking
Networking, Lens, Common Lens API Requests
Click on the descriptions below to see the source code of scripts that will perform these common requests.
Enumerate MAC addresses and bound IP addresses found on a network
This script will enumerate all the MAC addresses and any bound IP addresses for a network.
NOTE: This revised example demonstrates how to "dress up" a result in order to fetch more data with less work and fewer queries. In this example, all of the data are returned together in one result. There is no need to match the mac_port and ip_mac objects by MAC address and time because the API can package the related data together.
#!/usr/bin/perl -w # # Author: (jwm) Jonathan Marks # Thu Oct 15 11:57:30 CDT 2009 # Copyright (c) 2009 University of Illinois Board of Trustees. # # Lens API example script: enumerates MAC addresses and bound IP addresses # found on a network. # use LWP; use YAML; use Term::ReadPassword; use strict; my $net = shift @ARGV || die "Missing network name.\n"; # Network expected on command line # Collect API contact information # my $hostname = $ENV{LENSAPI_HOSTNAME} || 'lens-api.techservices.illinois.edu'; my $port = $ENV{LENSAPI_PORT} || 443; my $auth_realm = $ENV{LENSAPI_REALM} || 'Lens API'; my $username = $ENV{LENSAPI_USERNAME} || getpwuid($>); my $passwd = $ENV{LENSAPI_PASSWORD} || read_password("Password for $username: "); # Construct an HTTP client agent, loaded with authentication credentials my $ua = LWP::UserAgent->new; $ua->credentials("$hostname:$port", $auth_realm, $username, $passwd); # Build the query URL and issue GET request for YAML-encoded mac_port data my $url = "https://$hostname:$port/api/mac_port?vlan_name=$net"; $url .= "&dressings=mpt_ip_addresses"; my $response = $ua->get($url, content_type => 'text/x-yaml'); die "HTTPS Request Failed with ", $response->status_line, "\n" unless ($response->is_success); # Turn the YAML-encoded result into plain ol' perlish data. # See the result object format docs for a breakdown of the object! my $mac_port_result = YAML::Load($response->content); die "API Call failed with \"$mac_port_result->{error}\"\n" if ($mac_port_result->{status} ne 'SUCCESS'); # The answer is in hand. Every mac_port object identified in the # result list is dressed with the IP addresses that bound the MAC. # So for each mac_port ID in the result list... foreach my $mac_port_id (@{$mac_port_result->{result}}) { # Fetch the actual object from the mac_port section of the objects table my $mac_port = $mac_port_result->{objects}{mac_port}{$mac_port_id}; print "MAC $mac_port->{mac} seen on ", "$mac_port->{device_name} port $mac_port->{ifname}\n", "\tbetween $mac_port->{first_seen} and $mac_port->{last_seen}\n"; # Then find the list of ip_mac IDs in its "ip_addresses" field foreach my $ip_mac_id (@{$mac_port->{ip_addresses}}) { # Fetch it from the "ip_mac" object table and print them together my $ip_mac = $mac_port_result->{objects}{ip_mac}{$ip_mac_id}; print "\tWith IP $ip_mac->{ip} between ", max($mac_port->{first_seen}, $ip_mac->{first_seen}), " and ", min($mac_port->{last_seen}, $ip_mac->{last_seen}), "\n"; } } # Note the time format compares the same lexicographically as # chronologically. How convenient is THAT! sub min { ($_[0] lt $_[1]) ? $_[0] : $_[1] } sub max { ($_[0] lt $_[1]) ? $_[1] : $_[0] }
Enumerate current IP/port information by MAC address
NOTE: This revised example demonstrates how to "dress up" a result in order to fetch more data with less work and fewer queries. In this example, all of the data are returned together in one result. There is no need to match the mac_port and ip_mac objects with multiple queries.
#!/usr/bin/perl -w # # Author: (jwm) Jonathan Marks # Thu Oct 15 # Copyright (c) 2009 University of Illinois Board of Trustees. # # Lens API example script: Shows the current IP address and # switch port for a MAC address given as a command-line argument. # use LWP; use YAML; use Term::ReadPassword; use strict; my $mac = shift @ARGV || die "Missing MAC address.\n"; # Network expected on command line # Lens API wants an unpunctuated uppercase MAC format. Leave only alphanums $mac =~ s/[^\w]|_//og; $mac = uc($mac); # Collect API contact information # my $hostname = $ENV{LENSAPI_HOSTNAME} || 'lens-api.techservices.illinois.edu'; my $port = $ENV{LENSAPI_PORT} || 443; my $auth_realm = $ENV{LENSAPI_REALM} || 'Lens API'; my $username = $ENV{LENSAPI_USERNAME} || getpwuid($>); my $passwd = $ENV{LENSAPI_PASSWORD} || read_password("Password for $username: "); # Construct an HTTP client agent, loaded with authentication credentials my $ua = LWP::UserAgent->new; $ua->credentials("$hostname:$port", $auth_realm, $username, $passwd); # Build the query URL and issue GET request for YAML-encoded mac_port data. # The query seeks a current mac_port observation and dresses in ip_mac # items related by its "ip_addresses" relationship. my $url = "https://$hostname:$port/api" . "/mac_port?mac=$mac&dressings=mpt_ip_addresses"; my $response = $ua->get($url, content_type => 'text/x-yaml'); die "HTTPS Request Failed with ", $response->status_line, "\n" unless ($response->is_success); # Turn the YAML-encoded result into plain ol' perlish data. # See the result object format docs for a breakdown of the object! my $mac_port_result = YAML::Load($response->content); die "API Call failed with \"$mac_port_result->{error}\"\n" if ($mac_port_result->{status} ne 'SUCCESS'); if (! @{$mac_port_result->{result}}) { # Empty result list means no observations are available print "MAC $mac is not presently seen.\n"; exit(0); } # A MAC may never be found in two places on one VLAN. If there are multiple # records then the MAC is on more than one VLAN somehow. (A Sun host? Recently # moved between networks so that multiple switches still remember it?) Well, # this *could* happen, but each mac_port observation is individually dressed # with its related ip_mac observations so there isn't anything left to fetch # or sort out. It's all here so I'll print it. foreach my $mac_port_id (@{$mac_port_result->{result}}) { # Each mac_port ID in the object result list has its instance in the # objects map. Fetch the current instance. my $mac_port = $mac_port_result->{objects}{mac_port}{$mac_port_id}; print "MAC $mac_port->{mac} seen on ", "$mac_port->{device_name} port $mac_port->{ifname} ", "on VLAN $mac_port->{vlan_name}\n", "\tbetween $mac_port->{first_seen} and $mac_port->{last_seen}\n"; # Each mac_port instance has an "ip_addresses" attribute added to it, and # its value is a list of ip_mac IDs for related ip_mac objects. Take the # list and use it to fetch the related ip_mac data from the same result. my @ip_mac_ids = @{$mac_port->{ip_addresses} || []}; my @ip_macs = map { $mac_port_result->{objects}{ip_mac}{$_} } @ip_mac_ids; # map from the ID list to a list of ip_mac instances fetched per ID foreach my $ip_mac (@ip_macs) { print "\tWith IP $ip_mac->{ip} between ", max($mac_port->{first_seen}, $ip_mac->{first_seen}), " and ", min($mac_port->{last_seen}, $ip_mac->{last_seen}), "\n"; } print "\tNo IP addresses found.\n" unless (@ip_macs); } # Note the time format compares the same lexicographically as # chronologically. How convenient is THAT! sub min { ($_[0] lt $_[1]) ? $_[0] : $_[1] } sub max { ($_[0] lt $_[1]) ? $_[1] : $_[0] }
Show the IP address and switch port history for a MAC address
NOTE: This revised example demonstrates how to "dress up" a result in order to fetch more data with less work and fewer queries. In this example, all of the data are returned together in one result. There is no need to match the mac_port and ip_mac objects with multiple queries. In fact, the program is simplified enough to closely resemble the program above with only the addition of date context parameters for historical query.
#!/usr/bin/perl -w # # Author: (jwm) Jonathan Marks # Thu Oct 15 # Copyright (c) 2009 University of Illinois Board of Trustees. # # Lens API example script: Shows the IP address and switch port # history for a MAC address given as a command-line argument. # use LWP; use YAML; use Term::ReadPassword; use strict; my $mac = shift @ARGV || die "Missing MAC address.\n"; # Network expected on command line # Lens API wants an unpunctuated uppercase MAC format. Leave only alphanums $mac =~ s/[^\w]|_//og; $mac = uc($mac); my $start_date = shift @ARGV or die "Missing start date.\n"; my $end_date = shift @ARGV or die "Missing end date.\n"; # Collect API contact information # my $hostname = $ENV{LENSAPI_HOSTNAME} || 'lens-api.techservices.illinois.edu'; my $port = $ENV{LENSAPI_PORT} || 443; my $auth_realm = $ENV{LENSAPI_REALM} || 'Lens API'; my $username = $ENV{LENSAPI_USERNAME} || getpwuid($>); my $passwd = $ENV{LENSAPI_PASSWORD} || read_password("Password for $username: "); # Construct an HTTP client agent, loaded with authentication credentials my $ua = LWP::UserAgent->new; $ua->credentials("$hostname:$port", $auth_realm, $username, $passwd); # Build the query URL and issue GET request for YAML-encoded mac_port data. # The query seeks a current mac_port observation and dresses in ip_mac # items related by its "ip_addresses" relationship. my $context_clause = "&context:start_date=$start_date&context:end_date=$end_date"; my $url = "https://$hostname:$port/api" . "/mac_port?mac=$mac&dressings=mpt_ip_addresses" . $context_clause; my $response = $ua->get($url, content_type => 'text/x-yaml'); die "HTTPS Request Failed with ", $response->status_line, "\n" unless ($response->is_success); # Turn the YAML-encoded result into plain ol' perlish data. # See the result object format docs for a breakdown of the object! my $mac_port_result = YAML::Load($response->content); die "API Call failed with \"$mac_port_result->{error}\"\n" if ($mac_port_result->{status} ne 'SUCCESS'); if (! @{$mac_port_result->{result}}) { # Empty result list means no observations are available print "MAC $mac is unknown.\n"; exit(0); } # A MAC may never be found in two places on one VLAN. If there are multiple # records then the MAC is on more than one VLAN somehow. (A Sun host? Recently # moved between networks so that multiple switches still remember it?) Well, # this *could* happen, but each mac_port observation is individually dressed # with its related ip_mac observations so there isn't anything left to fetch # or sort out. It's all here so I'll print it. foreach my $mac_port_id (@{$mac_port_result->{result}}) { # Each mac_port ID in the object result list has its instance in the # objects map. Fetch the current instance. my $mac_port = $mac_port_result->{objects}{mac_port}{$mac_port_id}; print "MAC $mac_port->{mac} seen on ", "$mac_port->{device_name} port $mac_port->{ifname} ", "on VLAN $mac_port->{vlan_name}\n", "\tbetween $mac_port->{first_seen} and $mac_port->{last_seen}\n"; # Each mac_port instance has an "ip_addresses" attribute added to it, and # its value is a list of ip_mac IDs for related ip_mac objects. Take the # list and use it to fetch the related ip_mac data from the same result. my @ip_mac_ids = @{$mac_port->{ip_addresses} || []}; my @ip_macs = map { $mac_port_result->{objects}{ip_mac}{$_} } @ip_mac_ids; # map from the ID list to a list of ip_mac instances fetched per ID foreach my $ip_mac (@ip_macs) { print "\tWith IP $ip_mac->{ip} between ", max($mac_port->{first_seen}, $ip_mac->{first_seen}), " and ", min($mac_port->{last_seen}, $ip_mac->{last_seen}), "\n"; } print "\tNo IP addresses found.\n" unless (@ip_macs); } # Note the time format compares the same lexicographically as # chronologically. How convenient is THAT! sub min { ($_[0] lt $_[1]) ? $_[0] : $_[1] } sub max { ($_[0] lt $_[1]) ? $_[1] : $_[0] }