mirror of https://github.com/knative/func.git
Merge remote-tracking branch 'lkingland/templates' into develop
This commit is contained in:
commit
95db3bd133
|
@ -1 +1,3 @@
|
|||
/faas
|
||||
/templates/go/events/go.sum
|
||||
/templates/go/http/go.sum
|
||||
|
|
|
@ -52,7 +52,7 @@ faas
|
|||
```
|
||||
## Examples
|
||||
|
||||
Create a new Service Function:
|
||||
Create a new Function:
|
||||
|
||||
```shell
|
||||
> mkdir -p example.com/www
|
||||
|
|
|
@ -26,7 +26,7 @@ func NewBuilder(registry, namespace string) *Builder {
|
|||
}
|
||||
|
||||
// Build an image from the function source at path.
|
||||
func (n *Builder) Build(name, language, path string) (image string, err error) {
|
||||
func (n *Builder) Build(name, runtime, path string) (image string, err error) {
|
||||
// Check for the appsody binary explicitly so that we can return
|
||||
// an extra-friendly error message.
|
||||
_, err = exec.LookPath("appsody")
|
||||
|
|
|
@ -14,9 +14,9 @@ import (
|
|||
// NameMappings are short-name to repository full name mappings,
|
||||
// enabling shorthand `faas create go` rather than `faas create go-ce-functions`
|
||||
var StackShortNames = map[string]string{
|
||||
"go": "go-ce-functions",
|
||||
"js": "node-ce-functions",
|
||||
"java": "quarkus-ce-functions",
|
||||
"go": "go-ce-functions",
|
||||
"node": "node-ce-functions",
|
||||
"quarkus": "quarkus-ce-functions",
|
||||
}
|
||||
|
||||
// Initializer of functions using the appsody binary.
|
||||
|
@ -30,8 +30,8 @@ func NewInitializer() *Initializer {
|
|||
return &Initializer{}
|
||||
}
|
||||
|
||||
// Initialize a new function of the given name, of the given language, at the given path.
|
||||
func (n *Initializer) Initialize(name, language, path string) error {
|
||||
// Initialize a new function of the given name, of the given runtime, at the given path.
|
||||
func (n *Initializer) Initialize(name, runtime, path string) error {
|
||||
// Check for the appsody binary explicitly so that we can return
|
||||
// an extra-friendly error message.
|
||||
_, err := exec.LookPath("appsody")
|
||||
|
@ -49,14 +49,14 @@ func (n *Initializer) Initialize(name, language, path string) error {
|
|||
}
|
||||
|
||||
// Dereference stack short name. ex. "go" -> "go-ce-functions"
|
||||
stackName, ok := StackShortNames[language]
|
||||
stackName, ok := StackShortNames[runtime]
|
||||
if !ok {
|
||||
languages := []string{}
|
||||
runtimes := []string{}
|
||||
for k, _ := range StackShortNames {
|
||||
languages = append(languages, k)
|
||||
runtimes = append(runtimes, k)
|
||||
}
|
||||
|
||||
return errors.New(fmt.Sprintf("Unrecognized lanugage '%v'. Please choose one: %v.", language, strings.Join(languages, ", ")))
|
||||
return errors.New(fmt.Sprintf("Unrecognized runtime '%v'. Please choose one: %v.", runtime, strings.Join(runtimes, ", ")))
|
||||
}
|
||||
|
||||
// set up the command, specifying a sanitized project name and connecting
|
||||
|
|
|
@ -14,7 +14,7 @@ func TestRun(t *testing.T) {
|
|||
t.Skip()
|
||||
}
|
||||
|
||||
// Testdata Service Function
|
||||
// Testdata Function
|
||||
//
|
||||
// The directory has been pre-populated with a runnable base function by running
|
||||
// init and committing the result, such that this test is not dependent on a
|
||||
|
|
|
@ -5,10 +5,11 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/buildpacks/pack"
|
||||
"github.com/buildpacks/pack/logging"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/buildpacks/pack"
|
||||
"github.com/buildpacks/pack/logging"
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
|
@ -21,18 +22,19 @@ func NewBuilder(registry, namespace string) *Builder {
|
|||
return &Builder{registry: registry, namespace: namespace}
|
||||
}
|
||||
|
||||
var lang2pack = map[string]string{
|
||||
"java": "quay.io/boson/faas-quarkus-builder",
|
||||
"js": "quay.io/boson/faas-nodejs-builder",
|
||||
var runtime2pack = map[string]string{
|
||||
"quarkus": "quay.io/boson/faas-quarkus-builder",
|
||||
"node": "quay.io/boson/faas-nodejs-builder",
|
||||
"go": "quay.io/boson/faas-go-builder",
|
||||
}
|
||||
|
||||
func (builder *Builder) Build(name, language, path string) (image string, err error) {
|
||||
func (builder *Builder) Build(name, runtime, path string) (image string, err error) {
|
||||
|
||||
registry := fmt.Sprintf("%s/%s", builder.registry, builder.namespace)
|
||||
image = fmt.Sprintf("%s/%s", registry, name)
|
||||
packBuilder, ok := lang2pack[language]
|
||||
packBuilder, ok := runtime2pack[runtime]
|
||||
if !ok {
|
||||
err = errors.New(fmt.Sprint("unsupported language: ", language))
|
||||
err = errors.New(fmt.Sprint("unsupported runtime: ", runtime))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
45
client.go
45
client.go
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
const DefaultNamespace = "faas"
|
||||
|
||||
// Client for a given Service Function.
|
||||
// Client for a given Function.
|
||||
type Client struct {
|
||||
verbose bool // print verbose logs
|
||||
local bool // Run in local-only mode
|
||||
|
@ -17,8 +17,8 @@ type Client struct {
|
|||
initializer Initializer // Creates initial local function implementation
|
||||
builder Builder // Builds a runnable image from function source
|
||||
pusher Pusher // Pushes a built image to a registry
|
||||
deployer Deployer // Deploys a Service Function
|
||||
updater Updater // Updates a deployed Service Function
|
||||
deployer Deployer // Deploys a Function
|
||||
updater Updater // Updates a deployed Function
|
||||
runner Runner // Runs the function locally
|
||||
remover Remover // Removes remote services
|
||||
lister Lister // Lists remote services
|
||||
|
@ -28,18 +28,18 @@ type Client struct {
|
|||
progressListener ProgressListener // progress listener
|
||||
}
|
||||
|
||||
// Initializer creates the initial/stub Service Function code on first create.
|
||||
// Initializer creates the initial/stub Function code on first create.
|
||||
type Initializer interface {
|
||||
// Initialize a Service Function of the given name, using the templates for
|
||||
// the given language, written into the given path.
|
||||
Initialize(name, language, path string) error
|
||||
// Initialize a Function of the given name, template configuration `
|
||||
// (expected signature) using a context template.
|
||||
Initialize(runtime, template, path string) error
|
||||
}
|
||||
|
||||
// Builder of function source to runnable image.
|
||||
type Builder interface {
|
||||
// Build a service function of the given name with source located at path.
|
||||
// returns the image name built.
|
||||
Build(name, language, path string) (image string, err error)
|
||||
Build(name, runtime, path string) (image string, err error)
|
||||
}
|
||||
|
||||
// Pusher of function image to a registry.
|
||||
|
@ -110,13 +110,13 @@ type Describer interface {
|
|||
Describe(name string) (description FunctionDescription, err error)
|
||||
}
|
||||
|
||||
// DNSProvider exposes DNS services necessary for serving the Service Function.
|
||||
// DNSProvider exposes DNS services necessary for serving the Function.
|
||||
type DNSProvider interface {
|
||||
// Provide the given name by routing requests to address.
|
||||
Provide(name, address string)
|
||||
}
|
||||
|
||||
// New client for Service Function management.
|
||||
// New client for Function management.
|
||||
func New(options ...Option) (c *Client, err error) {
|
||||
// Instantiate client with static defaults.
|
||||
c = &Client{
|
||||
|
@ -165,7 +165,7 @@ func WithInternal(i bool) Option {
|
|||
}
|
||||
}
|
||||
|
||||
// WithInitializer provides the concrete implementation of the Service Function
|
||||
// WithInitializer provides the concrete implementation of the Function
|
||||
// initializer (generates stub code on initial create).
|
||||
func WithInitializer(i Initializer) Option {
|
||||
return func(c *Client) {
|
||||
|
@ -255,11 +255,11 @@ func WithDomainSearchLimit(limit int) Option {
|
|||
}
|
||||
}
|
||||
|
||||
// Create a service function of the given language.
|
||||
// Create a service function of the given runtime.
|
||||
// Name and Root are optional:
|
||||
// Name is derived from root if possible.
|
||||
// Root is defaulted to the current working directory.
|
||||
func (c *Client) Create(language, name, root string) (err error) {
|
||||
func (c *Client) Create(runtime, template, name, root string) (err error) {
|
||||
c.progressListener.SetTotal(5)
|
||||
c.progressListener.Increment("Initializing")
|
||||
defer c.progressListener.Done()
|
||||
|
@ -271,14 +271,19 @@ func (c *Client) Create(language, name, root string) (err error) {
|
|||
}
|
||||
|
||||
// Initialize, writing out a template implementation and a config file.
|
||||
err = f.Initialize(language, name, c.domainSearchLimit, c.initializer)
|
||||
// TODO: the function's Initialize parameters are slightly different than
|
||||
// the Initializer interface, and can thus cause confusion (one passes an
|
||||
// optional name the other passes root path). This could easily cause
|
||||
// confusion and thus we may want to rename Initalizer to the more specific
|
||||
// task it performs: ContextTemplateWriter or similar.
|
||||
err = f.Initialize(runtime, template, name, c.domainSearchLimit, c.initializer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Build the now-initialized service function
|
||||
c.progressListener.Increment("Building")
|
||||
image, err := c.builder.Build(f.name, language, f.root)
|
||||
image, err := c.builder.Build(f.name, runtime, f.root)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -338,11 +343,11 @@ func (c *Client) Update(root string) (err error) {
|
|||
|
||||
if !f.Initialized() {
|
||||
// TODO: this needs a test.
|
||||
return errors.New(fmt.Sprintf("the given path '%v' does not contain an initialized Service Function. Please create one at this path before updating.", root))
|
||||
return errors.New(fmt.Sprintf("the given path '%v' does not contain an initialized Function. Please create one at this path before updating.", root))
|
||||
}
|
||||
|
||||
// Build an image from the current state of the service function's implementation.
|
||||
image, err := c.builder.Build(f.name, f.language, f.root)
|
||||
image, err := c.builder.Build(f.name, f.runtime, f.root)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -368,7 +373,7 @@ func (c *Client) Run(root string) error {
|
|||
|
||||
if !f.Initialized() {
|
||||
// TODO: this needs a test.
|
||||
return errors.New(fmt.Sprintf("the given path '%v' does not contain an initialized Service Function. Please create one at this path in order to run.", root))
|
||||
return errors.New(fmt.Sprintf("the given path '%v' does not contain an initialized Function. Please create one at this path in order to run.", root))
|
||||
}
|
||||
|
||||
// delegate to concrete implementation of runner entirely.
|
||||
|
@ -429,14 +434,14 @@ func (c *Client) Remove(name, root string) error {
|
|||
|
||||
type noopInitializer struct{ output io.Writer }
|
||||
|
||||
func (n *noopInitializer) Initialize(name, language, root string) error {
|
||||
func (n *noopInitializer) Initialize(runtime, template, root string) error {
|
||||
fmt.Fprintln(n.output, "skipping initialize: client not initialized WithInitializer")
|
||||
return nil
|
||||
}
|
||||
|
||||
type noopBuilder struct{ output io.Writer }
|
||||
|
||||
func (n *noopBuilder) Build(name, language, path string) (image string, err error) {
|
||||
func (n *noopBuilder) Build(name, runtime, path string) (image string, err error) {
|
||||
fmt.Fprintln(n.output, "skipping build: client not initialized WithBuilder")
|
||||
return "", nil
|
||||
}
|
||||
|
|
|
@ -32,11 +32,11 @@ func TestNewWithInterferingFiles(t *testing.T) {
|
|||
// TODO
|
||||
}
|
||||
|
||||
// TestCreate ensures that creation of a supported language succeeds with all
|
||||
// TestCreate ensures that creation of a supported runtime succeeds with all
|
||||
// defaults (base case).
|
||||
func TestCreate(t *testing.T) {
|
||||
// Client with all defaults other than an initializer that verifies the
|
||||
// specified language.
|
||||
// specified runtime.
|
||||
client, err := faas.New(
|
||||
faas.WithInitializer(mock.NewInitializer()))
|
||||
if err != nil {
|
||||
|
@ -48,8 +48,8 @@ func TestCreate(t *testing.T) {
|
|||
os.MkdirAll(root, 0700)
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
// A supported langauge should not error, even when both language and name are empty.
|
||||
if err := client.Create("go", "", root); err != nil {
|
||||
// A supported langauge should not error
|
||||
if err := client.Create("go", "", "", root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -72,47 +72,47 @@ func TestCreateUnderivableName(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// create a Service Function with a missing name, but when the name is
|
||||
// create a Function with a missing name, but when the name is
|
||||
// underivable (in this case due to limited recursion, but would equally
|
||||
// apply if run from /tmp or similar)
|
||||
if err := client.Create("go", "", ""); err == nil {
|
||||
if err := client.Create("go", "", "", ""); err == nil {
|
||||
t.Fatal("did not receive expected error")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TestCreateMissingLanguage ensures that instantiation fails if the required
|
||||
// language parameter is not passed to Create.
|
||||
func TestCreateMissingLanguage(t *testing.T) {
|
||||
// TestCreateMissingRuntime ensures that instantiation fails if the required
|
||||
// runtime parameter is not passed to Create.
|
||||
func TestCreateMissingRuntime(t *testing.T) {
|
||||
client, err := faas.New(
|
||||
faas.WithInitializer(mock.NewInitializer()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// create a Service Function call missing language should error
|
||||
if err := client.Create("", "", ""); err == nil {
|
||||
t.Fatal("missing language did not generate error")
|
||||
// create a Function call missing runtime should error
|
||||
if err := client.Create("", "", "", ""); err == nil {
|
||||
t.Fatal("missing runtime did not generate error")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateUnsupportedLanguage ensures that instantiation fails if the required
|
||||
// language parameter is of an unsupported language.
|
||||
func TestCreateUnsupportedLanguage(t *testing.T) {
|
||||
// TestCreateUnsupportedRuntime ensures that instantiation fails if the required
|
||||
// runtime parameter is of an unsupported runtime.
|
||||
func TestCreateUnsupportedRuntime(t *testing.T) {
|
||||
client, err := faas.New(
|
||||
faas.WithInitializer(mock.NewInitializer())) // validtes language passed
|
||||
faas.WithInitializer(mock.NewInitializer())) // validtes runtime passed
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// create a Service Function call witn an unsupported language should bubble
|
||||
// create a Function call witn an unsupported runtime should bubble
|
||||
// the error generated by the underlying initializer.
|
||||
if err := client.Create("cobol", "", ""); err == nil {
|
||||
t.Fatal("unsupported language did not generate error")
|
||||
if err := client.Create("cobol", "", "", ""); err == nil {
|
||||
t.Fatal("unsupported runtime did not generate error")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateDelegeates ensures that a call to Create invokes the Service Function
|
||||
// TestCreateDelegeates ensures that a call to Create invokes the Function
|
||||
// Initializer, Builder, Pusher and Deployer with expected parameters.
|
||||
func TestCreateDelegates(t *testing.T) {
|
||||
var (
|
||||
|
@ -144,13 +144,13 @@ func TestCreateDelegates(t *testing.T) {
|
|||
// -------------
|
||||
|
||||
// The initializer should receive the name expected from the path,
|
||||
// the passed language, and an absolute path to the funciton soruce.
|
||||
initializer.InitializeFn = func(name, language, path string) error {
|
||||
if name != "admin.example.com" {
|
||||
t.Fatalf("initializer expected name 'admin.example.com', got '%v'", name)
|
||||
// the passed runtime, and an absolute path to the funciton soruce.
|
||||
initializer.InitializeFn = func(runtime, context, path string) error {
|
||||
if runtime != "go" {
|
||||
t.Fatalf("initializer expected runtime 'go', got '%v'", runtime)
|
||||
}
|
||||
if language != "go" {
|
||||
t.Fatalf("initializer expected language 'go', got '%v'", language)
|
||||
if context != "" {
|
||||
t.Fatalf("initializer expected empty context template name, got '%v'", name)
|
||||
}
|
||||
expectedPath, err := filepath.Abs("./testdata/example.com/admin")
|
||||
if err != nil {
|
||||
|
@ -210,7 +210,7 @@ func TestCreateDelegates(t *testing.T) {
|
|||
|
||||
// Invoke the creation, triggering the function delegates, and
|
||||
// perform follow-up assertions that the functions were indeed invoked.
|
||||
if err := client.Create("go", "", root); err != nil {
|
||||
if err := client.Create("go", "", "", root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -261,8 +261,8 @@ func TestCreateLocal(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create a new Service Function
|
||||
if err := client.Create("go", "", root); err != nil {
|
||||
// Create a new Function
|
||||
if err := client.Create("go", "", "", root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Ensure that none of the remote delegates were invoked
|
||||
|
@ -304,7 +304,7 @@ func TestCreateDomain(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := client.Create("go", "", root); err != nil {
|
||||
if err := client.Create("go", "", "", root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !dnsProvider.ProvideInvoked {
|
||||
|
@ -332,7 +332,7 @@ func TestCreateSubdomain(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := client.Create("go", "", root); err != nil {
|
||||
if err := client.Create("go", "", "", root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !dnsProvider.ProvideInvoked {
|
||||
|
@ -539,18 +539,18 @@ func TestRemoveDefaultCurrent(t *testing.T) {
|
|||
}
|
||||
|
||||
// TestWithName ensures that an explicitly passed name is used in leau of the
|
||||
// path derived name when provide, and persists through instantiations.
|
||||
// path derived name when provided, and persists through instantiations.
|
||||
// This also ensures that an initialized service function's name persists if
|
||||
// the path is changed after creation.
|
||||
func TestWithName(t *testing.T) {
|
||||
// Explicit name to use
|
||||
name := "service.example.com"
|
||||
|
||||
// Root which would derive to service.groupA.example.com were it not for the
|
||||
// Path which would derive to service.groupA.example.com were it not for the
|
||||
// explicitly provided name.
|
||||
root := "testdata/example.com/groupA/service"
|
||||
os.MkdirAll(root, 0700)
|
||||
defer os.RemoveAll(root)
|
||||
path := "testdata/example.com/groupA/service"
|
||||
os.MkdirAll(path, 0700)
|
||||
defer os.RemoveAll(path)
|
||||
|
||||
initializer := mock.NewInitializer()
|
||||
c, err := faas.New(
|
||||
|
@ -559,20 +559,28 @@ func TestWithName(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Ensure that initializing receives the specified name.
|
||||
initializer.InitializeFn = func(name2, language, path string) error {
|
||||
if name2 != name {
|
||||
t.Fatalf("initializer expected name '%v', got '%v'", name, name2)
|
||||
// Ensure that initializing receives the specified path.
|
||||
initializer.InitializeFn = func(runtime, context, path2 string) error {
|
||||
expectedPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if path2 != expectedPath {
|
||||
t.Fatalf("initializer expected path '%v', got '%v'", expectedPath, path2)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create the service with the explict name at the non-matching root.
|
||||
if err := c.Create("go", name, root); err != nil {
|
||||
// Create the service with the explict name at the non-matching path.
|
||||
if err := c.Create("go", "", name, path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create new client to test updating.
|
||||
// TODO: create a Function about the path and check the name is loaded.
|
||||
|
||||
// Create a new client about the now initialized path and test that
|
||||
// the explicitly-provided name is sent to the updater, proving that
|
||||
// it was
|
||||
updater := mock.NewUpdater()
|
||||
c, err = faas.New(
|
||||
faas.WithUpdater(updater))
|
||||
|
@ -589,7 +597,7 @@ func TestWithName(t *testing.T) {
|
|||
}
|
||||
|
||||
// Invoke update
|
||||
if err := c.Update(root); err != nil {
|
||||
if err := c.Update(path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,9 @@ package cmd
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -27,7 +28,7 @@ For bash:
|
|||
source <(faas completion bash)
|
||||
|
||||
`,
|
||||
ValidArgs: []string{"bash", "zsh"},
|
||||
ValidArgs: []string{"bash", "zsh"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
if len(args) < 1 {
|
||||
|
@ -57,13 +58,13 @@ function _faas {
|
|||
cmnds)
|
||||
commands=(
|
||||
"completion:Generates bash/zsh completion scripts"
|
||||
"create:Create a Service Function"
|
||||
"delete:Delete deployed Service Function"
|
||||
"describe:Describe Service Function"
|
||||
"create:Create a Function"
|
||||
"delete:Delete deployed Function"
|
||||
"describe:Describe Function"
|
||||
"help:Help about any command"
|
||||
"list:Lists deployed Service Functions"
|
||||
"run:Run Service Function locally"
|
||||
"update:Update or create a deployed Service Function"
|
||||
"list:Lists deployed Functions"
|
||||
"run:Run Function locally"
|
||||
"update:Update or create a deployed Function"
|
||||
"version:Print version"
|
||||
)
|
||||
_describe "command" commands
|
||||
|
@ -106,7 +107,7 @@ function _list_funs() {
|
|||
}
|
||||
|
||||
function _list_langs() {
|
||||
compadd js go java
|
||||
compadd node go quarkus
|
||||
}
|
||||
|
||||
function _list_fmts() {
|
||||
|
@ -194,4 +195,4 @@ function _faas_version {
|
|||
}
|
||||
return errors.New("unknown shell, only bash and zsh are supported")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,14 @@ package cmd
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"os/user"
|
||||
"path"
|
||||
|
||||
"github.com/boson-project/faas"
|
||||
"github.com/boson-project/faas/appsody"
|
||||
"github.com/boson-project/faas/knative"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
"os/user"
|
||||
"path"
|
||||
)
|
||||
|
||||
func CompleteFunctionList(cmd *cobra.Command, args []string, toComplete string) (strings []string, directive cobra.ShellCompDirective) {
|
||||
|
@ -26,7 +27,7 @@ func CompleteFunctionList(cmd *cobra.Command, args []string, toComplete string)
|
|||
directive = cobra.ShellCompDirectiveDefault
|
||||
return
|
||||
}
|
||||
func CompleteLanguageList(cmd *cobra.Command, args []string, toComplete string) (strings []string, directive cobra.ShellCompDirective) {
|
||||
func CompleteRuntimeList(cmd *cobra.Command, args []string, toComplete string) (strings []string, directive cobra.ShellCompDirective) {
|
||||
strings = make([]string, 0, len(appsody.StackShortNames))
|
||||
for lang, _ := range appsody.StackShortNames {
|
||||
strings = append(strings, lang)
|
||||
|
@ -66,4 +67,4 @@ func CompleteRegistryList(cmd *cobra.Command, args []string, toComplete string)
|
|||
}
|
||||
directive = cobra.ShellCompDirectiveDefault
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,19 @@ package cmd
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/boson-project/faas/buildpacks"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/ory/viper"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/boson-project/faas"
|
||||
"github.com/boson-project/faas/appsody"
|
||||
"github.com/boson-project/faas/buildpacks"
|
||||
"github.com/boson-project/faas/docker"
|
||||
"github.com/boson-project/faas/embedded"
|
||||
"github.com/boson-project/faas/kubectl"
|
||||
"github.com/boson-project/faas/progress"
|
||||
"github.com/boson-project/faas/prompt"
|
||||
|
@ -24,25 +28,29 @@ func init() {
|
|||
createCmd.Flags().StringP("name", "n", "", "optionally specify an explicit name for the serive, overriding path-derivation. $FAAS_NAME")
|
||||
createCmd.Flags().StringP("registry", "r", "quay.io", "image registry (ex: quay.io). $FAAS_REGISTRY")
|
||||
createCmd.Flags().StringP("namespace", "s", "", "namespace at image registry (usually username or org name). $FAAS_NAMESPACE")
|
||||
createCmd.Flags().StringP("template", "t", embedded.DefaultTemplate, "Function template (ex: 'http','events'). $FAAS_TEMPLATE")
|
||||
createCmd.Flags().StringP("templates", "", filepath.Join(configPath(), "faas", "templates"), "Extensible templates path. $FAAS_TEMPLATES")
|
||||
createCmd.RegisterFlagCompletionFunc("registry", CompleteRegistryList)
|
||||
}
|
||||
|
||||
// The create command invokes the Service Funciton Client to create a new,
|
||||
// The create command invokes the Funciton Client to create a new,
|
||||
// functional, deployed service function with a noop implementation. It
|
||||
// can be optionally created only locally (no deploy) using --local.
|
||||
var createCmd = &cobra.Command{
|
||||
Use: "create <language>",
|
||||
Short: "Create a Service Function",
|
||||
SuggestFor: []string{"init", "new"},
|
||||
ValidArgsFunction: CompleteLanguageList,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: create,
|
||||
Use: "create <runtime>",
|
||||
Short: "Create a Function",
|
||||
SuggestFor: []string{"init", "new"},
|
||||
ValidArgsFunction: CompleteRuntimeList,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: create,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
viper.BindPFlag("local", cmd.Flags().Lookup("local"))
|
||||
viper.BindPFlag("internal", cmd.Flags().Lookup("internal"))
|
||||
viper.BindPFlag("name", cmd.Flags().Lookup("name"))
|
||||
viper.BindPFlag("registry", cmd.Flags().Lookup("registry"))
|
||||
viper.BindPFlag("namespace", cmd.Flags().Lookup("namespace"))
|
||||
viper.BindPFlag("template", cmd.Flags().Lookup("template"))
|
||||
viper.BindPFlag("templates", cmd.Flags().Lookup("templates"))
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -73,9 +81,21 @@ type createConfig struct {
|
|||
// images will be stored by their canonical name.
|
||||
Namespace string
|
||||
|
||||
// Language is the first argument, and specifies the resultant Function
|
||||
// implementation language.
|
||||
Language string
|
||||
// Template is the form of the resultant function, i.e. the function signature
|
||||
// and contextually avaialable resources. For example 'http' for a funciton
|
||||
// expected to be invoked via straight HTTP requests, or 'events' for a
|
||||
// function which will be invoked with CloudEvents.
|
||||
Template string
|
||||
|
||||
// Templates is an optional path that, if it exists, will be used as a source
|
||||
// for additional templates not included in the binary. If not provided
|
||||
// explicitly as a flag (--templates) or env (FAAS_TEMPLATES), the default
|
||||
// location is $XDG_CONFIG_HOME/templates ($HOME/.config/faas/templates)
|
||||
Templates string
|
||||
|
||||
// Runtime is the first argument, and specifies the resultant Function
|
||||
// implementation runtime.
|
||||
Runtime string
|
||||
|
||||
// Path of the Function implementation on local disk. Defaults to current
|
||||
// working directory of the process.
|
||||
|
@ -84,9 +104,9 @@ type createConfig struct {
|
|||
|
||||
// create a new service function using the client about config.
|
||||
func create(cmd *cobra.Command, args []string) (err error) {
|
||||
// Assert a language parameter was provided
|
||||
// Assert a runtime parameter was provided
|
||||
if len(args) == 0 {
|
||||
return errors.New("'faas create' requires a language argument.")
|
||||
return errors.New("'faas create' requires a runtime argument.")
|
||||
}
|
||||
|
||||
// Create a deafult configuration populated first with environment variables,
|
||||
|
@ -98,8 +118,10 @@ func create(cmd *cobra.Command, args []string) (err error) {
|
|||
Name: viper.GetString("name"),
|
||||
Registry: viper.GetString("registry"),
|
||||
Namespace: viper.GetString("namespace"),
|
||||
Language: args[0],
|
||||
Path: ".", // will be expanded to process current working dir.
|
||||
Template: viper.GetString("template"), // to use
|
||||
Templates: viper.GetString("templates"), // extendex repos
|
||||
Runtime: args[0],
|
||||
Path: ".", // will be expanded to current working dir.
|
||||
}
|
||||
|
||||
// If path is provided
|
||||
|
@ -121,9 +143,11 @@ func create(cmd *cobra.Command, args []string) (err error) {
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
// Initializer creates a deployable noop function implementation in the
|
||||
// configured path.
|
||||
initializer := appsody.NewInitializer()
|
||||
initializer := embedded.NewInitializer(config.Templates)
|
||||
initializer.Verbose = config.Verbose
|
||||
|
||||
// Builder creates images from function source.
|
||||
|
@ -157,11 +181,11 @@ func create(cmd *cobra.Command, args []string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// Invoke the creation of the new Service Function locally.
|
||||
// Invoke the creation of the new Function locally.
|
||||
// Returns the final address.
|
||||
// Name can be empty string (path-dervation will be attempted)
|
||||
// Path can be empty, defaulting to current working directory.
|
||||
return client.Create(config.Language, config.Name, config.Path)
|
||||
return client.Create(config.Runtime, config.Template, config.Name, config.Path)
|
||||
}
|
||||
|
||||
func gatherFromUser(config createConfig) (c createConfig, err error) {
|
||||
|
@ -174,11 +198,12 @@ func gatherFromUser(config createConfig) (c createConfig, err error) {
|
|||
config.Internal = prompt.ForBool("Internal; no public route", config.Internal)
|
||||
config.Registry = prompt.ForString("Image registry", config.Registry)
|
||||
config.Namespace = prompt.ForString("Namespace at registry", config.Namespace)
|
||||
config.Language = prompt.ForString("Language of source", config.Language)
|
||||
config.Runtime = prompt.ForString("Runtime of source", config.Runtime)
|
||||
config.Template = prompt.ForString("Function Template", config.Template)
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// Prompting for Service Name with Default
|
||||
// Prompting for Name with Default
|
||||
// Early calclation of service function name is required to provide a sensible
|
||||
// default. If the user did not provide a --name parameter or FAAS_NAME,
|
||||
// this funciton sets the default to the value that the client would have done
|
||||
|
@ -205,3 +230,15 @@ var confirmExp = regexp.MustCompile("(?i)y(?:es)?|1")
|
|||
func fromYN(s string) bool {
|
||||
return confirmExp.MatchString(s)
|
||||
}
|
||||
|
||||
func configPath() (path string) {
|
||||
if path = os.Getenv("XDG_CONFIG_HOME"); path != "" {
|
||||
return
|
||||
}
|
||||
|
||||
path, err := homedir.Expand("~/.config")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "could not derive home directory for use as default templates path: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ func init() {
|
|||
|
||||
var deleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "Delete deployed Service Function",
|
||||
Long: `Removes the deployed Service Function for the current directory, but does not delete anything locally. If no code updates have been made beyond the defaults, this would bring the current codebase back to a state equivalent to having run "create --local".`,
|
||||
Short: "Delete deployed Function",
|
||||
Long: `Removes the deployed Function for the current directory, but does not delete anything locally. If no code updates have been made beyond the defaults, this would bring the current codebase back to a state equivalent to having run "create --local".`,
|
||||
SuggestFor: []string{"remove", "rm"},
|
||||
RunE: delete,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
|
|
|
@ -27,13 +27,13 @@ func init() {
|
|||
}
|
||||
|
||||
var describeCmd = &cobra.Command{
|
||||
Use: "describe",
|
||||
Short: "Describe Service Function",
|
||||
Long: `Describe Service Function`,
|
||||
SuggestFor: []string{"desc"},
|
||||
Use: "describe",
|
||||
Short: "Describe Function",
|
||||
Long: `Describe Function`,
|
||||
SuggestFor: []string{"desc"},
|
||||
ValidArgsFunction: CompleteFunctionList,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: describe,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: describe,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
viper.BindPFlag("output", cmd.Flags().Lookup("output"))
|
||||
viper.BindPFlag("name", cmd.Flags().Lookup("name"))
|
||||
|
|
|
@ -15,8 +15,8 @@ func init() {
|
|||
|
||||
var listCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "Lists deployed Service Functions",
|
||||
Long: `Lists deployed Service Functions`,
|
||||
Short: "Lists deployed Functions",
|
||||
Long: `Lists deployed Functions`,
|
||||
SuggestFor: []string{"ls"},
|
||||
RunE: list,
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ var root = &cobra.Command{
|
|||
SilenceUsage: true, // no usage dump on error
|
||||
Long: `Function as a Service
|
||||
|
||||
Manage your Service Functions.`,
|
||||
Create and run Functions as a Service.`,
|
||||
}
|
||||
|
||||
// When the code is loaded into memory upon invocation, the cobra/viper packages
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package cmd_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/boson-project/faas/cmd"
|
||||
)
|
||||
|
||||
// TestNewRoot ensures that NewRoot returns a non-nil command with at least a name that
|
||||
// prints help (has no run statement).
|
||||
func TestRootCommand(t *testing.T) {
|
||||
root := cmd.NewRoot("")
|
||||
|
||||
if root == nil {
|
||||
t.Fatal("returned a nil command")
|
||||
}
|
||||
if root.Name() == "" {
|
||||
t.Fatal("root command's name was not set")
|
||||
}
|
||||
if root.Run != nil || root.RunE != nil {
|
||||
t.Fatal("root command should print usage, but has a run function set")
|
||||
}
|
||||
}
|
||||
|
||||
// TestVersion ensures that the root command sets the passed version.
|
||||
func TestVersion(t *testing.T) {
|
||||
v := "v0.0.0"
|
||||
root := cmd.NewRoot(v)
|
||||
if root.Version != v {
|
||||
t.Fatalf("expected root command to have version '%v', got '%v'", v, root.Version)
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ func init() {
|
|||
|
||||
var runCmd = &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "Run Service Function locally",
|
||||
Short: "Run Function locally",
|
||||
Long: "Runs the function locally within an isolated environment. Modifications to the function trigger a reload. This holds open the current window with the logs from the running function, and the run is canceled on interrupt.",
|
||||
RunE: run,
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@ package cmd
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/boson-project/faas/buildpacks"
|
||||
"github.com/boson-project/faas/knative"
|
||||
|
||||
"github.com/ory/viper"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/boson-project/faas"
|
||||
"github.com/boson-project/faas/buildpacks"
|
||||
"github.com/boson-project/faas/docker"
|
||||
"github.com/boson-project/faas/knative"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -22,7 +22,7 @@ func init() {
|
|||
|
||||
var updateCmd = &cobra.Command{
|
||||
Use: "update",
|
||||
Short: "Update or create a deployed Service Function",
|
||||
Short: "Update or create a deployed Function",
|
||||
Long: `Update deployed function to match the current local state.`,
|
||||
SuggestFor: []string{"push", "deploy"},
|
||||
RunE: update,
|
||||
|
@ -58,7 +58,7 @@ func update(cmd *cobra.Command, args []string) (err error) {
|
|||
pusher.Verbose = verbose
|
||||
|
||||
// Deployer of built images.
|
||||
updater,err := knative.NewUpdater(faas.DefaultNamespace)
|
||||
updater, err := knative.NewUpdater(faas.DefaultNamespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't create updater: %v", err)
|
||||
}
|
||||
|
|
10
config.go
10
config.go
|
@ -20,8 +20,8 @@ type Config struct {
|
|||
// not over the Option WithName, if provided.
|
||||
Name string `yaml:"name"`
|
||||
|
||||
// Language of the implementation.
|
||||
Language string `yaml:"language"`
|
||||
// Runtime of the implementation.
|
||||
Runtime string `yaml:"runtime"`
|
||||
|
||||
// Add new values to the applyConfig function as necessary.
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ type Config struct {
|
|||
// post-instantiation.
|
||||
func newConfig(f *Function) Config {
|
||||
return Config{
|
||||
Name: f.name,
|
||||
Language: f.language,
|
||||
Name: f.name,
|
||||
Runtime: f.runtime,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ func applyConfig(f *Function, root string) error {
|
|||
// Apply the config to the client object, which effectiely writes back the default
|
||||
// if it was not defined in the yaml.
|
||||
f.name = cfg.Name
|
||||
f.language = cfg.Language
|
||||
f.runtime = cfg.Runtime
|
||||
|
||||
// NOTE: cleverness < clarity
|
||||
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
package embedded
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/markbates/pkger"
|
||||
)
|
||||
|
||||
// Updating Templates:
|
||||
// See documentation in faas/templates for instructions on including template
|
||||
// updates in the binary for access by pkger.
|
||||
|
||||
// DefautlTemplate is the default function signature / environmental context
|
||||
// of the resultant template. All runtimes are expected to have at least
|
||||
// an HTTP Handler ("http") and Cloud Events ("events")
|
||||
const DefaultTemplate = "events"
|
||||
|
||||
// FileAccessor encapsulates methods for accessing template files.
|
||||
type FileAccessor interface {
|
||||
Stat(name string) (os.FileInfo, error)
|
||||
Open(p string) (file, error)
|
||||
}
|
||||
|
||||
type file interface {
|
||||
Readdir(int) ([]os.FileInfo, error)
|
||||
Read([]byte) (int, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
// When pkger is run, code analysis detects this Include statement,
|
||||
// triggering the serializaation of the templates directory and all
|
||||
// its contents into pkged.go, which is then made available via
|
||||
// a pkger FileAccessor.
|
||||
// Path is relative to the go module root.
|
||||
func init() {
|
||||
pkger.Include("/templates")
|
||||
}
|
||||
|
||||
type Initializer struct {
|
||||
Verbose bool
|
||||
templates string
|
||||
}
|
||||
|
||||
// NewInitializer with an optional path to extended repositories directory
|
||||
// (by default only internally embedded templates are used)
|
||||
func NewInitializer(templates string) *Initializer {
|
||||
return &Initializer{templates: templates}
|
||||
}
|
||||
|
||||
func (n *Initializer) Initialize(runtime, template string, dest string) error {
|
||||
if template == "" {
|
||||
template = DefaultTemplate
|
||||
}
|
||||
|
||||
// TODO: Confirm the dest path is empty? This is currently in an earlier
|
||||
// step of the create process but future calls directly to initialize would
|
||||
// be better off being made safe.
|
||||
|
||||
if isEmbedded(runtime, template) {
|
||||
return copyEmbedded(runtime, template, dest)
|
||||
}
|
||||
if n.templates != "" {
|
||||
return copyFilesystem(n.templates, runtime, template, dest)
|
||||
}
|
||||
return errors.New(fmt.Sprintf("A template for runtime '%v' template '%v' was not found internally and no extended repository path was defined.", runtime, template))
|
||||
}
|
||||
|
||||
func copyEmbedded(runtime, template, dest string) error {
|
||||
// Copy files to the destination
|
||||
// Example embedded path:
|
||||
// /templates/go/http
|
||||
src := filepath.Join("/templates", runtime, template)
|
||||
return copy(src, dest, embeddedAccessor{})
|
||||
}
|
||||
|
||||
func copyFilesystem(templatesPath, runtime, templateFullName, dest string) error {
|
||||
// ensure that the templateFullName is of the format "repoName/templateName"
|
||||
cc := strings.Split(templateFullName, "/")
|
||||
if len(cc) != 2 {
|
||||
return errors.New("Template name must be in the format 'REPO/NAME'")
|
||||
}
|
||||
repo := cc[0]
|
||||
template := cc[1]
|
||||
|
||||
// Example FileSystem path:
|
||||
// /home/alice/.config/faas/templates/boson-experimental/go/json
|
||||
src := filepath.Join(templatesPath, repo, runtime, template)
|
||||
return copy(src, dest, filesystemAccessor{})
|
||||
}
|
||||
|
||||
func isEmbedded(runtime, template string) bool {
|
||||
_, err := pkger.Stat(filepath.Join("/templates", runtime, template))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
type embeddedAccessor struct{}
|
||||
|
||||
func (a embeddedAccessor) Stat(path string) (os.FileInfo, error) {
|
||||
return pkger.Stat(path)
|
||||
}
|
||||
|
||||
func (a embeddedAccessor) Open(path string) (file, error) {
|
||||
return pkger.Open(path)
|
||||
}
|
||||
|
||||
type filesystemAccessor struct{}
|
||||
|
||||
func (a filesystemAccessor) Stat(path string) (os.FileInfo, error) {
|
||||
return os.Stat(path)
|
||||
}
|
||||
|
||||
func (a filesystemAccessor) Open(path string) (file, error) {
|
||||
return os.Open(path)
|
||||
}
|
||||
|
||||
func copy(src, dest string, accessor FileAccessor) (err error) {
|
||||
node, err := accessor.Stat(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if node.IsDir() {
|
||||
return copyNode(src, dest, accessor)
|
||||
} else {
|
||||
return copyLeaf(src, dest, accessor)
|
||||
}
|
||||
}
|
||||
|
||||
func copyNode(src, dest string, accessor FileAccessor) (err error) {
|
||||
node, err := accessor.Stat(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = os.MkdirAll(dest, node.Mode())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
children, err := ReadDir(src, accessor)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, child := range children {
|
||||
if err = copy(filepath.Join(src, child.Name()), filepath.Join(dest, child.Name()), accessor); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ReadDir(src string, accessor FileAccessor) ([]os.FileInfo, error) {
|
||||
f, err := accessor.Open(src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list, err := f.Readdir(-1)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func copyLeaf(src, dest string, accessor FileAccessor) (err error) {
|
||||
srcFile, err := accessor.Open(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
srcFileInfo, err := accessor.Stat(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
destFile, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcFileInfo.Mode())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
_, err = io.Copy(destFile, srcFile)
|
||||
return
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package embedded
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestInitialize ensures that on initialization of a the reference runtime
|
||||
// (Go), the template is written.
|
||||
func TestInitialize(t *testing.T) {
|
||||
var (
|
||||
path = "testdata/example.com/www"
|
||||
testFile = "handle.go"
|
||||
template = "http"
|
||||
)
|
||||
os.MkdirAll(path, 0744)
|
||||
defer os.RemoveAll(path)
|
||||
|
||||
err := NewInitializer("").Initialize("go", template, path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test that the directory is not empty
|
||||
if _, err := os.Stat(filepath.Join(path, testFile)); os.IsNotExist(err) {
|
||||
t.Fatalf("Initialize did not result in '%v' being written to '%v'", testFile, path)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDefaultTemplate ensures that if no template is provided, files are still written.
|
||||
func TestDefaultTemplate(t *testing.T) {
|
||||
var (
|
||||
path = "testdata/example.com/www"
|
||||
testFile = "handle.go"
|
||||
template = ""
|
||||
)
|
||||
os.MkdirAll(path, 0744)
|
||||
defer os.RemoveAll(path)
|
||||
|
||||
err := NewInitializer("").Initialize("go", template, path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(filepath.Join(path, testFile)); os.IsNotExist(err) {
|
||||
t.Fatalf("Initializing without providing a template did not result in '%v' being written to '%v'", testFile, path)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCustom ensures that a custom repository can be used as a template.
|
||||
// Custom repository location is not defined herein but expected to be
|
||||
// provided because, for example, a CLI may want to use XDG_CONFIG_HOME.
|
||||
// Assuming a repository path $FAAS_TEMPLATES, a Go template named 'json'
|
||||
// which is provided in the repository repository 'boson-experimental',
|
||||
// would be expected to be in the location:
|
||||
// $FAAS_TEMPLATES/boson-experimental/go/json
|
||||
// See the CLI for full details, but a standard default location is
|
||||
// $HOME/.config/templates/boson-experimental/go/json
|
||||
func TestCustom(t *testing.T) {
|
||||
var (
|
||||
path = "testdata/example.com/www"
|
||||
testFile = "handle.go"
|
||||
template = "boson-experimental/json"
|
||||
// repos = "testdata/templates"
|
||||
)
|
||||
os.MkdirAll(path, 0744)
|
||||
defer os.RemoveAll(path)
|
||||
|
||||
// Unrecognized runtime/template should error
|
||||
err := NewInitializer("").Initialize("go", template, path)
|
||||
if err == nil {
|
||||
t.Fatal("An unrecognized runtime/template should generate an error")
|
||||
}
|
||||
|
||||
// Recognized external (non-embedded) path should succeed
|
||||
err = NewInitializer("testdata/templates").Initialize("go", template, path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The template should have been written to the given path.
|
||||
if _, err := os.Stat(filepath.Join(path, testFile)); os.IsNotExist(err) {
|
||||
t.Fatalf("Initializing a custom did not result in the expected '%v' being written to '%v'", testFile, path)
|
||||
} else if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestEmbeddedFileMode ensures that files from the embedded templates are
|
||||
// written with the same mode from whence they came
|
||||
func TestEmbeddedFileMode(t *testing.T) {
|
||||
var path = "testdata/example.com/www"
|
||||
os.MkdirAll(path, 0744)
|
||||
defer os.RemoveAll(path)
|
||||
|
||||
// Initialize a quarkus app from the embedded templates.
|
||||
if err := NewInitializer("").Initialize("quarkus", "events", path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The file mode of the embedded mvnw should be -rwxr-xr-x
|
||||
// See source file at: templates/quarkus/events/mvnw
|
||||
// Assert mode is preserved
|
||||
sourceMode := os.FileMode(0755)
|
||||
dest, err := os.Stat(filepath.Join(path, "mvnw"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if dest.Mode() != sourceMode {
|
||||
t.Fatalf("The dest mode should be %v but was %v", sourceMode, dest.Mode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestCustomFileMode ensures that files from a file-system derived repository
|
||||
// of templates are written with the same mode from whence they came
|
||||
func TestFileMode(t *testing.T) {
|
||||
var (
|
||||
path = "testdata/example.com/www"
|
||||
template = "boson-experimental/http"
|
||||
)
|
||||
os.MkdirAll(path, 0744)
|
||||
defer os.RemoveAll(path)
|
||||
|
||||
// Initialize a quarkus app from the custom repo in ./testdata
|
||||
if err := NewInitializer("testdata/templates").Initialize("quarkus", template, path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Assert mode is preserved
|
||||
source, err := os.Stat(filepath.Join("testdata/templates/boson-experimental/quarkus/http/mvnw"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dest, err := os.Stat(filepath.Join(path, "mvnw"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if dest.Mode() != source.Mode() {
|
||||
t.Fatalf("The dest mode should be %v but was %v", source.Mode(), dest.Mode())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,305 @@
|
|||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar"
|
||||
else
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar"
|
||||
fi
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if $cygwin; then
|
||||
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
else
|
||||
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||
else
|
||||
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||
fi
|
||||
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaClass=`cygpath --path --windows "$javaClass"`
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
fi
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
24
function.go
24
function.go
|
@ -12,9 +12,9 @@ import (
|
|||
)
|
||||
|
||||
type Function struct {
|
||||
root string
|
||||
language string // will be empty unless initialized/until initialized
|
||||
name string // will be empty unless initialized/until initialized.
|
||||
root string
|
||||
runtime string // will be empty unless initialized/until initialized
|
||||
name string // will be empty unless initialized/until initialized.
|
||||
|
||||
initializer Initializer
|
||||
}
|
||||
|
@ -43,10 +43,10 @@ func (f *Function) DerivedName(searchLimit int) string {
|
|||
return pathToDomain(f.root, searchLimit)
|
||||
}
|
||||
|
||||
func (f *Function) Initialize(language, name string, domainSearchLimit int, initializer Initializer) (err error) {
|
||||
// Assert language is provided
|
||||
if language == "" {
|
||||
err = errors.New("language not specified")
|
||||
func (f *Function) Initialize(runtime, context, name string, domainSearchLimit int, initializer Initializer) (err error) {
|
||||
// Assert runtime is provided
|
||||
if runtime == "" {
|
||||
err = errors.New("runtime not specified")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -77,12 +77,12 @@ func (f *Function) Initialize(language, name string, domainSearchLimit int, init
|
|||
}
|
||||
f.name = name
|
||||
|
||||
// Write the template implementation in the appropriate language
|
||||
if err = initializer.Initialize(name, language, f.root); err != nil {
|
||||
// Write the template implementation in the appropriate runtime
|
||||
if err = initializer.Initialize(runtime, context, f.root); err != nil {
|
||||
return
|
||||
}
|
||||
// language was validated
|
||||
f.language = language
|
||||
// runtime was validated
|
||||
f.runtime = runtime
|
||||
|
||||
// Write out the state as a config file and return.
|
||||
return writeConfig(f)
|
||||
|
@ -91,7 +91,7 @@ func (f *Function) Initialize(language, name string, domainSearchLimit int, init
|
|||
func (f *Function) Initialized() bool {
|
||||
// TODO: this should probably be more robust than checking what amounts to a
|
||||
// side-effect of the initialization process.
|
||||
return (f.language != "" && f.name != "")
|
||||
return (f.runtime != "" && f.name != "")
|
||||
}
|
||||
|
||||
// contentiousFiles are files which, if extant, preclude the creation of a
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
)
|
||||
|
||||
// TestPathToDomain validatest the calculation used to derive a default domain
|
||||
// for a Service Function from the current directory path (used as a default
|
||||
// for a Function from the current directory path (used as a default
|
||||
// in the absence of an explicit setting).
|
||||
// NOTE: although the implementation uses os.PathSeparator and is developed with
|
||||
// non-unix platforms in mind, these tests are written using unix-style paths.
|
||||
|
|
3
go.mod
3
go.mod
|
@ -9,7 +9,8 @@ require (
|
|||
github.com/buildpacks/pack v0.11.0
|
||||
github.com/golang/mock v1.4.3 // indirect
|
||||
github.com/google/go-containerregistry v0.0.0-20200423114255-8f808463544c // indirect
|
||||
github.com/onsi/gomega v1.10.1 // indirect
|
||||
github.com/markbates/pkger v0.17.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/openzipkin/zipkin-go v0.2.2 // indirect
|
||||
github.com/ory/viper v1.7.4
|
||||
github.com/robfig/cron v1.2.0 // indirect
|
||||
|
|
72
go.sum
72
go.sum
|
@ -1,7 +1,6 @@
|
|||
bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
|
@ -172,7 +171,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
|
|||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
|
@ -203,26 +201,24 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp
|
|||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI=
|
||||
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
||||
|
@ -230,24 +226,15 @@ github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
|||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
|
@ -293,7 +280,6 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
|
|||
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
|
||||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
|
@ -337,12 +323,10 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3
|
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
|
@ -354,6 +338,8 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN
|
|||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/markbates/pkger v0.17.0 h1:RFfyBPufP2V6cddUyyEVSHBpaAnM1WzaMNyqomeT+iY=
|
||||
github.com/markbates/pkger v0.17.0/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
|
@ -372,7 +358,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
|
|||
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e h1:Qa6dnn8DlasdXRnacluu8HzPts0S1I9zvvUPDbBnXFI=
|
||||
github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e/go.mod h1:waEya8ee1Ro/lgxpVhkJI4BVASzkm3UZqkx/cFJiYHM=
|
||||
|
@ -393,28 +378,21 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
|
|||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34=
|
||||
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
|
@ -436,10 +414,8 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181
|
|||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@ -454,7 +430,6 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf
|
|||
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
|
@ -466,7 +441,6 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
|
|||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
|
@ -496,7 +470,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
|||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
|
||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||
|
@ -507,7 +480,6 @@ github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4S
|
|||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
|
@ -524,8 +496,6 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6
|
|||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
|
@ -536,12 +506,10 @@ github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jW
|
|||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
|
@ -571,7 +539,6 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:
|
|||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.1 h1:8dP3SGL7MPB94crU3bEPplMPe83FI4EouesJUeFHv50=
|
||||
|
@ -646,7 +613,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
|
@ -654,7 +620,6 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
|
|||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
|
@ -684,12 +649,10 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -704,7 +667,6 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -734,7 +696,6 @@ golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17 h1:a/Fd23DJvg1CaeDH0dYHahE+hCI0v9rFgxSNIThoUcM=
|
||||
golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -745,7 +706,6 @@ gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3m
|
|||
gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
|
||||
google.golang.org/api v0.4.0 h1:KKgc1aqhV8wDPbDzlDtpvyjZFY3vjz85FP7p4wcQUyI=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
|
@ -753,17 +713,14 @@ google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn
|
|||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.10.0 h1:7tmAxx3oKE98VMZ+SBZzvYYWRQ9HODBxmC8mXUsraSQ=
|
||||
google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.2 h1:j8RI1yW0SkI+paT6uGwMlrMI/6zwYA6/CFil8rxOzGI=
|
||||
google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7 h1:ZUjXAXmrAyrmmCPHgCA/vChHcpsX27MZ3yBonD/z1KE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
@ -771,7 +728,6 @@ google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRn
|
|||
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51 h1:Ex1mq5jaJof+kRnYi3SlYJ8KKa9Ao3NHyIT5XJ1gF6U=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20200313141609-30c55424f95d h1:pyQjO6BnPvrPMldYxgDlXq9PLahtc0EKnUTYX1pWwXU=
|
||||
google.golang.org/genproto v0.0.0-20200313141609-30c55424f95d/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
|
@ -779,30 +735,20 @@ google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9M
|
|||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
|
||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -834,7 +780,7 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
|
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -894,9 +840,7 @@ modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
|
|||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=
|
||||
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
|
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
|
|
|
@ -11,7 +11,7 @@ func NewBuilder() *Builder {
|
|||
}
|
||||
}
|
||||
|
||||
func (i *Builder) Build(name, language, path string) (string, error) {
|
||||
func (i *Builder) Build(name, runtime, path string) (string, error) {
|
||||
i.BuildInvoked = true
|
||||
return i.BuildFn(name, path)
|
||||
}
|
||||
|
|
|
@ -7,30 +7,29 @@ import (
|
|||
)
|
||||
|
||||
type Initializer struct {
|
||||
SupportedLanguages []string
|
||||
InitializeInvoked bool
|
||||
InitializeFn func(name, language, path string) error
|
||||
SupportedRuntimes []string
|
||||
InitializeInvoked bool
|
||||
InitializeFn func(runtime, template, path string) error
|
||||
}
|
||||
|
||||
func NewInitializer() *Initializer {
|
||||
return &Initializer{
|
||||
SupportedLanguages: []string{"go"},
|
||||
InitializeFn: func(string, string, string) error { return nil },
|
||||
SupportedRuntimes: []string{"go"},
|
||||
InitializeFn: func(string, string, string) error { return nil },
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Initializer) Initialize(name, language, path string) error {
|
||||
fmt.Printf("Validating language supported: %v\n", language)
|
||||
func (i *Initializer) Initialize(runtime, template, path string) error {
|
||||
i.InitializeInvoked = true
|
||||
if !i.supportsLanguage(language) {
|
||||
return errors.New(fmt.Sprintf("unsupported language '%v'", language))
|
||||
if !i.supportsRuntime(runtime) {
|
||||
return errors.New(fmt.Sprintf("unsupported runtime '%v'", runtime))
|
||||
}
|
||||
return i.InitializeFn(name, language, path)
|
||||
return i.InitializeFn(runtime, template, path)
|
||||
}
|
||||
|
||||
func (i *Initializer) supportsLanguage(language string) bool {
|
||||
for _, supported := range i.SupportedLanguages {
|
||||
if strings.ToLower(language) == supported {
|
||||
func (i *Initializer) supportsRuntime(runtime string) bool {
|
||||
for _, supported := range i.SupportedRuntimes {
|
||||
if strings.ToLower(runtime) == supported {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ func TestForStringRequired(t *testing.T) {
|
|||
output := string(out.Bytes())
|
||||
expected := ": \nplease enter a value\n: "
|
||||
if output != expected {
|
||||
t.Fatalf("Unexpected prompt received for a required value.", expected, output)
|
||||
t.Fatalf("Unexpected prompt received for a required value. expected '%v', got '%v'", expected, output)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Templates
|
||||
|
||||
## Updating
|
||||
|
||||
When any templates are modified, `../pkged.go` should be regenerated.
|
||||
|
||||
```
|
||||
go get github.com/markbates/pkger/cmd/pkger
|
||||
cd embedded && pkger
|
||||
```
|
||||
Generates a pkged.go containing serialized versions of the contents of
|
||||
the templates directory, made accessible at runtime.
|
||||
|
||||
Until such time as embedding static assets in binaries is included in the
|
||||
base go build funcitonality (see https://github.com/golang/go/issues/35950)
|
||||
a third-party tool is required and pkger provides an API largely compatible
|
||||
with the os package.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
module function
|
||||
|
||||
go 1.13
|
||||
|
||||
require github.com/cloudevents/sdk-go/v2 v2.0.0
|
|
@ -0,0 +1,32 @@
|
|||
package function
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
cloudevents "github.com/cloudevents/sdk-go/v2"
|
||||
)
|
||||
|
||||
// Handle a CloudEvent.
|
||||
// Supported function signatures:
|
||||
// func()
|
||||
// func() error
|
||||
// func(context.Context)
|
||||
// func(context.Context) error
|
||||
// func(cloudevents.Event)
|
||||
// func(cloudevents.Event) error
|
||||
// func(context.Context, cloudevents.Event)
|
||||
// func(context.Context, cloudevents.Event) error
|
||||
// func(cloudevents.Event, *cloudevents.EventResponse)
|
||||
// func(cloudevents.Event, *cloudevents.EventResponse) error
|
||||
// func(context.Context, cloudevents.Event, *cloudevents.EventResponse)
|
||||
// func(context.Context, cloudevents.Event, *cloudevents.EventResponse) error
|
||||
func Handle(ctx context.Context, event cloudevents.Event) error {
|
||||
if err := event.Validate(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "invalid event received. %v", err)
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%v\n", event)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package function
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/cloudevents/sdk-go/v2/event"
|
||||
)
|
||||
|
||||
// TestHandle ensures that Handle accepts a valid CloudEvent without error.
|
||||
func TestHandle(t *testing.T) {
|
||||
// A minimal, but valid, event.
|
||||
event := event.New()
|
||||
event.SetID("TEST-EVENT-01")
|
||||
event.SetType("com.example.event.test")
|
||||
event.SetSource("http://localhost:8080/")
|
||||
|
||||
// Invoke the defined handler.
|
||||
if err := Handle(context.Background(), event); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleInvalid ensures that an invalid input event generates an error.
|
||||
func TestInvalidInput(t *testing.T) {
|
||||
invalidEvent := event.New() // missing required fields
|
||||
|
||||
// Attempt to handle the invalid event, ensuring that the handler validats events.
|
||||
if err := Handle(context.Background(), invalidEvent); err == nil {
|
||||
t.Fatalf("handler did not generate error on invalid event. Missing .Validate() check?")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module function
|
||||
|
||||
go 1.13
|
|
@ -0,0 +1,13 @@
|
|||
package function
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Handle an HTTP Request.
|
||||
func Handle(ctx context.Context, res http.ResponseWriter, req *http.Request) error {
|
||||
res.Header().Add("Content-Type", "text/plain")
|
||||
res.Write([]byte("OK\n"))
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package function
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestHandle ensures that Handle executes without error, returns 2000 and sets
|
||||
// and sets a content-type.
|
||||
func TestHandle(t *testing.T) {
|
||||
var (
|
||||
w = httptest.NewRecorder()
|
||||
req = httptest.NewRequest("GET", "http://example.com/test", nil)
|
||||
res *http.Response
|
||||
err error
|
||||
)
|
||||
|
||||
// Invoke the Handler via a standard Go http.Handler
|
||||
func(w http.ResponseWriter, req *http.Request) {
|
||||
err = Handle(context.Background(), w, req)
|
||||
}(w, req)
|
||||
res = w.Result()
|
||||
|
||||
// Assert postconditions
|
||||
if err != nil {
|
||||
t.Fatalf("unepected error in Handle: %v", err)
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
t.Fatalf("unexpected response code: %v", res.StatusCode)
|
||||
}
|
||||
if res.Header.Get("Content-Type") == "" {
|
||||
t.Fatal("Handler did not set a content type for the response")
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
# Node.js Cloud Events Function
|
||||
|
||||
Welcome to your new Node.js function project! The boilerplate function code can be found in [`index.js`](./index.js). This function is meant to respond exclusively to [Cloud Events](https://cloudevents.io/), but you can remove the check for this in the function and it will respond just fine to plain vanilla incoming HTTP requests. Additionally, this example function is written asynchronously, returning a `Promise`. If your function does not perform any asynchronous execution, you can safely remove the `async` keyword from the function, and return raw values intead of a `Promise`.
|
||||
|
||||
## Local execution
|
||||
|
||||
After executing `npm install`, you can run this function locally by executing `npm run local`.
|
||||
|
||||
The runtime will expose three endpoints.
|
||||
|
||||
* `/` The endpoint for your function.
|
||||
* `/health/readiness` The endpoint for a readiness health check
|
||||
* `/health/liveness` The endpoint for a liveness health check
|
||||
|
||||
The health checks can be accessed in your browser at [http://localhost:8080/health/readiness]() and [http://localhost:8080/health/liveness](). You can use `curl` to `POST` an event to the function endpoint:
|
||||
|
||||
```console
|
||||
curl -X POST -d '{"hello": "world"}' \
|
||||
-H'Content-type: application/json' \
|
||||
-H'Ce-id: 1' \
|
||||
-H'Ce-source: cloud-event-example' \
|
||||
-H'Ce-type: dev.knative.example' \
|
||||
-H'Ce-specversion: 1.0' \
|
||||
http://localhost:8080
|
||||
```
|
||||
|
||||
The readiness and liveness endpoints use [overload-protection](https://www.npmjs.com/package/overload-protection) and will respond with `HTTP 503 Service Unavailable` with a `Client-Retry` header if your function is determined to be overloaded, based on the memory usage and event loop delay.
|
||||
|
||||
## Testing
|
||||
|
||||
This function project includes a [unit test](./test/unit.js) and an [integration test](./test/integration.js). All `.js` files in the test directory are run.
|
||||
|
||||
```console
|
||||
npm test
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = async function (context) {
|
||||
if (!context.cloudevent) {
|
||||
return Promise.reject(new Error('No cloud event received'));
|
||||
}
|
||||
context.log.info(`Cloud event received: ${JSON.stringify(context.cloudevent)}`);
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(_ => resolve({ data: context.cloudevent.data }), 500);
|
||||
});
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
"use strict";
|
||||
|
||||
const runtime = require('@redhat/faas-js-runtime');
|
||||
const func = require('./index.js');
|
||||
const ON_DEATH = require('death')({ uncaughtException: true });
|
||||
|
||||
runtime(func, server => {
|
||||
ON_DEATH(_ => {
|
||||
server.close();
|
||||
});
|
||||
|
||||
console.log(`
|
||||
The server has started.
|
||||
|
||||
You can use curl to POST an event to the endpoint:
|
||||
|
||||
curl -X POST -d '{"hello": "world"}' \\
|
||||
-H'Content-type: application/json' \\
|
||||
-H'Ce-id: 1' \\
|
||||
-H'Ce-source: cloud-event-example' \\
|
||||
-H'Ce-type: dev.knative.example' \\
|
||||
-H'Ce-specversion: 1.0' \\
|
||||
http://localhost:8080
|
||||
`);
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "event-handler",
|
||||
"version": "0.1.0",
|
||||
"description": "Node.js CloudEvent Handler",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": ""
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node test/unit.js && node test/integration.js",
|
||||
"local": "node local.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@redhat/faas-js-runtime": "0.2.0",
|
||||
"cloudevents-sdk": "^1.0.0",
|
||||
"death": "^1.1.0",
|
||||
"supertest": "^4.0.2",
|
||||
"tape": "^4.13.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
'use strict';
|
||||
|
||||
const runtime = require('@redhat/faas-js-runtime');
|
||||
const request = require('supertest');
|
||||
|
||||
const func = require('..');
|
||||
const test = require('tape');
|
||||
const cloudevents = require('cloudevents-sdk/v1');
|
||||
|
||||
const Spec = {
|
||||
version: 'ce-specversion',
|
||||
type: 'ce-type',
|
||||
id: 'ce-id',
|
||||
source: 'ce-source'
|
||||
};
|
||||
|
||||
test('Integration: handles a valid event', t => {
|
||||
runtime(func, server => {
|
||||
t.plan(1);
|
||||
request(server)
|
||||
.post('/')
|
||||
.send({ message: 'hello' })
|
||||
.set(Spec.id, 'TEST-EVENT-1')
|
||||
.set(Spec.source, 'http://localhost:8080/integration-test')
|
||||
.set(Spec.type, 'dev.faas.example')
|
||||
.set(Spec.version, '1.0')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.end((err, res) => {
|
||||
t.error(err, 'No error');
|
||||
// Check response values that your function produces
|
||||
// Uncomment this line to validate the template implementation
|
||||
// t.equal(res.body.data.message, 'hello');
|
||||
t.end();
|
||||
server.close();
|
||||
});
|
||||
}, { log: false });
|
||||
});
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
const func = require('..');
|
||||
const test = require('tape');
|
||||
const cloudevents = require('cloudevents-sdk/v1');
|
||||
|
||||
// Ensure that the function completes cleanly when passed a valid event.
|
||||
test('Unit: andles a valid event', t => {
|
||||
t.plan(1);
|
||||
// A valid event includes id, type and source at a minimum.
|
||||
const cloudevent = cloudevents.event()
|
||||
.id('TEST-EVENT-01')
|
||||
.type('com.example.cloudevents.test')
|
||||
.source('http://localhost:8080/')
|
||||
.data({ message: 'hello' });
|
||||
|
||||
// Invoke the function with the valid event, which should compelte without error.
|
||||
t.ok(func({ cloudevent, log: { info: console.log } }));
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Appsody: run",
|
||||
"type": "shell",
|
||||
"command": "appsody run",
|
||||
"group": "build",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Appsody: debug",
|
||||
"type": "shell",
|
||||
"command": "appsody debug",
|
||||
"group": "build",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Appsody: test",
|
||||
"type": "shell",
|
||||
"command": "appsody test",
|
||||
"group": "test",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Appsody: build",
|
||||
"type": "shell",
|
||||
"command": "appsody build",
|
||||
"group": "build",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Appsody: deploy",
|
||||
"type": "shell",
|
||||
"command": "appsody deploy",
|
||||
"group": "build",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Appsody: stop",
|
||||
"type": "shell",
|
||||
"command": "appsody stop",
|
||||
"group": "build",
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
# Quarkus Cloud Events Function
|
||||
|
||||
Welcome to your new Quarkus function project! This sample project contains three functions:
|
||||
* org.funqy.demo.GreetingFunctions.greet()
|
||||
* org.funqy.demo.PrimitiveFunctions.toLowerCase()
|
||||
* org.funqy.demo.PrimitiveFunctions.doubleIt()
|
||||
|
||||
Only one of the function is active at the time.
|
||||
Which one is determined by the `quarkus.funqy.export` property in `src/main/resources/application.properties`.
|
||||
|
||||
The `greet` function demonstrates work with java beans,
|
||||
it accepts `Identity` bean (data of incoming cloud event)
|
||||
and it returns `Greeting` bean (data of outgoing cloud event).
|
||||
|
||||
The `toLowerCase` function accepts string and returns string.
|
||||
As its name suggests it returns input string with all characters in lowercase.
|
||||
|
||||
The `doubleIt` function accepts integer and returns its value doubled.
|
||||
|
||||
You can test those functions by using `curl` cmd utility.
|
||||
Parameters for `curl` can be found at [Cloud Event emulation](#cloud-event-emulation).
|
||||
|
||||
## Local execution
|
||||
Make sure that `maven 3.6.2` and `Java 11 SDK` is installed.
|
||||
|
||||
To start server locally run `mvn quarkus:dev`.
|
||||
The command starts http server and automatically watches for changes of source code.
|
||||
If source code changes the change will be propagated to running server. It also opens debugging port `5005`
|
||||
so debugger can be attached if needed.
|
||||
|
||||
To run test locally run `mvn test`.
|
||||
|
||||
## Cloud Event emulation
|
||||
|
||||
sample cloud event for the `greet` function
|
||||
```shell script
|
||||
curl -v "localhost:8080" \
|
||||
-X POST \
|
||||
-H "Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f79" \
|
||||
-H "Ce-specversion: 0.3" \
|
||||
-H "Ce-Type: dev.nodeshift.samples.quarkus-funqy" \
|
||||
-H "Ce-Source: dev.nodeshift.samples/quarkus-funqy-source" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"name\": \"$(whoami)\"}\"";
|
||||
|
||||
```
|
||||
|
||||
sample event for the `toLowerCase` function
|
||||
```shell script
|
||||
curl -v "localhost:8080" \
|
||||
-X POST \
|
||||
-H "Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f79" \
|
||||
-H "Ce-specversion: 0.3" \
|
||||
-H "Ce-Type: dev.nodeshift.samples.quarkus-funqy" \
|
||||
-H "Ce-Source: dev.nodeshift.samples/quarkus-funqy-source" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '"wEiRDly CaPiTaLisEd sTrInG"'
|
||||
```
|
||||
|
||||
sample event for the `doubleIt` function
|
||||
```shell script
|
||||
curl -v "localhost:8080" \
|
||||
-X POST \
|
||||
-H "Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f79" \
|
||||
-H "Ce-specversion: 0.3" \
|
||||
-H "Ce-Type: dev.nodeshift.samples.quarkus-funqy" \
|
||||
-H "Ce-Source: dev.nodeshift.samples/quarkus-funqy-source" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '21'
|
||||
```
|
|
@ -0,0 +1,305 @@
|
|||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar"
|
||||
else
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar"
|
||||
fi
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if $cygwin; then
|
||||
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
else
|
||||
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||
else
|
||||
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||
fi
|
||||
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaClass=`cygpath --path --windows "$javaClass"`
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
fi
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
|
@ -0,0 +1,172 @@
|
|||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar"
|
||||
|
||||
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
echo Found %WRAPPER_JAR%
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar"
|
||||
)
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
|
@ -0,0 +1,111 @@
|
|||
<?xml version="1.0"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.funqy.demo</groupId>
|
||||
<artifactId>funq-demo</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<properties>
|
||||
<compiler-plugin.version>3.8.1</compiler-plugin.version>
|
||||
<maven.compiler.parameters>true</maven.compiler.parameters>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<quarkus-plugin.version>1.5.0.Final</quarkus-plugin.version>
|
||||
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
|
||||
<quarkus.platform.version>1.5.0.Final</quarkus.platform.version>
|
||||
<surefire-plugin.version>2.22.1</surefire-plugin.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${quarkus.platform.group-id}</groupId>
|
||||
<artifactId>${quarkus.platform.artifact-id}</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-funqy-knative-events</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<version>${quarkus-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${compiler-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${surefire-plugin.version}</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>native</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>native</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>${surefire-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<quarkus.package.type>native</quarkus.package.type>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
|
@ -0,0 +1,22 @@
|
|||
package org.funqy.demo;
|
||||
|
||||
public class Greeting {
|
||||
private String name;
|
||||
private String message;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package org.funqy.demo;
|
||||
|
||||
import io.quarkus.funqy.Funq;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class GreetingFunctions {
|
||||
private static final Logger log = Logger.getLogger("funqy.greeting");
|
||||
|
||||
private static final ScheduledExecutorService executor = Executors.newScheduledThreadPool(16);
|
||||
|
||||
@Inject
|
||||
GreetingService service;
|
||||
|
||||
@Funq
|
||||
public CompletionStage<Greeting> greet(Identity name) {
|
||||
CompletableFuture<Greeting> result = new CompletableFuture<>();
|
||||
executor.schedule(()-> {
|
||||
try {
|
||||
log.info("*** In greeting service ***");
|
||||
String message = service.hello(name.getName());
|
||||
log.info("Sending back: " + message);
|
||||
Greeting greeting = new Greeting();
|
||||
greeting.setMessage(message);
|
||||
greeting.setName(name.getName());
|
||||
result.complete(greeting);
|
||||
|
||||
} catch (Throwable t) {
|
||||
result.completeExceptionally(t);
|
||||
}
|
||||
}, 100, TimeUnit.MILLISECONDS);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.funqy.demo;
|
||||
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class GreetingService {
|
||||
private String greeting = "Hello";
|
||||
private String punctuation = "!";
|
||||
|
||||
public void setGreeting(String greet) {
|
||||
greeting = greet;
|
||||
}
|
||||
|
||||
public void setPunctuation(String punctuation) {
|
||||
this.punctuation = punctuation;
|
||||
}
|
||||
|
||||
public String hello(String val) {
|
||||
return greeting + " " + val + punctuation;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package org.funqy.demo;
|
||||
|
||||
public class Identity {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package org.funqy.demo;
|
||||
|
||||
import io.quarkus.funqy.Funq;
|
||||
|
||||
public class PrimitiveFunctions {
|
||||
@Funq
|
||||
public String toLowerCase(String val) {
|
||||
return val.toLowerCase();
|
||||
}
|
||||
|
||||
@Funq
|
||||
public int doubleIt(int val) {
|
||||
return val * 2;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
quarkus.funqy.export=greet
|
|
@ -0,0 +1,67 @@
|
|||
package org.funqy.demo;
|
||||
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.parsing.Parser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
@QuarkusTest
|
||||
public class DemoTest {
|
||||
|
||||
@Test
|
||||
public void testVanilla() {
|
||||
RestAssured.given().contentType("application/json")
|
||||
.body("{\"name\": \"Bill\"}")
|
||||
.post("/")
|
||||
.then().statusCode(200)
|
||||
.header("ce-id", nullValue())
|
||||
.body("name", equalTo("Bill"))
|
||||
.body("message", equalTo("Hello Bill!"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinary() {
|
||||
RestAssured.given().contentType("application/json")
|
||||
.body("{\"name\": \"Bill\"}")
|
||||
.header("ce-id", "1234")
|
||||
.header("ce-specversion", "1.0")
|
||||
.post("/")
|
||||
.then().statusCode(200)
|
||||
.header("ce-id", notNullValue())
|
||||
.header("ce-specversion", equalTo("1.0"))
|
||||
.header("ce-source", equalTo("greet"))
|
||||
.header("ce-type", equalTo("greet.output"))
|
||||
.body("name", equalTo("Bill"))
|
||||
.body("message", equalTo("Hello Bill!"));
|
||||
}
|
||||
|
||||
static final String event = "{ \"id\" : \"1234\", " +
|
||||
" \"specversion\": \"1.0\", " +
|
||||
" \"source\": \"/foo\", " +
|
||||
" \"type\": \"sometype\", " +
|
||||
" \"datacontenttype\": \"application/json\", " +
|
||||
" \"data\": { \"name\": \"Bill\" } " +
|
||||
"}";
|
||||
|
||||
@Test
|
||||
public void testStructured() {
|
||||
RestAssured.given().contentType("application/cloudevents+json")
|
||||
.body(event)
|
||||
.post("/")
|
||||
.then().statusCode(200)
|
||||
.defaultParser(Parser.JSON)
|
||||
.body("id", notNullValue())
|
||||
.body("specversion", equalTo("1.0"))
|
||||
.body("type", equalTo("greet.output"))
|
||||
.body("source", equalTo("greet"))
|
||||
.body("datacontenttype", equalTo("application/json"))
|
||||
.body("data.name", equalTo("Bill"))
|
||||
.body("data.message", equalTo("Hello Bill!"));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.funqy.demo;
|
||||
|
||||
import io.quarkus.test.junit.NativeImageTest;
|
||||
|
||||
@NativeImageTest
|
||||
public class NativeDemoIT extends DemoTest {
|
||||
|
||||
// Execute the same tests but in native mode.
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
name: www.example.com
|
||||
language: go
|
||||
runtime: go
|
||||
|
|
Loading…
Reference in New Issue