cfft

package module
v0.8.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 8, 2024 License: MIT Imports: 42 Imported by: 0

README

cfft

cfft is a testing tool for CloudFront Functions.

Description

cfft is a testing tool for CloudFront Functions. cfft helps you to test CloudFront Functions in development stage.

cfft supports the following features.

  • Initialize files for testing CloudFront Functions.
  • Test CloudFront Functions in development stage.
  • Compare the result with the expect object.
  • Ignore fields in the expect object.
  • Diff function code.
  • Publish function.
  • Output JSON for Terraform. See Cooperate with Terraform.

cfft supports management of CloudFront KeyValueStore. See Use CloudFront KeyValueStore.

Install

Homebrew
$ brew install fujiwara/tap/cfft
Download binary

Download the binary from GitHub Releases.

aqua

aquaproj supports cfft. fujiwara/cfft is available in aqua-registory.

$ aqua init
$ aqua g -i fujiwara/cfft

Usage

Usage: cfft <command>

Flags:
  -h, --help                  Show context-sensitive help.
  -c, --config="cfft.yaml"    config file
      --debug                 enable debug log
      --log-format="text"     log format (text,json)

Commands:
  test
    test function

  init --name=STRING
    initialize files

  diff
    diff function code

  publish
    publish function

  kvs list
    list key values

  kvs get <key>
    get value of key

  kvs put <key> <value>
    put value of key

  kvs delete <key>
    delete key

  kvs info
    show info of key value store

  render
    render function code

  tf
    output JSON for tf

  version
    show version

Run "cfft <command> --help" for more information on a command.
Example of initializing files for testing CloudFront Functions

cfft init creates a config file and a function file and an example event file.

Usage: cfft init --name=STRING

initialize function

Flags:
  -h, --help                           Show context-sensitive help.
  -c, --config="cfft.yaml"             config file

      --name=STRING                    function name
      --format="json"                  output event file format (json,jsonnet,yaml)
      --event-type="viewer-request"    event type (viewer-request,viewer-response)

If the function is already exists in the CloudFront Functions, cfft downloads the function code and creates a config file.

If the function is not found, cfft creates a new config file and a function file and example event file. You can edit the function file and event file and test the function with cfft test --create-if-missing.

Example of testing CloudFront Functions

cfft test executes CloudFront Functions in the DEVELOPMENT stage and compares the result with the expect object if specified.

Usage: cfft test

test function

Flags:
  -h, --help                  Show context-sensitive help.
  -c, --config="cfft.yaml"    config file

      --create-if-missing     create function if missing
Add Cache-Control header in viewer-response

See examples/add-cache-control directory.

# cfft.yaml
name: my-function
function: function.js
testCases:
  - name: add-cache-control
    event: event.json
// function.js
async function handler(event) {
  const response = event.response;
  const headers = response.headers;

  // Set the cache-control header
  headers['cache-control'] = { value: 'public, max-age=63072000' };
  console.log('[on the edge] Cache-Control header set.');

  // Return response to viewers
  return response;
}

event.json

{
    "version": "1.0",
    "context": {
        "eventType": "viewer-response"
    },
    "viewer": {
        "ip": "1.2.3.4"
    },
    "request": {
        "method": "GET",
        "uri": "/index.html",
        "headers": {},
        "cookies": {},
        "querystring": {}
    },
    "response": {
        "statusCode": 200,
        "statusDescription": "OK",
        "headers": {},
        "cookies": {}
    }
}
$ cfft test
2024-01-19T22:35:26+09:00 [info] function my-function found
2024-01-19T22:35:26+09:00 [info] function code is not changed
2024-01-19T22:35:26+09:00 [info] [testcase:add-cache-control] testing function
2024-01-19T22:35:26+09:00 [info] [testcase:add-cache-control] ComputeUtilization: 31 optimal
2024-01-19T22:35:26+09:00 [info] [testcase:add-cache-control] [from:my-function] [on the edge] Cache-Control header set.
2024-01-19T22:35:26+09:00 [info] [testcase:add-cache-control] OK
2024-01-19T22:35:27+09:00 [info] 1 testcases passed

cfft executes my-function with event.json at CloudFront Functions in development stage.

