github.com/smugmug/godynamo@v0.0.0-20151122084750-7913028f6623/README.md (about)

     1  # GoDynamo: A User's Guide
     2  
     3  ## Introduction
     4  
     5  GoDynamo is a API for the DynamoDB database (http://aws.amazon.com/documentation/dynamodb/) written in Go.
     6  
     7  GoDynamo supports all endpoints, uses AWSv4 request signing, and supports IAM authentication as well
     8  as traditional AWS keys.
     9  
    10  To install GoDynamo, run the following command:
    11  
    12  ```bash
    13  go get github.com/smugmug/godynamo
    14  ```
    15  
    16  which installs a package that requires the rest of the packages in the library.
    17  
    18  Also installed as dependencies are [goawsroles](https://github.com/smugmug/goawsroles) which manages support for IAM roles, namely: https://github.com/smugmug/goawsroles/tree/master/roles_files
    19  
    20  GoDynamo is the foundation of *bbpd*, the http proxy daemon for DynamoDB.
    21  You may find that package here: https://github.com/smugmug/bbpd
    22  
    23  To understand how to use Go code in your environment, please see: http://golang.org/doc/install
    24  
    25  and other documentation on the golang.org site.
    26  
    27  ## Configuration
    28  
    29  GoDynamo is configured with an external file. This allows you to write programs that do not contain
    30  hardcoded authentication values. The `conf_file` package contains an exported method `Read`
    31  that must be called to read these configuration variables into your program state, where they
    32  will be visible as the exported global variable `Conf`. The `Read` method will first look for
    33  `~/.aws-config.json`, and then `/etc/aws-config.json`. You may also set an environment variable
    34  `GODYNAMO_CONF_FILE` that will permit you to specify a fully-qualified file path for your own
    35  conf file. If none of those files are present,
    36  the `Read` method will return false and it is advised that your program terminate.
    37  
    38  A sample of a skeleton `aws-config.json` file is found in `conf/SAMPLE-aws-config.json`.
    39  Please see the go docs for the `conf` package to see an explanation of the fields and their use.
    40  It is recommended that you set file permissions on the configuration file to be as restrictive
    41  as possible.
    42  
    43  For convenience, here is the sample configuration file (comments nonstandard):
    44  
    45  ```
    46  {
    47      "extends":[],
    48      "services": {
    49          "default_settings":{
    50              "params":{
    51                  // Traditional AWS access/secret authentication pair.
    52                  "access_key_id":"xxx",
    53                  "secret_access_key":"xxx",
    54                  // If you use syslogd (a linux or *bsd system), you may set this to "true".
    55                  // (currently unusued)
    56                  "use_sys_log":true
    57              }
    58          },
    59          "dynamo_db": {
    60              "host":"dynamodb.us-east-1.amazonaws.com",
    61              "zone":"us-east-1",
    62              // You can alternately set the scheme/port to be https/443.
    63              "scheme":"http",
    64              "port":80,
    65              // If set to true, programs that are written with godynamo may
    66              // opt to launch the keepalive goroutine to keep conns open.
    67              "keepalive":true,
    68              "iam": {
    69                  // If you do not want to use IAM (i.e. just use access_key/secret),
    70                  // set this to false and use the settings above.
    71                  "use_iam":true,
    72                  // The role provider is described in the goawsroles package.
    73                  // See: https://github.com/smugmug/goawsroles/
    74                  // Currently the only support is for the "file" provider, whereby
    75                  // roles data is written to local files.
    76                  "role_provider":"file",
    77                  // The identifier (filename, etc) for the IAM Access Key
    78                  "access_key":"role_access_key",
    79                  // The identifier (filename, etc) for the IAM Secret Key
    80                  "secret_key":"role_secret_key",
    81                  // The identifier (filename, etc) for the IAM Token
    82                  "token":"role_token",
    83                  // If using the "file" role provider, the base dir to read IAM files.
    84                  "base_dir":"/dir/where/you/update/role_files",
    85                  // Set to true if you would like the roles resource watched for changes
    86                  // and automatically (and atomically) updated.
    87                  "watch":true
    88              }
    89          }
    90      }
    91  }
    92  ```
    93  
    94  In this configuration example, the recommended option of using IAM credentials has been selected,
    95  with the source for these credentials being local text files. Creating the automation to
    96  retrieve these credential files and store them on your host is specific to your installation
    97  as IAM is capable of setting fine-grained permissions. See your sysadmin for assistance. If
    98  you do not wish to use IAM or cannot create the automation to keep your local credential files
    99  up to date, you may wish to set `use_iam` to false and just set the access and secret keypair.
   100  
   101  ## Example Program
   102  
   103  In any program you write using GoDynamo, you must first make sure that your configuration has
   104  been initialized properly. You will optionally wish to use IAM support for authentication.
   105  
   106  See the files in `tests` for full examples for various endpoints. Below is a small example
   107  illustrating the way a program using GoDynamo is set up:
   108  
   109  ```go
   110  package main
   111  
   112  import (
   113  	"fmt"
   114  	"github.com/smugmug/godynamo/conf"
   115  	"github.com/smugmug/godynamo/conf_file"
   116  	conf_iam "github.com/smugmug/godynamo/conf_iam"
   117  	put "github.com/smugmug/godynamo/endpoints/put_item"
   118  	keepalive "github.com/smugmug/godynamo/keepalive"
   119  	"github.com/smugmug/godynamo/types/attributevalue"
   120  	"log"
   121  	"net/http"
   122  )
   123  
   124  // This example will attempt to put an item to a imaginary test table.
   125  func main() {
   126  	// Let's try to read a conf file located at `$HOME/.aws-config.json`.
   127  	home := os.Getenv("HOME")
   128  	home_conf_file := home + string(os.PathSeparator) + "." + conf.CONF_NAME
   129  	home_conf, home_conf_err := conf_file.ReadConfFile(home_conf_file)
   130  	if home_conf_err != nil {
   131  		panic("cannot read conf from " + home_conf_file)
   132  	}
   133  	home_conf.ConfLock.RLock()
   134  	if home_conf.Initialized == false {
   135  		panic("conf struct has not been initialized")
   136  	}
   137  
   138  	// A convenience to keep connections to AWS open, which is not needed if you
   139  	// are generating many requests through normal use.
   140  	if home_conf.Network.DynamoDB.KeepAlive {
   141  		log.Printf("launching background keepalive")
   142  		go keepalive.KeepAlive([]string{home_conf.Network.DynamoDB.URL})
   143  	}
   144  
   145  	// Initialize a goroutine which will watch for changes in the local files
   146  	// we have chosen (in our conf file) to contain our IAM authentication values.
   147  	// It is assumed that another process refreshes these files.
   148  	// If you opt to use plain old AWS authentication pairs, you don't need this.
   149  	if home_conf.UseIAM {
   150  		iam_ready_chan := make(chan bool)
   151  		go conf_iam.GoIAM(iam_ready_chan)
   152  		iam_ready := <-iam_ready_chan
   153  		if iam_ready {
   154  			fmt.Printf("using iam\n")
   155  		} else {
   156  			fmt.Printf("not using iam\n")
   157  		}
   158  	}
   159  
   160  	home_conf.ConfLock.RUnlock()
   161  
   162  	put1 := put.NewPutItem()
   163  	put1.TableName = "test-godynamo-livetest"
   164  
   165  	hashKey := fmt.Sprintf("my-hash-key")
   166  	rangeKey := fmt.Sprintf("%v", 1)
   167  	put1.Item["TheHashKey"] = &attributevalue.AttributeValue{S: hashKey}
   168  	put1.Item["TheRangeKey"] = &attributevalue.AttributeValue{N: rangeKey}
   169  
   170  	// All endpoints now support a parameterized conf.
   171  	body, code, err := put1.EndpointReqWithConf(home_conf)
   172  	if err != nil || code != http.StatusOK {
   173  		fmt.Printf("put failed %d %v %s\n", code, err, body)
   174  	}
   175  	fmt.Printf("%v\n%v\n,%v\n", string(body), code, err)
   176  
   177  }
   178  ```
   179  
   180  For more examples that demonstrate how you might wish to use various endpoint libraries, please refer to the
   181  `tests` directory which contains a series of files that are intended to run against AWS, so executing them
   182  will require valid AWS credentials.
   183  
   184  ## Special Features
   185  
   186  One noteworthy feature of GoDynamo is some convenience functions to get around some static limitations of the
   187  default DynamoDB service. In particular, in `endpoints/batch_get_item` you will find a function `DoBatchGet`
   188  which allows an input structure with an arbitrary number of get requests, which are dispatched in segments
   189  and re-assembled. Likewise, in `endpoints/batch_write_item` you will find a function `DoBatchWrite` which
   190  allows an input structure with an arbitrary number of write requests. These functions are provided
   191  as a convenience and do not alter your provisioning model, so be careful.
   192  
   193  *Throttling* occurs in DynamoDB operations when AWS wishes to shape traffic to their service.
   194  GoDynamo utilizes the standard *exponential decay* resubmission algorithm as described in
   195  the AWS documentation. While you will see messages regarding the throttling, GoDynamo continues to
   196  retry your request as per the resubmission algorithm.
   197  
   198  ### JSON Documents
   199  
   200  Amazon has been augmenting their SDKs with wrappers that allow the caller to coerce
   201  their Items (both when writing and reading) to what I will refer to as "basic JSON".
   202  
   203  Basic JSON is stripped of the type signifiers ('S','NS', etc) that AWS specifies in their
   204  `AttributeValue` specification (http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_AttributeValue.html).
   205  
   206  For example, the `AttributeValue`
   207  
   208  ```json
   209  {"AString":{"S":"this is a string"}}
   210  ```
   211  
   212  is translated to this basic JSON:
   213  
   214  ```json
   215  {"AString":"this is a string"}
   216  ```
   217  
   218  Here are some other examples:
   219  
   220  `AttributeValue`:
   221  
   222  ```json
   223  {"AStringSet":{"SS":["a","b","c"]}}
   224  {"ANumber":{"N":"4"}}
   225  {"AList":[{"N":"4"},{"SS":["a","b","c"]}]}
   226  ```
   227  
   228  are translated to these basic JSON values:
   229  
   230  ```json
   231  {"AStringSet":["a","b","c"]}
   232  {"ANumber":4}
   233  {"AList":[4,["a","b","c"]]}
   234  ```
   235  
   236  GoDynamo now includes support for passing in basic JSON documents in place of Items in the
   237  following endpoints:
   238  
   239  - GetItem
   240  - PutItem
   241  - BatchGetItem
   242  - BatchWriteItem
   243  
   244  In the case of `GetItem` and `BatchGetItem`, the method is to call the methods
   245  `ToResponseItemJSON` and `ToResponseItemsJSON` respective methods on the `Response`
   246  types for each package, unmarshaled from the response strings returned from AWS
   247  after calling `EndpointReq` to complete requests.
   248  
   249  In the case of `PutItem`, use `NewPutItemJSON()` to initialize a variable of type
   250  `PutItemJSON`. The `Item` field of this struct is an `interface{}`, to which you
   251  can assign data representing basic JSON. Once done, call the `ToPutItem()` method on the `PutItemJSON`
   252  variable to translate the basic JSON into `AttributeValue` types and return a `PutItem`
   253  type that you can now call `EndpointReq` on.
   254  
   255  In the case of `PutItem`, use `NewBatchWriteItemJSON()` to initialize a variable of type
   256  `BatchWriteItemJSON`. The `Item` field of this `PutRequest` subfield is an `interface {}` you 
   257  can assign data representing basic JSON. Once done, call the `ToBatchWriteItem()` method on the `BatchWriteItemJSON`
   258  variable to translate the basic JSON into `AttributeValue` types and return a `BatchWriteItem`
   259  type that you can now call `EndpointReq` on.
   260  
   261  Note that AWS itself does not support basic JSON - the support is always delivered by a
   262  coercion of basic JSON to and from `AttrbiuteValue`. This coercion is lossy! For example,
   263  a `B` or `BS` will be coerced to a string type (`S`, `SS`) and `NULL` types will be
   264  coerced to `BOOL`. Use with caution.
   265  
   266  This feature is only enabled for `Item` types, not for `Key` or other `AttributeValue`
   267  aliases. So for example, `BatchWriteItemJSON` requests of type `DeleteRequest` cannot use
   268  basic JSON, only `PutRequest`.
   269  
   270  ## Troubleshooting
   271  
   272  GoDynamo provides verbose error messages when appropriate, as well as STDERR messaging. If error
   273  reporting is not useful, it is possible that DynamoDB itself has a new or changed feature that is
   274  not reflected in GoDynamo. 
   275  
   276  ## Recent Noteworthy Changes
   277  
   278  Early versions of GoDynamo utilized a global configuration that was accessed inside relevant
   279  functions once set. Many developers requested that these configurations become parameterized
   280  so they could utilize different configurations simultaneously. GoDynamo now supports
   281  parameterized configurations in every function. These new functions are called `EndpointReqWithConf`.
   282  
   283  Parameterized configuration has been moved into the full api including the core authorization
   284  functions.
   285  
   286  ## Contact Us
   287  
   288  Please contact opensource@smugmug.com for information related to this package. Pull requests also welcome!