AWS SDK for the Go programming language.

AWS SDK for Go

API Reference Join the chat at https://gitter.im/aws/aws-sdk-go Build Status Apache V2 License

aws-sdk-go is the official AWS SDK for the Go programming language.

Checkout our release notes for information about the latest bug fixes, updates, and features added to the SDK.

We announced the General Availability for the AWS SDK for Go V2 (v2). The v2 SDK source is available at https://github.com/aws/aws-sdk-go-v2. Review the v2 SDK's Developer Guide to get started with AWS SDK for Go V2 or review the migration guide if you already use version 1.

Jump To:

Getting Started

Installing

Use go get to retrieve the SDK to add it to your GOPATH workspace, or project's Go module dependencies.

go get github.com/aws/aws-sdk-go

To update the SDK use go get -u to retrieve the latest version of the SDK.

go get -u github.com/aws/aws-sdk-go

Dependencies

The SDK includes a vendor folder containing the runtime dependencies of the SDK. The metadata of the SDK's dependencies can be found in the Go module file go.mod or Dep file Gopkg.toml.

Go Modules

If you are using Go modules, your go get will default to the latest tagged release version of the SDK. To get a specific release version of the SDK use @<tag> in your go get command.

go get github.com/aws/[email protected]

To get the latest SDK repository change use @latest.

go get github.com/aws/aws-sdk-go@latest

Go 1.5

If you are using Go 1.5 without vendoring enabled, (GO15VENDOREXPERIMENT=1), you will need to use ... when retrieving the SDK to get its dependencies.

go get github.com/aws/aws-sdk-go/...

This will still include the vendor folder. The vendor folder can be deleted if not used by your environment.

rm -rf $GOPATH/src/github.com/aws/aws-sdk-go/vendor

Quick Examples

Complete SDK Example

This example shows a complete working Go file which will upload a file to S3 and use the Context pattern to implement timeout logic that will cancel the request if it takes too long. This example highlights how to use sessions, create a service client, make a request, handle the error, and process the response.

  package main

  import (
  	"context"
  	"flag"
  	"fmt"
  	"os"
  	"time"

  	"github.com/aws/aws-sdk-go/aws"
  	"github.com/aws/aws-sdk-go/aws/awserr"
  	"github.com/aws/aws-sdk-go/aws/request"
  	"github.com/aws/aws-sdk-go/aws/session"
  	"github.com/aws/aws-sdk-go/service/s3"
  )

  // Uploads a file to S3 given a bucket and object key. Also takes a duration
  // value to terminate the update if it doesn't complete within that time.
  //
  // The AWS Region needs to be provided in the AWS shared config or on the
  // environment variable as `AWS_REGION`. Credentials also must be provided
  // Will default to shared config file, but can load from environment if provided.
  //
  // Usage:
  //   # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
  //   go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt
  func main() {
  	var bucket, key string
  	var timeout time.Duration

  	flag.StringVar(&bucket, "b", "", "Bucket name.")
  	flag.StringVar(&key, "k", "", "Object key name.")
  	flag.DurationVar(&timeout, "d", 0, "Upload timeout.")
  	flag.Parse()

  	// All clients require a Session. The Session provides the client with
 	// shared configuration such as region, endpoint, and credentials. A
 	// Session should be shared where possible to take advantage of
 	// configuration and credential caching. See the session package for
 	// more information.
  	sess := session.Must(session.NewSession())

 	// Create a new instance of the service's client with a Session.
 	// Optional aws.Config values can also be provided as variadic arguments
 	// to the New function. This option allows you to provide service
 	// specific configuration.
  	svc := s3.New(sess)

  	// Create a context with a timeout that will abort the upload if it takes
  	// more than the passed in timeout.
  	ctx := context.Background()
  	var cancelFn func()
  	if timeout > 0 {
  		ctx, cancelFn = context.WithTimeout(ctx, timeout)
  	}
  	// Ensure the context is canceled to prevent leaking.
  	// See context package for more information, https://golang.org/pkg/context/
	if cancelFn != nil {
  		defer cancelFn()
	}

  	// Uploads the object to S3. The Context will interrupt the request if the
  	// timeout expires.
  	_, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
  		Bucket: aws.String(bucket),
  		Key:    aws.String(key),
  		Body:   os.Stdin,
  	})
  	if err != nil {
  		if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
  			// If the SDK can determine the request or retry delay was canceled
  			// by a context the CanceledErrorCode error code will be returned.
  			fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err)
  		} else {
  			fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err)
  		}
  		os.Exit(1)
  	}

  	fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key)
  }

Overview of SDK's Packages

The SDK is composed of two main components, SDK core, and service clients. The SDK core packages are all available under the aws package at the root of the SDK. Each client for a supported AWS service is available within its own package under the service folder at the root of the SDK.

  • aws - SDK core, provides common shared types such as Config, Logger, and utilities to make working with API parameters easier.

    • awserr - Provides the error interface that the SDK will use for all errors that occur in the SDK's processing. This includes service API response errors as well. The Error type is made up of a code and message. Cast the SDK's returned error type to awserr.Error and call the Code method to compare returned error to specific error codes. See the package's documentation for additional values that can be extracted such as RequestID.

    • credentials - Provides the types and built in credentials providers the SDK will use to retrieve AWS credentials to make API requests with. Nested under this folder are also additional credentials providers such as stscreds for assuming IAM roles, and ec2rolecreds for EC2 Instance roles.

    • endpoints - Provides the AWS Regions and Endpoints metadata for the SDK. Use this to lookup AWS service endpoint information such as which services are in a region, and what regions a service is in. Constants are also provided for all region identifiers, e.g UsWest2RegionID for "us-west-2".

    • session - Provides initial default configuration, and load configuration from external sources such as environment and shared credentials file.

    • request - Provides the API request sending, and retry logic for the SDK. This package also includes utilities for defining your own request retryer, and configuring how the SDK processes the request.

  • service - Clients for AWS services. All services supported by the SDK are available under this folder.

How to Use the SDK's AWS Service Clients

The SDK includes the Go types and utilities you can use to make requests to AWS service APIs. Within the service folder at the root of the SDK you'll find a package for each AWS service the SDK supports. All service clients follow common pattern of creation and usage.