About an event object, see also CloudFront Functions event structure.

  • If my-function is not found, cfft test --create-if-missing creates a new function with the name and runtime cloudfront-js-2.0.
  • If the function is found and the code is different from the function.js, cfft updates the function code.
  • Shows logs and compute utilization of the function after the execution.
Compare the result with the expect object

When you specify the expect element in test cases, cfft compares the result with the expect object.

# cfft.yaml
name: my-function
function: function.js
testCases:
  - name: add-cache-control
    event: event.json
    expect: expect.json

If the result is different from the expect.json, cfft exits with a non-zero status code.

2024-01-19T22:39:33+09:00 [info] function my-function found
2024-01-19T22:39:33+09:00 [info] function code or kvs association is changed, updating...
2024-01-19T22:39:34+09:00 [info] [testcase:add-cache-control] testing function
2024-01-19T22:39:35+09:00 [info] [testcase:add-cache-control] ComputeUtilization: 29
2024-01-19T22:39:35+09:00 [info] [testcase:add-cache-control] [from:my-function] [on the edge] Cache-Control header set.
--- expect
+++ actual
@@ -4,7 +4,7 @@
     "statusDescription": "OK",
     "headers": {
       "cache-control": {
-        "value": "public, max-age=6307200"
+        "value": "public, max-age=63072000"
       }
     }
   }

2024-01-19T22:39:35+09:00 [error] failed to run test case add-cache-control, expect and actual are not equal

expect.json

{
  "response": {
    "headers": {
      "cache-control": {
        "value": "public, max-age=6307200"
      }
    },
    "statusDescription": "OK",
    "cookies": {},
    "statusCode": 200
  }
}
Ignore fields in the expect object

If you want to ignore some fields in the expect object, you can use the ignore element in test cases.

# cfft.yaml
name: my-function
function: function.js
testCases:
  - name: add-cache-control
    event: event.json
    expect: expect.json
    ignore: ".response.cookies, .response.headers.date"

The .response.cookies and .response.headers.date are ignored in the expect object.

Event and Expect file format

The event and expect file format is JSON, Jsonnet or YAML.

# cfft.yaml
name: my-function
function: function.js
testCases:
  - name: add-cache-control
    event: event.jsonnet
    expect: expect.yaml

cfft supports the following file extensions.

  • .json
  • .jsonnet
  • .yaml
  • .yml
HTTP text format for Request and Response objects

cfft supports an HTTP text format for Request and Response objects.

The following example is the HTTP text format of the Request object.

GET /index.html HTTP/1.1
Host: example.com

The request object is converted to the following JSON object.

{
  "method": "GET",
  "uri": "/index.html",
  "headers": {
    "host": {
      "value": "example.com"
    }
  }
}

The following example is the HTTP text format of the Response object.

HTTP/1.1 302 Found
Location: https://example.com/

The response object is converted to the following JSON object.

{
  "statusCode": 302,
  "statusDescription": "Found",
  "headers": {
    "location": {
      "value": "https://example.com/"
    }
  }
}

You can convert from HTTP text to JSON object with cfft util parse-request and cfft util parse-response commands.

$ cfft util parse-request < request.txt
{
  "method": "GET",
  "uri": "/index.html",
  "headers": {
    "host": {
      "value": "example.com"
    }
  }
}

For use of the text format, I recommend using YAML or Jsonnet format for the event and expect files instead of plain JSON. YAML and Jsonnet support multiline strings.

# event.yaml
---
version: "1.0"
context:
  eventType: viewer-response
viewer:
  ip: 1.2.3.4
request: |
  GET /index.html HTTP/1.1
  Host: example.com
response: |
  HTTP/1.1 302 Found
  Location: https://example.com/
{
  version: '1.0',
  context: {
    eventType: 'viewer-response',
  },
  viewer: {
    ip: '1.2.3.4',
  },
  request: |||
    GET /index.html HTTP/1.1
    Host: example.com
  |||,
  response: |||
    HTTP/1.1 302 Found
    Location: https://example.com/
  |||,
}
Chain multiple functions

cfft supports chaining multiple functions. The feature is useful to test the combined function.

# cfft.yaml
name: my-function
runtime: cloudfront-js-2.0 # required
function:
  event-type: viewer-request
  functions:
    - function1.js
    - function2.js
  filter_command: "npx esbuild --minify"
testCases:
## ...

