Arista eAPI from Microsoft PowerShell

I haven’t really played around with Windows in a while, but I’ve had a few people show me some cool things in PowerShell, so I thought I’d give it a try with eAPI. Here’s a really simple script that is able to fetch information from an Arista switch, and put it into an PowerShell object so that it can be used for whatever you’d like. Now I just need to find an excuse to buy a Surface Pro 2 🙂

I start off by just setting up some variables for the username, password, etc.. Variables in PowerShell start with a $ sign.

$username = "admin"
$password = "admin"
$switchIp = "172.22.28.157"

I’m able to insert variables directly into the string for the URL.

#URL
$eApiUrl = "https://$switchIp/command-api"

Now I create an array to hold the commands I want to send, and put that inside a hash table. Arrays are created with @() and Hash tables (Dictionaries in Python, Maps in Go) with @{}:

$cmds = @('show version')
$params = @{version= 1;cmds= $cmds; format="json"}

Now I create a new PowerShell object with all the required fields. PowerShell has this cool pipe operator (|) like Unix and Elixir. This allows you string together a bunch of stuff, in this case we end with piping the output to ConvertTo-Json to turn the object into a JSON string. Then I have to convert that string into an ASCII one to make it web friendly:

$command = (New-Object PSObject | Add-Member -PassThru NoteProperty jsonrpc '2.0' |
Add-Member -PassThru NoteProperty method 'runCmds' |
Add-Member -PassThru NoteProperty params $params |
Add-Member -PassThru NoteProperty id '1') | ConvertTo-Json
$bytes = [System.Text.Encoding]::ASCII.GetBytes($command)

After we have our command ready to go, we create the web connection and POST the JSON-RPC call. I also tell the system to ignore the web certificate since I haven’t installed the cert for the SSL connection.

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
$web = [System.Net.WebRequest]::Create($eApiUrl)
$web.Method = "POST"
$web.ContentType = "application/json"
$web.Credentials = New-Object System.Net.NetworkCredential -ArgumentList $username, $password
$stream = $web.GetRequestStream()
$stream.Write($bytes, 0, $bytes.Length)
$stream.close()

Finally we take the response, and put it back into a PowerShell object using ConvertFrom-Json

$reader = New-Object System.IO.StreamReader -ArgumentList $web.GetResponse().GetResponseStream()
$response = $reader.ReadToEnd() | ConvertFrom-Json
$reader.Close()

Once we’ve got an object we can pull out pieces of the response:

$response.result
Write-Host "Model is: " + $response.result.modelName

This is what the output looks like:
Screen Shot 2014-08-20 at 4.44.14 PM

Here’s the full script from start to finish:

Advertisements

Arista eAPI (JSON-RPC over HTTP) in Go

I’ve been wanting to try out Go for a while, and finally decided to give it a try. This is a first stab at using Go to communicate with Arista eAPI via JSON-RPC over HTTP. There is a standard JSON-RPC library in Go, but unfortunately it doesn’t work over HTTP. Here is the code:

I start out by defining a package. Since I’m just using this standalone at this point, we’re using package main.
Next I import a few libraries. One to note is the "github.com/mitchellh/mapstructure" library. This is a handy tool for decoding map structures into Go structures, which we’ll make use of when taking in the ‘unknown’ JSON data and putting it into a struct. To install this library Go has a handy tool that can fetch directly from Github:

go get github.com/mitchellh/mapstructure

Now I move on to defining structs to hold our data in. The first three: Parameters, Request, and JsonRpcResponse are used to decode the initial JSON-RPC stuff. Just as a refresher here’s what JSON-RPC request will look like:

{
   "jsonrpc": "2.0",
   "method": "runCmds",
   "params": {
      "version": 1,
      "cmds": [
         "show version"
      ],
      "format": "json"
   },
   "id": "1"
}

Some things to note when looking at the structs for newcomers to Go like myself:
* The `json:"jsonrpc"` tags tell the JSON library to use that as the actual JSON object name instead of the name given in the struct. I ended up having to do that a lot due to the need for having the struct variable name be capitalized.
* I use the type []map[string]interface{} whenever I’m dealing with data that is not known beforehand, such as the result from the RPC.

Starting a line 54, I create a function to call eAPI via HTTP. I start by filling out the JSON Request struct fields, then marshaling them into a JSON object. After we have the JSON object, I execute an HTTP POST to send the command over and return the response as the return value of the function. Before returning the response I run it through decodeEapiResponse to take the raw response data and put it inside a JsonRpcResponse struct. All of this gets called down in the main function in lines 107-110.

Next you’ll see two functions I implemented to decode the result further into more usable structs. The first was my initial attempt for ShowVersion, which I wrote before I found the mapstructure library. This takes the response and puts everything into the appropriate fields of the struct and returns a ShowVersion struct.

The second decoding function makes use of the mapstructure library and is much cleaner. Now mapstructure takes care of all the manual mapping I did in the previous function for me.

I hope to take this and use goroutines for the calls, that will allow these to happen concurrently. The upside of this will be that I could have commands sent to a number of switches more efficiently. Go isn’t quite as easy as Python, but has some definite advantages in speed, concurrency, and static type checking that make it a useful alternative when performance matters. Any comments or suggestions for improvements are certainly welcome! The code can be cloned from github:
https://github.com/fredhsu/go-eapi.git

JSON RPC in Objective C

I am working on a side project for work using JSON RPC from an iPhone (Arista eAPI calls from an iPhone app), so I had to get familiar with using JSON RPC using the iOS Objective C libraries. Here’s a quick rundown of how it works:

There are two major components:
NSJSONSerialization – Converts JSON Data to Dictionaries/Arrays, and vice versa
NSURLConnection – Handles HTTP connection to the API server

First I create a NSMutableDictionary with all the keys/values that I want to encode into JSON to send to the server (or switch in this case). In this example, commands is an array of strings, specific to eAPI calls, and paramsDict puts the other eAPI wrappers around the API call. Then I wrap paramsDict inside the JSON RPC Request format, which is rpcDict:

    NSMutableDictionary *paramsDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:1], @"version",
                                       commands, @"cmds",
                                       @"json", @"format", nil];
    NSMutableDictionary *rpcDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"2.0", @"jsonrpc",
                                    @"runCmds", @"method",
                                    paramsDict, @"params",
                                    @"CapiExplorer-123", @"id", nil];

Now I take rpcDict, and serialize it into a NSData JSON object, the resulting jsonData is ready to be sent to the API server:

    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:rpcDict options:NSJSONWritingPrettyPrinted error:&error];

Now I create the URL request that the application will use to make the RPC request. In this case I’m providing my username and password in the URL string, and _aristaSwitch.switchIP is an NSString containing the IP address of the switch. Also note that I needed to set the content type, and used the jsonData data object as the body:

    NSString *urlString = [NSString stringWithFormat:@"http://user:pass@%@/command-api",
                           _aristaSwitch.switchIP];
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:url];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setHTTPBody:jsonData];

Now I can make the connection, send the request, and start receiving a reply:

    NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
    [connection start];

Once I’ve sent the request, I need to then handle the data coming back from the server. To do this, I have the class implement NSURLConnectionDelegate and NSURLConnectionDataDelegate. These delegates handle the connection response, and downloading data. Now I implement the necessary functions, the first two handle the initial response and data stream. I’m using receivedData as a global variable to hold the data coming from the server:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    // It can be called multiple times, for example in the case of a
    // redirect, so each time we reset the data.
    [self.receivedData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    // Append the new data to receivedData.
    [self.receivedData appendData:data];
}

The final method to implement takes care of the data once the connection has finished. Here I use NSJSONSerialization again to turn the received JSON data back into an NSDictionary that I can use.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSError *error;
    
    NSDictionary *myDictionary = [NSJSONSerialization JSONObjectWithData:self.receivedData options:NSJSONReadingMutableContainers error:&error];
    NSLog(@"myDict %@ %@", myDictionary, error);
    connection = nil;
    self.receivedData = nil;
}