Examples: Test Agents
Creating and Deploying a New Test Agent
To be able to perform measurements in Paragon Active Assurance, you first need to create one or more Test Agents in your Paragon Active Assurance account. This section tells how to create virtual Test Agents using the REST API.
We proceed in the following steps, which are detailed in the following:
- At the outset, the account "demo" has no Test Agents in its inventory.
- A Test Agent called "vta1" is created through the REST API. At this stage, no real Test Agent exists yet (that is, it has not yet been started).
- The Test Agent is deployed in OpenStack. (Deployment on that platform is chosen here as one possibility among others.)
- The Test Agent connects to the Control Center account "demo" and is now ready for use.
Step 1: At the outset, there are no Test Agents in the account "demo". See the screenshot below from the Control Center web GUI.
Step 2: A Test Agent is created in Control Center using the REST API POST operation for Test Agents.
We will do this in Python below. To write the Python code, it is helpful to inspect the full range of configuration options for a Test Agent in the REST API.
- Go to
https://<Control Center host IP>/rest
. - Under test_agent, expand the POST
operation for
/accounts/{account}/test_agents/
.
- Under Description, click Model.
Below, we create a Test Agent having three physical interfaces "eth0", "eth1", and "eth2", where eth0 has a DHCP address. An NTP server is configured on eth0, and eth0 is also the management interface (that is, the interface that connects to Control Center).
(The import
commands are omitted from subsequent examples unless
they differ from the code below. The parser
commands are also
omitted, since they are always the same. Regarding the REST API token and how to
obtain it, read more in the section Obtaining an Authorization Token.)
import argparse import json import requests parser = argparse.ArgumentParser(description='Example for') parser.add_argument('--ncc-url', help='The URL where NCC is found, for example https://<hostname>/rest', required=True) parser.add_argument('--token', help='The REST API token', required=True) parser.add_argument('--account', help='The Netrounds account', required=True) args = parser.parse_args() # Request settings url = '%s/accounts/%s/test_agents/' % (args.ncc_url, args.account) # JSON content json_data = json.dumps({ 'description': 'Test agent description', 'interface_config': { 'eth0': { 'address': { 'type': 'dhcp_ip4', }, 'address6': { 'type': 'dhcp_ip6', }, 'description': 'eth0', 'mtu': 1500, 'speed': 'AUTO', 'type': 'physical' }, 'eth1': { 'address': { 'type': 'none_ip4' }, 'address6': { 'type': 'none_ip6' }, 'description': 'eth1', 'mtu': 1500, 'speed': 'AUTO', 'type': 'physical' }, 'eth2': { 'address': { 'type': 'none_ip4' }, 'address6': { 'type': 'none_ip6' }, 'description': 'eth2', 'mtu': 1500, 'speed': 'AUTO', 'type': 'physical' } }, 'license': 'UNLIMITED', 'management_interface': 'eth0', 'name': 'Test Agent 2', 'ntp_config': { 'interface_name': 'eth0', 'server': 'time.google.com', 'enable_ipv6': False }, 'type': 'appliance' }) # Create Test Agent response = requests.post(url=url, data=json_data, headers={ 'API-Token': args.token, 'Accept': 'application/json; indent=4', 'Content-Type': 'application/json', }) print 'Status code: %s' % response.status_code print json.dumps(response.json(), indent=4)
If no signed SSL certificates are present, you need to add
verify=False
to the "requests" command: see below. This is
however strongly discouraged in a production environment. You should obtain
proper, signed SSL certificates to ensure an encrypted and secure connection.
See also the section on SSL certificate configuration in the Installation
Guide, chapter Service Configuration.
# Create Test Agent response = requests.post(url=URL, data=json_data, headers={ 'API-Token': TOKEN, 'Accept': 'application/json; indent=4', 'Content-Type': 'application/json' }, verify=False )
Just to show that you might as well use a different programming language, here is how to accomplish the same thing in curl:
curl -X POST "https://<Control Center host and port>/accounts/demo/test_agents/" -H "accept: application/json" -H "content-type: application/json" -d "{ \"description\": \"Created via REST API\", \"interface_config\": { \"eth0\": { \"address\": { \"type\": \"dhcp_ip4\" }, \"address6\": { \"type\": \"dhcp_ip6\" }, \"description\": \"eth0\", \"mtu\": \"1500\", \"speed\": \"AUTO\", \"type\": \"physical\" }, \"eth1\": { \"address\": { \"type\": \"none_ip4\" }, \"address6\": { \"type\": \"none_ip6\" }, \"description\": \"eth1\", \"mtu\": \"1500\", \"speed\": \"AUTO\", \"type\": \"physical\" } }, \"license\": \"UNLIMITED\", \"management_interface\": \"eth0\", \"name\": \"vta1\", \"ntp_config\": { \"interface_name\": \"eth0\", \"server\": \"time.google.com\" }, \"type\": \"appliance\" }"
In the absence of signed SSL certificates, you need to add the
--insecure
flag here.
Once the Test Agent has been created, it will exist in the configuration database and in Control Center. See the screenshot below of the Test Agent inventory, showing the Test Agent "vta1":
Step 3: It is now time to deploy the Test Agent "vta1".
In this guide we will deploy the virtual Test Agent in OpenStack. However, it is equally possible to do the deployment in some other virtualized environment.
In OpenStack the Test Agent will use cloud-init user data to retrieve the information on how to connect to Control Center. Specifically, the user data text file has the following contents:
The #cloud-config
and netrounds_test_agent
lines must be present, and the remaining lines must be indented.
#cloud-config netrounds_test_agent: name: MyvTA # Name of vTA to appear in Control Center inventory email: john.doe@example.com # Email you use when logging in to the system password: secret # Login password account: theaccount # Account name server: <login-server>:<port> # Control Center host and port (default == SaaS) # Note: With an IPv6 server address the whole string # including port must be in double quotes
For further information, please refer to the document "How to Deploy Virtual Test Agents in OpenStack", available at https://www.juniper.net/documentation/product/en_US/paragon-active-assurance.
Once the Test Agent has been deployed and has connected to Control Center, the configuration will be pushed from Control Center to the Test Agent.
Step 4: The Test Agent is now online in Control Center and has obtained its configuration. The Test Agent is ready for use in tests and monitoring. See these sections:
Listing the Test Agents in Your Paragon Active Assurance Account
Below is example Python code for listing the Test Agents in a Paragon Active Assurance account:
# Request settings # NOTE: User is able to pass additional parameters as a query string ?limit=100&offset=111: # limit: Changes number of elements returned from API # offset: Changes element from which results will be returned url = '%s/accounts/%s/test_agents/%s' % (args.ncc_url, args.account, args.query_params) # Get list of Test Agents response = requests.get(url=url, headers={'API-Token': args.token})
Running this code gives output similar to that below:
{ "count": 2, "exclude_default": [ "interface_config", "ntp_config", "management_interface", "interface_names", "interface_states", "uptime", "memory", "cpu", "load_avg" ], "items": [ { "description": "Created via REST API", "gps_lat": 22.222222, "gps_long": -33.333333, "id": 1, "interface_names": [ "eth0", "eth1" ], "is_owner": true, "license": "SW_LARG", "name": "Test Agent A", "online": true, "type": "appliance", "use_public_address": false, "version": "3.3.0" } { ... "name": "Test Agent B", ... (same items listed for this Test Agent) } ], "limit": 10, "next": null, "offset": 0, "previous": null }
Retrieving Configuration Data and Status for a Test Agent
By applying a GET operation to an individual Test Agent, you retrieve both configuration and status information for the Test Agent and its interfaces. The status information includes online status, uptime, CPU load, and memory usage.
# Request settings url = '%s/accounts/%s/test_agents/%s/' % (args.ncc_url, args.account, args.test_agent_id) # Get Test Agent response = requests.get(url=url, headers={'API-Token': args.token})
The output will look something like this:
{ "cpu": 0.8, "description": "", "gps_lat": 22.222222, "gps_long": -33.333333, "hidden": false, "id": 5, "interface_config": { "eth0": { "address": { "type": "dhcp_ip4", "vendor": null }, "address6": { "type": "none_ip6" }, "description": "", "mac": null, "management": true, "mtu": 8900, "speed": "AUTO", "tags": [], "type": "physical" }, "eth1": { "address": { "dhcpd": null, "dns": [], "ip": "10.1.1.66/24", "routes": {}, "type": "static_ip4" }, "address6": { "dns": null, "ip": "2001:0DB8::1/64", "routes": {}, "type": "static_ip6" }, "description": "", "mac": null, "management": false, "mtu": 1500, "speed": "AUTO", "tags": [], "type": "physical" } }, "interface_states": { "eth0": { "ip4_address": "192.168.100.4/24", "ip6_address": [], "mac_hw": "08:00:27:30:be:03" }, "eth1": { "ip4_address": "10.1.1.66/24", "ip6_address": [ "2001:0DB8::1/64" ], "mac_hw": "08:00:27:80:57:51" } }, "is_owner": true, "license": "SW_MEDI", "load_avg": [ 0, 0.01, 0.05 ], "management_interface": "eth0", "memory": 22.18, "name": "VTA1", "ntp_config": { "interface_name": "eth0", "server": "time.google.com" }, "online": true, "tags": [], "type": "appliance", "uptime": 47319, "use_public_address": false, "version": "2.23.0" }
Modifying the Configuration of a Test Agent
To modify the configuration of a Test Agent you use the PUT command.
PUT requires that you supply the entire configuration in the JSON data, just as when creating the Test Agent as described in the section Creating and Deploying a New Test Agent. The code for doing this is therefore the same as for Test Agent creation, except that the URL points to a specific, existing Test Agent
# Request settings url = '%s/accounts/%s/test_agents/%s/' % (args.ncc_url, args.account, args.test_agent_id)
and the PUT command
# Update Test Agent response = requests.put(url=url, data=json_data, headers={ 'API-Token': args.token, 'Accept': 'application/json; indent=4', 'Content-Type': 'application/json', })
is used instead of POST.
Updating Test Agent Software
The REST API provides a POST operation for updating Test Agent software to the latest version, either for all Test Agents or for a specified subset.
Below is an example of how to apply a software update to a subset of Test Agents:
# Request settings url = '%s/accounts/%s/test_agents/update/' % (args.ncc_url, args.account) # JSON content: Subset of Test Agents on which to update software # POST http://server/accounts/acount_name/test_agents/update json_data = json.dumps({ 'test_agent_ids': args.test_agent_ids.split(',') }) # Update Test Agent version response = requests.post(url=url, data=json_data, headers={ 'API-Token': args.token, 'Accept': 'application/json; indent=4', 'Content-Type': 'application/json', })
If you want to update software on all Test Agents, leave json_data
empty and append the ?all
switch to the URL:
# Request settings url = '%s/accounts/%s/test_agents/update/?all' % (args.ncc_url, args.account)
Test Agents: Advanced Examples
In order to make use of all configuration options for the Test Agent (or indeed any other entity in the REST API), you need to be familiar with the REST API Swagger schema.
As previously mentioned, a link to the schema in JSON format is provided at the top of the page. This is rather hard to read; to make the content easier to parse, you can copy the file into the following page:
which will convert the schema to more human-readable YAML.
Note that in the examples below, some parts of the schemas have been rearranged for greater readability, rather than sorted alphabetically.
For example, say that we want to configure a Test Agent with a static IPv4 address.
We will do this by construcing the body
of a HTTP
POST
request.
The end goal is to construct this request:
{ "name": "Test Agent 1", "description": "This is my Test Agent", "interface_config": { "eth0": { "type": "physical", "address": { "type": "static_ip4", "ip": "192.168.0.123/24" } } } }
The question is, how do we know this is how we should format it?
To find out the correct syntax, we need to consult the Test Agent schema. In fact, we
need to check out the extended version of it; search for
TestAgentExtendedSchema
in the Swagger schema:
TestAgentExtendedSchema: properties: ...name: type: stringmaxLength: 100minLength: 1...description: type: stringmaxLength: 100 ...
To begin with, this schema has name
and description
as attributes. The HTTP request body
should therefore begin as
follows:
{ "name": "Test Agent 1", "description": "This is my Test Agent" }
Some of the properties
are defined as read-only
.
These can be omitted from the request, since they will be ignored by the server.
Now for the interface configuration, and more specifically the IP address, which take a bit more work.
The address is specified in the interface_config
property, which
contains a reference to InterfaceConfigSchema
as seen below:
TestAgentExtendedSchema: type: objectproperties: ...interface_config: type: objectadditionalProperties: $ref: '#/definitions/InterfaceConfigSchema'
We can start by adding to our request:
{ "name": "Test Agent 1", "description": "This is my Test Agent", "interface_config": {} }
This would add an empty interface_config
, so to understand how to
construct the interface_config
JSON object we must go to the
InterfaceConfigSchema
part of the schema:
InterfaceConfigSchema: type: objectrequired: - typediscriminator: typeproperties: description: type: stringtype: type: stringenum: - physical - vlan - bridge - bridged - mobile - wifi
The schema has a property named type
which is required. This is used
to specify which type of interface we want to define. This type
has
a list of valid choices, which is represented in the schema as an
enum
.
The discriminator
part of the schema is used to point us to the
specific type we need to use.
For people familiar with object-oriented programming (OOP) an analogy to this would be "inheritance", or polymorphism.
The InterfaceConfigSchema
has a list of subtypes which are defined
in the enum
.
In our case, we want a "normal" network interface, so we should specify
physical
as our type
.
So now we can look up the schema for the physical
type:
physical: description: A representation of Physical Interface allOf: - $ref: '#/definitions/InterfaceConfigSchema' - properties: type: objectaddress: $ref: '#/definitions/InterfaceIPv4AddressSchema'address6: $ref: '#/definitions/InterfaceIPv6AddressSchema'...
Here the allOf
attribute is used to say that the
physical
interface type has all properties from
InterfaceConfigSchema
, as well as the
properties
listed inline.
That is, it "inherits" the properties
from
InterfaceConfigSchema
in OOP terminology.
So we can continue constructing our HTTP POST
request
body
. Since we want a static IPv4 address, we specify
address
rather than address6
which is for
IPv6.
{ "name": "Test Agent 1", "description": "This is my Test Agent", "interface_config": { "eth0": { "type": "physical", "address": {} } } }
So, using the same process we now look up
InterfaceIPv4AddressSchema
:
InterfaceIPv4AddressSchema: type: objectrequired: - typediscriminator: typeproperties: type: type: stringenum: - none_ip4 - static_ip4 - dhcp_ip4
Again, we specify the type
, which is used to identify the specific
schema to use. We want static_ip4
as found in the
enum
:
{ "name": "Test Agent 1", "description": "This is my Test Agent", "interface_config": { "eth0": { "type": "physical", "address": { "type": "static_ip4" } } } }
We then look up the schema for static_ip4
:
static_ip4: description: IPv4 static addressallOf: - $ref: '#/definitions/InterfaceIPv4AddressSchema' - properties: type: object...ip: type: string...
Here we can see that we need to specify the ip
property. In general,
in Netrounds, IP addresses are entered using the CIDR notation.
All the other properties
here are optional.
So now we can finalize our JSON:
{ "name": "Test Agent 1", "description": "This is my Test Agent", "interface_config": { "eth0": { "type": "physical", "address": { "type": "static_ip4", "ip": "192.168.0.123/24" } } } }
Deleting a Test Agent
After a test has completed, it might be relevant in some use cases to delete the Test Agent.
Below is code for doing this through the REST API:
# Request settings url = '%s/accounts/%s/test_agents/%s/' % (args.ncc-url, args.account, args.test-agent-id) # Delete Test Agent response = requests.delete(url=url, headers={'API-Token': args.token})