The runtime must be cloudfront-js-2.0.

  • function element allows you to specify multiple function files.
    • event-type must be viewer-request or viewer-response. required.
    • functions element is an array of function files.
    • filter_command is a command to filter the chained function code. optional.

When you specify the multiple functions in function, cfft automatically creates a combined function chained with all functions.

The combined function works as the following steps.

  1. The first function in the functions array is evaluated.
  2. The result of the first function is passed to the second function.
  3. ...(repeat)

When the event-type is viewer-response and any step returns a response object(includes statusCode), the response object is returned to the viewer immidiately. The following functions are not evaluated.

The filter_command is a command to filter the chained function code. The command must accepts the function code from stdin and outputs the filtered function code to stdout. For example, use npx esbuild --minify to minify the function code.

Note: esbuild --minify may change identifiers in js code, so it may not work for js file includes import syntax.

You can review the generated combined function code with cfft render command.

Use CloudFront KeyValueStore

cfft supports CloudFront KeyVakueStore.

# cfft.yaml
name: function-with-kvs
function: function.js
kvs:
  name: hostnames

If you specify the kvs element in the config file, cfft test --create-if-missing creates a KeyValueStore with the name if not exsites, and associates the KeyValueStore with the function. You can use the KeyValueStore in the function code.

In a function code, the KVS id is available in the KVS_ID environment variable.

import cf from 'cloudfront';

const kvsId = "{{ must_env `KVS_ID` }}";
const kvsHandle = cf.kvs(kvsId);

async function handler(event) {
  const request = event.request;
  const clientIP = event.viewer.ip;
  const hostname = (await kvsHandle.exists(clientIP)) ? await kvsHandle.get(clientIP) : 'unknown';

  request.headers['x-hostname'] = { value: hostname };
  return request;
}
Manage KVS key values with cfft kvs command

cfft kvs command manages KVS key values.

  • cfft kvs list lists all key values.
  • cfft kvs get <key> gets the value of the key.
  • cfft kvs put <key> <value> puts the value of the key.
  • cfft kvs delete <key> deletes the key.
  • cfft kvs info shows the information of the KeyValueStore.
Diff function code

cfft diff compares the function code with the code in the CloudFront Functions in the "DEVELOPMENT" stage.

$ cfft diff
2024-01-19T22:41:18+09:00 [info] function my-function found
--- E3UN6WX5RRO2AG
+++ function.js
@@ -1,5 +1,5 @@
 async function handler(event) {
   const request = event.request;
-  console.log('hello cfft world');
+  console.log('hello cfft');
   return request;
 }

cfft diff --live compares the function code with the code in the CloudFront Functions in the "LIVE" stage.

Publish function

cfft publish publishes the function to the CloudFront Functions.

$ cfft publish

cfft publish fails if the local function code differs from the CloudFront Functions code.

Before publishing the function, you need to run cfft diff to check the difference and run cfft test to check the function behavior.

Render function code, event and expect object

cfft render renders the function code or event object or expect object to STDOUT.

Usage: cfft render [<target>]

render function code

Arguments:
  [<target>]    render target (function,event,expect)

Flags:
       --test-case="" test case name (for target event or expect)
$ cfft render

You can use cfft render to check the function code after rendering the template syntax.

cfft render event --test-case=foo renders the event object of the test case named 'foo'.

The --test-case flag is available only for the event and expect targets. If --test-case is not specified, cfft renders the event or expect object of the first test case.

Template syntax

cfft read files (config, function, event, and expect) with the following template syntax by kayac/go-config.

must_env function renders the environment variable value.

{{ must_env `FOO` }}

If the environment variable FOO is not set, cfft exits with a non-zero status code. You can use env function to set a default value.

{{ env `BAR` `default_of_BAR` }}

See examples/true-client-ip directory to see how to use the template syntax.

testCases:
  - name: localhost
    event: event.json
    expect: expect.json
    env:
      IP: 127.0.0.1
      HOSTNAME: localhost
  - name: home
    event: event.json
    expect: expect.json
    env:
      IP: 192.168.1.1
      HOSTNAME: home

In testCases, env overrides the environment variables. These values are used in event.json and expect.json.

event.json

{
  "version": "1.0",
  "context": {
    "eventType": "viewer-request"
  },
  "viewer": {
    "ip": "{{ env `IP` `127.0.0.2` }}"
  },
  "request": {
    "method": "GET",
    "uri": "/index.html",
    "headers": {},
    "cookies": {},
    "querystring": {}
  }
}

