github.com/mweagle/Sparta@v1.15.0/docs_source/content/example_service/step1.md (about)

     1  ---
     2  date: 2017-10-03 07:15:40
     3  title: Overview
     4  weight: 10
     5  ---
     6  
     7  Sparta is a framework for developing and deploying **go** based AWS Lambda-backed microservices. To help understand what that means we'll begin with a "Hello World" lambda function and eventually deploy that to AWS. Note that we're not going to handle all error cases to keep the example code to a minimum.
     8  
     9  {{% notice warning %}}
    10  Please be aware that running Lambda functions may incur [costs](https://aws.amazon.com/lambda/pricing"). Be sure to decommission Sparta stacks after you are finished using them (via the `delete` command line option) to avoid unwanted charges. It's likely that you'll be well under the free tier, but secondary AWS resources provisioned during development (eg, Kinesis streams) are not pay-per-invocation.
    11  {{% /notice %}}
    12  
    13  # Preconditions
    14  
    15  Sparta uses the [AWS SDK for Go](http://aws.amazon.com/sdk-for-go/) to interact with AWS APIs. Before you get started, ensure that you've properly configured the [SDK credentials](https://github.com/aws/aws-sdk-go/wiki/configuring-sdk).
    16  
    17  Note that you must use an AWS region that supports Lambda. Consult the [Global Infrastructure](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/) page for the most up to date release information.
    18  
    19  # Lambda Definition
    20  
    21  The first place to start is with the lambda function definition.
    22  
    23  ```go
    24  // Standard AWS λ function
    25  func helloWorld(ctx context.Context) (string, error) {
    26    return "Hello World!", nil
    27  }
    28  ```
    29  
    30  The `ctx` parameter includes the following entries:
    31  
    32  - The [AWS LambdaContext](https://godoc.org/github.com/aws/aws-lambda-go/lambdacontext#FromContext)
    33  - A [\*logrus.Logger](https://github.com/sirupsen/logrus) instance (`sparta.ContextKeyLogger`)
    34  - A per-request annotated [\*logrus.Entry](https://godoc.org/github.com/sirupsen/logrus#Entry) instance (`sparta.ContextKeyRequestLogger`)
    35  
    36  # Creation
    37  
    38  The next step is to create a Sparta-wrapped version of the `helloWorld` function.
    39  
    40  ```go
    41  var lambdaFunctions []*sparta.LambdaAWSInfo
    42  helloWorldFn, _ := sparta.NewAWSLambda("Hello World",
    43    helloWorld,
    44    sparta.IAMRoleDefinition{})
    45  ```
    46  
    47  We first declare an empty slice `lambdaFunctions` to which all our service's lambda functions will be appended. The next step is to register a new lambda target via [NewAWSLambda](https://godoc.org/github.com/mweagle/Sparta#NewAWSLambda). `NewAWSLambda` accepts three parameters:
    48  
    49  - `string`: The function name. A sanitized version of this value is used as the [FunctionName](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-functionname).
    50  - `func(...)`: The **go** function to execute.
    51  - `string|IAMRoleDefinition` : _Either_ a string literal that refers to a pre-existing IAM Role under which the lambda function will be executed, _OR_ a `sparta.IAMRoleDefinition` value that will be provisioned as part of this deployment and used as the execution role for the lambda function.
    52    - In this example, we're defining a new `IAMRoleDefinition` as part of the stack. This role definition will automatically include privileges for actions such as CloudWatch logging, and since our function doesn't access any additional AWS services that's all we need.
    53  
    54  # Delegation
    55  
    56  The final step is to define a Sparta service under your application's `main` package and provide the non-empty slice of lambda functions:
    57  
    58  ```go
    59  sparta.Main("MyHelloWorldStack",
    60    "Simple Sparta application that demonstrates core functionality",
    61    lambdaFunctions,
    62    nil,
    63    nil)
    64  ```
    65  
    66  `sparta.Main` accepts five parameters:
    67  
    68  - `serviceName` : The string to use as the CloudFormation stackName. Note that there can be only a single stack with this name within a given AWS account, region pair.
    69    - The `serviceName` is used as the stable identifier to determine when updates should be applied rather than new stacks provisioned, as well as the target of a `delete` command line request.
    70    - Consider using [UserScopedStackName](https://godoc.org/github.com/mweagle/Sparta/aws/cloudformation#UserScopedStackName) to generate unique, stable names across a team.
    71  - `serviceDescription`: An optional string used to describe the stack.
    72  - `[]*LambdaAWSInfo` : Slice of `sparta.lambdaAWSInfo` that define a service
    73  - `*API` : Optional pointer to data if you would like to provision and associate an API Gateway with the set of lambda functions.
    74    - We'll walk through how to do that in [another section](/reference/apigateway/apigateway/), but for now our lambda function will only be accessible via the AWS SDK or Console.
    75  - `*S3Site` : Optional pointer to data if you would like to provision an [static website on S3](http://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html), initialized with local resources.
    76    - We'll walk through how to do that in [another section](/reference/s3site), but for now our lambda function will only be accessible via the AWS SDK or Console.
    77  
    78  Delegating `main()` to `Sparta.Main()` transforms the set of lambda functions into a standalone executable with several command line options. Run `go run main.go --help` to see the available options.
    79  
    80  # Putting It Together
    81  
    82  Putting everything together, and including the necessary imports, we have:
    83  
    84  ```go
    85  // File: main.go
    86  package main
    87  
    88  import (
    89    "context"
    90  
    91    sparta "github.com/mweagle/Sparta"
    92  )
    93  
    94  // Standard AWS λ function
    95  func helloWorld(ctx context.Context) (string, error) {
    96    return "Hello World!", nil
    97  }
    98  
    99  func main() {
   100    var lambdaFunctions []*sparta.LambdaAWSInfo
   101    helloWorldFn, _ := sparta.NewAWSLambda("Hello World",
   102      helloWorld,
   103      sparta.IAMRoleDefinition{})
   104    lambdaFunctions = append(lambdaFunctions, helloWorldFn)
   105    sparta.Main("MyHelloWorldStack",
   106      "Simple Sparta application that demonstrates core functionality",
   107      lambdaFunctions,
   108      nil,
   109      nil)
   110  }
   111  ```
   112  
   113  # Running It
   114  
   115  Next download the Sparta dependencies via:
   116  
   117  - `go get ./...`
   118  
   119  in the directory that you saved _main.go_. Once the packages are downloaded, first get a view of what's going on by the `describe` command (replacing `$S3_BUCKET` with an S3 bucket you own):
   120  
   121  ```nohighlight
   122  $ go run main.go --level info describe --out ./graph.html --s3Bucket $S3_BUCKET
   123  INFO[0000] ════════════════════════════════════════════════
   124  INFO[0000] ╔═╗╔═╗╔═╗╦═╗╔╦╗╔═╗   Version : 1.13.0
   125  INFO[0000] ╚═╗╠═╝╠═╣╠╦╝ ║ ╠═╣   SHA     : 03cdb90
   126  INFO[0000] ╚═╝╩  ╩ ╩╩╚═ ╩ ╩ ╩   Go      : go1.13.3
   127  INFO[0000] ════════════════════════════════════════════════
   128  INFO[0000] Service: MyHelloWorldStack-123412341234       LinkFlags= Option=describe UTC="2019-12-07T20:01:48Z"
   129  INFO[0000] ════════════════════════════════════════════════
   130  INFO[0000] Provisioning service                          BuildID=none CodePipelineTrigger= InPlaceUpdates=false NOOP=true Tags=
   131  INFO[0000] Verifying IAM Lambda execution roles
   132  INFO[0000] IAM roles verified                            Count=1
   133  INFO[0000] Skipping S3 preconditions check due to -n/-noop flag  Bucket=weagle Region=us-west-2 VersioningEnabled=false
   134  INFO[0000] Running `go generate`
   135  INFO[0000] Compiling binary                              Name=Sparta.lambda.amd64
   136  INFO[0001] Creating code ZIP archive for upload          TempName=./.sparta/MyHelloWorldStack_123412341234-code.zip
   137  INFO[0001] Lambda code archive size                      Size="24 MB"
   138  INFO[0001] Skipping S3 upload due to -n/-noop flag       Bucket=weagle File=MyHelloWorldStack_123412341234-code.zip Key=MyHelloWorldStack-123412341234/MyHelloWorldStack_123412341234-code-ec0d6f8bae7b6a7abaa77db394c96265e213d20d.zip Size="24 MB"
   139  INFO[0001] Skipping Stack creation due to -n/-noop flag  Bucket=weagle TemplateName=MyHelloWorldStack_123412341234-cftemplate.json
   140  INFO[0001] ════════════════════════════════════════════════
   141  INFO[0001] MyHelloWorldStack-123412341234 Summary
   142  INFO[0001] ════════════════════════════════════════════════
   143  INFO[0001] Verifying IAM roles                           Duration (s)=0
   144  INFO[0001] Verifying AWS preconditions                   Duration (s)=0
   145  INFO[0001] Creating code bundle                          Duration (s)=1
   146  INFO[0001] Uploading code                                Duration (s)=0
   147  INFO[0001] Ensuring CloudFormation stack                 Duration (s)=0
   148  INFO[0001] Total elapsed time                            Duration (s)=1
   149  ```
   150  
   151  Then open _graph.html_ in your browser (also linked [here](/images/overview/graph.html) ) to see what will be provisioned.
   152  
   153  Since everything looks good, we'll provision the stack via `provision` and verify the lambda function. Note that the `$S3_BUCKET` value must be an S3 bucket to which you have write access since Sparta uploads the lambda package and CloudFormation template to that bucket as part of provisioning.
   154  
   155  ```nohighlight
   156  INFO[0000] ════════════════════════════════════════════════
   157  INFO[0000] ╔═╗╔═╗╔═╗╦═╗╔╦╗╔═╗   Version : 1.13.0
   158  INFO[0000] ╚═╗╠═╝╠═╣╠╦╝ ║ ╠═╣   SHA     : 03cdb90
   159  INFO[0000] ╚═╝╩  ╩ ╩╩╚═ ╩ ╩ ╩   Go      : go1.13.3
   160  INFO[0000] ════════════════════════════════════════════════
   161  INFO[0000] Service: MyHelloWorldStack-123412341234       LinkFlags= Option=provision UTC="2019-12-07T19:53:24Z"
   162  INFO[0000] ════════════════════════════════════════════════
   163  INFO[0000] Using `git` SHA for StampedBuildID            Command="git rev-parse HEAD" SHA=b114e329ed37b532e1f7d2e727aa8211d9d5889c
   164  INFO[0000] Provisioning service                          BuildID=b114e329ed37b532e1f7d2e727aa8211d9d5889c CodePipelineTrigger= InPlaceUpdates=false NOOP=false Tags=
   165  INFO[0000] Verifying IAM Lambda execution roles
   166  INFO[0000] IAM roles verified                            Count=1
   167  INFO[0000] Checking S3 versioning                        Bucket=weagle VersioningEnabled=true
   168  INFO[0000] Checking S3 region                            Bucket=weagle Region=us-west-2
   169  INFO[0000] Running `go generate`
   170  INFO[0001] Compiling binary                              Name=Sparta.lambda.amd64
   171  INFO[0002] Creating code ZIP archive for upload          TempName=./.sparta/MyHelloWorldStack_123412341234-code.zip
   172  INFO[0002] Lambda code archive size                      Size="24 MB"
   173  INFO[0002] Uploading local file to S3                    Bucket=weagle Key=MyHelloWorldStack-123412341234/MyHelloWorldStack_123412341234-code.zip Path=./.sparta/MyHelloWorldStack_123412341234-code.zip Size="24 MB"
   174  INFO[0011] Uploading local file to S3                    Bucket=weagle Key=MyHelloWorldStack-123412341234/MyHelloWorldStack_123412341234-cftemplate.json Path=./.sparta/MyHelloWorldStack_123412341234-cftemplate.json Size="2.2 kB"
   175  INFO[0011] Issued CreateChangeSet request                StackName=MyHelloWorldStack-123412341234
   176  INFO[0016] Issued ExecuteChangeSet request               StackName=MyHelloWorldStack-123412341234
   177  INFO[0033] CloudFormation Metrics ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
   178  INFO[0033]     Operation duration                        Duration=8.26s Resource=MyHelloWorldStack-123412341234 Type="AWS::CloudFormation::Stack"
   179  INFO[0033]     Operation duration                        Duration=1.35s Resource=HelloWorldLambda80576f7b21690b0cb485a6b69c927aac972cd693 Type="AWS::Lambda::Function"
   180  INFO[0033] Stack provisioned                             CreationTime="2019-11-28 00:05:04.508 +0000 UTC" StackId="arn:aws:cloudformation:us-west-2:123412341234:stack/MyHelloWorldStack-123412341234/bab01fb0-1172-11ea-84a9-0ab88639bbc6" StackName=MyHelloWorldStack-123412341234
   181  INFO[0033] ════════════════════════════════════════════════
   182  INFO[0033] MyHelloWorldStack-123412341234 Summary
   183  INFO[0033] ════════════════════════════════════════════════
   184  INFO[0033] Verifying IAM roles                           Duration (s)=0
   185  INFO[0033] Verifying AWS preconditions                   Duration (s)=0
   186  INFO[0033] Creating code bundle                          Duration (s)=1
   187  INFO[0033] Uploading code                                Duration (s)=9
   188  INFO[0033] Ensuring CloudFormation stack                 Duration (s)=22
   189  INFO[0033] Total elapsed time                            Duration (s)=33
   190  ```
   191  
   192  Once the stack has been provisioned (`CREATE_COMPLETE`), login to the AWS console and navigate to the Lambda section.
   193  
   194  # Testing
   195  
   196  Find your Lambda function in the list of AWS Lambda functions and click the hyperlink. The display name will be prefixed by the name of your stack (_MyHelloWorldStack_ in our example):
   197  
   198  ![AWS Lambda List](/images/overview/AWS_Lambda_List.png)
   199  
   200  On the Lambda details page, click the _Test_ button:
   201  
   202  ![AWS Lambda Test](/images/overview/AWS_Lambda_Test.png)
   203  
   204  Accept the and name the _Hello World_ event template sample (our Lambda function doesn't consume the event data) and click _Save and test_. The execution result pane should display something similar to:
   205  
   206  ![AWS Lambda Execution](/images/overview/AWS_Lambda_Execution.png)
   207  
   208  # Cleaning Up
   209  
   210  To prevent unauthorized usage and potential charges, make sure to `delete` your stack before moving on:
   211  
   212  ```nohighlight
   213  $ go run main.go delete
   214  
   215  INFO[0000] ════════════════════════════════════════════════
   216  INFO[0000] ╔═╗┌─┐┌─┐┬─┐┌┬┐┌─┐   Version : 1.0.2
   217  INFO[0000] ╚═╗├─┘├─┤├┬┘ │ ├─┤   SHA     : b37b93e
   218  INFO[0000] ╚═╝┴  ┴ ┴┴└─ ┴ ┴ ┴   Go      : go1.9.2
   219  INFO[0000] ════════════════════════════════════════════════
   220  INFO[0000] Service: MyHelloWorldStack                    LinkFlags= Option=delete UTC="2018-01-27T22:01:59Z"
   221  INFO[0000] ════════════════════════════════════════════════
   222  INFO[0000] Stack existence check                         Exists=true Name=MyHelloWorldStack
   223  INFO[0000] Delete request submitted                      Response="{\n\n}"
   224  ```
   225  
   226  # Conclusion
   227  
   228  Congratulations! You've just deployed your first "serverless" service. The following sections will dive
   229  deeper into what's going on under the hood as well as how to integrate your lambda function(s) into the broader AWS landscape.
   230  
   231  # Next Steps
   232  
   233  Walkthrough what Sparta actually does to deploy your application in the [next section](/reference/intro_example/step2/).