mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
HTTP trigger http-stream tests (#1241)
This commit is contained in:
212
Gopkg.lock
generated
212
Gopkg.lock
generated
@@ -2,23 +2,18 @@
|
|||||||
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:4af4d05ade1fe949a30dc3a2e712943cf096a16c7e68b386c93952c1b71ce704"
|
|
||||||
name = "git.apache.org/thrift.git"
|
name = "git.apache.org/thrift.git"
|
||||||
packages = ["lib/go/thrift"]
|
packages = ["lib/go/thrift"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "272470790ad6db791bd6f9db399b2cd2d5879f74"
|
revision = "272470790ad6db791bd6f9db399b2cd2d5879f74"
|
||||||
source = "github.com/apache/thrift"
|
source = "github.com/apache/thrift"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:3721a10686511b80c052323423f0de17a8c06d417dbdd3b392b1578432a33aae"
|
|
||||||
name = "github.com/Nvveen/Gotty"
|
name = "github.com/Nvveen/Gotty"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "cd527374f1e5bff4938207604a14f2e38a9cf512"
|
revision = "cd527374f1e5bff4938207604a14f2e38a9cf512"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:63776251fbaa60062742412a9d2fa1e4b7cd24bcf5527fa9656b314ea8d60913"
|
|
||||||
name = "github.com/aws/aws-sdk-go"
|
name = "github.com/aws/aws-sdk-go"
|
||||||
packages = [
|
packages = [
|
||||||
"aws",
|
"aws",
|
||||||
@@ -48,53 +43,41 @@
|
|||||||
"service/s3",
|
"service/s3",
|
||||||
"service/s3/s3iface",
|
"service/s3/s3iface",
|
||||||
"service/s3/s3manager",
|
"service/s3/s3manager",
|
||||||
"service/sts",
|
"service/sts"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "bff41fb23b7550368282029f6478819d6a99ae0f"
|
revision = "bff41fb23b7550368282029f6478819d6a99ae0f"
|
||||||
version = "v1.12.79"
|
version = "v1.12.79"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:c0bec5f9b98d0bc872ff5e834fac186b807b656683bd29cb82fb207a1513fabb"
|
|
||||||
name = "github.com/beorn7/perks"
|
name = "github.com/beorn7/perks"
|
||||||
packages = ["quantile"]
|
packages = ["quantile"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:8f4ae450cb47d944eb7fc75edcca20449915b7c0f5ddfa2e7d145ba07f9fdceb"
|
|
||||||
name = "github.com/boltdb/bolt"
|
name = "github.com/boltdb/bolt"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "fa5367d20c994db73282594be0146ab221657943"
|
revision = "fa5367d20c994db73282594be0146ab221657943"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:54f28fa28bb8fc90169e37ae25182cb0e7d06e38fa8530a90bedb497410fed0d"
|
|
||||||
name = "github.com/containerd/continuity"
|
name = "github.com/containerd/continuity"
|
||||||
packages = ["pathdriver"]
|
packages = ["pathdriver"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "246e49050efdf45e8f17fbbcf1547ee376f9939e"
|
revision = "246e49050efdf45e8f17fbbcf1547ee376f9939e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:3c3f68ebab415344aef64363d23471e953a4715645115604aaf57923ae904f5e"
|
|
||||||
name = "github.com/coreos/go-semver"
|
name = "github.com/coreos/go-semver"
|
||||||
packages = ["semver"]
|
packages = ["semver"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "8ab6407b697782a06568d4b7f1db25550ec2e4c6"
|
revision = "8ab6407b697782a06568d4b7f1db25550ec2e4c6"
|
||||||
version = "v0.2.0"
|
version = "v0.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:437eb8b3aff726370e97dddbea5366eff786728582cc785033a274c1491f2710"
|
|
||||||
name = "github.com/dchest/siphash"
|
name = "github.com/dchest/siphash"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "4ebf1de738443ea7f45f02dc394c4df1942a126d"
|
revision = "4ebf1de738443ea7f45f02dc394c4df1942a126d"
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:5bd14ec4eacea32533d819153f9a972f219c7004a995763c4f3e0d9da6841855"
|
|
||||||
name = "github.com/docker/docker"
|
name = "github.com/docker/docker"
|
||||||
packages = [
|
packages = [
|
||||||
"api/types",
|
"api/types",
|
||||||
@@ -118,129 +101,101 @@
|
|||||||
"pkg/mount",
|
"pkg/mount",
|
||||||
"pkg/pools",
|
"pkg/pools",
|
||||||
"pkg/stdcopy",
|
"pkg/stdcopy",
|
||||||
"pkg/system",
|
"pkg/system"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "c3e32938430e03a316311f9e4fbdb743e492a07e"
|
revision = "c3e32938430e03a316311f9e4fbdb743e492a07e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:a5ecc2e70260a87aa263811281465a5effcfae8a54bac319cee87c4625f04d63"
|
|
||||||
name = "github.com/docker/go-connections"
|
name = "github.com/docker/go-connections"
|
||||||
packages = ["nat"]
|
packages = ["nat"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "3ede32e2033de7505e6500d6c868c2b9ed9f169d"
|
revision = "3ede32e2033de7505e6500d6c868c2b9ed9f169d"
|
||||||
version = "v0.3.0"
|
version = "v0.3.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:582d54fcb7233da8dde1dfd2210a5b9675d0685f84246a8d317b07d680c18b1b"
|
|
||||||
name = "github.com/docker/go-units"
|
name = "github.com/docker/go-units"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
|
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
|
||||||
version = "v0.3.3"
|
version = "v0.3.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:6a9b61ab4f59a90724b309215446a880a1f29c327f67bd54de5101e1125fe6dc"
|
|
||||||
name = "github.com/docker/libnetwork"
|
name = "github.com/docker/libnetwork"
|
||||||
packages = ["ipamutils"]
|
packages = ["ipamutils"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "0ae9b6f38f24f65567d4b46602502b33c95cf57a"
|
revision = "0ae9b6f38f24f65567d4b46602502b33c95cf57a"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:209f213526a6c3f2d6ef431bb4303bd97fa4af8350e67b5b4d43b53fd469a005"
|
|
||||||
name = "github.com/fnproject/fdk-go"
|
name = "github.com/fnproject/fdk-go"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"utils",
|
"utils"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
revision = "19c8e175e8563669762773c3c3f68e6bf995b16a"
|
||||||
revision = "1eb29530716f262bad5b83eb9a5b3f7483636949"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:eb53021a8aa3f599d29c7102e65026242bdedce998a54837dc67f14b6a97c5fd"
|
|
||||||
name = "github.com/fsnotify/fsnotify"
|
name = "github.com/fsnotify/fsnotify"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||||
version = "v1.4.7"
|
version = "v1.4.7"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:fb02a20784a57cb6229a8097d97546fdc4a14f3506463ae8cc73d5727f326532"
|
|
||||||
name = "github.com/fsouza/go-dockerclient"
|
name = "github.com/fsouza/go-dockerclient"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"internal/archive",
|
"internal/archive",
|
||||||
"internal/jsonmessage",
|
"internal/jsonmessage",
|
||||||
"internal/term",
|
"internal/term"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "1b33efcb40bef3494af8bc6a1f73600f37a3c9d1"
|
revision = "1b33efcb40bef3494af8bc6a1f73600f37a3c9d1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:9525d0e79ccf382e32edeef466b9a91f16eb0eebdca5971a03fad1bb3be9cd89"
|
|
||||||
name = "github.com/garyburd/redigo"
|
name = "github.com/garyburd/redigo"
|
||||||
packages = [
|
packages = [
|
||||||
"internal",
|
"internal",
|
||||||
"redis",
|
"redis"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "a69d19351219b6dd56f274f96d85a7014a2ec34e"
|
revision = "a69d19351219b6dd56f274f96d85a7014a2ec34e"
|
||||||
version = "v1.6.0"
|
version = "v1.6.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:629d5458c77f7df2e78f011d535da90aaf117cee238e44407952d65691a954a0"
|
|
||||||
name = "github.com/gin-contrib/cors"
|
name = "github.com/gin-contrib/cors"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "cf4846e6a636a76237a28d9286f163c132e841bc"
|
revision = "cf4846e6a636a76237a28d9286f163c132e841bc"
|
||||||
version = "v1.2"
|
version = "v1.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:1120f960f5c334f0f94bad29eefaf73d52d226893369693686148f66c1993f15"
|
|
||||||
name = "github.com/gin-contrib/sse"
|
name = "github.com/gin-contrib/sse"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae"
|
revision = "22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:348ceb76f2ac958e541e4ba3190484b68df28c38ac9720ed4ef8d36af69ce52e"
|
|
||||||
name = "github.com/gin-gonic/gin"
|
name = "github.com/gin-gonic/gin"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"binding",
|
"binding",
|
||||||
"render",
|
"render"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "d459835d2b077e44f7c9b453505ee29881d5d12d"
|
revision = "d459835d2b077e44f7c9b453505ee29881d5d12d"
|
||||||
version = "v1.2"
|
version = "v1.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:617b3e0f5989d4ff866a1820480990c65dfc9257eb080da749a45e2d76681b02"
|
|
||||||
name = "github.com/go-ini/ini"
|
name = "github.com/go-ini/ini"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "06f5f3d67269ccec1fe5fe4134ba6e982984f7f5"
|
revision = "06f5f3d67269ccec1fe5fe4134ba6e982984f7f5"
|
||||||
version = "v1.37.0"
|
version = "v1.37.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:54e2545b223c001f4265c38a66a5ed631536801f6cd869a63e35c7ba6f14b188"
|
|
||||||
name = "github.com/go-sql-driver/mysql"
|
name = "github.com/go-sql-driver/mysql"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "21d7e97c9f760ca685a01ecea202e1c84276daa1"
|
revision = "21d7e97c9f760ca685a01ecea202e1c84276daa1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:0a3f6a0c68ab8f3d455f8892295503b179e571b7fefe47cc6c556405d1f83411"
|
|
||||||
name = "github.com/gogo/protobuf"
|
name = "github.com/gogo/protobuf"
|
||||||
packages = ["proto"]
|
packages = ["proto"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
|
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:f958a1c137db276e52f0b50efee41a1a389dcdded59a69711f3e872757dab34b"
|
|
||||||
name = "github.com/golang/protobuf"
|
name = "github.com/golang/protobuf"
|
||||||
packages = [
|
packages = [
|
||||||
"proto",
|
"proto",
|
||||||
@@ -248,220 +203,174 @@
|
|||||||
"ptypes/any",
|
"ptypes/any",
|
||||||
"ptypes/duration",
|
"ptypes/duration",
|
||||||
"ptypes/empty",
|
"ptypes/empty",
|
||||||
"ptypes/timestamp",
|
"ptypes/timestamp"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
|
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:be28c0531a755f2178acf1e327e6f5a8a3968feb5f2567cdc968064253141751"
|
|
||||||
name = "github.com/google/btree"
|
name = "github.com/google/btree"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "e89373fe6b4a7413d7acd6da1725b83ef713e6e4"
|
revision = "e89373fe6b4a7413d7acd6da1725b83ef713e6e4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:9a0b2dd1f882668a3d7fbcd424eed269c383a16f1faa3a03d14e0dd5fba571b1"
|
|
||||||
name = "github.com/grpc-ecosystem/go-grpc-middleware"
|
name = "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "c250d6563d4d4c20252cd865923440e829844f4e"
|
revision = "c250d6563d4d4c20252cd865923440e829844f4e"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:6f49eae0c1e5dab1dafafee34b207aeb7a42303105960944828c2079b92fc88e"
|
|
||||||
name = "github.com/jmespath/go-jmespath"
|
name = "github.com/jmespath/go-jmespath"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "0b12d6b5"
|
revision = "0b12d6b5"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:617ee2434b77e911fa26b678730be9a617f75243b194eadc8201c8ac860844aa"
|
|
||||||
name = "github.com/jmoiron/sqlx"
|
name = "github.com/jmoiron/sqlx"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"reflectx",
|
"reflectx"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "0dae4fefe7c0e190f7b5a78dac28a1c82cc8d849"
|
revision = "0dae4fefe7c0e190f7b5a78dac28a1c82cc8d849"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:b352d4ebd13c046f4585b0538b095ce7f8ffcf2cca7b87c6a86083782aac1325"
|
|
||||||
name = "github.com/leanovate/gopter"
|
name = "github.com/leanovate/gopter"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"gen",
|
"gen",
|
||||||
"prop",
|
"prop"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "1f4d0ba27bd5df5390eb622bcb458f8f7ac2573c"
|
revision = "1f4d0ba27bd5df5390eb622bcb458f8f7ac2573c"
|
||||||
version = "v0.2.2"
|
version = "v0.2.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:09792d732b079867772cdbabdf7dc54ef9f9d04c998a9ce6226657151fccbb94"
|
|
||||||
name = "github.com/lib/pq"
|
name = "github.com/lib/pq"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"oid",
|
"oid"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "90697d60dd844d5ef6ff15135d0203f65d2f53b8"
|
revision = "90697d60dd844d5ef6ff15135d0203f65d2f53b8"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:78229b46ddb7434f881390029bd1af7661294af31f6802e0e1bedaad4ab0af3c"
|
|
||||||
name = "github.com/mattn/go-isatty"
|
name = "github.com/mattn/go-isatty"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||||
version = "v0.0.3"
|
version = "v0.0.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:bc03901fc8f0965ccba8bc453eae21a9b04f95999eab664c7de6dc7290f4e8f4"
|
|
||||||
name = "github.com/mattn/go-sqlite3"
|
name = "github.com/mattn/go-sqlite3"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "25ecb14adfc7543176f7d85291ec7dba82c6f7e4"
|
revision = "25ecb14adfc7543176f7d85291ec7dba82c6f7e4"
|
||||||
version = "v1.9.0"
|
version = "v1.9.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:63722a4b1e1717be7b98fc686e0b30d5e7f734b9e93d7dee86293b6deab7ea28"
|
|
||||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||||
packages = ["pbutil"]
|
packages = ["pbutil"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
||||||
version = "v1.0.1"
|
version = "v1.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:5d9b668b0b4581a978f07e7d2e3314af18eb27b3fb5d19b70185b7c575723d11"
|
|
||||||
name = "github.com/opencontainers/go-digest"
|
name = "github.com/opencontainers/go-digest"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
|
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
|
||||||
version = "v1.0.0-rc1"
|
version = "v1.0.0-rc1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:f26c8670b11e29a49c8e45f7ec7f2d5bac62e8fd4e3c0ae1662baa4a697f984a"
|
|
||||||
name = "github.com/opencontainers/image-spec"
|
name = "github.com/opencontainers/image-spec"
|
||||||
packages = [
|
packages = [
|
||||||
"specs-go",
|
"specs-go",
|
||||||
"specs-go/v1",
|
"specs-go/v1"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "d60099175f88c47cd379c4738d158884749ed235"
|
revision = "d60099175f88c47cd379c4738d158884749ed235"
|
||||||
version = "v1.0.1"
|
version = "v1.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:fa19ddee0e5ee5951a6a450a4b6ec635a42957f86bfc87d9d778eeee04ad2036"
|
|
||||||
name = "github.com/opencontainers/runc"
|
name = "github.com/opencontainers/runc"
|
||||||
packages = ["libcontainer/user"]
|
packages = ["libcontainer/user"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "baf6536d6259209c3edfa2b22237af82942d3dfa"
|
revision = "baf6536d6259209c3edfa2b22237af82942d3dfa"
|
||||||
version = "v0.1.1"
|
version = "v0.1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:aec3ca6ffc2c0dd856e858b2f3d3bcc291123fff7ed1456e0a1a6dac8a986b75"
|
|
||||||
name = "github.com/openzipkin/zipkin-go"
|
name = "github.com/openzipkin/zipkin-go"
|
||||||
packages = [
|
packages = [
|
||||||
"model",
|
"model",
|
||||||
"reporter",
|
"reporter",
|
||||||
"reporter/http",
|
"reporter/http"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "f197ec29e729f226d23370ea60f0e49b8f44ccf4"
|
revision = "f197ec29e729f226d23370ea60f0e49b8f44ccf4"
|
||||||
version = "v0.1.0"
|
version = "v0.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:4c0404dc03d974acd5fcd8b8d3ce687b13bd169db032b89275e8b9d77b98ce8c"
|
|
||||||
name = "github.com/patrickmn/go-cache"
|
name = "github.com/patrickmn/go-cache"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0"
|
revision = "a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0"
|
||||||
version = "v2.1.0"
|
version = "v2.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:c24598ffeadd2762552269271b3b1510df2d83ee6696c1e543a0ff653af494bc"
|
|
||||||
name = "github.com/petar/GoLLRB"
|
name = "github.com/petar/GoLLRB"
|
||||||
packages = ["llrb"]
|
packages = ["llrb"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
|
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:7365acd48986e205ccb8652cc746f09c8b7876030d53710ea6ef7d0bd0dcd7ca"
|
|
||||||
name = "github.com/pkg/errors"
|
name = "github.com/pkg/errors"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||||
version = "v0.8.0"
|
version = "v0.8.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:4142d94383572e74b42352273652c62afec5b23f325222ed09198f46009022d1"
|
|
||||||
name = "github.com/prometheus/client_golang"
|
name = "github.com/prometheus/client_golang"
|
||||||
packages = [
|
packages = [
|
||||||
"prometheus",
|
"prometheus",
|
||||||
"prometheus/promhttp",
|
"prometheus/promhttp"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "c5b7fccd204277076155f10851dad72b76a49317"
|
revision = "c5b7fccd204277076155f10851dad72b76a49317"
|
||||||
version = "v0.8.0"
|
version = "v0.8.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:60aca47f4eeeb972f1b9da7e7db51dee15ff6c59f7b401c1588b8e6771ba15ef"
|
|
||||||
name = "github.com/prometheus/client_model"
|
name = "github.com/prometheus/client_model"
|
||||||
packages = ["go"]
|
packages = ["go"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c"
|
revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:bfbc121ef802d245ef67421cff206615357d9202337a3d492b8f668906b485a8"
|
|
||||||
name = "github.com/prometheus/common"
|
name = "github.com/prometheus/common"
|
||||||
packages = [
|
packages = [
|
||||||
"expfmt",
|
"expfmt",
|
||||||
"internal/bitbucket.org/ww/goautoneg",
|
"internal/bitbucket.org/ww/goautoneg",
|
||||||
"model",
|
"model"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "7600349dcfe1abd18d72d3a1770870d9800a7801"
|
revision = "7600349dcfe1abd18d72d3a1770870d9800a7801"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:cccf925b20ad15bfad909bdfed67a0d9a29c7e2264597199858067e7eeada232"
|
|
||||||
name = "github.com/prometheus/procfs"
|
name = "github.com/prometheus/procfs"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"internal/util",
|
"internal/util",
|
||||||
"nfs",
|
"nfs",
|
||||||
"xfs",
|
"xfs"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "7d6f385de8bea29190f15ba9931442a0eaef9af7"
|
revision = "7d6f385de8bea29190f15ba9931442a0eaef9af7"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:d85b68f829b376e76d36b3f7841fb544495d96b8999ce6ebf7317b74386ca602"
|
|
||||||
name = "github.com/sirupsen/logrus"
|
name = "github.com/sirupsen/logrus"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"hooks/syslog",
|
"hooks/syslog"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "89742aefa4b206dcf400792f3bd35b542998eb3b"
|
revision = "89742aefa4b206dcf400792f3bd35b542998eb3b"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:2e7f653483e51243b6cd6de60ce39bde0d6927d10a3c24295ab0f82cb1efeae2"
|
|
||||||
name = "github.com/ugorji/go"
|
name = "github.com/ugorji/go"
|
||||||
packages = ["codec"]
|
packages = ["codec"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "b4c50a2b199d93b13dc15e78929cfb23bfdf21ab"
|
revision = "b4c50a2b199d93b13dc15e78929cfb23bfdf21ab"
|
||||||
version = "v1.1.1"
|
version = "v1.1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:8778190ba18941ba540ea3a065bfe3e6c4126ab16aa2f8a240076ef51af9ab75"
|
|
||||||
name = "go.opencensus.io"
|
name = "go.opencensus.io"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@@ -479,23 +388,19 @@
|
|||||||
"tag",
|
"tag",
|
||||||
"trace",
|
"trace",
|
||||||
"trace/internal",
|
"trace/internal",
|
||||||
"trace/propagation",
|
"trace/propagation"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "7b558058b7cc960667590e5413ef55157b06652e"
|
revision = "7b558058b7cc960667590e5413ef55157b06652e"
|
||||||
version = "v0.15.0"
|
version = "v0.15.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:2b051135019435c0cf95756a3ff5366b87ddc7e06e91571506c6264ce721784f"
|
|
||||||
name = "golang.org/x/crypto"
|
name = "golang.org/x/crypto"
|
||||||
packages = ["ssh/terminal"]
|
packages = ["ssh/terminal"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "7f39a6fea4fe9364fb61e1def6a268a51b4f3a06"
|
revision = "7f39a6fea4fe9364fb61e1def6a268a51b4f3a06"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:5dc6753986b9eeba4abdf05dedc5ba06bb52dad43cc8aad35ffb42bb7adfa68f"
|
|
||||||
name = "golang.org/x/net"
|
name = "golang.org/x/net"
|
||||||
packages = [
|
packages = [
|
||||||
"context",
|
"context",
|
||||||
@@ -504,32 +409,26 @@
|
|||||||
"http2/hpack",
|
"http2/hpack",
|
||||||
"idna",
|
"idna",
|
||||||
"internal/timeseries",
|
"internal/timeseries",
|
||||||
"trace",
|
"trace"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
|
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:b2ea75de0ccb2db2ac79356407f8a4cd8f798fe15d41b381c00abf3ae8e55ed1"
|
|
||||||
name = "golang.org/x/sync"
|
name = "golang.org/x/sync"
|
||||||
packages = ["semaphore"]
|
packages = ["semaphore"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:a6a50b355ef54a65de2aa58cf9fa8f4554159e42f1881a30f76541e43090d217"
|
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = [
|
packages = [
|
||||||
"unix",
|
"unix",
|
||||||
"windows",
|
"windows"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "ad87a3a340fa7f3bed189293fbfa7a9b7e021ae1"
|
revision = "ad87a3a340fa7f3bed189293fbfa7a9b7e021ae1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4"
|
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
packages = [
|
packages = [
|
||||||
"collate",
|
"collate",
|
||||||
@@ -545,38 +444,30 @@
|
|||||||
"unicode/bidi",
|
"unicode/bidi",
|
||||||
"unicode/cldr",
|
"unicode/cldr",
|
||||||
"unicode/norm",
|
"unicode/norm",
|
||||||
"unicode/rangetable",
|
"unicode/rangetable"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||||
version = "v0.3.0"
|
version = "v0.3.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:55a681cb66f28755765fa5fa5104cbd8dc85c55c02d206f9f89566451e3fe1aa"
|
|
||||||
name = "golang.org/x/time"
|
name = "golang.org/x/time"
|
||||||
packages = ["rate"]
|
packages = ["rate"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
|
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:7d15746ff4df12481c89fd953a28122fa75368fb1fb1bb1fed918a78647b3c3a"
|
|
||||||
name = "google.golang.org/api"
|
name = "google.golang.org/api"
|
||||||
packages = ["support/bundler"]
|
packages = ["support/bundler"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "2eea9ba0a3d94f6ab46508083e299a00bbbc65f6"
|
revision = "2eea9ba0a3d94f6ab46508083e299a00bbbc65f6"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:d88c2eb6750028f5707971ed1340a02407d5f0967af85bf6ac70c031533f6c15"
|
|
||||||
name = "google.golang.org/genproto"
|
name = "google.golang.org/genproto"
|
||||||
packages = ["googleapis/rpc/status"]
|
packages = ["googleapis/rpc/status"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "32ee49c4dd805befd833990acba36cb75042378c"
|
revision = "32ee49c4dd805befd833990acba36cb75042378c"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:5f31b45ee9da7a87f140bef3ed0a7ca34ea2a6d38eb888123b8e28170e8aa4f2"
|
|
||||||
name = "google.golang.org/grpc"
|
name = "google.golang.org/grpc"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@@ -603,83 +494,26 @@
|
|||||||
"stats",
|
"stats",
|
||||||
"status",
|
"status",
|
||||||
"tap",
|
"tap",
|
||||||
"transport",
|
"transport"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "168a6198bcb0ef175f7dacec0b8691fc141dc9b8"
|
revision = "168a6198bcb0ef175f7dacec0b8691fc141dc9b8"
|
||||||
version = "v1.13.0"
|
version = "v1.13.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:dd549e360e5a8f982a28c2bcbe667307ceffe538ed9afc7c965524f1ac285b3f"
|
|
||||||
name = "gopkg.in/go-playground/validator.v8"
|
name = "gopkg.in/go-playground/validator.v8"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf"
|
revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf"
|
||||||
version = "v8.18.2"
|
version = "v8.18.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2"
|
|
||||||
name = "gopkg.in/yaml.v2"
|
name = "gopkg.in/yaml.v2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||||
version = "v2.2.1"
|
version = "v2.2.1"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
input-imports = [
|
inputs-digest = "caf9da7776a8bba243fa98193ff57c7fff65abe07019dd4115c228ae54f19770"
|
||||||
"github.com/aws/aws-sdk-go/aws",
|
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr",
|
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials",
|
|
||||||
"github.com/aws/aws-sdk-go/aws/session",
|
|
||||||
"github.com/aws/aws-sdk-go/service/s3",
|
|
||||||
"github.com/aws/aws-sdk-go/service/s3/s3manager",
|
|
||||||
"github.com/boltdb/bolt",
|
|
||||||
"github.com/coreos/go-semver/semver",
|
|
||||||
"github.com/dchest/siphash",
|
|
||||||
"github.com/fnproject/fdk-go",
|
|
||||||
"github.com/fnproject/fdk-go/utils",
|
|
||||||
"github.com/fsnotify/fsnotify",
|
|
||||||
"github.com/fsouza/go-dockerclient",
|
|
||||||
"github.com/garyburd/redigo/redis",
|
|
||||||
"github.com/gin-contrib/cors",
|
|
||||||
"github.com/gin-gonic/gin",
|
|
||||||
"github.com/go-sql-driver/mysql",
|
|
||||||
"github.com/golang/protobuf/proto",
|
|
||||||
"github.com/golang/protobuf/ptypes/empty",
|
|
||||||
"github.com/google/btree",
|
|
||||||
"github.com/grpc-ecosystem/go-grpc-middleware",
|
|
||||||
"github.com/jmoiron/sqlx",
|
|
||||||
"github.com/leanovate/gopter",
|
|
||||||
"github.com/leanovate/gopter/gen",
|
|
||||||
"github.com/leanovate/gopter/prop",
|
|
||||||
"github.com/lib/pq",
|
|
||||||
"github.com/mattn/go-sqlite3",
|
|
||||||
"github.com/openzipkin/zipkin-go/reporter/http",
|
|
||||||
"github.com/patrickmn/go-cache",
|
|
||||||
"github.com/prometheus/client_golang/prometheus",
|
|
||||||
"github.com/sirupsen/logrus",
|
|
||||||
"github.com/sirupsen/logrus/hooks/syslog",
|
|
||||||
"go.opencensus.io/exporter/jaeger",
|
|
||||||
"go.opencensus.io/exporter/prometheus",
|
|
||||||
"go.opencensus.io/exporter/zipkin",
|
|
||||||
"go.opencensus.io/plugin/ochttp",
|
|
||||||
"go.opencensus.io/plugin/ochttp/propagation/b3",
|
|
||||||
"go.opencensus.io/stats",
|
|
||||||
"go.opencensus.io/stats/view",
|
|
||||||
"go.opencensus.io/tag",
|
|
||||||
"go.opencensus.io/trace",
|
|
||||||
"golang.org/x/net/context",
|
|
||||||
"golang.org/x/net/trace",
|
|
||||||
"golang.org/x/sys/unix",
|
|
||||||
"golang.org/x/time/rate",
|
|
||||||
"google.golang.org/grpc",
|
|
||||||
"google.golang.org/grpc/codes",
|
|
||||||
"google.golang.org/grpc/credentials",
|
|
||||||
"google.golang.org/grpc/metadata",
|
|
||||||
"google.golang.org/grpc/peer",
|
|
||||||
"google.golang.org/grpc/status",
|
|
||||||
]
|
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -130,7 +130,12 @@ docker-test:
|
|||||||
-v ${CURDIR}:/go/src/github.com/fnproject/fn \
|
-v ${CURDIR}:/go/src/github.com/fnproject/fn \
|
||||||
-w /go/src/github.com/fnproject/fn \
|
-w /go/src/github.com/fnproject/fn \
|
||||||
fnproject/go:dev go test \
|
fnproject/go:dev go test \
|
||||||
-v $(shell docker run --rm -ti -v ${CURDIR}:/go/src/github.com/fnproject/fn -w /go/src/github.com/fnproject/fn -e GOPATH=/go golang:alpine sh -c 'go list ./... | grep -v vendor | grep -v examples | grep -v tool | grep -v fn')
|
-v $(shell docker run --rm -ti -v ${CURDIR}:/go/src/github.com/fnproject/fn -w /go/src/github.com/fnproject/fn -e GOPATH=/go golang:alpine sh -c 'go list ./... | \
|
||||||
|
grep -v vendor | \
|
||||||
|
grep -v examples | \
|
||||||
|
grep -v test/fn-api-tests | \
|
||||||
|
grep -v test/fn-system-tests | \
|
||||||
|
grep -v images/fn-test-utils')
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: dep generate build
|
all: dep generate build
|
||||||
|
|||||||
@@ -755,13 +755,18 @@ func (s *hotSlot) dispatch(ctx context.Context, call *call) chan error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
// TODO it's possible we can get rid of this (after getting rid of logs API) - may need for call id/debug mode still
|
||||||
|
// TODO there's a timeout race for swapping this back if the container doesn't get killed for timing out, and don't you forget it
|
||||||
|
swapBack := s.container.swap(nil, call.stderr, call.stderr, &call.Stats)
|
||||||
|
defer swapBack()
|
||||||
|
|
||||||
resp, err := s.udsClient.Do(req)
|
resp, err := s.udsClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Logger(ctx).WithError(err).Error("Got error from UDS socket")
|
common.Logger(ctx).WithError(err).Error("Got error from UDS socket")
|
||||||
errApp <- models.NewAPIError(http.StatusBadGateway, errors.New("error receiving function response"))
|
errApp <- models.NewAPIError(http.StatusBadGateway, errors.New("error receiving function response"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
common.Logger(ctx).WithField("status", resp.StatusCode).Debug("Got resp from UDS socket")
|
common.Logger(ctx).WithField("resp", resp).Debug("Got resp from UDS socket")
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
|||||||
@@ -11,15 +11,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
|
|
||||||
"net/textproto"
|
|
||||||
|
|
||||||
"github.com/fnproject/fn/api/agent/drivers"
|
"github.com/fnproject/fn/api/agent/drivers"
|
||||||
"github.com/fnproject/fn/api/common"
|
"github.com/fnproject/fn/api/common"
|
||||||
"github.com/fnproject/fn/api/id"
|
"github.com/fnproject/fn/api/id"
|
||||||
"github.com/fnproject/fn/api/models"
|
"github.com/fnproject/fn/api/models"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Call interface {
|
type Call interface {
|
||||||
@@ -55,44 +52,6 @@ const (
|
|||||||
invokePath = "/invoke"
|
invokePath = "/invoke"
|
||||||
)
|
)
|
||||||
|
|
||||||
var skipTriggerHeaders = map[string]bool{
|
|
||||||
"Connection": true,
|
|
||||||
"Keep-Alive": true,
|
|
||||||
"Trailer": true,
|
|
||||||
"Transfer-Encoding": true,
|
|
||||||
"TE": true,
|
|
||||||
"Upgrade": true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets up a call from an http trigger request
|
|
||||||
func FromHTTPTriggerRequest(app *models.App, fn *models.Fn, trigger *models.Trigger, req *http.Request) CallOpt {
|
|
||||||
return func(c *call) error {
|
|
||||||
// transpose trigger headers into HTTP
|
|
||||||
headers := make(http.Header)
|
|
||||||
for k, vs := range req.Header {
|
|
||||||
// should be generally unnecessary but to be doubly sure.
|
|
||||||
k = textproto.CanonicalMIMEHeaderKey(k)
|
|
||||||
if skipTriggerHeaders[k] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rewriteKey := fmt.Sprintf("Fn-Http-H-%s", k)
|
|
||||||
for _, v := range vs {
|
|
||||||
headers.Add(rewriteKey, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
requestUrl := reqURL(req)
|
|
||||||
|
|
||||||
headers.Set("Fn-Http-Method", req.Method)
|
|
||||||
headers.Set("Fn-Http-Request-Url", requestUrl)
|
|
||||||
headers.Set("Fn-Intent", "httprequest")
|
|
||||||
req.Header = headers
|
|
||||||
|
|
||||||
err := FromHTTPFnRequest(app, fn, req)(c)
|
|
||||||
c.Model().TriggerID = trigger.ID
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets up a call from an http trigger request
|
// Sets up a call from an http trigger request
|
||||||
func FromHTTPFnRequest(app *models.App, fn *models.Fn, req *http.Request) CallOpt {
|
func FromHTTPFnRequest(app *models.App, fn *models.Fn, req *http.Request) CallOpt {
|
||||||
return func(c *call) error {
|
return func(c *call) error {
|
||||||
@@ -235,7 +194,17 @@ func FromModelAndInput(mCall *models.Call, in io.ReadCloser) CallOpt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithWriter sets the writier that the call uses to send its output message to
|
// WithTrigger adds trigger specific bits to a call.
|
||||||
|
// TODO consider removal, this is from a shuffle
|
||||||
|
func WithTrigger(t *models.Trigger) CallOpt {
|
||||||
|
return func(c *call) error {
|
||||||
|
// right now just set the trigger id
|
||||||
|
c.TriggerID = t.ID
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithWriter sets the writer that the call uses to send its output message to
|
||||||
// TODO this should be required
|
// TODO this should be required
|
||||||
func WithWriter(w io.Writer) CallOpt {
|
func WithWriter(w io.Writer) CallOpt {
|
||||||
return func(c *call) error {
|
return func(c *call) error {
|
||||||
@@ -330,7 +299,6 @@ type call struct {
|
|||||||
requestState RequestState
|
requestState RequestState
|
||||||
containerState ContainerState
|
containerState ContainerState
|
||||||
slotHashId string
|
slotHashId string
|
||||||
isLB bool
|
|
||||||
|
|
||||||
// LB & Pure Runner Extra Config
|
// LB & Pure Runner Extra Config
|
||||||
extensions map[string]string
|
extensions map[string]string
|
||||||
@@ -378,12 +346,6 @@ func (c *call) Start(ctx context.Context) error {
|
|||||||
c.StartedAt = common.DateTime(time.Now())
|
c.StartedAt = common.DateTime(time.Now())
|
||||||
c.Status = "running"
|
c.Status = "running"
|
||||||
|
|
||||||
if !c.isLB {
|
|
||||||
if rw, ok := c.w.(http.ResponseWriter); ok { // TODO need to figure out better way to wire response headers in
|
|
||||||
rw.Header().Set("XXX-FXLB-WAIT", time.Time(c.StartedAt).Sub(time.Time(c.CreatedAt)).String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Type == models.TypeAsync {
|
if c.Type == models.TypeAsync {
|
||||||
// XXX (reed): make sure MQ reservation is lengthy. to skirt MQ semantics,
|
// XXX (reed): make sure MQ reservation is lengthy. to skirt MQ semantics,
|
||||||
// we could add a new message to MQ w/ delay of call.Timeout and delete the
|
// we could add a new message to MQ w/ delay of call.Timeout and delete the
|
||||||
|
|||||||
@@ -119,7 +119,6 @@ func (a *lbAgent) GetCall(opts ...CallOpt) (Call, error) {
|
|||||||
|
|
||||||
setupCtx(&c)
|
setupCtx(&c)
|
||||||
|
|
||||||
c.isLB = true
|
|
||||||
c.handler = a.cda
|
c.handler = a.cda
|
||||||
c.ct = a
|
c.ct = a
|
||||||
c.stderr = &nullReadWriter{}
|
c.stderr = &nullReadWriter{}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ func (g *ghostWriter) awaitRealWriter() (io.Writer, bool) {
|
|||||||
g.cond.L.Unlock()
|
g.cond.L.Unlock()
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
if _, ok := g.inner.(*waitWriter); ok {
|
if _, ok := g.inner.(*waitWriter); ok || g.inner == nil {
|
||||||
g.cond.Wait()
|
g.cond.Wait()
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
@@ -180,7 +180,7 @@ func (g *ghostReader) awaitRealReader() (io.Reader, bool) {
|
|||||||
g.cond.L.Unlock()
|
g.cond.L.Unlock()
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
if _, ok := g.inner.(*waitReader); ok {
|
if _, ok := g.inner.(*waitReader); ok || g.inner == nil {
|
||||||
g.cond.Wait()
|
g.cond.Wait()
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fnproject/fn/api"
|
"github.com/fnproject/fn/api"
|
||||||
"github.com/fnproject/fn/api/agent"
|
"github.com/fnproject/fn/api/agent"
|
||||||
@@ -20,16 +19,6 @@ var (
|
|||||||
bufPool = &sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}
|
bufPool = &sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}
|
||||||
)
|
)
|
||||||
|
|
||||||
type ResponseBufferingWriter interface {
|
|
||||||
http.ResponseWriter
|
|
||||||
io.Reader
|
|
||||||
Status() int
|
|
||||||
GetBuffer() *bytes.Buffer
|
|
||||||
SetBuffer(*bytes.Buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ ResponseBufferingWriter = new(syncResponseWriter)
|
|
||||||
|
|
||||||
// implements http.ResponseWriter
|
// implements http.ResponseWriter
|
||||||
// this little guy buffers responses from user containers and lets them still
|
// this little guy buffers responses from user containers and lets them still
|
||||||
// set headers and such without us risking writing partial output [as much, the
|
// set headers and such without us risking writing partial output [as much, the
|
||||||
@@ -41,13 +30,10 @@ type syncResponseWriter struct {
|
|||||||
*bytes.Buffer
|
*bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncResponseWriter) Header() http.Header { return s.headers }
|
var _ http.ResponseWriter = new(syncResponseWriter) // nice compiler errors
|
||||||
|
|
||||||
// By storing the status here, we effectively buffer the response
|
func (s *syncResponseWriter) Header() http.Header { return s.headers }
|
||||||
func (s *syncResponseWriter) WriteHeader(code int) { s.status = code }
|
func (s *syncResponseWriter) WriteHeader(code int) { s.status = code }
|
||||||
func (s *syncResponseWriter) Status() int { return s.status }
|
|
||||||
func (s *syncResponseWriter) GetBuffer() *bytes.Buffer { return s.Buffer }
|
|
||||||
func (s *syncResponseWriter) SetBuffer(buf *bytes.Buffer) { s.Buffer = buf }
|
|
||||||
|
|
||||||
// handleFnInvokeCall executes the function, for router handlers
|
// handleFnInvokeCall executes the function, for router handlers
|
||||||
func (s *Server) handleFnInvokeCall(c *gin.Context) {
|
func (s *Server) handleFnInvokeCall(c *gin.Context) {
|
||||||
@@ -79,71 +65,84 @@ func (s *Server) handleFnInvokeCall2(c *gin.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ServeFnInvoke(c *gin.Context, app *models.App, fn *models.Fn) error {
|
func (s *Server) ServeFnInvoke(c *gin.Context, app *models.App, fn *models.Fn) error {
|
||||||
writer := &syncResponseWriter{
|
return s.fnInvoke(c.Writer, c.Request, app, fn, nil)
|
||||||
headers: c.Writer.Header(),
|
}
|
||||||
|
|
||||||
|
func (s *Server) fnInvoke(resp http.ResponseWriter, req *http.Request, app *models.App, fn *models.Fn, trig *models.Trigger) error {
|
||||||
|
// TODO: we should get rid of the buffers, and stream back (saves memory (+splice), faster (splice), allows streaming, don't have to cap resp size)
|
||||||
|
// buffer the response before writing it out to client to prevent partials from trying to stream
|
||||||
|
buf := bufPool.Get().(*bytes.Buffer)
|
||||||
|
buf.Reset()
|
||||||
|
bufWriter := syncResponseWriter{
|
||||||
|
headers: resp.Header(),
|
||||||
|
status: 200,
|
||||||
|
Buffer: buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
call, err := s.agent.GetCall(agent.WithWriter(writer), // XXX (reed): order matters [for now]
|
var writer http.ResponseWriter = &bufWriter
|
||||||
agent.FromHTTPFnRequest(app, fn, c.Request))
|
writer = &jsonContentTypeTrapper{ResponseWriter: writer}
|
||||||
|
|
||||||
|
opts := []agent.CallOpt{
|
||||||
|
agent.WithWriter(writer), // XXX (reed): order matters [for now]
|
||||||
|
agent.FromHTTPFnRequest(app, fn, req),
|
||||||
|
}
|
||||||
|
if trig != nil {
|
||||||
|
opts = append(opts, agent.WithTrigger(trig))
|
||||||
|
}
|
||||||
|
|
||||||
|
call, err := s.agent.GetCall(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.fnInvoke(c, app, fn, writer, call)
|
err = s.agent.Submit(call)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// because we can...
|
||||||
|
writer.Header().Set("Content-Length", strconv.Itoa(int(buf.Len())))
|
||||||
|
|
||||||
|
// buffered response writer traps status (so we can add headers), we need to write it still
|
||||||
|
if bufWriter.status > 0 {
|
||||||
|
resp.WriteHeader(bufWriter.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
io.Copy(resp, buf)
|
||||||
|
bufPool.Put(buf) // at this point, submit returned without timing out, so we can re-use this one
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) fnInvoke(c *gin.Context, app *models.App, fn *models.Fn, writer ResponseBufferingWriter, call agent.Call) error {
|
// TODO kill this thing after removing tests for http/json/default formats
|
||||||
// TODO: we should get rid of the buffers, and stream back (saves memory (+splice), faster (splice), allows streaming, don't have to cap resp size)
|
type jsonContentTypeTrapper struct {
|
||||||
buf := bufPool.Get().(*bytes.Buffer)
|
http.ResponseWriter
|
||||||
buf.Reset()
|
committed bool
|
||||||
var submitErr error
|
}
|
||||||
defer func() {
|
|
||||||
if buf.Len() == 0 && submitErr == nil {
|
|
||||||
bufPool.Put(buf) // TODO need to ensure this is safe with Dispatch?
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
writer.SetBuffer(buf)
|
|
||||||
|
|
||||||
model := call.Model()
|
var _ http.ResponseWriter = new(jsonContentTypeTrapper) // nice compiler errors
|
||||||
{ // scope this, to disallow ctx use outside of this scope. add id for handleV1ErrorResponse logger
|
|
||||||
ctx, _ := common.LoggerWithFields(c.Request.Context(), logrus.Fields{"id": model.ID})
|
|
||||||
c.Request = c.Request.WithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
submitErr = s.agent.Submit(call)
|
func (j *jsonContentTypeTrapper) Write(b []byte) (int, error) {
|
||||||
if submitErr != nil {
|
if !j.committed {
|
||||||
// NOTE if they cancel the request then it will stop the call (kind of cool),
|
// override default content type detection behavior to add json
|
||||||
// we could filter that error out here too as right now it yells a little
|
j.detectContentType(b)
|
||||||
if submitErr == models.ErrCallTimeoutServerBusy || submitErr == models.ErrCallTimeout {
|
|
||||||
// TODO maneuver
|
|
||||||
// add this, since it means that start may not have been called [and it's relevant]
|
|
||||||
c.Writer.Header().Add("XXX-FXLB-WAIT", time.Now().Sub(time.Time(model.CreatedAt)).String())
|
|
||||||
}
|
}
|
||||||
return submitErr
|
j.committed = true
|
||||||
}
|
|
||||||
// if they don't set a content-type - detect it
|
// write inner
|
||||||
// TODO: remove this after removing all the formats (too many tests to scrub til then)
|
return j.ResponseWriter.Write(b)
|
||||||
if writer.Header().Get("Content-Type") == "" {
|
}
|
||||||
// see http.DetectContentType, the go server is supposed to do this for us but doesn't appear to?
|
|
||||||
|
func (j *jsonContentTypeTrapper) detectContentType(b []byte) {
|
||||||
|
if j.Header().Get("Content-Type") == "" {
|
||||||
|
// see http.DetectContentType
|
||||||
var contentType string
|
var contentType string
|
||||||
jsonPrefix := [1]byte{'{'} // stack allocated
|
jsonPrefix := [1]byte{'{'} // stack allocated
|
||||||
if bytes.HasPrefix(writer.GetBuffer().Bytes(), jsonPrefix[:]) {
|
if bytes.HasPrefix(b, jsonPrefix[:]) {
|
||||||
// try to detect json, since DetectContentType isn't a hipster.
|
// try to detect json, since DetectContentType isn't a hipster.
|
||||||
contentType = "application/json; charset=utf-8"
|
contentType = "application/json; charset=utf-8"
|
||||||
} else {
|
} else {
|
||||||
contentType = http.DetectContentType(writer.GetBuffer().Bytes())
|
contentType = http.DetectContentType(b)
|
||||||
}
|
}
|
||||||
writer.Header().Set("Content-Type", contentType)
|
j.Header().Set("Content-Type", contentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.Header().Set("Content-Length", strconv.Itoa(int(writer.GetBuffer().Len())))
|
|
||||||
|
|
||||||
if writer.Status() > 0 {
|
|
||||||
c.Writer.WriteHeader(writer.Status())
|
|
||||||
}
|
|
||||||
|
|
||||||
io.Copy(c.Writer, writer)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ func TestFnInvokeRunnerExecution(t *testing.T) {
|
|||||||
maxBody = 1024
|
maxBody = 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
callIds[i] = rec.Header().Get("Fn_call_id")
|
callIds[i] = rec.Header().Get("Fn-Call-Id")
|
||||||
cid := callIds[i]
|
cid := callIds[i]
|
||||||
|
|
||||||
if rec.Code != test.expectedCode {
|
if rec.Code != test.expectedCode {
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/textproto"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fnproject/fn/api"
|
"github.com/fnproject/fn/api"
|
||||||
"github.com/fnproject/fn/api/agent"
|
|
||||||
"github.com/fnproject/fn/api/models"
|
"github.com/fnproject/fn/api/models"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@@ -60,21 +61,19 @@ func (s *Server) handleTriggerHTTPFunctionCall2(c *gin.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type triggerResponseWriter struct {
|
type triggerResponseWriter struct {
|
||||||
syncResponseWriter
|
inner http.ResponseWriter
|
||||||
committed bool
|
committed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ ResponseBufferingWriter = new(triggerResponseWriter)
|
|
||||||
|
|
||||||
func (trw *triggerResponseWriter) Header() http.Header {
|
func (trw *triggerResponseWriter) Header() http.Header {
|
||||||
return trw.headers
|
return trw.inner.Header()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (trw *triggerResponseWriter) Write(b []byte) (int, error) {
|
func (trw *triggerResponseWriter) Write(b []byte) (int, error) {
|
||||||
if !trw.committed {
|
if !trw.committed {
|
||||||
trw.WriteHeader(http.StatusOK)
|
trw.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
return trw.GetBuffer().Write(b)
|
return trw.inner.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (trw *triggerResponseWriter) WriteHeader(statusCode int) {
|
func (trw *triggerResponseWriter) WriteHeader(statusCode int) {
|
||||||
@@ -83,56 +82,98 @@ func (trw *triggerResponseWriter) WriteHeader(statusCode int) {
|
|||||||
}
|
}
|
||||||
trw.committed = true
|
trw.committed = true
|
||||||
|
|
||||||
for k, vs := range trw.Header() {
|
var fnStatus int
|
||||||
if strings.HasPrefix(k, "Fn-Http-H-") {
|
realHeaders := trw.Header()
|
||||||
// TODO strip out content-length and stuff here.
|
gwHeaders := make(http.Header, len(realHeaders))
|
||||||
realHeader := strings.TrimPrefix(k, "Fn-Http-H-")
|
for k, vs := range realHeaders {
|
||||||
if realHeader != "" { // case where header is exactly the prefix
|
switch {
|
||||||
for _, v := range vs {
|
case strings.HasPrefix(k, "Fn-Http-H-"):
|
||||||
trw.Header().Del(k)
|
gwHeader := strings.TrimPrefix(k, "Fn-Http-H-")
|
||||||
trw.Header().Add(realHeader, v)
|
if gwHeader != "" { // case where header is exactly the prefix
|
||||||
|
gwHeaders[gwHeader] = vs
|
||||||
|
}
|
||||||
|
case k == "Fn-Http-Status":
|
||||||
|
if len(vs) > 0 {
|
||||||
|
statusInt, err := strconv.Atoi(vs[0])
|
||||||
|
if err == nil {
|
||||||
|
fnStatus = statusInt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case k == "Content-Type", k == "Fn-Call-Id":
|
||||||
|
gwHeaders[k] = vs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX(reed): this is O(3n)... yes sorry for making it work without making it perfect first
|
||||||
|
for k := range realHeaders {
|
||||||
|
realHeaders.Del(k)
|
||||||
|
}
|
||||||
|
for k, vs := range gwHeaders {
|
||||||
|
realHeaders[k] = vs
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX(reed): simplify / add tests for these behaviors...
|
||||||
gatewayStatus := 200
|
gatewayStatus := 200
|
||||||
|
|
||||||
if statusCode >= 400 {
|
if statusCode >= 400 {
|
||||||
gatewayStatus = 502
|
gatewayStatus = 502
|
||||||
|
} else if fnStatus > 0 {
|
||||||
|
gatewayStatus = fnStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
status := trw.Header().Get("Fn-Http-Status")
|
trw.inner.WriteHeader(gatewayStatus)
|
||||||
if status != "" {
|
|
||||||
statusInt, err := strconv.Atoi(status)
|
|
||||||
if err == nil {
|
|
||||||
gatewayStatus = statusInt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trw.WriteHeader(gatewayStatus)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//ServeHTTPTr igger serves an HTTP trigger for a given app/fn/trigger based on the current request
|
var skipTriggerHeaders = map[string]bool{
|
||||||
|
"Connection": true,
|
||||||
|
"Keep-Alive": true,
|
||||||
|
"Trailer": true,
|
||||||
|
"Transfer-Encoding": true,
|
||||||
|
"TE": true,
|
||||||
|
"Upgrade": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
func reqURL(req *http.Request) string {
|
||||||
|
if req.URL.Scheme == "" {
|
||||||
|
if req.TLS == nil {
|
||||||
|
req.URL.Scheme = "http"
|
||||||
|
} else {
|
||||||
|
req.URL.Scheme = "https"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.URL.Host == "" {
|
||||||
|
req.URL.Host = req.Host
|
||||||
|
}
|
||||||
|
return req.URL.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServeHTTPTrigger serves an HTTP trigger for a given app/fn/trigger based on the current request
|
||||||
// This is exported to allow extensions to handle their own trigger naming and publishing
|
// This is exported to allow extensions to handle their own trigger naming and publishing
|
||||||
func (s *Server) ServeHTTPTrigger(c *gin.Context, app *models.App, fn *models.Fn, trigger *models.Trigger) error {
|
func (s *Server) ServeHTTPTrigger(c *gin.Context, app *models.App, fn *models.Fn, trigger *models.Trigger) error {
|
||||||
triggerWriter := &triggerResponseWriter{
|
// transpose trigger headers into the request
|
||||||
syncResponseWriter{
|
req := c.Request
|
||||||
headers: c.Writer.Header()},
|
headers := make(http.Header, len(req.Header))
|
||||||
false,
|
for k, vs := range req.Header {
|
||||||
|
// should be generally unnecessary but to be doubly sure.
|
||||||
|
k = textproto.CanonicalMIMEHeaderKey(k)
|
||||||
|
if skipTriggerHeaders[k] {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
// GetCall can mod headers, assign an id, look up the route/app (cached),
|
switch k {
|
||||||
// strip params, etc.
|
case "Content-Type":
|
||||||
// this should happen ASAP to turn app name to app ID
|
default:
|
||||||
|
k = fmt.Sprintf("Fn-Http-H-%s", k)
|
||||||
// GetCall can mod headers, assign an id, look up the route/app (cached),
|
|
||||||
// strip params, etc.
|
|
||||||
|
|
||||||
call, err := s.agent.GetCall(agent.WithWriter(triggerWriter), // XXX (reed): order matters [for now]
|
|
||||||
agent.FromHTTPTriggerRequest(app, fn, trigger, c.Request))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return s.fnInvoke(c, app, fn, triggerWriter, call)
|
headers[k] = vs
|
||||||
|
}
|
||||||
|
requestURL := reqURL(req)
|
||||||
|
|
||||||
|
headers.Set("Fn-Http-Method", req.Method)
|
||||||
|
headers.Set("Fn-Http-Request-Url", requestURL)
|
||||||
|
headers.Set("Fn-Intent", "httprequest")
|
||||||
|
req.Header = headers
|
||||||
|
|
||||||
|
// trap the headers and rewrite them for http trigger
|
||||||
|
rw := &triggerResponseWriter{inner: c.Writer}
|
||||||
|
|
||||||
|
return s.fnInvoke(rw, req, app, fn, trigger)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/fnproject/fn/api/logs"
|
"github.com/fnproject/fn/api/logs"
|
||||||
"github.com/fnproject/fn/api/models"
|
"github.com/fnproject/fn/api/models"
|
||||||
"github.com/fnproject/fn/api/mqs"
|
"github.com/fnproject/fn/api/mqs"
|
||||||
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
func envTweaker(name, value string) func() {
|
func envTweaker(name, value string) func() {
|
||||||
@@ -273,10 +274,11 @@ func TestTriggerRunnerExecution(t *testing.T) {
|
|||||||
httpDneRegistryFn := &models.Fn{ID: "http_dnereg_fn_id", Name: "http_dnereg_fn", AppID: app.ID, Image: rImgBs2, Format: "http", ResourceConfig: models.ResourceConfig{Memory: 64, Timeout: 30, IdleTimeout: 30}, Config: rCfg}
|
httpDneRegistryFn := &models.Fn{ID: "http_dnereg_fn_id", Name: "http_dnereg_fn", AppID: app.ID, Image: rImgBs2, Format: "http", ResourceConfig: models.ResourceConfig{Memory: 64, Timeout: 30, IdleTimeout: 30}, Config: rCfg}
|
||||||
jsonFn := &models.Fn{ID: "json_fn_id", Name: "json_fn", AppID: app.ID, Image: rImg, Format: "json", ResourceConfig: models.ResourceConfig{Memory: 64, Timeout: 30, IdleTimeout: 30}, Config: rCfg}
|
jsonFn := &models.Fn{ID: "json_fn_id", Name: "json_fn", AppID: app.ID, Image: rImg, Format: "json", ResourceConfig: models.ResourceConfig{Memory: 64, Timeout: 30, IdleTimeout: 30}, Config: rCfg}
|
||||||
oomFn := &models.Fn{ID: "http_oom_fn_id", Name: "http_fn", AppID: app.ID, Image: rImg, Format: "http", ResourceConfig: models.ResourceConfig{Memory: 8, Timeout: 30, IdleTimeout: 30}, Config: rCfg}
|
oomFn := &models.Fn{ID: "http_oom_fn_id", Name: "http_fn", AppID: app.ID, Image: rImg, Format: "http", ResourceConfig: models.ResourceConfig{Memory: 8, Timeout: 30, IdleTimeout: 30}, Config: rCfg}
|
||||||
|
httpStreamFn := &models.Fn{ID: "http_stream_fn_id", Name: "http_stream_fn", AppID: app.ID, Image: rImg, Format: "http-stream", ResourceConfig: models.ResourceConfig{Memory: 64, Timeout: 30, IdleTimeout: 30}, Config: rCfg}
|
||||||
|
|
||||||
ds := datastore.NewMockInit(
|
ds := datastore.NewMockInit(
|
||||||
[]*models.App{app},
|
[]*models.App{app},
|
||||||
[]*models.Fn{defaultFn, defaultDneFn, httpDneRegistryFn, oomFn, httpFn, jsonFn, httpDneFn},
|
[]*models.Fn{defaultFn, defaultDneFn, httpDneRegistryFn, oomFn, httpFn, jsonFn, httpDneFn, httpStreamFn},
|
||||||
[]*models.Trigger{
|
[]*models.Trigger{
|
||||||
{ID: "1", Name: "1", Source: "/", Type: "http", AppID: app.ID, FnID: defaultFn.ID},
|
{ID: "1", Name: "1", Source: "/", Type: "http", AppID: app.ID, FnID: defaultFn.ID},
|
||||||
{ID: "2", Name: "2", Source: "/myhot", Type: "http", AppID: app.ID, FnID: httpFn.ID},
|
{ID: "2", Name: "2", Source: "/myhot", Type: "http", AppID: app.ID, FnID: httpFn.ID},
|
||||||
@@ -290,6 +292,7 @@ func TestTriggerRunnerExecution(t *testing.T) {
|
|||||||
{ID: "10", Name: "10", Source: "/mybigoutputcold", Type: "http", AppID: app.ID, FnID: defaultFn.ID},
|
{ID: "10", Name: "10", Source: "/mybigoutputcold", Type: "http", AppID: app.ID, FnID: defaultFn.ID},
|
||||||
{ID: "11", Name: "11", Source: "/mybigoutputhttp", Type: "http", AppID: app.ID, FnID: httpFn.ID},
|
{ID: "11", Name: "11", Source: "/mybigoutputhttp", Type: "http", AppID: app.ID, FnID: httpFn.ID},
|
||||||
{ID: "12", Name: "12", Source: "/mybigoutputjson", Type: "http", AppID: app.ID, FnID: jsonFn.ID},
|
{ID: "12", Name: "12", Source: "/mybigoutputjson", Type: "http", AppID: app.ID, FnID: jsonFn.ID},
|
||||||
|
{ID: "13", Name: "13", Source: "/httpstream", Type: "http", AppID: app.ID, FnID: httpStreamFn.ID},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
ls := logs.NewMock()
|
ls := logs.NewMock()
|
||||||
@@ -310,7 +313,7 @@ func TestTriggerRunnerExecution(t *testing.T) {
|
|||||||
crasher := `{"echoContent": "_TRX_ID_", "isDebug": true, "isCrash": true}` // crash container
|
crasher := `{"echoContent": "_TRX_ID_", "isDebug": true, "isCrash": true}` // crash container
|
||||||
oomer := `{"echoContent": "_TRX_ID_", "isDebug": true, "allocateMemory": 12000000}` // ask for 12MB
|
oomer := `{"echoContent": "_TRX_ID_", "isDebug": true, "allocateMemory": 12000000}` // ask for 12MB
|
||||||
badHot := `{"echoContent": "_TRX_ID_", "invalidResponse": true, "isDebug": true}` // write a not json/http as output
|
badHot := `{"echoContent": "_TRX_ID_", "invalidResponse": true, "isDebug": true}` // write a not json/http as output
|
||||||
ok := `{"echoContent": "_TRX_ID_", "isDebug": true}` // good response / ok
|
ok := `{"echoContent": "_TRX_ID_", "responseContentType": "application/json; charset=utf-8", "isDebug": true}` // good response / ok
|
||||||
respTypeLie := `{"echoContent": "_TRX_ID_", "responseContentType": "foo/bar", "isDebug": true}` // Content-Type: foo/bar
|
respTypeLie := `{"echoContent": "_TRX_ID_", "responseContentType": "foo/bar", "isDebug": true}` // Content-Type: foo/bar
|
||||||
respTypeJason := `{"echoContent": "_TRX_ID_", "jasonContentType": "foo/bar", "isDebug": true}` // Content-Type: foo/bar
|
respTypeJason := `{"echoContent": "_TRX_ID_", "jasonContentType": "foo/bar", "isDebug": true}` // Content-Type: foo/bar
|
||||||
|
|
||||||
@@ -319,8 +322,26 @@ func TestTriggerRunnerExecution(t *testing.T) {
|
|||||||
bigoutput := `{"echoContent": "_TRX_ID_", "isDebug": true, "trailerRepeat": 1000}` // 1000 trailers to exceed 2K
|
bigoutput := `{"echoContent": "_TRX_ID_", "isDebug": true, "trailerRepeat": 1000}` // 1000 trailers to exceed 2K
|
||||||
smalloutput := `{"echoContent": "_TRX_ID_", "isDebug": true, "trailerRepeat": 1}` // 1 trailer < 2K
|
smalloutput := `{"echoContent": "_TRX_ID_", "isDebug": true, "trailerRepeat": 1}` // 1 trailer < 2K
|
||||||
|
|
||||||
|
statusChecker := `{"echoContent": "_TRX_ID_", "isDebug": true, "responseCode":202, "responseContentType": "application/json; charset=utf-8"}`
|
||||||
|
|
||||||
|
fooHeader := map[string][]string{"Content-Type": {"application/hateson"}, "Test-Header": {"foo"}}
|
||||||
|
expFooHeaders := map[string][]string{"Content-Type": {"application/hateson"}, "Return-Header": {"foo", "bar"}}
|
||||||
|
expFooHeadersBody := `{"echoContent": "_TRX_ID_",
|
||||||
|
"expectHeaders": {
|
||||||
|
"Content-Type":["application/hateson"],
|
||||||
|
"Fn-Http-H-Test-Header":["foo"],
|
||||||
|
"Fn-Http-Method":["POST"],
|
||||||
|
"Fn-Http-Request-Url":["http://127.0.0.1:8080/t/myapp/httpstream"]
|
||||||
|
},
|
||||||
|
"returnHeaders": {
|
||||||
|
"Return-Header":["foo","bar"]
|
||||||
|
},
|
||||||
|
"responseContentType":"application/hateson",
|
||||||
|
"isDebug": true}`
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
path string
|
path string
|
||||||
|
headers map[string][]string
|
||||||
body string
|
body string
|
||||||
method string
|
method string
|
||||||
expectedCode int
|
expectedCode int
|
||||||
@@ -328,34 +349,47 @@ func TestTriggerRunnerExecution(t *testing.T) {
|
|||||||
expectedErrSubStr string
|
expectedErrSubStr string
|
||||||
expectedLogsSubStr []string
|
expectedLogsSubStr []string
|
||||||
}{
|
}{
|
||||||
{"/t/myapp/", ok, "GET", http.StatusOK, expHeaders, "", nil},
|
{"/t/myapp/", nil, ok, "GET", http.StatusOK, expHeaders, "", nil},
|
||||||
|
|
||||||
{"/t/myapp/myhot", badHot, "GET", http.StatusBadGateway, expHeaders, "invalid http response", nil},
|
{"/t/myapp/myhot", nil, badHot, "GET", http.StatusBadGateway, expHeaders, "invalid http response", nil},
|
||||||
// hot container now back to normal:
|
// hot container now back to normal:
|
||||||
{"/t/myapp/myhot", ok, "GET", http.StatusOK, expHeaders, "", nil},
|
{"/t/myapp/myhot", nil, ok, "GET", http.StatusOK, expHeaders, "", nil},
|
||||||
|
|
||||||
{"/t/myapp/myhotjason", badHot, "GET", http.StatusBadGateway, expHeaders, "invalid json response", nil},
|
{"/t/myapp/myhotjason", nil, badHot, "GET", http.StatusBadGateway, expHeaders, "invalid json response", nil},
|
||||||
// hot container now back to normal:
|
// hot container now back to normal:
|
||||||
{"/t/myapp/myhotjason", ok, "GET", http.StatusOK, expHeaders, "", nil},
|
{"/t/myapp/myhotjason", nil, ok, "GET", http.StatusOK, expHeaders, "", nil},
|
||||||
|
|
||||||
{"/t/myapp/myhot", respTypeLie, "GET", http.StatusOK, expCTHeaders, "", nil},
|
{"/t/myapp/myhot", nil, respTypeLie, "GET", http.StatusOK, expCTHeaders, "", nil},
|
||||||
{"/t/myapp/myhotjason", respTypeLie, "GET", http.StatusOK, expCTHeaders, "", nil},
|
{"/t/myapp/myhotjason", nil, respTypeLie, "GET", http.StatusOK, expCTHeaders, "", nil},
|
||||||
{"/t/myapp/myhotjason", respTypeJason, "GET", http.StatusOK, expCTHeaders, "", nil},
|
{"/t/myapp/myhotjason", nil, respTypeJason, "GET", http.StatusOK, expCTHeaders, "", nil},
|
||||||
|
|
||||||
{"/t/myapp/myroute", ok, "GET", http.StatusOK, expHeaders, "", nil},
|
// XXX(reed): we test a lot of stuff in invoke, we really only need to test headers / status code here dude...
|
||||||
{"/t/myapp/myerror", crasher, "GET", http.StatusBadGateway, expHeaders, "container exit code 1", nil},
|
{"/t/myapp/httpstream", nil, ok, "POST", http.StatusOK, expHeaders, "", nil},
|
||||||
{"/t/myapp/mydne", ``, "GET", http.StatusNotFound, nil, "pull access denied", nil},
|
{"/t/myapp/httpstream", nil, statusChecker, "POST", 202, expHeaders, "", nil},
|
||||||
{"/t/myapp/mydnehot", ``, "GET", http.StatusNotFound, nil, "pull access denied", nil},
|
{"/t/myapp/httpstream", fooHeader, expFooHeadersBody, "POST", http.StatusOK, expFooHeaders, "", nil},
|
||||||
{"/t/myapp/mydneregistry", ``, "GET", http.StatusInternalServerError, nil, "connection refused", nil},
|
// NOTE: we can't test bad response framing anymore easily (eg invalid http response), should we even worry about it?
|
||||||
{"/t/myapp/myoom", oomer, "GET", http.StatusBadGateway, nil, "container out of memory", nil},
|
{"/t/myapp/httpstream", nil, respTypeLie, "POST", http.StatusOK, expCTHeaders, "", nil},
|
||||||
{"/t/myapp/myhot", multiLog, "GET", http.StatusOK, nil, "", multiLogExpectHot},
|
//{"/t/myapp/httpstream", nil, crasher, "POST", http.StatusBadGateway, expHeaders, "error receiving function response", nil},
|
||||||
{"/t/myapp/", multiLog, "GET", http.StatusOK, nil, "", multiLogExpectCold},
|
//// XXX(reed): we could stop buffering function responses so that we can stream things?
|
||||||
{"/t/myapp/mybigoutputjson", bigoutput, "GET", http.StatusBadGateway, nil, "function response too large", nil},
|
//{"/t/myapp/httpstream", nil, bigoutput, "POST", http.StatusBadGateway, nil, "function response too large", nil},
|
||||||
{"/t/myapp/mybigoutputjson", smalloutput, "GET", http.StatusOK, nil, "", nil},
|
//{"/t/myapp/httpstream", nil, smalloutput, "POST", http.StatusOK, expHeaders, "", nil},
|
||||||
{"/t/myapp/mybigoutputhttp", bigoutput, "GET", http.StatusBadGateway, nil, "", nil},
|
//// XXX(reed): meh we really should try to get oom out, but maybe it's better left to the logs?
|
||||||
{"/t/myapp/mybigoutputhttp", smalloutput, "GET", http.StatusOK, nil, "", nil},
|
//{"/t/myapp/httpstream", nil, oomer, "POST", http.StatusBadGateway, nil, "error receiving function response", nil},
|
||||||
{"/t/myapp/mybigoutputcold", bigoutput, "GET", http.StatusBadGateway, nil, "", nil},
|
|
||||||
{"/t/myapp/mybigoutputcold", smalloutput, "GET", http.StatusOK, nil, "", nil},
|
{"/t/myapp/myroute", nil, ok, "GET", http.StatusOK, expHeaders, "", nil},
|
||||||
|
{"/t/myapp/myerror", nil, crasher, "GET", http.StatusBadGateway, expHeaders, "container exit code 1", nil},
|
||||||
|
{"/t/myapp/mydne", nil, ``, "GET", http.StatusNotFound, nil, "pull access denied", nil},
|
||||||
|
{"/t/myapp/mydnehot", nil, ``, "GET", http.StatusNotFound, nil, "pull access denied", nil},
|
||||||
|
{"/t/myapp/mydneregistry", nil, ``, "GET", http.StatusInternalServerError, nil, "connection refused", nil},
|
||||||
|
{"/t/myapp/myoom", nil, oomer, "GET", http.StatusBadGateway, nil, "container out of memory", nil},
|
||||||
|
{"/t/myapp/myhot", nil, multiLog, "GET", http.StatusOK, nil, "", multiLogExpectHot},
|
||||||
|
{"/t/myapp/", nil, multiLog, "GET", http.StatusOK, nil, "", multiLogExpectCold},
|
||||||
|
{"/t/myapp/mybigoutputjson", nil, bigoutput, "GET", http.StatusBadGateway, nil, "function response too large", nil},
|
||||||
|
{"/t/myapp/mybigoutputjson", nil, smalloutput, "GET", http.StatusOK, nil, "", nil},
|
||||||
|
{"/t/myapp/mybigoutputhttp", nil, bigoutput, "GET", http.StatusBadGateway, nil, "", nil},
|
||||||
|
{"/t/myapp/mybigoutputhttp", nil, smalloutput, "GET", http.StatusOK, nil, "", nil},
|
||||||
|
{"/t/myapp/mybigoutputcold", nil, bigoutput, "GET", http.StatusBadGateway, nil, "", nil},
|
||||||
|
{"/t/myapp/mybigoutputcold", nil, smalloutput, "GET", http.StatusOK, nil, "", nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
callIds := make([]string, len(testCases))
|
callIds := make([]string, len(testCases))
|
||||||
@@ -364,7 +398,11 @@ func TestTriggerRunnerExecution(t *testing.T) {
|
|||||||
t.Run(fmt.Sprintf("Test_%d_%s", i, strings.Replace(test.path, "/", "_", -1)), func(t *testing.T) {
|
t.Run(fmt.Sprintf("Test_%d_%s", i, strings.Replace(test.path, "/", "_", -1)), func(t *testing.T) {
|
||||||
trx := fmt.Sprintf("_trx_%d_", i)
|
trx := fmt.Sprintf("_trx_%d_", i)
|
||||||
body := strings.NewReader(strings.Replace(test.body, "_TRX_ID_", trx, 1))
|
body := strings.NewReader(strings.Replace(test.body, "_TRX_ID_", trx, 1))
|
||||||
_, rec := routerRequest(t, srv.Router, test.method, test.path, body)
|
req := createRequest(t, test.method, test.path, body)
|
||||||
|
if test.headers != nil {
|
||||||
|
req.Header = test.headers
|
||||||
|
}
|
||||||
|
_, rec := routerRequest2(t, srv.Router, req)
|
||||||
respBytes, _ := ioutil.ReadAll(rec.Body)
|
respBytes, _ := ioutil.ReadAll(rec.Body)
|
||||||
respBody := string(respBytes)
|
respBody := string(respBytes)
|
||||||
maxBody := len(respBody)
|
maxBody := len(respBody)
|
||||||
@@ -372,7 +410,7 @@ func TestTriggerRunnerExecution(t *testing.T) {
|
|||||||
maxBody = 1024
|
maxBody = 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
callIds[i] = rec.Header().Get("Fn_call_id")
|
callIds[i] = rec.Header().Get("Fn-Call-Id")
|
||||||
|
|
||||||
if rec.Code != test.expectedCode {
|
if rec.Code != test.expectedCode {
|
||||||
isFailure = true
|
isFailure = true
|
||||||
@@ -396,10 +434,10 @@ func TestTriggerRunnerExecution(t *testing.T) {
|
|||||||
|
|
||||||
if test.expectedHeaders != nil {
|
if test.expectedHeaders != nil {
|
||||||
for name, header := range test.expectedHeaders {
|
for name, header := range test.expectedHeaders {
|
||||||
if header[0] != rec.Header().Get(name) {
|
if !reflect.DeepEqual(header, rec.Header()[name]) {
|
||||||
isFailure = true
|
isFailure = true
|
||||||
t.Errorf("Test %d: Expected header `%s` to be `%s` but was `%s`. body: `%s`",
|
t.Errorf("Test %d: Expected header `%s` to be `%v` but was `%v`. body: `%s`",
|
||||||
i, name, header[0], rec.Header().Get(name), respBody)
|
i, name, header, rec.Header()[name], respBody)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,14 +204,14 @@ curl -v localhost:8080/r/newapp/envsync
|
|||||||
> Accept: */*
|
> Accept: */*
|
||||||
>
|
>
|
||||||
< HTTP/1.1 200 OK
|
< HTTP/1.1 200 OK
|
||||||
< Fn_call_id: f5621e8b-725a-4ba9-8323-b8cdc02ce37e
|
< Fn-Call-Id: f5621e8b-725a-4ba9-8323-b8cdc02ce37e
|
||||||
< Date: Fri, 02 Jun 2017 12:31:30 GMT
|
< Date: Fri, 02 Jun 2017 12:31:30 GMT
|
||||||
< Content-Length: 489
|
< Content-Length: 489
|
||||||
< Content-Type: text/plain; charset=utf-8
|
< Content-Type: text/plain; charset=utf-8
|
||||||
<
|
<
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
Corresponding HTTP header is `Fn_call_id`.
|
Corresponding HTTP header is `Fn-Call-Id`.
|
||||||
|
|
||||||
### Per-route calls
|
### Per-route calls
|
||||||
|
|
||||||
|
|||||||
2
images/fn-test-utils/Gopkg.lock
generated
2
images/fn-test-utils/Gopkg.lock
generated
@@ -8,7 +8,7 @@
|
|||||||
".",
|
".",
|
||||||
"utils"
|
"utils"
|
||||||
]
|
]
|
||||||
revision = "d1fa834929bb1579d770eded860a3a54e1f3502b"
|
revision = "bd03f2c17b4d9e43525829d194174b35b5c47b54"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ type AppRequest struct {
|
|||||||
PostErrGarbage string `json:"postErrGarbage,omitempty"`
|
PostErrGarbage string `json:"postErrGarbage,omitempty"`
|
||||||
// test empty body
|
// test empty body
|
||||||
IsEmptyBody bool `json:"isEmptyBody,omitempty"`
|
IsEmptyBody bool `json:"isEmptyBody,omitempty"`
|
||||||
|
// test headers that come into function
|
||||||
|
ExpectHeaders map[string][]string `json:"expectHeaders,omitempty"`
|
||||||
|
// send some headers out explicitly
|
||||||
|
ReturnHeaders map[string][]string `json:"returnHeaders,omitempty"`
|
||||||
|
|
||||||
// TODO: simulate slow read/slow write
|
// TODO: simulate slow read/slow write
|
||||||
// TODO: simulate partial IO write/read
|
// TODO: simulate partial IO write/read
|
||||||
// TODO: simulate high cpu usage (async and sync)
|
// TODO: simulate high cpu usage (async and sync)
|
||||||
@@ -119,11 +124,6 @@ func AppHandler(ctx context.Context, in io.Reader, out io.Writer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func finalizeRequest(out io.Writer, req *AppRequest, resp *AppResponse) {
|
func finalizeRequest(out io.Writer, req *AppRequest, resp *AppResponse) {
|
||||||
// custom response code
|
|
||||||
if req.ResponseCode != 0 {
|
|
||||||
fdk.WriteStatus(out, req.ResponseCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom content type
|
// custom content type
|
||||||
if req.ResponseContentType != "" {
|
if req.ResponseContentType != "" {
|
||||||
fdk.SetHeader(out, "Content-Type", req.ResponseContentType)
|
fdk.SetHeader(out, "Content-Type", req.ResponseContentType)
|
||||||
@@ -137,6 +137,19 @@ func finalizeRequest(out io.Writer, req *AppRequest, resp *AppResponse) {
|
|||||||
fdk.SetHeader(out, "Content-Type", req.JasonContentType)
|
fdk.SetHeader(out, "Content-Type", req.JasonContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.ReturnHeaders != nil {
|
||||||
|
for k, vs := range req.ReturnHeaders {
|
||||||
|
for _, v := range vs {
|
||||||
|
fdk.AddHeader(out, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom response code
|
||||||
|
if req.ResponseCode != 0 {
|
||||||
|
fdk.WriteStatus(out, req.ResponseCode)
|
||||||
|
}
|
||||||
|
|
||||||
if !req.IsEmptyBody {
|
if !req.IsEmptyBody {
|
||||||
json.NewEncoder(out).Encode(resp)
|
json.NewEncoder(out).Encode(resp)
|
||||||
}
|
}
|
||||||
@@ -155,6 +168,7 @@ func processRequest(ctx context.Context, in io.Reader) (*AppRequest, *AppRespons
|
|||||||
log.Printf("Received format %v", format)
|
log.Printf("Received format %v", format)
|
||||||
log.Printf("Received request %#v", request)
|
log.Printf("Received request %#v", request)
|
||||||
log.Printf("Received headers %v", fnctx.Header)
|
log.Printf("Received headers %v", fnctx.Header)
|
||||||
|
log.Printf("Received http headers %v", fnctx.HTTPHeader)
|
||||||
log.Printf("Received config %v", fnctx.Config)
|
log.Printf("Received config %v", fnctx.Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,6 +233,23 @@ func processRequest(ctx context.Context, in io.Reader) (*AppRequest, *AppRespons
|
|||||||
log.Fatalln("Crash requested")
|
log.Fatalln("Crash requested")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if request.ExpectHeaders != nil {
|
||||||
|
for name, header := range request.ExpectHeaders {
|
||||||
|
if strings.HasPrefix(name, "Fn-Http-H-") {
|
||||||
|
// if it's an http header, make sure our other bucket works.
|
||||||
|
// idk this seems like a weird good idea, maybe we should only test/expose one or the other...
|
||||||
|
if h2 := fnctx.HTTPHeader.Get(strings.TrimPrefix(name, "Fn-Http-H-")); header[0] != h2 {
|
||||||
|
log.Fatalf("Expected http header `%s` to be `%s` but was `%s`.",
|
||||||
|
name, header[0], h2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if h2 := fnctx.Header.Get(name); header[0] != h2 {
|
||||||
|
log.Fatalf("Expected header `%s` to be `%s` but was `%s`",
|
||||||
|
name, header[0], h2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resp := AppResponse{
|
resp := AppResponse{
|
||||||
Data: data,
|
Data: data,
|
||||||
Request: request,
|
Request: request,
|
||||||
|
|||||||
33
vendor/github.com/fnproject/fdk-go/circle.yml
generated
vendored
Normal file
33
vendor/github.com/fnproject/fdk-go/circle.yml
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
version: 2
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
docker:
|
||||||
|
- image: circleci/golang:1.11.0
|
||||||
|
working_directory: ~/fdk-go
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- setup_remote_docker:
|
||||||
|
docker_layer_caching: true
|
||||||
|
- run: docker version
|
||||||
|
- run: docker pull fnproject/fnserver
|
||||||
|
# installing Fn CLI and starting the Fn server
|
||||||
|
- run:
|
||||||
|
command: |
|
||||||
|
curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh
|
||||||
|
- run:
|
||||||
|
command: fn build
|
||||||
|
working_directory: examples/hello
|
||||||
|
- deploy:
|
||||||
|
command: |
|
||||||
|
if [[ "${CIRCLE_BRANCH}" == "master" && -z "${CIRCLE_PR_REPONAME}" ]]; then
|
||||||
|
func_version=$(awk '/^version:/ { print $2; }' func.yaml)
|
||||||
|
printenv DOCKER_PASS | docker login -u ${DOCKER_USER} --password-stdin
|
||||||
|
git config --global user.email "ci@fnproject.com"
|
||||||
|
git config --global user.name "CI"
|
||||||
|
git branch --set-upstream-to=origin/${CIRCLE_BRANCH} ${CIRCLE_BRANCH}
|
||||||
|
docker tag "hello:${func_version}" "fnproject/fdk-go-hello:${func_version}"
|
||||||
|
docker tag "hello:${func_version}" "fnproject/fdk-go-hello:latest"
|
||||||
|
docker push "fnproject/fdk-go-hello:${func_version}"
|
||||||
|
docker push "fnproject/fdk-go-hello:latest"
|
||||||
|
fi
|
||||||
|
working_directory: examples/hello
|
||||||
2
vendor/github.com/fnproject/fdk-go/examples/hello/Gopkg.lock
generated
vendored
2
vendor/github.com/fnproject/fdk-go/examples/hello/Gopkg.lock
generated
vendored
@@ -8,7 +8,7 @@
|
|||||||
".",
|
".",
|
||||||
"utils"
|
"utils"
|
||||||
]
|
]
|
||||||
revision = "5d768b2006f11737b6a69a758ddd6d2fac04923e"
|
revision = "c6ce6afbce0935ffdf0e228471406d0f966736a5"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
|
|||||||
15
vendor/github.com/fnproject/fdk-go/examples/hello/func.go
generated
vendored
15
vendor/github.com/fnproject/fdk-go/examples/hello/func.go
generated
vendored
@@ -13,20 +13,17 @@ func main() {
|
|||||||
fdk.Handle(fdk.HandlerFunc(myHandler))
|
fdk.Handle(fdk.HandlerFunc(myHandler))
|
||||||
}
|
}
|
||||||
|
|
||||||
func myHandler(ctx context.Context, in io.Reader, out io.Writer) {
|
type Person struct {
|
||||||
var person struct {
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
json.NewDecoder(in).Decode(&person)
|
|
||||||
if person.Name == "" {
|
|
||||||
person.Name = "World"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func myHandler(ctx context.Context, in io.Reader, out io.Writer) {
|
||||||
|
p := &Person{Name: "World"}
|
||||||
|
json.NewDecoder(in).Decode(p)
|
||||||
msg := struct {
|
msg := struct {
|
||||||
Msg string `json:"message"`
|
Msg string `json:"message"`
|
||||||
}{
|
}{
|
||||||
Msg: fmt.Sprintf("Hello %s", person.Name),
|
Msg: fmt.Sprintf("Hello %s", p.Name),
|
||||||
}
|
}
|
||||||
|
|
||||||
json.NewEncoder(out).Encode(&msg)
|
json.NewEncoder(out).Encode(&msg)
|
||||||
}
|
}
|
||||||
|
|||||||
6
vendor/github.com/fnproject/fdk-go/examples/hello/func.yaml
generated
vendored
Normal file
6
vendor/github.com/fnproject/fdk-go/examples/hello/func.yaml
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
schema_version: 20180708
|
||||||
|
name: hello
|
||||||
|
version: 0.0.1
|
||||||
|
runtime: go
|
||||||
|
entrypoint: ./func
|
||||||
|
format: http-stream
|
||||||
14
vendor/github.com/fnproject/fdk-go/fdk.go
generated
vendored
14
vendor/github.com/fnproject/fdk-go/fdk.go
generated
vendored
@@ -24,6 +24,7 @@ func (f HandlerFunc) Serve(ctx context.Context, in io.Reader, out io.Writer) {
|
|||||||
func Context(ctx context.Context) *Ctx {
|
func Context(ctx context.Context) *Ctx {
|
||||||
utilsCtx := utils.Context(ctx)
|
utilsCtx := utils.Context(ctx)
|
||||||
return &Ctx{
|
return &Ctx{
|
||||||
|
HTTPHeader: utilsCtx.HTTPHeader,
|
||||||
Header: utilsCtx.Header,
|
Header: utilsCtx.Header,
|
||||||
Config: utilsCtx.Config,
|
Config: utilsCtx.Config,
|
||||||
RequestURL: utilsCtx.RequestURL,
|
RequestURL: utilsCtx.RequestURL,
|
||||||
@@ -33,6 +34,7 @@ func Context(ctx context.Context) *Ctx {
|
|||||||
|
|
||||||
func WithContext(ctx context.Context, fnctx *Ctx) context.Context {
|
func WithContext(ctx context.Context, fnctx *Ctx) context.Context {
|
||||||
utilsCtx := &utils.Ctx{
|
utilsCtx := &utils.Ctx{
|
||||||
|
HTTPHeader: fnctx.HTTPHeader,
|
||||||
Header: fnctx.Header,
|
Header: fnctx.Header,
|
||||||
Config: fnctx.Config,
|
Config: fnctx.Config,
|
||||||
RequestURL: fnctx.RequestURL,
|
RequestURL: fnctx.RequestURL,
|
||||||
@@ -43,7 +45,12 @@ func WithContext(ctx context.Context, fnctx *Ctx) context.Context {
|
|||||||
|
|
||||||
// Ctx provides access to Config and Headers from fn.
|
// Ctx provides access to Config and Headers from fn.
|
||||||
type Ctx struct {
|
type Ctx struct {
|
||||||
|
// Header are the unmodified headers as sent to the container, see
|
||||||
|
// HTTPHeader for specific trigger headers
|
||||||
Header http.Header
|
Header http.Header
|
||||||
|
// HTTPHeader are the request headers as they appear on the original HTTP request,
|
||||||
|
// for an http trigger.
|
||||||
|
HTTPHeader http.Header
|
||||||
Config map[string]string
|
Config map[string]string
|
||||||
RequestURL string
|
RequestURL string
|
||||||
Method string
|
Method string
|
||||||
@@ -78,5 +85,12 @@ func WriteStatus(out io.Writer, status int) {
|
|||||||
// function and fn server via any of the supported formats.
|
// function and fn server via any of the supported formats.
|
||||||
func Handle(handler Handler) {
|
func Handle(handler Handler) {
|
||||||
format, _ := os.LookupEnv("FN_FORMAT")
|
format, _ := os.LookupEnv("FN_FORMAT")
|
||||||
|
|
||||||
|
path := os.Getenv("FN_LISTENER")
|
||||||
|
if path != "" {
|
||||||
|
utils.StartHTTPServer(handler, path, format)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
utils.Do(handler, format, os.Stdin, os.Stdout)
|
utils.Do(handler, format, os.Stdin, os.Stdout)
|
||||||
}
|
}
|
||||||
|
|||||||
168
vendor/github.com/fnproject/fdk-go/utils/httpstream.go
generated
vendored
Normal file
168
vendor/github.com/fnproject/fdk-go/utils/httpstream.go
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// in case we go over the timeout, need to use a pool since prev buffer may not be freed
|
||||||
|
var bufPool = &sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}
|
||||||
|
|
||||||
|
type HTTPHandler struct {
|
||||||
|
handler Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
buf := bufPool.Get().(*bytes.Buffer)
|
||||||
|
defer bufPool.Put(buf)
|
||||||
|
|
||||||
|
resp := Response{
|
||||||
|
Writer: buf,
|
||||||
|
Status: 200,
|
||||||
|
Header: make(http.Header), // XXX(reed): pool these too
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := WithContext(r.Context(), &Ctx{
|
||||||
|
Config: BuildConfig(),
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx, cancel := decapHeaders(ctx, r)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
h.handler.Serve(ctx, r.Body, &resp)
|
||||||
|
|
||||||
|
encapHeaders(w, resp)
|
||||||
|
|
||||||
|
// XXX(reed): 504 if ctx is past due / handle errors with 5xx? just 200 for now
|
||||||
|
// copy response from user back up now with headers in place...
|
||||||
|
io.Copy(w, buf)
|
||||||
|
|
||||||
|
// XXX(reed): handle streaming, we have to intercept headers but not necessarily body (ie no buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encapHeaders(fn http.ResponseWriter, user Response) {
|
||||||
|
fnh := fn.Header()
|
||||||
|
fnh.Set("Fn-Http-Status", strconv.Itoa(user.Status))
|
||||||
|
|
||||||
|
for k, vs := range user.Header {
|
||||||
|
switch k {
|
||||||
|
case "Content-Type":
|
||||||
|
// don't modify this one...
|
||||||
|
default:
|
||||||
|
// prepend this guy
|
||||||
|
k = "Fn-Http-H-" + k
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range vs {
|
||||||
|
fnh.Add(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO can make this the primary means of context construction
|
||||||
|
func decapHeaders(ctx context.Context, r *http.Request) (_ context.Context, cancel func()) {
|
||||||
|
rctx := Context(ctx)
|
||||||
|
var deadline string
|
||||||
|
|
||||||
|
// copy the original headers in then reduce for http headers
|
||||||
|
rctx.Header = r.Header
|
||||||
|
rctx.HTTPHeader = make(http.Header, len(r.Header)) // XXX(reed): oversized, esp if not http
|
||||||
|
|
||||||
|
// find things we need, and for http headers add them to the httph bucket
|
||||||
|
|
||||||
|
for k, vs := range r.Header {
|
||||||
|
switch k {
|
||||||
|
case "Fn-Deadline":
|
||||||
|
deadline = vs[0]
|
||||||
|
case "Fn-Call-Id":
|
||||||
|
rctx.callId = vs[0]
|
||||||
|
case "Content-Type":
|
||||||
|
// just leave this one instead of deleting
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(k, "Fn-Http-") {
|
||||||
|
// XXX(reed): we need 2 header buckets on ctx, one for these and one for the 'original req' headers
|
||||||
|
// for now just nuke so the headers are clean...
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case k == "Fn-Http-Request-Url":
|
||||||
|
rctx.RequestURL = vs[0]
|
||||||
|
case k == "Fn-Http-Method":
|
||||||
|
rctx.Method = vs[0]
|
||||||
|
case strings.HasPrefix(k, "Fn-Http-H-"):
|
||||||
|
for _, v := range vs {
|
||||||
|
rctx.HTTPHeader.Add(strings.TrimPrefix(k, "Fn-Http-H-"), v)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// XXX(reed): just delete it? how is it here? maybe log/panic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CtxWithDeadline(ctx, deadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func StartHTTPServer(handler Handler, path, format string) {
|
||||||
|
|
||||||
|
uri, err := url.Parse(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("url parse error: ", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
server := http.Server{
|
||||||
|
Handler: &HTTPHandler{
|
||||||
|
handler: handler,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to remove pre-existing UDS: ignore errors here
|
||||||
|
phonySock := filepath.Join(filepath.Dir(uri.Path), "phony"+filepath.Base(uri.Path))
|
||||||
|
if uri.Scheme == "unix" {
|
||||||
|
os.Remove(phonySock)
|
||||||
|
os.Remove(uri.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
listener, err := net.Listen(uri.Scheme, phonySock)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("net.Listen error: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if uri.Scheme == "unix" {
|
||||||
|
sockPerm(phonySock, uri.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = server.Serve(listener)
|
||||||
|
if err != nil && err != http.ErrServerClosed {
|
||||||
|
log.Fatalln("serve error: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sockPerm(phonySock, realSock string) {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
// somehow this is the best way to get a permissioned sock file, don't ask questions, life is sad and meaningless
|
||||||
|
err := os.Chmod(phonySock, 0666)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("error giving sock file a perm", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Link(phonySock, realSock)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("error linking fake sock to real sock", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
13
vendor/github.com/fnproject/fdk-go/utils/utils.go
generated
vendored
13
vendor/github.com/fnproject/fdk-go/utils/utils.go
generated
vendored
@@ -26,12 +26,25 @@ func WithContext(ctx context.Context, fnctx *Ctx) context.Context {
|
|||||||
|
|
||||||
// Ctx provides access to Config and Headers from fn.
|
// Ctx provides access to Config and Headers from fn.
|
||||||
type Ctx struct {
|
type Ctx struct {
|
||||||
|
// Header are the unmodified headers as sent to the container, see
|
||||||
|
// HTTPHeader for specific trigger headers
|
||||||
Header http.Header
|
Header http.Header
|
||||||
|
|
||||||
|
// HTTPHeader are the request headers as they appear on the original HTTP request,
|
||||||
|
// for an http trigger.
|
||||||
|
HTTPHeader http.Header
|
||||||
Config map[string]string
|
Config map[string]string
|
||||||
RequestURL string
|
RequestURL string
|
||||||
Method string
|
Method string
|
||||||
|
|
||||||
|
// XXX(reed): should turn this whole mess into some kind of event that we can
|
||||||
|
// morph into another type of an event after http/json/default die
|
||||||
|
// XXX(reed): should strip out eg FN_APP_NAME, etc as fields so Config is actually the config not config + fn's env vars
|
||||||
|
callId string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Ctx) CallId() string { return c.callId }
|
||||||
|
|
||||||
type key struct{}
|
type key struct{}
|
||||||
|
|
||||||
var ctxKey = new(key)
|
var ctxKey = new(key)
|
||||||
|
|||||||
Reference in New Issue
Block a user