expect.json

{
  "request": {
    "cookies": {},
    "headers": {
      "true-client-ip": {
        "value": "{{ env `IP` `127.0.0.2` }}"
      },
      "x-hostname": {
        "value": "{{ env `HOSTNAME` `unknown` }}"
      }
    },
    "method": "GET",
    "querystring": {},
    "uri": "/index.html"
  }
}

Cooperate with Terraform

cfft is desined to use with Terraform.

cfft has two methods to cooperate with Terraform, cfft tf generates tf.json, and cfft tf --external generates JSON for Terraform's external data sources.

Generate tf.json

cfft tf command outputs a JSON defines a Terraform aws_cloudfront_function resource. The JSON file is read by Terraform as JSON Configuration Syntax.

$ cfft tf > cff.tf.json

cff.tf.json

{
  "//": "This file is generated by cfft. DO NOT EDIT.",
  "resource": {
    "aws_cloudfront_function": {
      "some-function": {
        "name": "some-function",
        "runtime": "cloudfront-js-2.0",
        "code": "....(function code)....",
        "comment": "comment of the function",
      }
    }
  }
}

Terraform creates or updates the function with the JSON. If you want to publish the function into the "LIVE" stage by terraform apply, set cfft tf --publish flag.

If you want to run cfft test before terraform (plan|apply), execute cfft test --create-if-missing to create a function in the DEVELOPMENT stage.

In this case, you have to define the import block in a .tf file because the function is already created by cfft, but Terraform does not know the function. After terraform apply, you can remove the import block.

import {
  to = aws_cloudfront_function.some-function
  id = "some-function"
}

