Friday, January 31, 2014

Introduction to DynamoDB with Node.js

To get started with DynamoDB and the AWS SDK for Node.js, leveraging IAM Roles in a simple t1.micro is a great place to start.

First, create an IAM Role with a policy which permits all DynamoDB APIs for now:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "dynamodb:*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

Once an instance is launched in that role, install Node and load the AWS SDK module:

$ npm install aws-sdk
$ node
>

Because we deployed the EC2 instance in a Role, the SDK automaticlly assumes the IAM Role for temporary credential management. So let's load the SDK and point to the desired region:

> var AWS = require('aws-sdk');
undefined  
> AWS.config.update({region: 'us-west-2'});
undefined  

Having already created the sample tables from documentation based on the public DynamoDB documentation, it's fairly easy to use the quick sample to query the tables in the region:

> var db = new AWS.DynamoDB();
undefined  
> db.listTables(function(err, data) {
...    console.log(data.TableNames);
... });
{ service: ... }
> [ 'Forum', 'ProductCatalog', 'Reply', 'Thread' ]

And there we go, a simple start to the use of Node.js with IAM Roles in EC2 instance to list existing tables in a specific region.

Wednesday, January 29, 2014

Zero to Build Failed in 20 minutes

In the process of learning Node.js, I elected to build some basic projects in the language, but also to leverage source control (GitHub, of course) and Continuous Integration. The obvious choice for this project is Travis CI, which provides free build testing for open source repositories.

First, you'll need to setup a .travis.yml. I shamelessly reviewed a few favorite node project's configurations along with the Travis CI help before settling on the simple, concise:

language: node_js  
node_js:  
  - "0.11"
  - "0.10"
  - "0.8"
  - "0.6"

That's more than enough testing, as I'll probably only use the 0.10 branch and 0.11 once it's released.
So what does Travis CI do for Node builds? Well it executes npm test, by default. What on earth does that do? Well, there's really nothing helpful in the documentation, but again, by perusing a few favorite projects it executes a script in the root of the project named test.js or all scripts in a folder named test.

Alright, so then just save an empty file named test right? Not so much. The easiest way to get started with some test driven development is to assert what you expect your functions to return for certain known values.
Consider a simple Fibonacci series:

module.exports = function fib(n) {  
   if ((n === 1) || (n === 0)) {
      return n;
   } else {
      return fib(n-1) + fib(n-2);
   }
}
And then require the module and assert in test.js:

// Import libraries
var fib = require('./fib.js');  
var assert = require('assert');

// Exercise fib
assert.equal(fib(4),3);  
assert.equal(fib(5),5);  
assert.equal(fib(6),8);  
assert.equal(fib(7),13);  

At this point, a git push to the repository, provided Travis CI is enabled for it, will result in the above code being executed in Travis CI's build environments and any uncaught exceptions will fail the build.
But consider this, if I purposely throw an exception then catch it, does my build fail when the application experience isn't actually passing?

module.exports = function buildHyjinx()  
{
try  
  {
     if(true) throw "empty";
  }
catch(err)  
  {
     console.log(err);
     return -1;
  }
}

Wait a minute! A build passes because we handled an exception appropriately? Yes. So build real life tests and include testing for functionality you don't yet have. Then fail your build, on purpose, or you'll never know what you haven't done yet.

Friday, July 19, 2013

Life with DRM

So my Sony Blu-Ray player can't play Netflix today.  Wonder why?  Well it's not Netflix, that works great on my PC.  And my iPhone and my Wii.  tcpdump to the rescue!

That's all fine an dandy if my DD-WRT device was my router instead of just an AP, I'd have to mount a CIFS share and download a package in order to do a tcpdump.

Instead, I've got a hand-me-down Juniper with ScreenOS.  Not being intimately familiar, I did recall it had some equivalent facilities if using the CLI, so without further ado, here's a cheat sheet for working with snoop:

ssg-> clear dbuf
ssg-> snoop info
Snoop: OFF
Filters Defined: 1, Active Filters 1
Detail: ON, Detail Display length: 96
Snoop tunnel traffic: ON
Snoop filter based on:
id 1(on): IP src-ip 172.16.37.101 dir(B)
ssg-> snoop filter ip src-ip 172.16.37.100 direction both
snoop filter added
ssg-> snoop
Start Snoop, type ESC or 'snoop off' to stop, continue? [y]/n y


clear dbuf clears the in memory buffer, then snoop info shows the current snoop state.  Then I use a filter to just watch one device, so I can determine what destination IPs are involved.  Later, we can re-run with a different filter to get a better sampling. 

I did a quick telnet test to www.google.com then stopped the snoop trace.

ssg-> snoop off
Snoop off

To view the trace, we send the dbuf to stream output and page through results.  If you're using a more detailed filter it will decode unencrypted HTTP requests a bit more.

ssg-> get dbuf stream91638.0: bgroup0(i) len=74:0019d28739e8->001db5ba738b/0800
              172.16.37.100 -> 8.8.8.8/17
              vhl=45, tos=00, id=2844, frag=0000, ttl=128 tlen=60
              udp:ports 56461->53, len=40
              00 1d b5 ba 73 8b 00 19 d2 87 39 e8 08 00 45 00     ....s.....9...E.
              00 3c 0b 1c 00 00 80 11 4e 11 ac 10 25 64 08 08     .<......N...%d..
              08 08 dc 8d 00 35 00 28 51 91 61 1e 01 00 00 01     .....5.(Q.a.....
              00 00 00 00 00 00 03 77 77 77 06 67 6f 6f 67 6c     .......www.googl
              65 03 63 6f 6d 00 00 01 00 01                       e.com.....   

91638.0: bgroup0(i) len=66:0019d28739e8->001db5ba738b/0800
              172.16.37.100 -> 173.194.33.17/6
              vhl=45, tos=00, id=2845, frag=4000, ttl=128 tlen=52
              tcp:ports 49295->80, seq=787237732, ack=0, flag=8002/SYN
              00 1d b5 ba 73 8b 00 19 d2 87 39 e8 08 00 45 00     ....s.....9...E.
              00 34 0b 1d 40 00 80 06 4f 5f ac 10 25 64 ad c2    
.4..@...O_..%d..
              21 11 c0 8f 00 50 2e ec 4b 64 00 00 00 00 80 02     !....P..Kd......
              20 00 73 98 00 00 02 04 05 b4 01 03 03 08 01 01     ..s.............
              04 02                                               ..           

91638.0: bgroup0(i) len=60:0019d28739e8->001db5ba738b/0800
              172.16.37.100 -> 173.194.33.17/6
              vhl=45, tos=00, id=2846, frag=4000, ttl=128 tlen=40
              tcp:ports 49295->80, seq=787237733, ack=1688811284, flag=5010/ACK
              00 1d b5 ba 73 8b 00 19 d2 87 39 e8 08 00 45 00     ....s.....9...E.
              00 28 0b 1e 40 00 80 06 4f 6a ac 10 25 64 ad c2     .(
..@...Oj..%d..
              21 11 c0 8f 00 50 2e ec 4b 65 64 a9 37 14 50 10     !....P..Ked.7.P.
              00 43 38 5b 00 00 00 00 b7 3d 3e 89                 .C8[.....=>. 

91641.0: bgroup0(i) len=60:0019d28739e8->001db5ba738b/0800
              172.16.37.100 -> 173.194.33.17/6
ssg-> snoop filter delete
All filters removed
ssg-> clear dbuf
ssg->


Lastly, I drop my filter and clear the in memory buffer to clean up. 

Later I facilitated this with a filter between my device and the device provisioning service over at Sony to determine why my Blu-Ray player couldn't play Netflix.  Sure enough, the device makes a connection to ssm1.internet.sony.tv and does a GET for /BDP/stv/STVgetTime/ and gets an HTTP 404 response.  Using IE10's F12 Developer Tools, I captured the response header and confirmed it's an Apache host.  Beyond that reverse lookup tricks and tracert didn't tell me much.

For fun, I also tested the Slacker radio plugin, and it fails hitting a similar host, ssm.internet.sony.tv and ssm2.internet.sony.tv, but there were also some exciting UDP packets going by on 1900.

So after contacting Sony support, I was directed to call their support team as my issue couldn't be solved on chat.  I feel sorry for the CS agent I spoke with because their first reaction after demonstrating my case was to use an HDMI cable instead.  So much for the OSI model.  This really points at how DRM can affect customer experience, especially if it's something the hardware vendor tacked on to their device on top of a 3rd party service that doesn't require it for other devices.  Even though I was (and still am) a PlayStation 3 fanboy, I'm having second thoughts about Sony devices. 

I watched Netflix on Wii today.   Because it just worked.