When creating a client for an AWS service you'll first need to have a Session value constructed. The Session provides shared configuration that can be shared between your service clients. When service clients are created you can pass in additional configuration via the aws.Config type to override configuration provided by in the Session to create service client instances with custom configuration.

Once the service's client is created you can use it to make API requests the AWS service. These clients are safe to use concurrently.

Configuring the SDK

In the AWS SDK for Go, you can configure settings for service clients, such as the log level and maximum number of retries. Most settings are optional; however, for each service client, you must specify a region and your credentials. The SDK uses these values to send requests to the correct AWS region and sign requests with the correct credentials. You can specify these values as part of a session or as environment variables.

See the SDK's configuration guide for more information.

See the session package documentation for more information on how to use Session with the SDK.

See the Config type in the aws package for more information on configuration options.

Configuring Credentials

When using the SDK you'll generally need your AWS credentials to authenticate with AWS services. The SDK supports multiple methods of supporting these credentials. By default the SDK will source credentials automatically from its default credential chain. See the session package for more information on this chain, and how to configure it. The common items in the credential chain are the following:

  • Environment Credentials - Set of environment variables that are useful when sub processes are created for specific roles.

  • Shared Credentials file (~/.aws/credentials) - This file stores your credentials based on a profile name and is useful for local development.

  • EC2 Instance Role Credentials - Use EC2 Instance Role to assign credentials to application running on an EC2 instance. This removes the need to manage credential files in production.

Credentials can be configured in code as well by setting the Config's Credentials value to a custom provider or using one of the providers included with the SDK to bypass the default credential chain and use a custom one. This is helpful when you want to instruct the SDK to only use a specific set of credentials or providers.

This example creates a credential provider for assuming an IAM role, "myRoleARN" and configures the S3 service client to use that role for API requests.

  // Initial credentials loaded from SDK's default credential chain. Such as
  // the environment, shared credentials (~/.aws/credentials), or EC2 Instance
  // Role. These credentials will be used to to make the STS Assume Role API.
  sess := session.Must(session.NewSession())

  // Create the credentials from AssumeRoleProvider to assume the role
  // referenced by the "myRoleARN" ARN.
  creds := stscreds.NewCredentials(sess, "myRoleArn")

  // Create service client value configured for credentials
  // from assumed role.
  svc := s3.New(sess, &aws.Config{Credentials: creds})

See the credentials package documentation for more information on credential providers included with the SDK, and how to customize the SDK's usage of credentials.

The SDK has support for the shared configuration file (~/.aws/config). This support can be enabled by setting the environment variable, "AWS_SDK_LOAD_CONFIG=1", or enabling the feature in code when creating a Session via the Option's SharedConfigState parameter.

  sess := session.Must(session.NewSessionWithOptions(session.Options{
      SharedConfigState: session.SharedConfigEnable,
  }))

Configuring AWS Region

In addition to the credentials you'll need to specify the region the SDK will use to make AWS API requests to. In the SDK you can specify the region either with an environment variable, or directly in code when a Session or service client is created. The last value specified in code wins if the region is specified multiple ways.

To set the region via the environment variable set the "AWS_REGION" to the region you want to the SDK to use. Using this method to set the region will allow you to run your application in multiple regions without needing additional code in the application to select the region.

AWS_REGION=us-west-2

The endpoints package includes constants for all regions the SDK knows. The values are all suffixed with RegionID. These values are helpful, because they reduce the need to type the region string manually.

To set the region on a Session use the aws package's Config struct parameter Region to the AWS region you want the service clients created from the session to use. This is helpful when you want to create multiple service clients, and all of the clients make API requests to the same region.

  sess := session.Must(session.NewSession(&aws.Config{
      Region: aws.String(endpoints.UsWest2RegionID),
  }))

See the endpoints package for the AWS Regions and Endpoints metadata.

In addition to setting the region when creating a Session you can also set the region on a per service client bases. This overrides the region of a Session. This is helpful when you want to create service clients in specific regions different from the Session's region.

  svc := s3.New(sess, &aws.Config{
      Region: aws.String(endpoints.UsWest2RegionID),
  })

See the Config type in the aws package for more information and additional options such as setting the Endpoint, and other service client configuration options.

Making API Requests

Once the client is created you can make an API request to the service. Each API method takes a input parameter, and returns the service response and an error. The SDK provides methods for making the API call in multiple ways.

In this list we'll use the S3 ListObjects API as an example for the different ways of making API requests.

  • ListObjects - Base API operation that will make the API request to the service.

  • ListObjectsRequest - API methods suffixed with Request will construct the API request, but not send it. This is also helpful when you want to get a presigned URL for a request, and share the presigned URL instead of your application making the request directly.

  • ListObjectsPages - Same as the base API operation, but uses a callback to automatically handle pagination of the API's response.

  • ListObjectsWithContext - Same as base API operation, but adds support for the Context pattern. This is helpful for controlling the canceling of in flight requests. See the Go standard library context package for more information. This method also takes request package's Option functional options as the variadic argument for modifying how the request will be made, or extracting information from the raw HTTP response.

  • ListObjectsPagesWithContext - same as ListObjectsPages, but adds support for the Context pattern. Similar to ListObjectsWithContext this method also takes the request package's Option function option types as the variadic argument.

In addition to the API operations the SDK also includes several higher level methods that abstract checking for and waiting for an AWS resource to be in a desired state. In this list we'll use WaitUntilBucketExists to demonstrate the different forms of waiters.

  • WaitUntilBucketExists. - Method to make API request to query an AWS service for a resource's state. Will return successfully when that state is accomplished.

  • WaitUntilBucketExistsWithContext - Same as WaitUntilBucketExists, but adds support for the Context pattern. In addition these methods take request package's WaiterOptions to configure the waiter, and how underlying request will be made by the SDK.

The API method will document which error codes the service might return for the operation. These errors will also be available as const strings prefixed with "ErrCode" in the service client's package. If there are no errors listed in the API's SDK documentation you'll need to consult the AWS service's API documentation for the errors that could be returned.

  ctx := context.Background()

  result, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{
      Bucket: aws.String("my-bucket"),
      Key: aws.String("my-key"),
  })
  if err != nil {
      // Cast err to awserr.Error to handle specific error codes.
      aerr, ok := err.(awserr.Error)
      if ok && aerr.Code() == s3.ErrCodeNoSuchKey {
          // Specific error code handling
      }
      return err
  }

  // Make sure to close the body when done with it for S3 GetObject APIs or
  // will leak connections.
  defer result.Body.Close()

  fmt.Println("Object Size:", aws.Int64Value(result.ContentLength))

API Request Pagination and Resource Waiters

Pagination helper methods are suffixed with "Pages", and provide the functionality needed to round trip API page requests. Pagination methods take a callback function that will be called for each page of the API's response.

   objects := []string{}
   err := svc.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{
       Bucket: aws.String(myBucket),
   }, func(p *s3.ListObjectsOutput, lastPage bool) bool {
       for _, o := range p.Contents {
           objects = append(objects, aws.StringValue(o.Key))
       }
       return true // continue paging
   })
   if err != nil {
       panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", myBucket, err))
   }

   fmt.Println("Objects in bucket:", objects)

Waiter helper methods provide the functionality to wait for an AWS resource state. These methods abstract the logic needed to check the state of an AWS resource, and wait until that resource is in a desired state. The waiter will block until the resource is in the state that is desired, an error occurs, or the waiter times out. If a resource times out the error code returned will be request.WaiterResourceNotReadyErrorCode.

  err := svc.WaitUntilBucketExistsWithContext(ctx, &s3.HeadBucketInput{
      Bucket: aws.String(myBucket),
  })
  if err != nil {
      aerr, ok := err.(awserr.Error)
      if ok && aerr.Code() == request.WaiterResourceNotReadyErrorCode {
          fmt.Fprintf(os.Stderr, "timed out while waiting for bucket to exist")
      }
      panic(fmt.Errorf("failed to wait for bucket to exist, %v", err))
  }
  fmt.Println("Bucket", myBucket, "exists")

Getting Help

Please use these community resources for getting help. We use the GitHub issues for tracking bugs and feature requests.

  • Ask a question on StackOverflow and tag it with the aws-sdk-go tag.
  • Come join the AWS SDK for Go community chat on gitter.
  • Open a support ticket with AWS Support.
  • If you think you may have found a bug, please open an issue.

This SDK implements AWS service APIs. For general issues regarding the AWS services and their limitations, you may also take a look at the Amazon Web Services Discussion Forums.

Opening Issues

If you encounter a bug with the AWS SDK for Go we would like to hear about it. Search the existing issues and see if others are also experiencing the issue before opening a new issue. Please include the version of AWS SDK for Go, Go language, and OS you’re using. Please also include reproduction case when appropriate.

The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for Go please make use of the resources listed in the Getting Help section. Keeping the list of open issues lean will help us respond in a timely manner.

Contributing

We work hard to provide a high-quality and useful SDK for our AWS services, and we greatly value feedback and contributions from our community. Please review our contributing guidelines before submitting any issues or pull requests to ensure we have all the necessary information to effectively respond to your bug report or contribution.

Maintenance and support for SDK major versions

For information about maintenance and support for SDK major versions and our underlying dependencies, see the following in the AWS SDKs and Tools Shared Configuration and Credentials Reference Guide:

Resources

Developer guide - This document is a general introduction on how to configure and make requests with the SDK. If this is your first time using the SDK, this documentation and the API documentation will help you get started. This document focuses on the syntax and behavior of the SDK. The Service Developer Guide will help you get started using specific AWS services.

SDK API Reference Documentation - Use this document to look up all API operation input and output parameters for AWS services supported by the SDK. The API reference also includes documentation of the SDK, and examples how to using the SDK, service client API operations, and API operation require parameters.

Service Documentation - Use this documentation to learn how to interface with AWS services. These guides are great for getting started with a service, or when looking for more information about a service. While this document is not required for coding, services may supply helpful samples to look out for.

SDK Examples - Included in the SDK's repo are several hand crafted examples using the SDK features and AWS services.

Forum - Ask questions, get help, and give feedback

Issues - Report issues, submit pull requests, and get involved (see Apache 2.0 License)