When a function code contains ${, this syntax conflicts with Terraform's interpolation syntax. In this case, cfft outputs the function code into Terraform's variable, and the aws_cloudfront_function resource refers to the variable.

The variable's default value is not parsed as Terraform's interpolation syntax. See also variable-blocks.

{
  "//": "This file is generated by cfft. DO NOT EDIT.",
  "variable": {
    "code_of_some-function": {
      "type": "string",
      "default": "...(function code)..."
    }
  },
  "resource": {
    "aws_cloudfront_function": {
      "some-function": {
        "name": "some-function",
        "code": "${var.code_of_some-function}",
        "runtime": "cloudfront-js-2.0"
      }
    }
  }
}

cfft tf --resource-name foo outputs the JSON with the tf resource name foo instead of the function name.

Generate JSON for Terraform external data sources

cfft tf --external command outputs a JSON for Terraform external data sources.

$ cfft tf --external
{
  "name": "some-function",
  "code": "....(function code)....",
  "comment": "comment of the function",
  "runtime": "cloudfront-js-2.0"
}

You can define the aws_cloudfront_function resource with the data.external data source calling cfft tf --external.

When you run terraform apply, cfft tf --external is executed and the function is created or updated. If publish is true, Terraform will publish the function into the "LIVE" stage.

Note: cfft tf --external does not output a publish attribute because the external data source does not accept non-string values.

resource "aws_cloudfront_function" "some-function" {
  name    = data.external.some-function.result["name"]
  runtime = data.external.some-function.result["runtime"]
  code    = data.external.some-function.result["code"]
  comment = data.external.some-function.result["comment"]
  publish = true
}

data "external" "some-function" {
  program = ["cfft", "--config", "cfft.yaml", "tf", "--external"]
}

If you want to execute cfft test before terraform apply, or you use the KeyValueStore, cfft test --create-if-missing creates a KeyValueStore and associates the KeyValueStore with the function. In this case, you have to define the import block in a .tf file because the function is already created by cfft, but Terraform does not know the function. After terraform apply, you can remove the import block.

import {
  to = aws_cloudfront_function.some-function
  id = "some-function"
}

LICENSE

MIT

Author

Fujiwara Shunichiro

Documentation

Index

Constants

View Source
const MaxCodeSize = 10 * 1024
View Source
const TFJSONComment = `This file is generated by cfft. DO NOT EDIT.`

Variables

View Source
var DefaultEventViewerRequest []byte
View Source
var DefaultEventViewerResponse []byte
View Source
var DefaultFunctionCodeViewerRequest []byte
View Source
var DefaultFunctionCodeViewerResponse []byte
View Source
var FuncMap = template.FuncMap{
	"join": strings.Join,
}
View Source
var FuncTemplate = template.Must(template.New("func").Parse(`
const {{.Name}} = async function(event) {
  {{.Code}}
  return handler(event);
}
`))
View Source
var MainTemplateRequest = template.Must(template.New("main").Funcs(FuncMap).Parse(`
{{- range .Imports }}
{{.}}
{{- end -}}
{{- range .FuncCodes }}
{{.}}
{{- end -}}

async function handler(event) {
  const funcs = [{{ join .FuncNames ","}}];
  for (let i = 0; i < funcs.length; i++) {
    const res = await funcs[i](event);
    if (res && res.statusCode) {
      // when viewer-request returns response object, return it immediately
      return res;
    }
    event.request = res;
  }
  return event.request;
}
`))
View Source
var MainTemplateResponse = template.Must(template.New("main").Funcs(FuncMap).Parse(`
{{- range .Imports -}}
{{.}}
{{- end -}}

{{- range .FuncCodes -}}
{{.}}
{{- end -}}

async function handler(event) {
  const funcs = [{{ join .FuncNames "," }}];
  for (let i = 0; i < funcs.length; i++) {
    event.response = await funcs[i](event);
  }
  return event.response;
}
`))
View Source
var Version = "dev"

Functions

func DefaultEvent added in v0.0.7

func DefaultEvent(t string) []byte

func DefaultFunctionCode added in v0.0.7

func DefaultFunctionCode(t string) []byte

func NewLogHandler added in v0.3.0

func NewLogHandler(w io.Writer, opts *HandlerOptions) slog.Handler

func ReadFile added in v0.0.7

func ReadFile(p string) ([]byte, error)

ReadFile supports jsonnet and yaml files. If the file is jsonnet or yaml, it will be evaluated and converted to json.

func RunCLI added in v0.0.5

func RunCLI(ctx context.Context, args []string) error

func WriteFile added in v0.0.7

func WriteFile(path string, b []byte, perm fs.FileMode) error

Types

type CFFBody added in v0.2.0

type CFFBody struct {
	Encoding string `json:"encoding"`
	Data     string `json:"data"`
}

type CFFContext added in v0.2.0

type CFFContext struct {
	DistributionDomainName string `json:"distributionDomainName,omitempty"`
	DistributionId         string `json:"distributionId,omitempty"`
	EventType              string `json:"eventType,omitempty"`
	RequestId              string `json:"requestId,omitempty"`
}

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-event-structure.html#functions-event-structure-context distributionDomainName The CloudFront domain name (for example, d111111abcdef8.cloudfront.net) of the distribution that's associated with the event.

distributionId The ID of the distribution (for example, EDFDVBD6EXAMPLE) that's associated with the event.

eventType The event type, either viewer-request or viewer-response.

requestId A string that uniquely identifies a CloudFront request (and its associated response).

type CFFCookieValue added in v0.2.0

type CFFCookieValue struct {
	Value      string           `json:"value"`
	Attributes string           `json:"attributes,omitempty"`
	MultiValue []CFFCookieValue `json:"multiValue,omitempty"`
}

type CFFEvent added in v0.2.0

type CFFEvent struct {
	Version  string       `json:"version,omitempty"`
	Context  *CFFContext  `json:"context,omitempty"`
	Viewer   *CFFViewer   `json:"viewer,omitempty"`
	Request  *CFFRequest  `json:"request,omitempty"`
	Response *CFFResponse `json:"response,omitempty"`
}

func (*CFFEvent) Bytes added in v0.2.0

func (e *CFFEvent) Bytes() []byte

type CFFExpect added in v0.2.0

type CFFExpect struct {
	Request *CFFRequest  `json:"request,omitempty"`
	Reponse *CFFResponse `json:"response,omitempty"`
}

func (*CFFExpect) ToMap added in v0.5.2

func (e *CFFExpect) ToMap() map[string]any

type CFFRequest added in v0.2.0

type CFFRequest struct {
	Method      string                    `json:"method"`
	URI         string                    `json:"uri"`
	QueryString map[string]CFFValue       `json:"querystring"`
	Headers     map[string]CFFValue       `json:"headers"`
	Cookies     map[string]CFFCookieValue `json:"cookies"`
}

func ParseRequest added in v0.2.0

func ParseRequest(text string) (CFFRequest, error)

func (*CFFRequest) UnmarshalJSON added in v0.2.0

func (r *CFFRequest) UnmarshalJSON(b []byte) error

type CFFResponse added in v0.2.0

type CFFResponse struct {
	StatusCode        int                       `json:"statusCode,omitempty"`
	StatusDescription string                    `json:"statusDescription,omitempty"`
	Headers           map[string]CFFValue       `json:"headers"`
	Cookies           map[string]CFFCookieValue `json:"cookies"`
	Body              *CFFBody                  `json:"body,omitempty"`
}

func ParseResponse added in v0.2.0

func ParseResponse(text string) (CFFResponse, error)

func (*CFFResponse) UnmarshalJSON added in v0.2.0

func (r *CFFResponse) UnmarshalJSON(b []byte) error

type CFFRunner added in v0.6.0

type CFFRunner struct {
	// contains filtered or unexported fields
}

func (*CFFRunner) Run added in v0.6.0

func (r *CFFRunner) Run(ctx context.Context, name, etag string, event []byte, logger *slog.Logger) ([]byte, error)

type CFFT

type CFFT struct {
	// contains filtered or unexported fields
}

func New added in v0.0.5

func New(ctx context.Context, config *Config) (*CFFT, error)

func (*CFFT) DiffFunction added in v0.0.7

func (app *CFFT) DiffFunction(ctx context.Context, opt *DiffCmd) error

func (*CFFT) Dispatch added in v0.0.5

func (app *CFFT) Dispatch(ctx context.Context, cmds []string, cli *CLI) error

func (*CFFT) InitFunction added in v0.0.7

func (app *CFFT) InitFunction(ctx context.Context, opt *InitCmd) error

func (*CFFT) KVSDelete added in v0.1.0

func (app *CFFT) KVSDelete(ctx context.Context, opt *KVSCmd) error

func (*CFFT) KVSGet added in v0.1.0

func (app *CFFT) KVSGet(ctx context.Context, opt *KVSCmd) error

func (*CFFT) KVSInfo added in v0.1.0

func (app *CFFT) KVSInfo(ctx context.Context, opt *KVSCmd) error

func (*CFFT) KVSList added in v0.1.0

func (app *CFFT) KVSList(ctx context.Context, opt *KVSCmd) error

func (*CFFT) KVSPut added in v0.1.0

func (app *CFFT) KVSPut(ctx context.Context, opt *KVSCmd) error

func (*CFFT) ManageKVS added in v0.1.0

func (app *CFFT) ManageKVS(ctx context.Context, op string, opt *KVSCmd) error

func (*CFFT) PublishFunction added in v0.0.8

func (app *CFFT) PublishFunction(ctx context.Context, opt *PublishCmd) error

func (*CFFT) Render added in v0.2.0

func (app *CFFT) Render(ctx context.Context, opt *RenderCmd) error

func (*CFFT) RunTF added in v0.5.0

func (app *CFFT) RunTF(ctx context.Context, opt *TFCmd) error

func (*CFFT) RunTestCase added in v0.6.0

func (app *CFFT) RunTestCase(ctx context.Context, etag string, cs *TestCase) error

func (*CFFT) RunUtil added in v0.2.0

func (app *CFFT) RunUtil(ctx context.Context, op string, opt *UtilCmd) error

func (*CFFT) SetStdout added in v0.5.0

func (app *CFFT) SetStdout(w io.Writer)

func (*CFFT) TestFunction

func (app *CFFT) TestFunction(ctx context.Context, opt *TestCmd) error

func (*CFFT) UtilParseRequest added in v0.2.0

func (app *CFFT) UtilParseRequest(ctx context.Context, opt ParseRequestCmd) error

func (*CFFT) UtilParseResponse added in v0.2.0

func (app *CFFT) UtilParseResponse(ctx context.Context, opt ParseResponseCmd) error

type CFFValue added in v0.2.0

type CFFValue struct {
	Value      string     `json:"value"`
	MultiValue []CFFValue `json:"multiValue,omitempty"`
}

type CFFViewer added in v0.2.0

type CFFViewer struct {
	IP string `json:"ip"`
}

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-event-structure.html#functions-event-structure-viewer

The viewer object contains an ip field whose value is the IP address of the viewer (client) that sent the request. If the viewer request came through an HTTP proxy or a load balancer, the value is the IP address of the proxy or load balancer.

type CLI

type CLI struct {
	Test    *TestCmd    `cmd:"" help:"test function"`
	Init    *InitCmd    `cmd:"" help:"initialize files"`
	Diff    *DiffCmd    `cmd:"" help:"diff function code"`
	Publish *PublishCmd `cmd:"" help:"publish function"`
	KVS     *KVSCmd     `cmd:"" help:"manage key-value store"`
	Render  *RenderCmd  `cmd:"" help:"render function code"`
	Util    *UtilCmd    `cmd:"" help:"utility commands"`
	TF      *TFCmd      `cmd:"tf" help:"output JSON for tf.json or external data source"`
	Version *VersionCmd `cmd:"" help:"show version"`

	Config    string `short:"c" long:"config" help:"config file" default:"cfft.yaml"`
	Debug     bool   `help:"enable debug log" default:"false"`
	LogFormat string `help:"log format (text,json)" default:"text" enum:"text,json"`
}

type Config added in v0.0.5

type Config struct {
	Name      string                `json:"name" yaml:"name"`
	Comment   string                `json:"comment" yaml:"comment"`
	Function  json.RawMessage       `json:"function" yaml:"function,omitempty"`
	Runtime   types.FunctionRuntime `json:"runtime" yaml:"runtime"`
	KVS       *KeyValueStoreConfig  `json:"kvs,omitempty" yaml:"kvs,omitempty"`
	TestCases []*TestCase           `json:"testCases" yaml:"testCases"`
	// contains filtered or unexported fields
}

func LoadConfig added in v0.0.5

func LoadConfig(ctx context.Context, path string) (*Config, error)

func (*Config) FunctionCode added in v0.1.0

func (c *Config) FunctionCode(ctx context.Context) ([]byte, error)

func (*Config) ReadFile added in v0.0.7

func (c *Config) ReadFile(p string) ([]byte, error)

ReadFile reads file from the same directory as config file.

type ConfigFunction added in v0.6.0

type ConfigFunction struct {
	EventType     string   `json:"event_type" yaml:"event_type"`
	Functions     []string `json:"functions" yaml:"functions"`
	FilterCommand string   `json:"filter_command" yaml:"filter_command"`
}

func (*ConfigFunction) FunctionCode added in v0.6.0

func (c *ConfigFunction) FunctionCode(ctx context.Context, readFile func(string) ([]byte, error)) ([]byte, error)

type ContextKey added in v0.8.1

type ContextKey string

type DiffCmd added in v0.0.7

type DiffCmd struct {
	Live bool `cmd:"" help:"diff with LIVE stage"`
}

type FuncTemplateArgs added in v0.6.0

type FuncTemplateArgs struct {
	Name string
	Code string
}

type FunctionRunner added in v0.6.0

type FunctionRunner interface {
	Run(ctx context.Context, name, etag string, event []byte, logger *slog.Logger) ([]byte, error)
}

type HandlerOptions added in v0.6.0

type HandlerOptions struct {
	slog.HandlerOptions
	Color bool
}

type InitCmd added in v0.0.5

type InitCmd struct {
	Name      string `help:"function name" required:"true"`
	Format    string `help:"output config and event file format (json,jsonnet,yaml)" default:"" enum:"jsonnet,json,yaml,yml,"`
	EventType string `help:"event type (viewer-request,viewer-response)" default:"viewer-request" enum:"viewer-request,viewer-response"`
}

type KVSCmd added in v0.1.0

type KVSCmd struct {
	List   *KVSListCmd   `cmd:"" help:"list key values"`
	Get    *KVSGetCmd    `cmd:"" help:"get value of key"`
	Put    *KVSPutCmd    `cmd:"" help:"put value of key"`
	Delete *KVSDeleteCmd `cmd:"" help:"delete key"`
	Info   struct{}      `cmd:"" help:"show info of key value store"`

	Output string `short:"o" help:"output format (json, text)" default:"json" enum:"json,text"`
}

type KVSDeleteCmd added in v0.1.0

type KVSDeleteCmd struct {
	Key string `arg:"" help:"key name" required:""`
}

type KVSGetCmd added in v0.1.0

type KVSGetCmd struct {
	Key string `arg:"" help:"key name" required:""`
}

type KVSItem added in v0.1.0

type KVSItem struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

type KVSListCmd added in v0.2.0

type KVSListCmd struct {
	MaxItems int32 `short:"m" help:"max items" default:"50"`
}

type KVSPutCmd added in v0.1.0

type KVSPutCmd struct {
	Key   string `arg:"" help:"key name" required:""`
	Value string `arg:"" help:"value" required:""`
}

type KeyValueStoreConfig added in v0.1.0

type KeyValueStoreConfig struct {
	Name string `json:"name" yaml:"name"`
}

type MainTemplateArgs added in v0.6.0

type MainTemplateArgs struct {
	Imports   []string
	FuncNames []string
	FuncCodes []string
}

type ParseRequestCmd added in v0.2.0

type ParseRequestCmd struct{}

type ParseResponseCmd added in v0.2.0

type ParseResponseCmd struct{}

type PublishCmd added in v0.0.8

type PublishCmd struct {
}

type RenderCmd added in v0.2.0

type RenderCmd struct {
	Target   string `arg:"" help:"render target (function,event,expect)" default:"function" enum:"function,event,expect"`
	TestCase string `cmd:"" help:"test case name (for target event or expect)" default:""`
}

type TFCFF added in v0.5.0

type TFCFF struct {
	AWSCloudFrontFunction map[string]TFOutout `json:"aws_cloudfront_function"`
}

type TFCmd added in v0.5.0

type TFCmd struct {
	External     bool   `cmd:"" help:"output JSON for external data source"`
	Publish      *bool  `cmd:"" help:"set publish flag" default:"false"`
	ResourceName string `cmd:"" help:"resource name"`
}

type TFJSON added in v0.5.0

type TFJSON struct {
	Comment  string           `json:"//"`
	Variable map[string]TFVar `json:"variable,omitempty"`
	Resource TFCFF            `json:"resource"`
}

type TFOutout added in v0.5.0

type TFOutout struct {
	Name    string                `json:"name"`
	Code    string                `json:"code"`
	Runtime types.FunctionRuntime `json:"runtime"`
	Comment string                `json:"comment"`
	Publish *bool                 `json:"publish,omitempty"`
}

type TFVar added in v0.5.0

type TFVar struct {
	Type        string `json:"type"`
	Default     string `json:"default"`
	Description string `json:"description"`
}

type TestCase

type TestCase struct {
	Name   string            `json:"name" yaml:"name"`
	Event  string            `json:"event" yaml:"event"`
	Expect string            `json:"expect" yaml:"expect"`
	Ignore string            `json:"ignore" yaml:"ignore"`
	Env    map[string]string `json:"env" yaml:"env"`
	// contains filtered or unexported fields
}

func (*TestCase) EventBytes added in v0.2.0

func (c *TestCase) EventBytes() []byte

func (*TestCase) ExpectBytes added in v0.2.0

func (c *TestCase) ExpectBytes() []byte

func (*TestCase) Identifier added in v0.0.5

func (c *TestCase) Identifier() string

func (*TestCase) Run added in v0.6.0

func (c *TestCase) Run(ctx context.Context, output []byte, logger *slog.Logger) error

func (*TestCase) Setup added in v0.0.5

func (c *TestCase) Setup(ctx context.Context, readFile func(string) ([]byte, error)) error

type TestCmd added in v0.0.5

type TestCmd struct {
	CreateIfMissing bool   `help:"create function if missing" default:"false"`
	Run             string `help:"regexp to run test case names" default:""`
	// contains filtered or unexported fields
}

func (*TestCmd) Setup added in v0.2.0

func (cmd *TestCmd) Setup() error

func (*TestCmd) ShouldRun added in v0.2.0

func (cmd *TestCmd) ShouldRun(name string) bool

type UtilCmd added in v0.2.0

type UtilCmd struct {
	ParseRequest  ParseRequestCmd  `cmd:"" help:"parse HTTP request text from STDIN"`
	ParseResponse ParseResponseCmd `cmd:"" help:"parse HTTP response text from STDIN"`
}

type VersionCmd added in v0.0.5

type VersionCmd struct{}

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL