- Overview
- Installation
- Upgrading
- Getting Started
- Building Local Documentation
- Testing
- Contributing
- License
The Go Client for eAPI provides a native Go implementation for programming Arista EOS network devices using Golang. The Go client provides the ability to build native applications in Go that can communicate with EOS remotely over a HTTP/S transport (off-box). It uses a standard INI-style configuration file to specifiy one or more connection profiles.
The goeapi implemenation also provides an API layer for building native Go objects that allow for configuration and state extraction of EOS nodes. The API layer provides a consistent implementation for working with EOS configuration resources. The implementation of the API layer is highly extensible and can be used as a foundation for building custom data models.
The libray is freely provided to the open source community for building robust applications using Arista EOS eAPI. Support is provided as best effort through Github iusses.
- Arista EOS v4.12 or later
- Arista eAPI enabled for either http or https
- Go 1.5+
First, it is assumed you have and are working in a standard Go workspace, as described in http://golang.org/doc/code.html, with proper GOPATH set. Go 1.5+ is what's recommended for using goeapi. To download and install goeapi:
$ go get github.com/aristanetworks/goeapi
After setting up Go and installing goeapi, any required build tools can be installed by bootstrapping your environment via:
$ make bootstrap
$ go get -u github.com/aristanetworks/goeapi
The following steps need to be followed to assure successful configuration of goeapi.
- EOS Command API must be enabled
To enable EOS Command API from configuration mode, configure proper protocol under management api, and then verify:
Switch# configure terminal
Switch(config)# management api http-commands
Switch(config-mgmt-api-http-cmds)# protocol ?
http Configure HTTP server options
https Configure HTTPS server options
unix-socket Configure Unix Domain Socket
Switch(config-mgmt-api-http-cmds)# protocol http
Switch(config-mgmt-api-http-cmds)# end
Switch# show management api http-commands
Enabled: Yes
HTTPS server: running, set to use port 443
HTTP server: running, set to use port 80
Local HTTP server: shutdown, no authentication, set to use port 8080
Unix Socket server: shutdown, no authentication
...
- Create configuration file with proper node properties. (See eapi.conf file examples below)
Note: The default search path for the conf file is ~/.eapi.conf
followed by /mnt/flash/eapi.conf
. This can be overridden by setting
EAPI_CONF=<path file conf file>
in your environment.
Below is an example of an eAPI conf file. The conf file can contain more than one node. Each node section must be prefaced by connection:<name> where <name> is the name of the connection.
The following configuration options are available for defining node entries:
- host - The IP address or FQDN of the remote device. If the host parameter is omitted then the connection name is used
- username - The eAPI username to use for authentication (only required for http or https connections)
- password - The eAPI password to use for authentication (only required for http or https connections)
- enablepwd - The enable mode password if required by the destination node
- transport - Configures the type of transport connection to use. The default value is https. Valid values are:
- http
- https
- https_certs
- socket
- port - Configures the port to use for the eAPI connection. (Currently Not Implemented)
- keyfile - The path to the client's private key file (only required for https_certs connections)
- certfile - The path to the client's certificate file (only required for https_certs connections)
Note: See the EOS User Manual found at arista.com for more details on configuring eAPI values.
Once goeapi has been installed and your .eapi.config file is setup correctly, you are now ready to try it out. Here is a working example of .eapi.config file and go program:
$ cat ~/.eapi.config
[connection:arista1]
host=arista1
username=admin
password=root
enablepwd=passwd
transport=https
$ cat example1.go
package main
import (
"fmt"
"github.com/aristanetworks/goeapi"
"github.com/aristanetworks/goeapi/module"
)
func main() {
// connect to our device
node, err := goeapi.ConnectTo("Arista1")
if err != nil {
panic(err)
}
// get the running config and print it
conf := node.RunningConfig()
fmt.Printf("Running Config:\n%s\n", conf)
// get api system module
sys := module.System(node)
// change the host name to "Ladie"
if ok := sys.SetHostname("Ladie"); !ok {
fmt.Printf("SetHostname Failed\n")
}
// get system info
sysInfo := sys.Get()
fmt.Printf("\nSysinfo: %#v\n", sysInfo.HostName())
}
goeapi provides a way for users to directly couple a command with a predefined response. The underlying api will issue the command and the response stored in the defined type. For example, lets say the configured vlan ports are needed for some form of processing. If we know the JSON response for the command composed like the following: (from Arista Command API Explorer):
{
"jsonrpc": "2.0",
"result": [
{
"sourceDetail": "",
"vlans": {
"2": {
"status": "active",
"name": "VLAN0002",
"interfaces": {
"Port-Channel10": {
"privatePromoted": false
},
"Ethernet2": {
"privatePromoted": false
},
"Ethernet1": {
"privatePromoted": false
},
"Port-Channel5": {
"privatePromoted": false
}
},
"dynamic": false
},
}
}
],
"id": "CapiExplorer-123"
}
We can then build our Go structures based on the response format and couple our show command with the type:
type MyShowVlan struct {
SourceDetail string `json:"sourceDetail"`
Vlans map[string]Vlan `json:"vlans"`
}
type Vlan struct {
Status string `json:"status"`
Name string `json:"name"`
Interfaces map[string]Interface `json:"interfaces"`
Dynamic bool `json:"dynamic"`
}
type Interface struct {
Annotation string `json:"annotation"`
PrivatePromoted bool `json:"privatePromoted"`
}
func (s *MyShowVlan) GetCmd() string {
return "show vlan configured-ports"
}
Since the command show vlan configured-ports
is coupled with the response structure, the underlying api knows to issue the command and the response needs to be filled in. The resulting code looks like:
package main
import (
"fmt"
"github.com/aristanetworks/goeapi"
)
type MyShowVlan struct {
SourceDetail string `json:"sourceDetail"`
Vlans map[string]Vlan `json:"vlans"`
}
type Vlan struct {
Status string `json:"status"`
Name string `json:"name"`
Interfaces map[string]Interface `json:"interfaces"`
Dynamic bool `json:"dynamic"`
}
type Interface struct {
Annotation string `json:"annotation"`
PrivatePromoted bool `json:"privatePromoted"`
}
func (s *MyShowVlan) GetCmd() string {
return "show vlan configured-ports"
}
func main() {
node, err := goeapi.ConnectTo("dut")
if err != nil {
panic(err)
}
sv := &MyShowVlan{}
handle, _ := node.GetHandle("json")
handle.AddCommand(sv)
if err := handle.Call(); err != nil {
panic(err)
}
for k, v := range sv.Vlans {
fmt.Printf("Vlan:%s\n", k)
fmt.Printf(" Name : %s\n", v.Name)
fmt.Printf(" Status: %s\n", v.Status)
}
}
Also, if several commands/responses have been defined, goeapi supports command stacking to batch issue all at once:
...
handle, _ := node.GetHandle("json")
handle.AddCommand(showVersion)
handle.AddCommand(showVlan)
handle.AddCommand(showHostname)
handle.AddCommand(showIp)
if err := handle.Call(); err != nil {
panic(err)
}
fmt.Printf("Version : %s\n", showVersion.Version)
fnt.Printf("Hostname : %s\n", showHostname.Hostname)
...
There are several go example's using goeapi (as well as example .eapi.config file) provided in the examples directory.
In the below code snippet, we got switchports information and printing key, value pair by looping the map:
package main
import (
"fmt"
"github.com/aristanetworks/goeapi"
"github.com/aristanetworks/goeapi/module"
)
func main() {
node, err := goeapi.ConnectTo("dut")
if err != nil {
panic(err)
}
// To get switchports
var sv module.ShowInterfacesSwitchport
handle, _ := node.GetHandle("json")
handle.AddCommand(&sv)
handle.Call()
for k, v := range sv.Switchports {
fmt.Printf("Interface: %s, Mode: %s \n", k, v.SwitchportInfo.Mode)
}
}
If we want to execute a list of commands,
package main
import (
"fmt"
"github.com/aristanetworks/goeapi"
"github.com/aristanetworks/goeapi/module"
"github.com/mitchellh/mapstructure"
)
func main() {
cmds := []string{"show version", "show interfaces et1", "show interfaces"}
node, err := goeapi.ConnectTo("dut")
if err != nil {
panic(err)
}
res, err := node.RunCommands(cmds, "json")
if err != nil {
panic(err)
}
// To get Version
var sv module.ShowVersion
mapstructure.Decode(res.Result[0], &sv)
fmt.Println("Version: ", sv.Version)
// To get the status of the Interface Ethernet1
var switchportEt1 module.InterfaceConfig
if ethernet1, ok := res.Result[1]["interfaces"].(map[string]interface{})["Ethernet1"].(map[string]interface{}); ok {
mapstructure.Decode(ethernet1, &switchportEt1)
}
fmt.Println("Interface Ethernet1 Status: ", switchportEt1["interfaceStatus"])
}
We can make use of RunCommands
method from the Node
object. Additionally Decode
function has been used from mapstructure
package for decoding the JSON response.
Goeapi supports certificate-based authentication for eAPI connections, eliminating the need for a username and password. Below is the example ~/.eapi.conf
,
[connection:dut]
host=dut
keyfile=/path/to/keyfile
certfile=/path/to/certificatefile
cacertfile=/path/to/cacertificatefile
transport=https_certs
Note: CA Certificate file is optional.
Documentation can be generated locally in plain text via:
$ godoc github.com/aristanetworks/goeapi
Or you can run the local godoc server and view the html version of the documentation by pointing your browser at http://localhost:6060
$ make doc
or
$ godoc -http=:6060 -index
The goeapi library provides various tests. To run System specific tests, you will need to
update the dut.conf
file (found in testutils/fixtures) to include the device level specifics
for your setup. The switch used for testing should have at least interfaces Ethernet1-7.
- For running System tests, issue the following from the root of the goeapi directory:
$ make systest
or
$ go test ./... -run SystemTest$
- Similarly, Unit tests can be run via:
$ make unittest
or
$ go test ./... -run UnitTest$
Verbose mode can be specified as a flag to provide additional information:
$ make GOTEST_FLAGS=-v test
Note: Test cases for XXX.go files live in respective XXX_test.go files and have the following function signature:
- Unit Tests:
TestXXX_UnitTest(t *testing.T){...
- System Tests:
TestXXX_SystemTest(t *testing.T){...
Any tests written must conform to this standard.
Contributing pull requests are gladly welcomed for this repository. Please note that all contributions that modify the library behavior require corresponding test cases otherwise the pull request will be rejected. More information here.
Copyright (c) 2015-2016, Arista Networks Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-
Neither the name of Arista Networks nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.