func Connect(transport string, host string, username string, passwd string,
	port int) (*Node, error) {
	conn, err := Connection(transport, host, username, passwd, port)
	if err != nil {
		return nil, err
	}
	return &Node{conn: conn, autoRefresh: true}, nil
}
Connect establishes a connection (using the supplied settings) and creates a Node instance.

This function will create a connection to an Arista EOS node using
the arguments.  All arguments are optional with default values.

Args:
transport (string): Specifies the type of connection transport to use.
Valid values for the connection are socket, http_local,
http, and https.  https is the default.
host (string): The IP addres or DNS host name of the connection device.
The default value is 'localhost'
username (string): The username to pass to the device to authenticate
the eAPI connection.   The default value is 'admin'
password (string): The password to pass to the device to authenticate
the eAPI connection.  The default value is ''
port (int): The TCP port of the endpoint for the eAPI connection.  If
this keyword is not specified, the default value is
automatically determined by the transport type.
(http=80, https=443)
Returns:
An instance of Node object for the specified transport.
package goeapi
import (
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"github.com/vaughan0/go-ini"
)
const (
	RunningConfig = "running-config"
	StartupConfig = "startup-config"
)
type Node struct {
	conn          EapiConnectionEntity
	runningConfig string
	startupConfig string
	autoRefresh   bool
	enablePasswd  string
}
func (n *Node) GetConnection() EapiConnectionEntity {
	if n == nil {
		return nil
	}
	return n.conn
}
func (n *Node) SetConnection(c EapiConnectionEntity) {
	if n == nil {
		return
	}
	n.conn = c
}
func (n *Node) SetAutoRefresh(val bool) {
	n.autoRefresh = val
}
func (n *Node) EnableAuthentication(passwd string) {
	n.enablePasswd = strings.TrimSpace(passwd)
}
func (n *Node) RunningConfig() string {
	if n.runningConfig != "" {
		return n.runningConfig
	}
	n.runningConfig, _ = n.getConfigText(RunningConfig, "all")
	return n.runningConfig
}
func (n *Node) StartupConfig() string {
	if n.startupConfig != "" {
		return n.startupConfig
	}
	n.startupConfig, _ = n.getConfigText(StartupConfig, "")
	return n.startupConfig
}
func (n *Node) Refresh() {
	n.runningConfig = ""
	n.runningConfig = ""
}
func GetHandle(n *Node, encoding string) (*EapiReqHandle, error) {
	if strings.ToLower(encoding) != "json" &&
		strings.ToLower(encoding) != "text" {
		return nil, fmt.Errorf("Invalid encoding specified: %s", encoding)
	}
	if n == nil {
		return nil, fmt.Errorf("Invalid node")
	}
	return &EapiReqHandle{node: n, encoding: encoding}, nil
}
func (n *Node) GetHandle(encoding string) (*EapiReqHandle, error) {
	return GetHandle(n, encoding)
}
func (n *Node) GetConfig(config, params, encoding string) (map[string]interface{}, error) {
	if config != RunningConfig && config != StartupConfig {
		return nil, fmt.Errorf("Invalid config type: %s", config)
	}
	commands := []string{strings.TrimSpace("show " + config + " " + params)}
	result, err := n.RunCommands(commands, encoding)
	if err != nil {
		return nil, err
	}
	return result.Result[0], nil
}
func (n *Node) getConfigText(config, params string) (string, error) {
	result, err := n.GetConfig(config, params, "text")
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(result["output"].(string)), nil
}
func (n *Node) GetSection(regex string, config string) (string, error) {
	var params string
	if config == "" || config == RunningConfig {
		config = RunningConfig
		params = "all"
	}
	if config != RunningConfig && config != StartupConfig {
		return "", fmt.Errorf("Invalid config type: %s", config)
	}
	sectionRegex, err := regexp.Compile(regex)
	if err != nil {
		return "", fmt.Errorf("Invalid regexp")
	}
	config, err = n.getConfigText(config, params)
	if err != nil || config == "" {
		return "", err
	}
	match := sectionRegex.FindStringIndex(config)
	if match == nil {
		return "", fmt.Errorf("Config section not found %d", match)
	}
	blockStart := match[0]
	lineEnd := match[1]
	blockRegex := regexp.MustCompile(`(?m)^[^\s]`)
	match = blockRegex.FindStringIndex(config[lineEnd:])
	if match == nil {
		return "", fmt.Errorf("Block section/end not found")
	}
	blockEnd := match[0]
	blockEnd = lineEnd + blockEnd
	return config[blockStart:blockEnd], nil
}
func (n *Node) ConfigWithErr(commands ...string) error {
	commands = append([]string{"configure terminal"}, commands...)
	_, err := n.RunCommands(commands, "json")
	if n.autoRefresh {
		n.Refresh()
	}
	return err
}
func (n *Node) Config(commands ...string) bool {
	err := n.ConfigWithErr(commands...)
	return (err == nil)
}
func (n *Node) Enable(commands []string) ([]map[string]string, error) {
	for _, cmd := range commands {
		found, _ := regexp.MatchString(`^\s*configure(\s+terminal)?\s*$`, cmd)
		if found {
			return nil, fmt.Errorf("Config mode commands not supported")
		}
	}
	results := make([]map[string]string, len(commands))
	rsp, err := n.RunCommands(commands, "text")
	if err != nil {
		return results, err
	}
	for idx, resp := range rsp.Result {
		results[idx] = make(map[string]string)
		results[idx]["command"] = commands[idx]
		results[idx]["result"] = strings.TrimSpace(resp["output"].(string))
	}
	return results, nil
}
func (n *Node) RunCommands(commands []string,
	encoding string) (*JSONRPCResponse, error) {
	var cmds []interface{}
	if n.enablePasswd != "" {
		cmds = n.prependEnableSequence(commands)
	} else {
		commands = append([]string{"enable"}, commands...)
		cmds = cmdsToInterface(commands)
	}
	result, err := n.conn.Execute(cmds, encoding)
	if err != nil {
		return nil, err
	}
	result.Result = append(result.Result[:0], result.Result[1:]...)
	return result, err
}
func (n *Node) prependEnableSequence(commands []string) []interface{} {
	length := len(commands) + 1
	var interfaceSlice []interface{}
	interfaceSlice = make([]interface{}, length)
	interfaceSlice[0] = map[string]interface{}{
		"cmd":   "enable",
		"input": n.enablePasswd,
	}
	for i := 1; i < length; i++ {
		interfaceSlice[i] = commands[i-1]
	}
	return interfaceSlice
}
func cmdsToInterface(commands []string) []interface{} {
	if commands == nil || len(commands) == 0 {
		return nil
	}
	var interfaceSlice []interface{}
	length := len(commands)
	interfaceSlice = make([]interface{}, length)
	for i := 0; i < length; i++ {
		interfaceSlice[i] = commands[i]
	}
	return interfaceSlice
}
var configGlobal = NewEapiConfig()
var configSearchPath = []string{
	"~/.eapi.conf",
	"/mnt/flash/eapi.conf",
}
type fn func(transport string, host string, username string,
	password string, port int) EapiConnectionEntity
var transports = map[string]fn{
	"socket":     NewSocketEapiConnection,
	"http_local": NewHTTPLocalEapiConnection,
	"http":       NewHTTPEapiConnection,
	"https":      NewHTTPSEapiConnection,
}
type EapiConfig struct {
	filename string
	ini.File
}
func NewEapiConfig() *EapiConfig {
	config := &EapiConfig{}
	config.AutoLoad()
	return config
}
func NewEapiConfigFile(filename string) *EapiConfig {
	config := &EapiConfig{filename: filename}
	config.AutoLoad()
	return config
}
func (e *EapiConfig) AutoLoad() {
	var searchPath []string
	path := os.Getenv("EAPI_CONF")
	if path == "" {
		if e.filename != "" {
			path = e.filename
		}
	}
	if path != "" {
		searchPath = append(searchPath, path)
	} else {
		searchPath = append(searchPath, configSearchPath...)
	}
	for _, file := range searchPath {
		file, _ = expandPath(file)
		if _, err := os.Stat(file); err == nil {
			e.filename = file
			e.Read(file)
			return
		}
	}
	e.File = make(ini.File)
	e.addDefaultConnection()
	return
}
func (e *EapiConfig) Connections() []string {
	if e == nil {
		return nil
	}
	var connections []string
	for name := range e.File {
		str := strings.Replace(name, "connection:", "", 1)
		connections = append(connections, str)
	}
	return connections
}
func Connections() []string {
	return configGlobal.Connections()
}
func (e *EapiConfig) Read(filename string) error {
	file, err := ini.LoadFile(filename)
	if err != nil {
		return fmt.Errorf("Cant read filename: %s, %#v", filename, err)
	}
	e.File = file
	for name := range e.File {
		if _, found := e.Get(name, "host"); !found {
			e.Section(name)["host"] = strings.Split(name, ":")[1]
		}
	}
	e.addDefaultConnection()
	return nil
}
func (e *EapiConfig) Load(filename string) bool {
	e.filename = filename
	e.Reload()
	return true
}
func (e *EapiConfig) Reload() bool {
	for name := range e.File {
		delete(e.File, name)
	}
	e.AutoLoad()
	return true
}
func (e *EapiConfig) GetConnection(name string) ini.Section {
	name = "connection:" + name
	section, found := e.File[name]
	if !found {
		return nil
	}
	return section
}
func (e *EapiConfig) AddConnection(name string) ini.Section {
	return e.Section("connection:" + name)
}
func (e *EapiConfig) addDefaultConnection() {
	conn := e.GetConnection("localhost")
	if conn == nil {
		e.AddConnection("localhost")["transport"] = "socket"
	}
}
func LoadConfig(filename string) {
	configGlobal.Load(filename)
}
func ConfigFor(name string) ini.Section {
	return configGlobal.GetConnection(name)
}
func ConnectTo(name string) (*Node, error) {
	section := ConfigFor(name)
	if section == nil {
		return nil, fmt.Errorf("Connection profile not found in config")
	}
	host := section["host"]
	username := section["username"]
	passwd := section["password"]
	transport := section["transport"]
	enablepwd := section["enablepwd"]
	var port = UseDefaultPortNum
	_, ok := section["port"]
	if ok {
		port, _ = strconv.Atoi(section["port"])
	}
	node, err := Connect(transport, host, username, passwd, port)
	if err != nil {
		return nil, err
	}
	node.EnableAuthentication(enablepwd)
	return node, nil
}