Comments
  • [S3] RequestError with UploadPart call

    [S3] RequestError with UploadPart call

    Please fill out the sections below to help us address your issue.

    Version of AWS SDK for Go?

    v1.18.2

    Version of Go (go version)?

    go version go1.10.4

    What issue did you see?

    We are using MultipartUpload for uploading some mp3 files to S3. At times, the S3.UploadPart function throws the following error:

    RequestError: send request failed
    caused by: Put https://<bucket_name>.s3.ap-southeast-1.amazonaws.com/filename.mp3?partNumber=1&uploadId=FQEnFylcgwfiSyqAFJSAaBPujuG_ooLOCrPnHv5vO_Un0W5_Ml8DYeqB4xx7US_IFbcdkjrWZqizTemAKyx3MNYwku6BPRqvLz3eGxAqndFUUw--: http: Request.ContentLength=4674720 with nil Body
    

    Here is the code the code that handles the uploading part:

    func uploadPart(svc *s3.S3, resp *s3.CreateMultipartUploadOutput, fileBytes []byte, partNumber int) (*s3.CompletedPart, error) {
    	tryNum := 1
    
    	body := bytes.NewReader(fileBytes)
    	partInput := &s3.UploadPartInput{
    		Body:          body,
    		Bucket:        resp.Bucket,
    		Key:           resp.Key,
    		PartNumber:    aws.Int64(int64(partNumber)),
    		UploadId:      resp.UploadId,
    		ContentLength: aws.Int64(int64(len(fileBytes))),
    	}
    
    	for tryNum <= maxRetries {
    		uploadResult, err := svc.UploadPart(partInput)
    		if err != nil {
    			if tryNum == maxRetries {
    				if aerr, ok := err.(awserr.Error); ok {
    					return nil, aerr
    				}
    				return nil, err
    			}
    			log.Printf("Retrying to upload part #%v\n", partNumber)
    			tryNum++
    		} else {
    			return &s3.CompletedPart{
    				ETag:       uploadResult.ETag,
    				PartNumber: aws.Int64(int64(partNumber)),
    			}, nil
    		}
    	}
    	return nil, nil
    }
    
    

    Steps to reproduce

    Not reproducable. Happens only some times. The body is not actually nil. Made sure of it by checking it in the logs.

  • Discussion: How should you unit test code which uses the aws-sdk-go

    Discussion: How should you unit test code which uses the aws-sdk-go

    Consider the following case:

    I have a package within my project which is my DAO package. It has methods like GetFooById("some-id"), which returns me the Foo object from dynamoDB which has the ID "some-id".

    This package constructs a dynamo condition, and calls DynamoClient.Query().

    How should one unit test my package without hitting a real DynamoDB, or without running a stub server which responds with AWS-like responses?

    Here's what I've considered/experimented with:

    1. Interface the parts of the AWS SDK which my code touches, and then use go-mock or alike. Cons: I have to then maintain a lot of extra interfaces, just for testing purposes
    2. Use withmock to replace the entire AWS package Cons: Withmock isn't well maintained, is slow, and doesn't play well with tools like godep or gocheck
    3. Wrap the calls to the sdk with a private variable defined function, which I can re-define in my tests, and manipulate to return fake objects. Cons: Is much like suggestion 1, and implies you have lines of code which aren't technically tested.

    Other options:

    • Have the AWS SDK present interfaces, so that using existing mocking tools doesn't require implementation of an interface.
    • Stub out AWS using a HTTP stub server.
    • Write some new mocking tool which achieves what we want...

    What are people's thoughts on this? What is the intention for onward testing of this sdk? (I see a small amount of unit tests at the client level, and some integration tests on the modules...)

  • aws/credential: Add credential_process provider

    aws/credential: Add credential_process provider

    Fixes #1834 Continuation of #1874

    How It Works

    If you have a method of sourcing credentials that isn't built in to the [SDK], you can integrate it by using credential_process in the config file. The [SDK] will call that command exactly as given and then read json data from stdout.

    For example, you may have this configuration (this example uses awsprocesscreds for SAML integration):

    [dev]
    credential_process = awsprocesscreds-saml -e https://example.okta.com/home/amazon_aws/blob/123 -u '[email protected]' -p okta -a arn:aws:iam::123456789012:role/okta-dev
    

    Assuming the process returns a valid json like this example (but with valid credentials):

    {
      "Version": 1,
      "AccessKeyId": "<access key id>",
      "SecretAccessKey": "<secret access key>",
      "SessionToken": "<optional session token>",
      "Expiration": "<optional expiration date in ISO8601>"
    }
    

    You could use it in your code like this:

    sess := session.Must(session.NewSessionWithOptions(session.Options{
        Profile: "dev",
    }))
    
    svc := s3.New(sess)
    
    result, err := svc.ListBuckets(nil)
    ...
    

    You can also provide the process command programmatically without using a config file.

    creds := credentials.NewCredentials(&processcreds.ProcessProvider{
        Process: "/path/to/a/cred/process",
    })
    
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        Credentials: creds,
    }))
    
    svc := s3.New(sess)
    

    This Pull Request

    This PR adds support for calling a credential_process and builds on the work of @micahhausler, taking into account review notes by @jasdel.

    Notable changes over #1874:

    • Rebased, fixing conflict
    • Removes the processcreds provider from the default credential chain
    • Adds further protection of credential_process including a timeout and small buffer limit (in case of a hung process or a process producing much data) - limits are configurable
    • Uses goroutines for executing process, reading data from the process
    • Moves the new provider and test into a processcreds package
    • Creates const error messages and default values
    • Completely avoids reading shared config file, leaving this to the existing providers
    • Process is passed via input parameter to the provider allowing for programmatic defining without need for shared config file
    • Makes Expiration of type Time
    • Carefully handles the environment (which is tricky when tests clear the env)
    • Avoids issues with string splitting the command by using subshells on Windows and Linux
    • Lets exec.Command fail rather than doing pre-checks
    • Captures both stdout and stderr in output
    • Does not mess with profiles, leaving that to existing resources
    • Does not use testify
    • Includes tests providing near 100% code coverage

    Please let me know if you have additional review.

    See related:

    • aws/aws-sdk-js#1923
    • boto/botocore#1316
    • serverless/serverless#4838
    • oktadeveloper/okta-aws-cli-assume-role#203
    • aws/aws-sdk-ruby#1820
    • aws/aws-sdk-java-v2#455
  • GetRecords  blocked for more than 10 minutes

    GetRecords blocked for more than 10 minutes

    Hi, I encounter an issue that it took more than 10 minutes to call GetRecords. So, there was an error "Iterator expired", when get records next time. It was correct when I started my application, and issue happened after several minutes. GetRecords should not be blocked, from AWS doc

    I enabled kinesis api debug info: log attached. Did you encounter this issue? And how to solve it?

    Thank you in advance!

    debug_info.log.gz get_record_code

  • Unable to make ec2metadata request (returning 301)

    Unable to make ec2metadata request (returning 301)

    I am receiving the following error when attempting to make a basic role request.

    EC2RoleRequestError: no EC2 instance role found\ncaused by: EC2MetadataError: failed to make EC2Metadata request

    sess := session.New()
    creds := ec2rolecreds.NewCredentials(sess)
    config = &aws.Config{
        Credentials: creds,
        Region:      aws.String("us-west-2"),
        LogLevel:    aws.LogLevel(aws.LogDebugWithHTTPBody),
    }
    svc = dynamodb.New(sess, config)
    

    When I look at the request log, I see that it's making a 301 because iamSecurityCredsPath is missing a trailing slash.

    We are running this inside a docker container, when we enter a bash prompt inside the container, we can make aws cli requests without issue.

  • Make v4 Signer public

    Make v4 Signer public

    Following @jasdel request, this is another try to make the aws v4 signer public, following in #662 footsteps.

    My current approach is to be minimally invasive: keep the private aws/signer/v4 package, which merely translates aws requests to the public aws/signer/v4 interface, which uses http.Request instead.

    A cleaner approach would be to remove the private signer entirely and adjust where necessary; also, we could split private/ public usage using struct embedding or similar, if necessary.

    The corehandler is still missing, since I'm not sure where this would be used internally.

    Feedback very welcome.

  • GetRecords hangs

    GetRecords hangs

    Hi,

    I'm having some problems with my application that is reading records from Kinesis. It seems to be randomly hanging on the GetRecords request until either Kinesis kills the connection or the subsequent GetRecords will fail due to an expired iterator.

    I have a stream with four shards. Total incoming data is around 500 kb/s. I have an application that starts a worker per shard- each worker is split into 5 parts, each communicating with the next over its own channel.

    The KinesisReader is very straight forward:

    ...
    for {
        // get records
        ts_start = time.Now()
        records, err := GetKinesisRecordsAndUpdateIterator(kinesisClient, iterator)
        if err != nil {
            log.Error("[WORKER #%v | KINESIS READER] Failed to get records (took=%v): %v", r.workerId, time.Since(ts_start), err)
            return
        }
        log.Info("[WORKER #%v | KINESIS READER] Read %v records from Kinesis (took=%v)", r.workerId, len(records), time.Since(ts_start))
        ...
    }
    ...
    
    func GetKinesisRecordsAndUpdateIterator(client *kinesis.Kinesis, iterator *string) ([]*kinesis.Record, error) {
        getRecordsInput := &kinesis.GetRecordsInput{
            ShardIterator: iterator,
        }
        resp, err := client.GetRecords(getRecordsInput)
        if err != nil {
            return nil, err
        }
        *iterator = *resp.NextShardIterator
    
        return resp.Records, nil
    }
    

    If it does not read any records it will go to sleep for 10 seconds. It will kill the worker on any errors and start a new one (hence it has failed 165 times in the last 12 hours).

    The three other workers happily continue reading records while this is happening.

    This results in the following log examples:

    2015/06/30 06:25:07.073380 INFO [WORKER #157 | KINESIS READER] Read 1 records from Kinesis (took=30.845742ms)
    2015/06/30 06:25:07.089282 INFO [WORKER #157 | KINESIS READER] Read 0 records from Kinesis (took=15.8282ms)
    2015/06/30 06:31:50.780351 INFO [WORKER #157 | KINESIS READER] Read 21 records from Kinesis (took=6m33.690849627s)
    2015/06/30 06:31:51.185088 ERROR [WORKER #157 | KINESIS READER] Failed to get records (took=73.276055ms): ExpiredIteratorException: Iterator expired. The iterator was created at time Tue Jun 30 06:25:17 UTC 2015 while right now it is Tue Jun 30 06:31:51 UTC 2015 which is further in the future than the tolerated delay of 300000 milliseconds.
    status code: 400, request id: []
    
    2015/06/30 06:37:24.780944 INFO [WORKER #165 | KINESIS READER] Read 0 records from Kinesis (took=20.868442ms)
    06:37:34.977293 INFO [WORKER #165 | KINESIS READER] Read 25 records from Kinesis (took=196.090744ms)
    2015/06/30 06:37:35.228885 INFO [WORKER #165 | KINESIS READER] Read 2 records from Kinesis (took=33.813113ms)
    2015/06/30 06:37:35.258778 INFO [WORKER #165 | KINESIS READER] Read 0 records from Kinesis (took=24.589261ms)
    2015/06/30 06:37:45.439487 INFO [WORKER #165 | KINESIS READER] Read 33 records from Kinesis (took=180.496173ms)
    2015/06/30 06:37:45.650751 INFO [WORKER #165 | KINESIS READER] Read 1 records from Kinesis (took=35.829663ms)
    2015/06/30 06:37:45.674542 INFO [WORKER #165 | KINESIS READER] Read 0 records from Kinesis (took=23.662061ms)
    2015/06/30 06:42:58.103110 ERROR [WORKER #165 | KINESIS READER] Failed to get records (took=5m2.42835127s): SerializationError: failed decoding JSON RPC response
    caused by: read tcp 54.239.19.115:443: connection reset by peer
    

    The second one is by far the most frequent example.

    Am I doing something wrong here? Any suggestions as to what might be wrong?

  • Support context pattern

    Support context pattern

    See this blog article:

    https://blog.golang.org/context

    We use this heavily in all aspects of our SOA, and it allows us to inject request scoped parameters to systems that need them to provide useful information -- such as logging or in-memory caches. Here is a drastically simplified example:

    type key int
    const LoggerKey key = 0
    const RequestIdKey key = 1
    const MethodNameKey key = 2
    
    type Logger interface {
        Debug(ctx context.Context, message, args ...interface{})
    }    
    
    // alternatively the context interface could have the log methods on them to avoid this step
    func LoggerFrom(ctx context.Context) Logger {
        if logger, ok := ctx.Value(LoggerKey).(Logger); ok {
            return logger
        } else {
            return nullLogger
        }
    }
    
    ctx := context.WithCancel(context.Background())
    ctx = context.WithValue(ctx, RequestIdKey, uuid.NewV4())
    ctx = context.WithValue(ctx, LoggerKey, myLogger)
    
    someFrontendMethod(ctx, other, arguments)
    
    ...
    
    func someFrontendMethod(ctx context.Context, other int, arguments string) {
        ctx = context.WithValue(ctx, MethodNameKey, "someFrontendMethod")
        result, err := aws.DynamoDb().Get(ctx, ...) 
        ...
    }
    
    // totally made up interface, not implying this should be the real AWS one
    func (d *DynamoDb) Get(ctx context.Context, some int, args string) (*Result, error) {
        LoggerFrom(ctx).Debug(ctx, "dynamodb.get - starting request")
        ...
    }
    

    This would then output something like:

    [DEBUG] [requestId=5f0712749191adda1079e71c2403ec24d65ebf32] someFrontendMethod: dynamodb.get - starting request
    

    Additionally, in the first method, you would be able to timeout the call to someFrontendMethod by closing the Done channel on the context. Depending upon how much of the callstack is using the context, every goroutine underneath it would be notified of the cancelled context and abort as soon as possible. In the case of the AWS lib, this could be used to abort an exponential backoff algorithm that is currently sleeping without the caller of the lib having to cancel manually somehow.

  • s3 error xml

    s3 error xml

    when we get an s3 error it's automatically unmarshalled: https://github.com/aws/aws-sdk-go/blob/master/service/s3/unmarshal_error.go which hides the original XML error message. In some case we want the original error, for example on a 301 we want to see what the correct bucket location should be. awserr.Error has an OrigErr() function but that field is always initialized to nil.

  • Connect to RDS using rdsutils.BuildAuthToken not working

    Connect to RDS using rdsutils.BuildAuthToken not working

    Please fill out the sections below to help us address your issue.

    Version of AWS SDK for Go?

    v1.8.19-6-g7b500fb

    Version of Go (go version)?

    go 1.8

    What issue did you see?

    following the doc but unable to make successful DB connection using IAM role from EC2 Also, this is particularly hard to debug because of not actually able to run code as EC2 on dev to test

    Steps to reproduce

    I follow the below step in https://docs.aws.amazon.com/sdk-for-go/api/service/rds/rdsutils/#BuildAuthToken and use the exact same code snippet but I believe there's some issue with the instruction:

    authToken, err := BuildAuthToken(dbEndpoint, awsRegion, dbUser, awsCreds)
    
    // Create the MySQL DNS string for the DB connection
    // user:password@protocol(endpoint)/dbname?<params>
    dnsStr = fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=true",
       dbUser, authToken, dbEndpoint, dbName,
    )
    
    // Use db to perform SQL operations on database
    db, err := sql.Open("mysql", dnsStr)
    

    I have tried the above instruction but it was throwing signing errors

    below is my latest code snippet, I have tried various different fortmat and this is the one i last end up with:

    // c.Hostname = host.xxxx.us-east-1.rds.amazonaws.com
    // c.Port = 3306
    
    hostlocation := fmt.Sprintf("https://%v:%v", c.Hostname, c.Port)
    token, stdErr := rdsutils.BuildAuthToken(hostlocation, "us-east-1", "appuser", stscreds.NewCredentials(sess, "arn:aws:iam::[AWS ID]:role/SomeRole"))
    
    dnsStr := fmt.Sprintf("[appuser:%s@tcp(%s)]:%v/%s?tls=true", token, c.Hostname, c.Port, "dbname")
    
    // Connect to database
    db, stdErr := sql.Open("mysql", dnsStr)
    

    for this one i got: StdError: invalid DSN: did you forget to escape a param value?

    the token returned is actually in the following format:

    host.xxxx.us-east-1.rds.amazonaws.com:3306?Action=connect&DBUser=appuser&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAJHJ4MX7HB6STZ5QQ%2F20170504%2Fus-east-1%2Frds-db%2Faws4_request&X-Amz-Date=20170504T164655Z&X-Amz-Expires=900&X-Amz-Security-Token=FQoDYXdzENr%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDB3PYlunbHE2bh4ylCLWAevRs7cztGGATW3iJm0tpL1J2G%2FsqJjilAlhI2uj6VW%2BWH0txpt2bZ7DgQeZ0lutoJj3rffcznu7o0VIG%2F7L8MXC11BjXOIOEXFwx%2BhEIAqM%2F3v9vpa9Jp1L2xqPBs%2FLuOYmHFxufykYE3D9%2BdoPRp3srEj3AqGbv9Nanw6zRXbsRkAj96VzsAnFTzyTAyOknBUDkWpBzjR%2Fo1Gqdd9gwu6HdJRcp6H%2B9oI0FLrDuQqUfSZez5BUspe4EYDWctSEuNoNREQzzUkkoU2yXB69m4KxA4TyIy4ogLatyAU%3D&X-Amz-SignedHeaders=host&X-Amz-Signature=2b249517f6dc4ad145232cdab3ea59e9b8b20dedad6666b07bbe686e33b6859e
    

    I am not sure if this is the right string that should replace the DSN/DNS password field as indicated in the doc

    Can anyone please help me figure out what the actual and correct DSN or DNS will look like? some example will be very helpful as I can just follow the same structure

    Thanks

  • Utilize io.Reader not io.ReadSeeker where possible

    Utilize io.Reader not io.ReadSeeker where possible

    Summary

    I noticed the s3 calls are using io.ReadSeeker for Body behind the scenes, which seems to be contributing to a huge waste of memory for general use cases. The issue is that ReadSeeker needs to persist bytes so that it can seek backwards, while the io.Reader interface can garbage collect bytes once it has read them, allowing it to Stream data from network or disk.

    Observed

    Using the s3 api for a web service which uses PutObject to place a file into s3, the file must be fully loaded into memory using io.ReadSeeker. For large objects (300MB) this meant a RAM use of about > 700MB.

    Expected

    The io.Reader interface should stream input bytes and allow them to be garbage collected once Read (and presumably written to s3).

    Additional Information

    Replacing aws-sdk-go with mitchellh/goamz dropped my RAM use per 300MB request from 700MB to ~8MB. I have a minimal test case to demonstrate this, if desired.

  • do the amazon light sail api exist?

    do the amazon light sail api exist?

    Describe the issue

    where we can find amazon light sail ap in go

    Links

    http://hamrah.ccc.com/web#action=302&model=calendar.event&view_type=calendar&cids=1&menu_id=202

  • Missing methods within s3manageriface package

    Missing methods within s3manageriface package

    Describe the bug

    The s3manageriface package is missing numerous methods that exist within the s3manager package.

    Expected Behavior

    All methods that exist within s3manager are able to be mocked by utilizing the s3manageriface package.

    Current Behavior

    Unable to mock the NewDeleteListIterator within the s3manager package.

    Reproduction Steps

    Attempt to mock functions like NewDeleteListIterator within the s3manager package.

    Possible Solution

    No response

    Additional Information/Context

    No response

    SDK version used

    v1.44.170

    Environment details (Version of Go (go version)? OS name and version, etc.)

    go1.19.1 darwin/arm64

  • ListObjectVersionsPagesWithContext can get into an infinite loop when using URL encoding

    ListObjectVersionsPagesWithContext can get into an infinite loop when using URL encoding

    Describe the bug

    When EncodingType is set to s3.EncodingTypeUrl, ListObjectVersionsPagesWithContext can call "fn" repeatedly with the same keys. It never reaches the end of the listing, and only stops if "fn" returns false.

    This happens if there is an object key containing a backslash ("\").

    Expected Behavior

    I expect each call to "fn" to have different keys, and I expect the listing to eventually end even if "fn" always returns true.

    Current Behavior

    "fn" is called repeatedly with the same keys.

    Reproduction Steps

    Run this program as "go run main.go -bucket <your-s3-bucket> -prefix <prefix-with-no-objects>. It will create two objects under the prefix and attempt to list them with ListObjectVersionsPagesWithContext. However, it gets into an infinite loop returning the first object again and again. Note: this program does not clean up the objects it created, you have to delete them manually.

    Sample output:

    ##### Create objects #####
    Put object key: test1/object\1, version ID: ""
    Put object key: test1/object\2, version ID: ""
    
    ##### List objects #####
    Listed key: test1/object\1, version ID: null
    Finished one page, next key marker: test1/object%5C1
    
    Listed key: test1/object\1, version ID: null
    Finished one page, next key marker: test1/object%5C1
    
    Listed key: test1/object\1, version ID: null
    Finished one page, next key marker: test1/object%5C1
    
    ^Csignal: interrupt
    

    The program

    package main
    
    import (
    	"bytes"
    	"context"
    	"flag"
    	"fmt"
    	"net/url"
    	"strings"
    
    	"github.com/aws/aws-sdk-go/aws"
    	"github.com/aws/aws-sdk-go/aws/session"
    	"github.com/aws/aws-sdk-go/service/s3"
    )
    
    func main() {
    	bucket := flag.String("bucket", "", "S3 bucket name")
    	prefixFlag := flag.String("prefix", "", "Prefix under which to create objects")
    	flag.Parse()
    
    	// Add a trailing "/" to the prefix if there isn't one
    	prefix := *prefixFlag
    	if !strings.HasSuffix(prefix, "/") {
    		prefix += "/"
    	}
    
    	sess := session.Must(session.NewSession())
    	api := s3.New(sess)
    
    	fmt.Println("##### Create objects #####")
    
    	// Create two objects under the provided prefix. The object keys contain a
    	// backslash, which is converted to "%5C" by URL encoding.
    	keys := []string{
    		"object\\1",
    		"object\\2",
    	}
    	for i, key := range keys {
    		fullKey := prefix + key
    		putInput := &s3.PutObjectInput{
    			Bucket: bucket,
    			Key:    aws.String(fullKey),
    			Body:   bytes.NewReader([]byte{byte(i)}),
    		}
    		output, err := api.PutObjectWithContext(context.Background(), putInput)
    		if err != nil {
    			panic(fmt.Sprintf("Failed to put object %v: %v", fullKey, err))
    		}
    		fmt.Printf("Put object key: %v, version ID: \"%v\"\n",
    			fullKey, aws.StringValue(output.VersionId))
    	}
    
    	fmt.Println()
    	fmt.Println("##### List objects #####")
    
    	// List objects under the prefix with URL encoding and MaxKeys set to 1.
    	listInput := &s3.ListObjectVersionsInput{
    		Bucket:       bucket,
    		Prefix:       aws.String(prefix),
    		EncodingType: aws.String(s3.EncodingTypeUrl),
    		MaxKeys:      aws.Int64(1),
    	}
    	err := api.ListObjectVersionsPagesWithContext(context.Background(), listInput,
    		func(output *s3.ListObjectVersionsOutput, cont bool) bool {
    			for _, content := range output.Versions {
    				fmt.Printf("Listed key: %v, version ID: %v\n",
    					urlDecode(aws.StringValue(content.Key)),
    					urlDecode(aws.StringValue(content.VersionId)))
    			}
    
    			for _, marker := range output.DeleteMarkers {
    				fmt.Printf("Listed delete marker: %v, version ID: %v\n",
    					urlDecode(aws.StringValue(marker.Key)),
    					urlDecode(aws.StringValue(marker.VersionId)))
    			}
    
    			fmt.Printf("Finished one page, next key marker: %v\n",
    				aws.StringValue(output.NextKeyMarker))
    			fmt.Println()
    
    			return true
    		})
    	if err != nil {
    		panic(fmt.Sprintf("Listing error: %v\n", err))
    	}
    
    	fmt.Println("Done listing")
    }
    
    // Decode a URL-encoded string. Panic if there is any error.
    func urlDecode(encoded string) string {
    	decoded, err := url.PathUnescape(encoded)
    	if err != nil {
    		panic(fmt.Sprintf("Unabled to URL decode string \"%v\": %v", encoded, err))
    	}
    	return decoded
    }
    

    Possible Solution

    It's possible that ListObjectVersionsPagesWithContext doesn't URL-decode NextKeyMarker from the ListObjectVersions response before using it as the KeyMarker for the next call to ListObjectVersions.

    The URL-encoding of "\" is "%5C", and "%" comes before "\" lexicographically.

    Additional Information/Context

    No response

    SDK version used

    github.com/aws/aws-sdk-go v1.44.83

    Environment details (Version of Go (go version)? OS name and version, etc.)

    go version go1.19.4 darwin/amd64, macOS Ventura 13.1

  • Allow custom `ignoredHeaders` with v4 signer

    Allow custom `ignoredHeaders` with v4 signer

    Describe the feature

    Currently, the ignoredHeaders is a private hard-coded list which includes auth header, User-agent, and the trace ID header. https://github.com/aws/aws-sdk-go/blob/183764bff45cc1d1e8ddecccd706dc26aaaa2c44/aws/signer/v4/v4.go#L92-L100

    Request to give an option for overwriting this list when using the v4 signer.

    Use Case

    Teleport implements a proxy for AWS APIs and uses the v4 signer for verifying incoming AWS requests.

    However, it's found that some AWS applications (e.g. AWS Java SDK v1, Athena JDBC driver) sign the requests including the User-agent header, like:

    SignedHeaders=amz-sdk-invocation-id;amz-sdk-request;amz-sdk-retry;content-type;host;user-agent;x-amz-content-sha256;x-amz-date
    

    Thus signature generated by golang SDK will never match the ones from these requests as the User-agent header is excluded in go.

    It would be great if the list of ignored headers list can be overwritten when creating the signer.

    Proposed Solution

    Have a new option to overwrite the ignored headers list, for example:

    signer := v4.NewSigner(credentials, v4.WithIgnoredHeaders([]string{"Authorization", "X-Amzn-Trace-Id", "expect"}))
    

    Other Information

    No response

    Acknowledgements

    • [X] I may be able to implement this feature request
    • [ ] This feature might incur a breaking change

    SDK version used

    v1.44.132

    Environment details (Version of Go (go version)? OS name and version, etc.)

    Go 1.19 macOS 13.0.1

  • remove failing Go versions on macos-latest

    remove failing Go versions on macos-latest

    For changes to files under the /model/ folder, and manual edits to autogenerated code (e.g. /service/s3/api.go) please create an Issue instead of a PR for those type of changes.

    Excluding Go versions which appear to fail when run on macos-latest. Exclude < 1.10 on macos-latest for without module support because of: https://github.com/golang/go/wiki/MacOS12BSDThreadRegisterIssue

    Excluding 1.12-1.15 on macos-latest because seeing somewhat consistent obscure errors on Deprecation tests with module support.

    If there is an existing bug or feature this PR is answers please reference it here.

  • aws-sdk-go doens't support new sso-session in a shared config

    aws-sdk-go doens't support new sso-session in a shared config

    Describe the bug

    2 weeks ago, awscli v2.9.0 was released and introduced sso-session section in $HOME/.aws/config. But it seetms aws-sdk-go doesn't support it yet, and failed to load the config.

    Expected Behavior

    aws-sdk-go should load sso-session section from a shared config correctly.

    Current Behavior

    aws-sdk-go just ignored sso-session section, and failed by missing required configuration: sso_region, sso_start_url.

    Reproduction Steps

    1. install awscli v2.9.0 or later.
    2. create a shared config by aws configure sso
    3. load the config from aws-sdk-go. I used session manager plugin.

    Possible Solution

    No response

    Additional Information/Context

    It would be nice if session manager plugin team in AWS would update aws-sdk-go version after releasing the fix.

    SDK version used

    v1.40.17

    Environment details (Version of Go (go version)? OS name and version, etc.)

    Linux

Sample apps and code written for Google Cloud in the Go programming language.
Sample apps and code written for Google Cloud in the Go programming language.

Google Cloud Platform Go Samples This repository holds sample code written in Go that demonstrates the Google Cloud Platform. Some samples have accomp

Jan 9, 2023
AWS Lambda to work around index.html S3/CloudFront mess

No more index.html mess with AWS CloudFront/S3 Problem Consider you have a statically generated site — a bunch of usual resources, including html file

Jan 2, 2023
Browse your AWS ECS Clusters in the Terminal
Browse your AWS ECS Clusters in the Terminal

Browse your AWS ECS Clusters in the Terminal. The ecsview application is a terminal-based UI for browsing Amazon Elastic Container Service (ECS) clust

Dec 14, 2022
Generate a basic IAM policy from AWS client-side monitoring (CSM)
Generate a basic IAM policy from AWS client-side monitoring (CSM)

iamlive Generate a basic IAM policy from AWS client-side monitoring (CSM) Installation Pre-built binaries Pre-built binaries for Windows, macOS and Li

Jan 8, 2023
AWS plugin for Steampipe
AWS plugin for Steampipe

Use SQL to query IAM users, EC2 instances and more from your AWS account.

Dec 29, 2022
This example shows how to serve private contents on AWS S3 through CloudFront signed URL.

AWS CloudFront with Signed URL This is the repository of my blog post. This example shows how to serve private contents on AWS S3 through CloudFront s

Oct 19, 2022
Go language interface to Swift / Openstack Object Storage / Rackspace cloud files (golang)

Swift This package provides an easy to use library for interfacing with Swift / Openstack Object Storage / Rackspace cloud files from the Go Language

Nov 9, 2022
AWS SDK for the Go programming language.

AWS SDK for Go aws-sdk-go is the official AWS SDK for the Go programming language. Checkout our release notes for information about the latest bug fix

Dec 31, 2022
Nextengine-sdk-go: the NextEngine SDK for the Go programming language

NextEngine SDK for Go nextengine-sdk-go is the NextEngine SDK for the Go programming language. Getting Started Install go get github.com/takaaki-s/nex

Dec 7, 2021
Simple no frills AWS S3 Golang Library using REST with V4 Signing (without AWS Go SDK)

simples3 : Simple no frills AWS S3 Library using REST with V4 Signing Overview SimpleS3 is a golang library for uploading and deleting objects on S3 b

Nov 4, 2022
A package for access aws service using AWS SDK for Golang

goaws ?? A package for access aws service using AWS SDK for Golang Advantage with goaws package Example for get user list IAM with AWS SDK for Golang

Nov 25, 2021
Floppa programming language inspired by the brainf*ck programming language. Created just for fun and you can convert your brainf*ck code to floppa code.

Floppa Programming Language Created just for fun. But if you want to contribute, why not? Floppa p.l. inspired by the brainf*ck programming language.

Oct 20, 2022
T# Programming Language. Something like Porth, Forth but written in Go. Stack-oriented programming language.

The T# Programming Language WARNING! THIS LANGUAGE IS A WORK IN PROGRESS! ANYTHING CAN CHANGE AT ANY MOMENT WITHOUT ANY NOTICE! Something like Forth a

Jun 29, 2022
Yayx programming language is begginer friendly programming language.
Yayx programming language is begginer friendly programming language.

Yayx Yayx programming language is begginer friendly programming language. What have yayx: Easy syntax Dynamic types Can be compiled to outhers program

Dec 27, 2021
Yayx programming language is begginer friendly programming language.

Yayx Yayx programming language is begginer friendly programming language. What have yayx: Easy syntax Dynamic types Can be compiled to outhers program

May 20, 2022
Advent of Code is an Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like.

Advent of Code 2021 Advent of Code is an Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved

Dec 2, 2021
Jan 4, 2022
A repository for showcasing my knowledge of the Google Go (2009) programming language, and continuing to learn the language.

Learning Google Golang (programming language) Not to be confused with the Go! programming language by Francis McCabe I don't know very much about the

Nov 6, 2022
A repository for showcasing my knowledge of the Go! (2003) programming language, and continuing to learn the language.
A repository for showcasing my knowledge of the Go! (2003) programming language, and continuing to learn the language.

Learning Go! (programming language) Not to be confused with Google Golang (2009) I don't know too much about the Go! programming language, but I know

Oct 22, 2022
Run the same Docker images in AWS Lambda and AWS ECS
Run the same Docker images in AWS Lambda and AWS ECS

serverlessish tl;dr Run the exact same image for websites in Lambda as you do in ECS, Kubernetes, etc. Just add this to your Dockerfile, listen on por

Dec 22, 2022