-
Notifications
You must be signed in to change notification settings - Fork 40
Quickstart: Hello World
This tutorial will walk you through building, installing, and running your first EOS SDK agent. By the end of this page, you will have created an agent that will say 'Hello' to a name configured via the CLI, and thereby redefining the term "Social Networking." This program, although simple, demonstrates the lifecycle of an agent along with various components of the SDK. We'll first walk you through creating the agent executable, then explain how to run your agent, and, finally, a walkthrough of the EOS SDK code. If you'd like to explore the code without setting running the switch, skip to the usage or code explanation sections.
The complete code for the agent can be found in the examples directory, at [HelloWorld.cpp](<<<<<) for the C++ version of the agent, and [HelloWorld.py](<<<<<) for the Python implementation. Note that you can easily access the raw versions of the example files (for easy wget
or scp
access) by clicking the 'Raw' link in the upper right of each file's GitHub page.
First, we'll need an EOS instance where we can run our new agent. That means we'll need either a vEOS virtual machine or a physical switch. We then need to install the EOS SDK RPM, which contains the binary implementation of the SDK. Follow the download and installation instructions for information on how to complete both of these steps.
If you want to use the Python version of the agent, there is no need to build anything. All you need to do is copy the script to the switch:
switch# copy https://raw.github.com/aristanetworks/EosSdk/blob/master/examples/HelloWorld.py file:/mnt/flash
For the C++ version of the agent, you'll need a 32-bit Linux environment with the stubs tarball downloaded, unpacked, and built. See [Building your agent](<<<<) for more information on setting up your build environment. Then, copy the HelloWorld.cpp file to your build directory and run:
bash# g++ -std=gnu++0x -o HelloWorldBinary HelloWorld.cpp -leos
This will create an executable named HelloWorldBinary
in your current directory. Copy that file to your switch's /mnt/flash
directory.
Now that we have a switch with the SDK installed along with an agent executable, let's run the agent!
bash# ssh admin@myAristaSwitch
switch> enable
switch# configure
switch(config)# daemon HelloWorldAgent
switch(config-daemon-HelloWorldAgent)# exec /mnt/flash/HelloWorld.py (or HelloWorldBinary for the C++ binary)
switch(config-daemon-HelloWorldAgent)# no shutdown
You can confirm that the program is running via the show daemon
command:
switch(config-daemon-HelloWorldAgent)# show daemon
Agent: HelloWorldAgent (running)
No configuration options stored.
Status:
Data Value
-------------- ---------------------------
greeting Welcome! What is your name?
Looks like everything is up and running! Let's now tell our friendly agent our name:
switch(config-daemon-HelloWorldAgent)# option name value Robert Metcalfe
switch(config-daemon-HelloWorldAgent)# show daemon
Agent: HelloWorldAgent (running)
Configuration:
Option Value
------------ ---------------
name Robert Metcalfe
Status:
Data Value
-------------- ----------------------
greeting Hello Robert Metcalfe!
And, ta-da, our agent reacted to the name
option and said "hi". Feel free to change your name via the option name value <new-name>
command and remove your name via no option name
, and observe how your newly created social network responds. When we're finished, we can stop our agent using the shutdown
command:
switch(config-daemon-HelloWorldAgent)# shutdown
switch(config-daemon-HelloWorldAgent)# show daemon
Agent: HelloWorldAgent (shutdown)
Configuration:
Option Value
------------ ---------------
name Robert Metcalfe
Status:
Data Value
-------------- ------
greeting Adios!
In this section, we will explore the code behind the HelloWorld C++ agent. The same explanations hold for the Python variant.
The agent executable first runs when you enter no shutdown
via the CLI. At this point, ProcMgr starts up an instance of your agent, using the command stored in the exec
CLI. As we set exec
to the path of our executable, ProcMgr will run this file, which, like all C++ programs, begins execution at the main()
function:
int main(int argc, char ** argv) {
eos::sdk sdk;
hello_world_agent agent(sdk);
sdk.main_loop(argc, argv);
}
The set-up for this agent is simple. We first create an instance of the SDK, using eos::sdk
's default constructor. We then construct the hello_world_agent
class, which contains the meat of the program's logic. Let's see what happens there:
class hello_world_agent : public eos::agent_handler {
public:
eos::agent_mgr * agent_mgr;
eos::tracer t;
explicit hello_world_agent(eos::sdk & sdk)
: eos::agent_handler(sdk.get_agent_mgr()),
agent_mgr(sdk.get_agent_mgr()),
t("HelloWorldCppAgent") {
t.trace0("Agent constructed");
}
// ...
};
The first thing to notice is that the hello_world_agent subclasses eos::agent_handler
. All agents should have at least one class that inherits from agent_handler
, as this handler provides agent-specific callbacks alerting you of startup, shutdown and configuration events. In many cases, your main class will inherit from several handlers, each providing specific on_xxx()
callbacks that let you react to other events. As our HelloWorld agent only cares about agent options, we only need to subclass from the agent_handler
.
In the hello_world_agent
constructor, we go ahead and initialize various elements:
- our superclass, which takes an
eos::agent_mgr
... - ... which we also store in a class
agent_mgr *
instance variable - and finally an
eos::tracer
object, which lets our agent output debug trace statements to its log file when tracing is enabled
At this point, all of the relevant classes, data structures, and logic are created, so, back in our main
function, we start the main_loop
. This function never returns and instead creates the continuously running event loop, managed by the SDK.
Before this point, our program has simply been a C++ class that has no connection to Sysdb. This means that none of the on_xxx()
callbacks will fire, and the agent_mgr
will not be able to set or read any state. Our call to start the main_loop
changes this: the SDK connects to Sysdb, synchronizes any state needed by the agent_mgr
, and registers itself for any relevant notifications. When this dance is complete, the agent_handler
's on_initialized
method is called, a method that our hello_world_agent
overrides:
void on_initialized() {
t.trace0("Initialized");
std::string name = agent_mgr->agent_option("name");
if(name.empty()) {
// No name initially set.
agent_mgr->status_set("greeting", "Welcome! What is your name?");
} else {
// Handle initial state.
on_agent_option("name", name);
}
}
The first thing we do upon initialization is check if Sysdb already has any relevant state set. For our agent, we just care if somebody has told us their name, so we go and ask the agent_mgr for the value corresponding to the agent_option called "name". If the option is not set, the call to agent_option
will result in an empty string (as documented in agent.h
), so we'll just set a welcome message. Otherwise, there was already a name set, so we jump to the on_agent_option logic, which handles handles the agent name.
You may wonder when any initial state could have been created. There are many ways that this could have happened:
- The user may have set the
name
option before runningno shutdown
from the CLI, thus seeding Sysdb with a name already. - The switch may have been rebooted, and the start-up configuration contained the command
option name value <name>
for this daemon, meaning the configuration was set before your agent was ever enabled. - A stateful switchover event happened, meaning that control transferred from one supervisor to another on a modular system. To your agent, this just looks like an agent restart where state already was set.
- Your agent was buggy and crashed, causing ProcMgr to restart it.
- Someone, or some other program, set that state in Sysdb.
- One of many other causes.
In any case, your agent was started, and needs to make sure it can sanely handle what is already in Sysdb. At this point, there is nothing more to do so we return control to the event loop and wait for another event to occur.
Let's assume the co-inventor of Ethernet now enters his name at the EOS CLI: option name value Robert Metcalfe
. Under the hood, this command sets a configuration option for agent in Sysdb. Sysdb notices that we registered for notifications on this state, and thus notifies this process of the new state via a connection that the SDK established when starting the main_loop
. The SDK, in turn, transforms this update into a std::string
key/value pair and calls on_agent_option
with the new value. Since we overrode this method as well, our callback runs:
void on_agent_option(std::string const & option_name,
std::string const & value) {
if(option_name == "name") {
if(value.empty()) {
// User deleted the 'name' option
t.trace3("Name deleted");
agent_mgr->status_set("greeting", "Goodbye!");
} else {
// Now *this* is what social networking is all
// about. Somebody set, or changed, the name option. Let's
// do some salutations!
t.trace3("Saying hi to %s", value.c_str());
agent_mgr->status_set("greeting", "Hello " + value + "!");
}
}
}
This method is straightforward: if the 'name' option changed, we go ahead and update the greeting appropriately. We then return to the event loop to await further notifications.
The last piece of functionality is the cleanup mechanism. If this agent is ever shutdown
from the CLI, we are given the chance to cleanup any status. Note that this cleanup is not guaranteed to run: the underlying agent process could be abruptly terminated by the system for any number of reasons. However, if we are cleanly disabled, the agent_handler
's on_enabled
callback will fire:
void on_agent_enabled(bool enabled) {
if (!enabled) {
t.trace0("Shutting down");
agent_mgr->status_set("greeting", "Adios!");
agent_mgr->agent_shutdown_complete_is(true);
}
}
In this case we don't have to do much: we just publish a goodbye message and alert the agent_mgr
that we have completed cleanup. Under the hood, the SDK then exits the event loop and the process exits.
Congratulations on finishing your first walkthrough of an EOS SDK agent!
Have a comment, question, or found a typo? Open an issue!