diff --git a/go.mod b/go.mod index 5e1f85cf47..32732f55ed 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76 // indirect github.com/dustin/go-humanize v1.0.0 github.com/elazarl/goproxy v0.0.0-20181111060418-2ce16c963a8a // indirect + github.com/emicklei/go-restful-openapi v1.2.0 // indirect github.com/fsnotify/fsnotify v1.4.7 github.com/ghodss/yaml v1.0.0 github.com/go-sql-driver/mysql v1.4.1 // indirect @@ -64,7 +65,7 @@ require ( github.com/satori/go.uuid v1.2.0 github.com/sirupsen/logrus v1.2.0 github.com/spf13/pflag v1.0.1 // indirect - github.com/stretchr/testify v1.2.2 + github.com/stretchr/testify v1.3.0 github.com/ulikunitz/xz v0.0.0-20180703112113-636d36a76670 // indirect github.com/urfave/cli v1.20.0 github.com/wcharczuk/go-chart v2.0.1+incompatible @@ -86,4 +87,5 @@ require ( k8s.io/apiextensions-apiserver v0.0.0-20190116211702-f0729a5940c5 k8s.io/apimachinery v0.0.0-20190116203031-d49e237a2683 k8s.io/client-go v7.0.0+incompatible + k8s.io/klog v0.3.3 // indirect ) diff --git a/go.sum b/go.sum index 83f3ab2a84..616a12160e 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,10 @@ github.com/Azure/go-autorest v9.9.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWA github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.3.5 h1:DtpNbljikUepEPD16hD4LvIcmhnhdLTiW/5pHgbmp14= github.com/DataDog/zstd v1.3.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/sarama v1.21.0 h1:0GKs+e8mn1RRUzfg9oUXv3v7ZieQLmOZF/bfnmmGhM8= github.com/Shopify/sarama v1.21.0/go.mod h1:yuqtN/pe8cXRWG5zPaO7hCfNJp5MwmkoJEoLjkm5tCQ= github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= @@ -27,6 +31,7 @@ github.com/bsm/sarama-cluster v2.1.15+incompatible/go.mod h1:r7ao+4tTNXvWm+VRpRJ github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9 h1:74lLNRzvsdIlkTgfDSMuaPjBr4cf6k7pwQQANm/yLKU= @@ -51,10 +56,22 @@ github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/elazarl/goproxy v0.0.0-20181111060418-2ce16c963a8a h1:A4wNiqeKqU56ZhtnzJCTyPZ1+cyu8jKtIchQ3TtxHgw= github.com/elazarl/goproxy v0.0.0-20181111060418-2ce16c963a8a/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1/igzWB8OmvPgoYX7w= +github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful-openapi v1.2.0 h1:ohRZ1yEZERGzqaozBgxa3A0lt6c6KF14xhs3IL9ECwg= +github.com/emicklei/go-restful-openapi v1.2.0/go.mod h1:cy7o3Ge8ZWZ5E90mpEY81sJZZFs2pkuYcLvfngYy1l0= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-openapi/jsonpointer v0.0.0-20180322222829-3a0015ad55fa h1:hr8WVDjg4JKtQptZpzyb196TmruCs7PIsdJz8KAOZp8= +github.com/go-openapi/jsonpointer v0.0.0-20180322222829-3a0015ad55fa/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonreference v0.0.0-20180322222742-3fb327e6747d h1:k3UQ7Z8yFYq0BNkYykKIheY0HlZBl1Hku+pO9HE9FNU= +github.com/go-openapi/jsonreference v0.0.0-20180322222742-3fb327e6747d/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/spec v0.0.0-20180415031709-bcff419492ee h1:eo0HQoNFtbiEc7+1gRF9pgW6azx8a1cO2fXcqq1MuD0= +github.com/go-openapi/spec v0.0.0-20180415031709-bcff419492ee/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/swag v0.0.0-20180405201759-811b1089cde9 h1:+vsw187FKvA2QUGAcE+vQSfyxqLbUXixPYRRMAzwu04= +github.com/go-openapi/swag v0.0.0-20180405201759-811b1089cde9/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= @@ -124,6 +141,8 @@ 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/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mailru/easyjson v0.0.0-20180323154445-8b799c424f57 h1:qhv1ir3dIyOFmFU+5KqG4dF3zSQTA4nn1DFhu2NQC44= +github.com/mailru/easyjson v0.0.0-20180323154445-8b799c424f57/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c h1:N7uWGS2fTwH/4BwxbHiJZNAFTSJ5yPU0emHsQWvkxEY= github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -181,10 +200,12 @@ github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 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/ulikunitz/xz v0.0.0-20180703112113-636d36a76670 h1:HQWT4ta3wW5GZ790GaqLCS+w1dvuA3rMfEQxLi+UOYU= github.com/ulikunitz/xz v0.0.0-20180703112113-636d36a76670/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= @@ -207,6 +228,7 @@ golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f h1:FO4MZ3N56GnxbqxGKqh+YTz golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -265,3 +287,5 @@ k8s.io/apimachinery v0.0.0-20190116203031-d49e237a2683 h1:BmOSGJ1vwLhZKgDhTQlLF6 k8s.io/apimachinery v0.0.0-20190116203031-d49e237a2683/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/client-go v7.0.0+incompatible h1:kiH+Y6hn+pc78QS/mtBfMJAMIIaWevHi++JvOGEEQp4= k8s.io/client-go v7.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/klog v0.3.3 h1:niceAagH1tzskmaie/icWd7ci1wbG7Bf2c6YGcQv+3c= +k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= diff --git a/pkg/apis/fission.io/v1/tool/README.md b/pkg/apis/fission.io/v1/tool/README.md new file mode 100644 index 0000000000..f3f4092dc0 --- /dev/null +++ b/pkg/apis/fission.io/v1/tool/README.md @@ -0,0 +1,7 @@ +# How to update swagger (OpenAPI) struct description + +Run `update-generated-swagger-docs.sh` and it will parse all comments in `types.go`. + +```bash +./update-generated-swagger-docs.sh +``` diff --git a/pkg/apis/fission.io/v1/tool/boilerplate.generatego.txt b/pkg/apis/fission.io/v1/tool/boilerplate.generatego.txt new file mode 100644 index 0000000000..ebeae43a1a --- /dev/null +++ b/pkg/apis/fission.io/v1/tool/boilerplate.generatego.txt @@ -0,0 +1,15 @@ +/* +Copyright 2019 The Fission Authors. + +Licensed 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. +*/ diff --git a/pkg/apis/fission.io/v1/tool/swagger.sh b/pkg/apis/fission.io/v1/tool/swagger.sh new file mode 100755 index 0000000000..d8e8338756 --- /dev/null +++ b/pkg/apis/fission.io/v1/tool/swagger.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +# Copyright 2016 The Kubernetes Authors. +# +# Licensed 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. + +# +# Please refer https://github.com/kubernetes/kubernetes/tree/master/hack for original file +# + +# Contains swagger related util functions. +# +set -o errexit +set -o nounset +set -o pipefail + +# Generates types_swagger_doc_generated file for the given group version. +# $1: Name of the group version +# $2: Path to the directory where types.go for that group version exists. This +# is the directory where the file will be generated. +kube::swagger::gen_types_swagger_doc() { + local group_version=$1 + local gv_dir=$2 + local TMPFILE + TMPFILE="${TMPDIR:-/tmp}/types_swagger_doc_generated.$(date +%s).go" + + echo "Generating swagger type docs for ${group_version} at ${gv_dir}" + + { + echo -e "$(cat boilerplate.generatego.txt)\n" + echo "package ${group_version##*/}" + cat < "${TMPFILE}" + + go run ./swagger_type_docs.go -s \ + "${gv_dir}/types.go" \ + -f - \ + >> "${TMPFILE}" + + echo "// AUTO-GENERATED FUNCTIONS END HERE" >> "${TMPFILE}" + + gofmt -w -s "${TMPFILE}" + mv "${TMPFILE}" "${gv_dir}/types_swagger_doc_generated.go" +} diff --git a/pkg/apis/fission.io/v1/tool/swagger_type_docs.go b/pkg/apis/fission.io/v1/tool/swagger_type_docs.go new file mode 100644 index 0000000000..184c3d18b6 --- /dev/null +++ b/pkg/apis/fission.io/v1/tool/swagger_type_docs.go @@ -0,0 +1,75 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed 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. +*/ + +// +// Please refer https://github.com/kubernetes/kubernetes/blob/master/cmd/genswaggertypedocs/swagger_type_docs.go for original file +// + +package main + +import ( + "fmt" + "io" + "os" + + kruntime "k8s.io/apimachinery/pkg/runtime" + + flag "github.com/spf13/pflag" + "k8s.io/klog" +) + +var ( + functionDest = flag.StringP("func-dest", "f", "-", "Output for swagger functions; '-' means stdout (default)") + typeSrc = flag.StringP("type-src", "s", "", "From where we are going to read the types") + verify = flag.BoolP("verify", "v", false, "Verifies if the given type-src file has documentation for every type") +) + +func main() { + flag.Parse() + + if *typeSrc == "" { + klog.Fatalf("Please define -s flag as it is the source file") + } + + var funcOut io.Writer + if *functionDest == "-" { + funcOut = os.Stdout + } else { + file, err := os.Create(*functionDest) + if err != nil { + klog.Fatalf("Couldn't open %v: %v", *functionDest, err) + } + defer file.Close() + funcOut = file + } + + docsForTypes := kruntime.ParseDocumentationFrom(*typeSrc) + + if *verify { + rc, err := kruntime.VerifySwaggerDocsExist(docsForTypes, funcOut) + if err != nil { + fmt.Fprintf(os.Stderr, "Error in verification process: %s\n", err) + } + os.Exit(rc) + } + + if len(docsForTypes) > 0 { + if err := kruntime.WriteSwaggerDocFunc(docsForTypes, funcOut); err != nil { + fmt.Fprintf(os.Stderr, "Error when writing swagger documentation functions: %s\n", err) + os.Exit(-1) + } + } +} diff --git a/pkg/apis/fission.io/v1/tool/update-generated-swagger-docs.sh b/pkg/apis/fission.io/v1/tool/update-generated-swagger-docs.sh new file mode 100755 index 0000000000..783ef719e3 --- /dev/null +++ b/pkg/apis/fission.io/v1/tool/update-generated-swagger-docs.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +# Copyright 2015 The Kubernetes Authors. +# +# Licensed 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. + +# Generates `types_swagger_doc_generated.go` files for API group +# versions. That file contains functions on API structs that return +# the comments that should be surfaced for the corresponding API type +# in our API docs. + + +# +# Please refer https://github.com/kubernetes/kubernetes/tree/master/hack for original file +# + +set -o errexit +set -o nounset +set -o pipefail + +FISSION_CRD_VERSION=v1 + +source "swagger.sh" + +# To avoid compile errors, remove the currently existing files. + +for group_version in "${FISSION_CRD_VERSION}"; do + kube::swagger::gen_types_swagger_doc "${group_version}" ../../${FISSION_CRD_VERSION} +done diff --git a/pkg/apis/fission.io/v1/typeDeepcopyFunc.go b/pkg/apis/fission.io/v1/typeDeepcopyFunc.go new file mode 100644 index 0000000000..6b33a24517 --- /dev/null +++ b/pkg/apis/fission.io/v1/typeDeepcopyFunc.go @@ -0,0 +1,291 @@ +/* +Copyright 2019 The Fission Authors. + +Licensed 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. +*/ + +package v1 + +import ( + "github.com/hashicorp/go-multierror" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// Each CRD type needs: +// GetObjectKind (to satisfy the Object interface) +// +// In addition, each singular CRD type needs: +// GetObjectMeta (to satisfy the ObjectMetaAccessor interface) +// +// And each list CRD type needs: +// GetListMeta (to satisfy the ListMetaAccessor interface) + +func (f *Function) GetObjectKind() schema.ObjectKind { + return &f.TypeMeta +} +func (e *Environment) GetObjectKind() schema.ObjectKind { + return &e.TypeMeta +} +func (ht *HTTPTrigger) GetObjectKind() schema.ObjectKind { + return &ht.TypeMeta +} +func (w *KubernetesWatchTrigger) GetObjectKind() schema.ObjectKind { + return &w.TypeMeta +} +func (t *TimeTrigger) GetObjectKind() schema.ObjectKind { + return &t.TypeMeta +} +func (m *MessageQueueTrigger) GetObjectKind() schema.ObjectKind { + return &m.TypeMeta +} +func (p *Package) GetObjectKind() schema.ObjectKind { + return &p.TypeMeta +} +func (c *CanaryConfig) GetObjectKind() schema.ObjectKind { + return &c.TypeMeta +} + +func (r *Recorder) GetObjectKind() schema.ObjectKind { + return &r.TypeMeta +} + +func (f *Function) GetObjectMeta() metav1.Object { + return &f.Metadata +} +func (e *Environment) GetObjectMeta() metav1.Object { + return &e.Metadata +} +func (ht *HTTPTrigger) GetObjectMeta() metav1.Object { + return &ht.Metadata +} +func (w *KubernetesWatchTrigger) GetObjectMeta() metav1.Object { + return &w.Metadata +} +func (t *TimeTrigger) GetObjectMeta() metav1.Object { + return &t.Metadata +} +func (m *MessageQueueTrigger) GetObjectMeta() metav1.Object { + return &m.Metadata +} +func (p *Package) GetObjectMeta() metav1.Object { + return &p.Metadata +} +func (c *CanaryConfig) GetObjectMeta() metav1.Object { + return &c.Metadata +} + +func (r *Recorder) GetObjectMeta() metav1.Object { + return &r.Metadata +} + +func (fl *FunctionList) GetObjectKind() schema.ObjectKind { + return &fl.TypeMeta +} +func (el *EnvironmentList) GetObjectKind() schema.ObjectKind { + return &el.TypeMeta +} +func (hl *HTTPTriggerList) GetObjectKind() schema.ObjectKind { + return &hl.TypeMeta +} +func (wl *KubernetesWatchTriggerList) GetObjectKind() schema.ObjectKind { + return &wl.TypeMeta +} +func (wl *TimeTriggerList) GetObjectKind() schema.ObjectKind { + return &wl.TypeMeta +} +func (ml *MessageQueueTriggerList) GetObjectKind() schema.ObjectKind { + return &ml.TypeMeta +} +func (pl *PackageList) GetObjectKind() schema.ObjectKind { + return &pl.TypeMeta +} +func (rl *RecorderList) GetObjectKind() schema.ObjectKind { + return &rl.TypeMeta +} + +func (cl *CanaryConfigList) GetObjectKind() schema.ObjectKind { + return &cl.TypeMeta +} + +func (fl *FunctionList) GetListMeta() metav1.ListInterface { + return &fl.Metadata +} +func (el *EnvironmentList) GetListMeta() metav1.ListInterface { + return &el.Metadata +} +func (hl *HTTPTriggerList) GetListMeta() metav1.ListInterface { + return &hl.Metadata +} +func (wl *KubernetesWatchTriggerList) GetListMeta() metav1.ListInterface { + return &wl.Metadata +} +func (wl *TimeTriggerList) GetListMeta() metav1.ListInterface { + return &wl.Metadata +} +func (ml *MessageQueueTriggerList) GetListMeta() metav1.ListInterface { + return &ml.Metadata +} +func (pl *PackageList) GetListMeta() metav1.ListInterface { + return &pl.Metadata +} + +func (rl *RecorderList) GetListMeta() metav1.ListInterface { + return &rl.Metadata +} + +func (cl *CanaryConfigList) GetListMeta() metav1.ListInterface { + return &cl.Metadata +} + +func validateMetadata(field string, m metav1.ObjectMeta) error { + return ValidateKubeReference(field, m.Name, m.Namespace) +} + +func (p *Package) Validate() error { + var result *multierror.Error + + result = multierror.Append(result, + validateMetadata("Package", p.Metadata), + p.Spec.Validate(), + p.Status.Validate()) + + return result.ErrorOrNil() +} + +func (pl *PackageList) Validate() error { + var result *multierror.Error + // not validate ListMeta + for _, p := range pl.Items { + result = multierror.Append(result, p.Validate()) + } + return result.ErrorOrNil() +} + +func (f *Function) Validate() error { + var result *multierror.Error + + result = multierror.Append(result, + validateMetadata("Function", f.Metadata), + f.Spec.Validate()) + + return result.ErrorOrNil() +} + +func (fl *FunctionList) Validate() error { + var result *multierror.Error + for _, f := range fl.Items { + result = multierror.Append(result, f.Validate()) + } + return result.ErrorOrNil() +} + +func (e *Environment) Validate() error { + var result *multierror.Error + + result = multierror.Append(result, + validateMetadata("Environment", e.Metadata), + e.Spec.Validate()) + + return result.ErrorOrNil() +} + +func (el *EnvironmentList) Validate() error { + var result *multierror.Error + for _, e := range el.Items { + result = multierror.Append(result, e.Validate()) + } + return result.ErrorOrNil() +} + +func (h *HTTPTrigger) Validate() error { + var result *multierror.Error + + result = multierror.Append(result, + validateMetadata("HTTPTrigger", h.Metadata), + h.Spec.Validate()) + + return result.ErrorOrNil() +} + +func (hl *HTTPTriggerList) Validate() error { + var result *multierror.Error + for _, h := range hl.Items { + result = multierror.Append(result, h.Validate()) + } + return result.ErrorOrNil() +} + +func (k *KubernetesWatchTrigger) Validate() error { + var result *multierror.Error + + result = multierror.Append(result, + validateMetadata("KubernetesWatchTrigger", k.Metadata), + k.Spec.Validate()) + + return result.ErrorOrNil() +} + +func (kl *KubernetesWatchTriggerList) Validate() error { + var result *multierror.Error + for _, k := range kl.Items { + result = multierror.Append(result, k.Validate()) + } + return result +} + +func (t *TimeTrigger) Validate() error { + var result *multierror.Error + + result = multierror.Append(result, + validateMetadata("TimeTrigger", t.Metadata), + t.Spec.Validate()) + + return result.ErrorOrNil() +} + +func (tl *TimeTriggerList) Validate() error { + var result *multierror.Error + for _, t := range tl.Items { + result = multierror.Append(result, t.Validate()) + } + return result.ErrorOrNil() +} + +func (m *MessageQueueTrigger) Validate() error { + var result *multierror.Error + + result = multierror.Append(result, + validateMetadata("MessageQueueTrigger", m.Metadata), + m.Spec.Validate()) + + return result.ErrorOrNil() +} + +func (ml *MessageQueueTriggerList) Validate() error { + var result *multierror.Error + for _, m := range ml.Items { + result = multierror.Append(result, m.Validate()) + } + return result.ErrorOrNil() +} + +func (r *Recorder) Validate() error { + var result *multierror.Error + + result = multierror.Append(result, + validateMetadata("Recorder", r.Metadata), + r.Spec.Validate()) + + return result.ErrorOrNil() +} diff --git a/pkg/apis/fission.io/v1/typefields.go b/pkg/apis/fission.io/v1/typefields.go deleted file mode 100644 index 49f9ce9de0..0000000000 --- a/pkg/apis/fission.io/v1/typefields.go +++ /dev/null @@ -1,363 +0,0 @@ -/* -Copyright 2018 The Fission Authors. - -Licensed 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. -*/ - -package v1 - -import ( - apiv1 "k8s.io/api/core/v1" -) - -type ( - // - // Functions and packages - // - - // ChecksumType specifies the checksum algorithm, such as - // sha256, used for a checksum. - ChecksumType string - - // Checksum of package contents when the contents are stored - // outside the Package struct. Type is the checksum algorithm; - // "sha256" is the only currently supported one. Sum is hex - // encoded. - Checksum struct { - Type ChecksumType `json:"type,omitempty"` - Sum string `json:"sum,omitempty"` - } - - // ArchiveType is either literal or URL, indicating whether - // the package is specified in the Archive struct or - // externally. - ArchiveType string - - // Package contains or references a collection of source or - // binary files. - Archive struct { - // Type defines how the package is specified: literal or URL. - Type ArchiveType `json:"type,omitempty"` - - // Literal contents of the package. Can be used for - // encoding packages below TODO (256KB?) size. - Literal []byte `json:"literal,omitempty"` - - // URL references a package. - URL string `json:"url,omitempty"` - - // Checksum ensures the integrity of packages - // refereced by URL. Ignored for literals. - Checksum Checksum `json:"checksum,omitempty"` - } - - EnvironmentReference struct { - Namespace string `json:"namespace"` - Name string `json:"name"` - } - - SecretReference struct { - Namespace string `json:"namespace"` - Name string `json:"name"` - } - - ConfigMapReference struct { - Namespace string `json:"namespace"` - Name string `json:"name"` - } - - BuildStatus string - - PackageSpec struct { - Environment EnvironmentReference `json:"environment"` - Source Archive `json:"source,omitempty"` - Deployment Archive `json:"deployment,omitempty"` - BuildCommand string `json:"buildcmd,omitempty"` - // In the future, we can have a debug build here too - } - - PackageStatus struct { - BuildStatus BuildStatus `json:"buildstatus,omitempty"` - BuildLog string `json:"buildlog,omitempty"` // output of the build (errors etc) - } - - PackageRef struct { - Namespace string `json:"namespace"` - Name string `json:"name"` - - // Including resource version in the reference forces the function to be updated on - // package update, making it possible to cache the function based on its metadata. - ResourceVersion string `json:"resourceversion,omitempty"` - } - - FunctionPackageRef struct { - PackageRef PackageRef `json:"packageref"` - - // FunctionName specifies a specific function within the package. This allows - // functions to share packages, by having different functions within the same - // package. - // - // Fission itself does not interpret this path. It is passed verbatim to - // build and runtime environments. - // - // This is optional: if unspecified, the environment has a default name. - FunctionName string `json:"functionName,omitempty"` - } - - //ExecutorType is the primary executor for an environment - ExecutorType string - - //StrategyType is the strategy to be used for function execution - StrategyType string - - // FunctionSpec describes the contents of the function. - FunctionSpec struct { - // Environment is the build and runtime environment that this function is - // associated with. An Environment with this name should exist, otherwise the - // function cannot be invoked. - Environment EnvironmentReference `json:"environment"` - - // Reference to a package containing deployment and optionally the source - Package FunctionPackageRef `json:"package"` - - Secrets []SecretReference `json:"secrets"` - ConfigMaps []ConfigMapReference `json:"configmaps"` - - // cpu and memory resources as per K8S standards - Resources apiv1.ResourceRequirements `json:"resources"` - - // InvokeStrategy is a set of controls which affect how function executes - InvokeStrategy InvokeStrategy - } - - /*InvokeStrategy is a set of controls over how the function executes. - It affects the performance and resource usage of the function. - - An InvokeStategy is of one of two types: ExecutionStrategy, which controls low-level - parameters such as which ExecutorType to use, when to autoscale, minimum and maximum - number of running instances, etc. A higher-level AbstractInvokeStrategy will also be - supported; this strategy would specify the target request rate of the function, - the target latency statistics, and the target cost (in terms of compute resources). - */ - InvokeStrategy struct { - ExecutionStrategy ExecutionStrategy - StrategyType StrategyType - } - - /*ExecutionStrategy specifies low-level parameters for function execution, - such as the number of instances. - - MinScale affects the cold start behaviour for a function. If MinScale is 0 then the - deployment is created on first invocation of function and is good for requests of - asynchronous nature. If MinScale is greater than 0 then MinScale number of pods are - created at the time of creation of function. This ensures faster response during first - invocation at the cost of consuming resources. - - MaxScale is the maximum number of pods that function will scale to based on TargetCPUPercent - and resources allocated to the function pod. - */ - ExecutionStrategy struct { - ExecutorType ExecutorType - MinScale int - MaxScale int - TargetCPUPercent int - } - - FunctionReferenceType string - - FunctionReference struct { - // Type indicates whether this function reference is by name or selector. For now, - // the only supported reference type is by name. Future reference types: - // * Function by label or annotation - // * Branch or tag of a versioned function - // * A "rolling upgrade" from one version of a function to another - Type FunctionReferenceType `json:"type"` - - // Name of the function. - Name string `json:"name"` - - // Function Reference by weight. this map contains function name as key and its weight - // as the value. - FunctionWeights map[string]int `json:"functionweights"` - } - - // - // Environments - // - - Runtime struct { - // Image for containing the language runtime. - Image string `json:"image"` - - // LoadEndpointPort defines the port on which the - // server listens for function load - // requests. Optional; default 8888. - LoadEndpointPort int32 `json:"loadendpointport"` - - // LoadEndpointPath defines the relative URL on which - // the server listens for function load - // requests. Optional; default "/specialize". - LoadEndpointPath string `json:"loadendpointpath"` - - // FunctionEndpointPort defines the port on which the - // server listens for function requests. Optional; - // default 8888. - FunctionEndpointPort int32 `json:"functionendpointport"` - - // Container allows the modification of the deployed runtime - // container using the Kubernetes Container spec. Fission overrides - // the following fields: - // - Name - // - Image; set to the Runtime.Image - // - TerminationMessagePath - // - ImagePullPolicy - // (optional) - Container *apiv1.Container `json:"container,omitempty"` - - // Podspec allows modification of deployed runtime pod with Kubernetes PodSpec - // The merging logic is briefly described below and detailed MergePodSpec function - // - Volumes mounts and env variables for function and fetcher container are appended - // - All additional containers and init containers are appended - // - Volume definitions are appended - // - Lists such as tolerations, ImagePullSecrets, HostAliases are appended - // - Structs are merged and variables from pod spec take precedence - // (optional) - PodSpec *apiv1.PodSpec `json:"podspec,omitempty"` - } - - Builder struct { - // Image for containing the language runtime. - Image string `json:"image,omitempty"` - - // (Optional) Default build command to run for this build environment. - Command string `json:"command,omitempty"` - - // Container allows the modification of the deployed builder - // container using the Kubernetes Container spec. Fission overrides - // the following fields: - // - Name - // - Image; set to the Builder.Image - // - Command; set to the Builder.Command - // - TerminationMessagePath - // - ImagePullPolicy - // - ReadinessProbe - // (optional) - Container *apiv1.Container `json:"container,omitempty"` - } - - EnvironmentSpec struct { - // Environment API version - Version int `json:"version"` - - // Runtime container image etc.; required - Runtime Runtime `json:"runtime"` - - // Optional - Builder Builder `json:"builder"` - - // Optional, but strongly encouraged. Used to populate - // links from UI, CLI, etc. - DocumentationURL string `json:"documentationurl,omitempty"` - - // Optional, defaults to 'AllowedFunctionsPerContainerSingle' - AllowedFunctionsPerContainer AllowedFunctionsPerContainer `json:"allowedFunctionsPerContainer,omitempty"` - - // Optional, defaults to 'false' - AllowAccessToExternalNetwork bool `json:"allowAccessToExternalNetwork,omitempty"` - - // Request and limit resources for the environment - Resources apiv1.ResourceRequirements `json:"resources"` - - // The initial pool size for environment - Poolsize int `json:"poolsize,omitempty"` - - // The grace time for pod to perform connection draining before termination. The unit is in seconds. - // Optional, defaults to 360 seconds - TerminationGracePeriod int64 - - // KeepArchive is used by fetcher to determine if the extracted archive - // or unarchived file should be placed, which is then used by specialize handler - KeepArchive bool `json:"keeparchive"` - } - - AllowedFunctionsPerContainer string - - // - // Triggers - // - - HTTPTriggerSpec struct { - Host string `json:"host"` - RelativeURL string `json:"relativeurl"` - CreateIngress bool `json:"createingress"` - Method string `json:"method"` - FunctionReference FunctionReference `json:"functionref"` - } - - KubernetesWatchTriggerSpec struct { - Namespace string `json:"namespace"` - Type string `json:"type"` - LabelSelector map[string]string `json:"labelselector"` - FunctionReference FunctionReference `json:"functionref"` - } - - MessageQueueType string - - // MessageQueueTriggerSpec defines a binding from a topic in a - // message queue to a function. - MessageQueueTriggerSpec struct { - FunctionReference FunctionReference `json:"functionref"` - MessageQueueType MessageQueueType `json:"messageQueueType"` - Topic string `json:"topic"` - ResponseTopic string `json:"respTopic,omitempty"` - ErrorTopic string `json:"errorTopic"` - MaxRetries int `json:"maxRetries"` - ContentType string `json:"contentType"` - } - - // RecorderSpec defines a policy for recording requests and responses - // to a function, that can be later inspected or replayed. - RecorderSpec struct { - Name string `json:"name"` - Function string `json:"function"` - Triggers []string `json:"triggers"` - RetentionPolicy string `json:"retentionPolicy"` - EvictionPolicy string `json:"evictionPolicy"` - Enabled bool `json:"enabled"` - } - - // TimeTrigger invokes the specific function at a time or - // times specified by a cron string. - TimeTriggerSpec struct { - Cron string `json:"cron"` - FunctionReference `json:"functionref"` - } - - FailureType string - - // Canary Config Spec - CanaryConfigSpec struct { - Trigger string `json:"trigger"` - NewFunction string `json:"newfunction"` - OldFunction string `json:"oldfunction"` - WeightIncrement int `json:"weightincrement"` - WeightIncrementDuration string `json:"duration"` - FailureThreshold int `json:"failurethreshold"` - FailureType FailureType `json:"failureType"` - } - - // CanaryConfig Status - CanaryConfigStatus struct { - Status string `json:"status"` - } -) diff --git a/pkg/apis/fission.io/v1/types.go b/pkg/apis/fission.io/v1/types.go index 7c5237539b..c28c44bedc 100644 --- a/pkg/apis/fission.io/v1/types.go +++ b/pkg/apis/fission.io/v1/types.go @@ -17,9 +17,8 @@ limitations under the License. package v1 import ( - "github.com/hashicorp/go-multierror" + apiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" ) // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -47,18 +46,19 @@ type ( Metadata metav1.ObjectMeta `json:"metadata"` Spec PackageSpec `json:"spec"` + // Status indicates the build status of package. Status PackageStatus `json:"status"` } + // PackageList is a list of Packages. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object PackageList struct { metav1.TypeMeta `json:",inline"` Metadata metav1.ListMeta `json:"metadata"` - - Items []Package `json:"items"` + Items []Package `json:"items"` } - // Functions. + // Function is function runs within environment runtime with given package and secrets/configmaps. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object Function struct { metav1.TypeMeta `json:",inline"` @@ -66,15 +66,15 @@ type ( Spec FunctionSpec `json:"spec"` } + // FunctionList is a list of Functions. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object FunctionList struct { metav1.TypeMeta `json:",inline"` Metadata metav1.ListMeta `json:"metadata"` - - Items []Function `json:"items"` + Items []Function `json:"items"` } - // Environments. + // Environment is environment for building and running user functions. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object Environment struct { metav1.TypeMeta `json:",inline"` @@ -82,14 +82,15 @@ type ( Spec EnvironmentSpec `json:"spec"` } + // EnvironmentList is a list of Environments. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object EnvironmentList struct { metav1.TypeMeta `json:",inline"` Metadata metav1.ListMeta `json:"metadata"` - - Items []Environment `json:"items"` + Items []Environment `json:"items"` } + // HTTPTrigger is the trigger invokes user functions when receiving HTTP requests. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object HTTPTrigger struct { metav1.TypeMeta `json:",inline"` @@ -97,15 +98,15 @@ type ( Spec HTTPTriggerSpec `json:"spec"` } + // HTTPTriggerList is a list of HTTPTriggers // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object HTTPTriggerList struct { metav1.TypeMeta `json:",inline"` Metadata metav1.ListMeta `json:"metadata"` - - Items []HTTPTrigger `json:"items"` + Items []HTTPTrigger `json:"items"` } - // Kubernetes Watches as triggers + // KubernetesWatchTrigger watches kubernetes resource events and invokes functions. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object KubernetesWatchTrigger struct { metav1.TypeMeta `json:",inline"` @@ -113,15 +114,15 @@ type ( Spec KubernetesWatchTriggerSpec `json:"spec"` } + // KubernetesWatchTriggerList is a list of KubernetesWatchTriggers // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object KubernetesWatchTriggerList struct { metav1.TypeMeta `json:",inline"` - Metadata metav1.ListMeta `json:"metadata"` - - Items []KubernetesWatchTrigger `json:"items"` + Metadata metav1.ListMeta `json:"metadata"` + Items []KubernetesWatchTrigger `json:"items"` } - // Time triggers + // TimeTrigger invokes functions based on given cron schedule. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object TimeTrigger struct { metav1.TypeMeta `json:",inline"` @@ -129,6 +130,7 @@ type ( Spec TimeTriggerSpec `json:"spec"` } + // TimeTriggerList is a list of TimeTriggers. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object TimeTriggerList struct { metav1.TypeMeta `json:",inline"` @@ -137,7 +139,7 @@ type ( Items []TimeTrigger `json:"items"` } - // Message Queue triggers + // MessageQueueTrigger invokes functions when messages arrive to certain topic that trigger subscribes to. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object MessageQueueTrigger struct { metav1.TypeMeta `json:",inline"` @@ -145,14 +147,15 @@ type ( Spec MessageQueueTriggerSpec `json:"spec"` } + // MessageQueueTriggerList is a list of MessageQueueTriggers. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object MessageQueueTriggerList struct { metav1.TypeMeta `json:",inline"` - Metadata metav1.ListMeta `json:"metadata"` - - Items []MessageQueueTrigger `json:"items"` + Metadata metav1.ListMeta `json:"metadata"` + Items []MessageQueueTrigger `json:"items"` } + // Recorder allows user to record all traffic payload to a certain function. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object Recorder struct { metav1.TypeMeta `json:",inline"` @@ -160,6 +163,7 @@ type ( Spec RecorderSpec `json:"spec"` } + // RecorderList is a list of Recorders. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object RecorderList struct { metav1.TypeMeta `json:",inline"` @@ -168,6 +172,7 @@ type ( Items []Recorder `json:"items"` } + // CanaryConfig is for canary deployment of two functions. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object CanaryConfig struct { metav1.TypeMeta `json:",inline"` @@ -176,6 +181,7 @@ type ( Status CanaryConfigStatus `json:"status"` } + // CanaryConfigList is a list of CanaryConfigs. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object CanaryConfigList struct { metav1.TypeMeta `json:",inline"` @@ -183,272 +189,468 @@ type ( Items []CanaryConfig `json:"items"` } -) -// Each CRD type needs: -// GetObjectKind (to satisfy the Object interface) -// -// In addition, each singular CRD type needs: -// GetObjectMeta (to satisfy the ObjectMetaAccessor interface) -// -// And each list CRD type needs: -// GetListMeta (to satisfy the ListMetaAccessor interface) - -func (f *Function) GetObjectKind() schema.ObjectKind { - return &f.TypeMeta -} -func (e *Environment) GetObjectKind() schema.ObjectKind { - return &e.TypeMeta -} -func (ht *HTTPTrigger) GetObjectKind() schema.ObjectKind { - return &ht.TypeMeta -} -func (w *KubernetesWatchTrigger) GetObjectKind() schema.ObjectKind { - return &w.TypeMeta -} -func (t *TimeTrigger) GetObjectKind() schema.ObjectKind { - return &t.TypeMeta -} -func (m *MessageQueueTrigger) GetObjectKind() schema.ObjectKind { - return &m.TypeMeta -} -func (p *Package) GetObjectKind() schema.ObjectKind { - return &p.TypeMeta -} -func (c *CanaryConfig) GetObjectKind() schema.ObjectKind { - return &c.TypeMeta -} - -func (r *Recorder) GetObjectKind() schema.ObjectKind { - return &r.TypeMeta -} - -func (f *Function) GetObjectMeta() metav1.Object { - return &f.Metadata -} -func (e *Environment) GetObjectMeta() metav1.Object { - return &e.Metadata -} -func (ht *HTTPTrigger) GetObjectMeta() metav1.Object { - return &ht.Metadata -} -func (w *KubernetesWatchTrigger) GetObjectMeta() metav1.Object { - return &w.Metadata -} -func (t *TimeTrigger) GetObjectMeta() metav1.Object { - return &t.Metadata -} -func (m *MessageQueueTrigger) GetObjectMeta() metav1.Object { - return &m.Metadata -} -func (p *Package) GetObjectMeta() metav1.Object { - return &p.Metadata -} -func (c *CanaryConfig) GetObjectMeta() metav1.Object { - return &c.Metadata -} - -func (r *Recorder) GetObjectMeta() metav1.Object { - return &r.Metadata -} - -func (fl *FunctionList) GetObjectKind() schema.ObjectKind { - return &fl.TypeMeta -} -func (el *EnvironmentList) GetObjectKind() schema.ObjectKind { - return &el.TypeMeta -} -func (hl *HTTPTriggerList) GetObjectKind() schema.ObjectKind { - return &hl.TypeMeta -} -func (wl *KubernetesWatchTriggerList) GetObjectKind() schema.ObjectKind { - return &wl.TypeMeta -} -func (wl *TimeTriggerList) GetObjectKind() schema.ObjectKind { - return &wl.TypeMeta -} -func (ml *MessageQueueTriggerList) GetObjectKind() schema.ObjectKind { - return &ml.TypeMeta -} -func (pl *PackageList) GetObjectKind() schema.ObjectKind { - return &pl.TypeMeta -} -func (rl *RecorderList) GetObjectKind() schema.ObjectKind { - return &rl.TypeMeta -} - -func (cl *CanaryConfigList) GetObjectKind() schema.ObjectKind { - return &cl.TypeMeta -} - -func (fl *FunctionList) GetListMeta() metav1.ListInterface { - return &fl.Metadata -} -func (el *EnvironmentList) GetListMeta() metav1.ListInterface { - return &el.Metadata -} -func (hl *HTTPTriggerList) GetListMeta() metav1.ListInterface { - return &hl.Metadata -} -func (wl *KubernetesWatchTriggerList) GetListMeta() metav1.ListInterface { - return &wl.Metadata -} -func (wl *TimeTriggerList) GetListMeta() metav1.ListInterface { - return &wl.Metadata -} -func (ml *MessageQueueTriggerList) GetListMeta() metav1.ListInterface { - return &ml.Metadata -} -func (pl *PackageList) GetListMeta() metav1.ListInterface { - return &pl.Metadata -} - -func (rl *RecorderList) GetListMeta() metav1.ListInterface { - return &rl.Metadata -} - -func (cl *CanaryConfigList) GetListMeta() metav1.ListInterface { - return &cl.Metadata -} - -func validateMetadata(field string, m metav1.ObjectMeta) error { - return ValidateKubeReference(field, m.Name, m.Namespace) -} - -func (p *Package) Validate() error { - var result *multierror.Error - - result = multierror.Append(result, - validateMetadata("Package", p.Metadata), - p.Spec.Validate(), - p.Status.Validate()) - - return result.ErrorOrNil() -} - -func (pl *PackageList) Validate() error { - var result *multierror.Error - // not validate ListMeta - for _, p := range pl.Items { - result = multierror.Append(result, p.Validate()) - } - return result.ErrorOrNil() -} - -func (f *Function) Validate() error { - var result *multierror.Error - - result = multierror.Append(result, - validateMetadata("Function", f.Metadata), - f.Spec.Validate()) - - return result.ErrorOrNil() -} - -func (fl *FunctionList) Validate() error { - var result *multierror.Error - for _, f := range fl.Items { - result = multierror.Append(result, f.Validate()) - } - return result.ErrorOrNil() -} - -func (e *Environment) Validate() error { - var result *multierror.Error - - result = multierror.Append(result, - validateMetadata("Environment", e.Metadata), - e.Spec.Validate()) - - return result.ErrorOrNil() -} - -func (el *EnvironmentList) Validate() error { - var result *multierror.Error - for _, e := range el.Items { - result = multierror.Append(result, e.Validate()) - } - return result.ErrorOrNil() -} - -func (h *HTTPTrigger) Validate() error { - var result *multierror.Error - - result = multierror.Append(result, - validateMetadata("HTTPTrigger", h.Metadata), - h.Spec.Validate()) - - return result.ErrorOrNil() -} - -func (hl *HTTPTriggerList) Validate() error { - var result *multierror.Error - for _, h := range hl.Items { - result = multierror.Append(result, h.Validate()) + // + // Functions and packages + // + + // ChecksumType specifies the checksum algorithm, such as + // sha256, used for a checksum. + ChecksumType string + + // Checksum of package contents when the contents are stored + // outside the Package struct. Type is the checksum algorithm; + // "sha256" is the only currently supported one. Sum is hex + // encoded. + Checksum struct { + Type ChecksumType `json:"type,omitempty"` + Sum string `json:"sum,omitempty"` } - return result.ErrorOrNil() -} -func (k *KubernetesWatchTrigger) Validate() error { - var result *multierror.Error + // ArchiveType is either literal or URL, indicating whether + // the package is specified in the Archive struct or + // externally. + ArchiveType string + + // Package contains or references a collection of source or + // binary files. + Archive struct { + // Type defines how the package is specified: literal or URL. + // Available value: + // - literal + // - url + Type ArchiveType `json:"type,omitempty"` + + // Literal contents of the package. Can be used for + // encoding packages below TODO (256KB?) size. + Literal []byte `json:"literal,omitempty"` + + // URL references a package. + URL string `json:"url,omitempty"` + + // Checksum ensures the integrity of packages + // refereced by URL. Ignored for literals. + Checksum Checksum `json:"checksum,omitempty"` + } - result = multierror.Append(result, - validateMetadata("KubernetesWatchTrigger", k.Metadata), - k.Spec.Validate()) + // EnvironmentReference is a reference to a environment. + EnvironmentReference struct { + Namespace string `json:"namespace"` + Name string `json:"name"` + } - return result.ErrorOrNil() -} + // SecretReference is a reference to a kubernetes secret. + SecretReference struct { + Namespace string `json:"namespace"` + Name string `json:"name"` + } -func (kl *KubernetesWatchTriggerList) Validate() error { - var result *multierror.Error - for _, k := range kl.Items { - result = multierror.Append(result, k.Validate()) + // ConfigMapReference is a reference to a kubernetes configmap. + ConfigMapReference struct { + Namespace string `json:"namespace"` + Name string `json:"name"` } - return result -} -func (t *TimeTrigger) Validate() error { - var result *multierror.Error + // BuildStatus indicates the current build status of a package. + BuildStatus string + + // PackageSpec includes source/deploy archives and the reference of environment to build the package. + PackageSpec struct { + // Environment is a reference to the environment for building source archive. + Environment EnvironmentReference `json:"environment"` - result = multierror.Append(result, - validateMetadata("TimeTrigger", t.Metadata), - t.Spec.Validate()) + // Source is the archive contains source code and dependencies file. + // If the package status is in PENDING state, builder manager will then + // notify builder to compile source and save the result as deployable archive. + Source Archive `json:"source,omitempty"` - return result.ErrorOrNil() -} + // Deployment is the deployable archive that environment runtime used to run user function. + Deployment Archive `json:"deployment,omitempty"` -func (tl *TimeTriggerList) Validate() error { - var result *multierror.Error - for _, t := range tl.Items { - result = multierror.Append(result, t.Validate()) + // BuildCommand is a custom build command that builder used to build the source archive. + BuildCommand string `json:"buildcmd,omitempty"` + + // In the future, we can have a debug build here too } - return result.ErrorOrNil() -} -func (m *MessageQueueTrigger) Validate() error { - var result *multierror.Error + // PackageStatus contains the build status of a package also the build log for examination. + PackageStatus struct { + // BuildStatus is the package build status. + BuildStatus BuildStatus `json:"buildstatus,omitempty"` - result = multierror.Append(result, - validateMetadata("MessageQueueTrigger", m.Metadata), - m.Spec.Validate()) + // BuildLog stores build log during the compilation. + BuildLog string `json:"buildlog,omitempty"` // output of the build (errors etc) + } - return result.ErrorOrNil() -} + // PackageRef is a reference to the package. + PackageRef struct { + Namespace string `json:"namespace"` + Name string `json:"name"` -func (ml *MessageQueueTriggerList) Validate() error { - var result *multierror.Error - for _, m := range ml.Items { - result = multierror.Append(result, m.Validate()) + // Including resource version in the reference forces the function to be updated on + // package update, making it possible to cache the function based on its metadata. + ResourceVersion string `json:"resourceversion,omitempty"` } - return result.ErrorOrNil() -} -func (r *Recorder) Validate() error { - var result *multierror.Error + // FunctionPackageRef includes the reference to the package also the entrypoint of package. + FunctionPackageRef struct { + // Package reference + PackageRef PackageRef `json:"packageref"` + + // FunctionName specifies a specific function within the package. This allows + // functions to share packages, by having different functions within the same + // package. + // + // Fission itself does not interpret this path. It is passed verbatim to + // build and runtime environments. + // + // This is optional: if unspecified, the environment has a default name. + FunctionName string `json:"functionName,omitempty"` + } + + // ExecutorType is the primary executor for an environment + ExecutorType string + + // StrategyType is the strategy to be used for function execution + StrategyType string + + // FunctionSpec describes the contents of the function. + FunctionSpec struct { + // Environment is the build and runtime environment that this function is + // associated with. An Environment with this name should exist, otherwise the + // function cannot be invoked. + Environment EnvironmentReference `json:"environment"` + + // Reference to a package containing deployment and optionally the source. + Package FunctionPackageRef `json:"package"` + + // Reference to a list of secrets. + Secrets []SecretReference `json:"secrets"` + + // Reference to a list of configmaps. + ConfigMaps []ConfigMapReference `json:"configmaps"` + + // cpu and memory resources as per K8S standards + // This is only for newdeploy to set up resource limitation + // when creating deployment for a function. + Resources apiv1.ResourceRequirements `json:"resources"` + + // InvokeStrategy is a set of controls which affect how function executes + InvokeStrategy InvokeStrategy + } + + // InvokeStrategy is a set of controls over how the function executes. + // It affects the performance and resource usage of the function. + // + // An InvokeStrategy is of one of two types: ExecutionStrategy, which controls low-level + // parameters such as which ExecutorType to use, when to autoscale, minimum and maximum + // number of running instances, etc. A higher-level AbstractInvokeStrategy will also be + // supported; this strategy would specify the target request rate of the function, + // the target latency statistics, and the target cost (in terms of compute resources). + InvokeStrategy struct { + + // ExecutionStrategy specifies low-level parameters for function execution, + // such as the number of instances. + ExecutionStrategy ExecutionStrategy + + // StrategyType is the strategy type of a function. + // Now it only supports 'execution'. + StrategyType StrategyType + } + + // ExecutionStrategy specifies low-level parameters for function execution, + // such as the number of instances. + // + // MinScale affects the cold start behaviour for a function. If MinScale is 0 then the + // deployment is created on first invocation of function and is good for requests of + // asynchronous nature. If MinScale is greater than 0 then MinScale number of pods are + // created at the time of creation of function. This ensures faster response during first + // invocation at the cost of consuming resources. + // + // MaxScale is the maximum number of pods that function will scale to based on TargetCPUPercent + // and resources allocated to the function pod. + ExecutionStrategy struct { + + // ExecutorType is the executor type of a function used. Defaults to "poolmgr". + // + // Available value: + // - poolmgr + // - newdeploy + ExecutorType ExecutorType + + // This is only for newdeploy to set up minimum replicas of deployment. + MinScale int + + // This is only for newdeploy to set up maximum replicas of deployment. + MaxScale int + + // This is only for newdeploy to set up target CPU utilization of HPA. + TargetCPUPercent int + } + + FunctionReferenceType string + + FunctionReference struct { + // Type indicates whether this function reference is by name or selector. For now, + // the only supported reference type is by "name". Future reference types: + // * Function by label or annotation + // * Branch or tag of a versioned function + // * A "rolling upgrade" from one version of a function to another + // Available value: + // - name + // - function-weights + Type FunctionReferenceType `json:"type"` + + // Name of the function. + Name string `json:"name"` + + // Function Reference by weight. this map contains function name as key and its weight + // as the value. This is for canary upgrade purpose. + FunctionWeights map[string]int `json:"functionweights"` + } + + // + // Environments + // + + // Runtime is the setting for environment runtime. + Runtime struct { + // Image for containing the language runtime. + Image string `json:"image"` + + // NOT USED NOW + // LoadEndpointPort defines the port on which the + // server listens for function load + // requests. Optional; default 8888. + LoadEndpointPort int32 `json:"-"` // `json:"loadendpointport"` + + // NOT USED NOW + // LoadEndpointPath defines the relative URL on which + // the server listens for function load + // requests. Optional; default "/specialize". + LoadEndpointPath string `json:"-"` // `json:"loadendpointpath"` + + // NOT USED NOW + // FunctionEndpointPort defines the port on which the + // server listens for function requests. Optional; + // default 8888. + FunctionEndpointPort int32 `json:"-"` // `json:"functionendpointport"` + + // (Optional) Container allows the modification of the deployed runtime + // container using the Kubernetes Container spec. Fission overrides + // the following fields: + // - Name + // - Image; set to the Runtime.Image + // - TerminationMessagePath + // - ImagePullPolicy + // + // You can set either PodSpec or Container, but not both. + Container *apiv1.Container `json:"container,omitempty"` + + // (Optional) Podspec allows modification of deployed runtime pod with Kubernetes PodSpec + // The merging logic is briefly described below and detailed MergePodSpec function + // - Volumes mounts and env variables for function and fetcher container are appended + // - All additional containers and init containers are appended + // - Volume definitions are appended + // - Lists such as tolerations, ImagePullSecrets, HostAliases are appended + // - Structs are merged and variables from pod spec take precedence + // + // You can set either PodSpec or Container, but not both. + PodSpec *apiv1.PodSpec `json:"podspec,omitempty"` + } + + // Builder is the setting for environment builder. + Builder struct { + // Image for containing the language compilation environment. + Image string `json:"image,omitempty"` + + // (Optional) Default build command to run for this build environment. + Command string `json:"command,omitempty"` + + // (Optional) Container allows the modification of the deployed builder + // container using the Kubernetes Container spec. Fission overrides + // the following fields: + // - Name + // - Image; set to the Builder.Image + // - Command; set to the Builder.Command + // - TerminationMessagePath + // - ImagePullPolicy + // - ReadinessProbe + Container *apiv1.Container `json:"container,omitempty"` + } + + // EnvironmentSpec contains with builder, runtime and some other related environment settings. + EnvironmentSpec struct { + // Version is the Environment API version + // + // Version "1" allows user to run code snippet in a file and + // it's supported by most of environments except tensorflow-serving. + // + // Version "2" supports downloading and compiling user function if source archive is not empty. + // + // Version "3" is almost the same with v2, but you're able to control the size of pre-warm pool of the environment. + Version int `json:"version"` + + // Runtime is configuration for running function, like container image etc. + Runtime Runtime `json:"runtime"` + + // (Optional) Builder is configuration for builder manager to launch environment builder to build source code into + // deployable binary. + Builder Builder `json:"builder"` + + // NOT USED NOW. + // (Optional) Strongly encouraged. Used to populate links from UI, CLI, etc. + DocumentationURL string `json:"-"` // `json:"documentationurl,omitempty"` + + // (Optional) defaults to 'single'. Fission workflow uses + // 'infinite' to load multiple functions in one function pod. + // Available value: + // - single + // - infinite + AllowedFunctionsPerContainer AllowedFunctionsPerContainer `json:"allowedFunctionsPerContainer,omitempty"` + + // Istio default blocks all egress traffic for safety. + // To enable accessibility of external network for builder/function pod, set to 'true'. + // (Optional) defaults to 'false' + AllowAccessToExternalNetwork bool `json:"allowAccessToExternalNetwork,omitempty"` + + // The request and limit CPU/MEM resource setting for poolmanager to set up pods in the pre-warm pool. + // (Optional) defaults to no limitation. + Resources apiv1.ResourceRequirements `json:"resources"` + + // The initial pool size for environment + Poolsize int `json:"poolsize,omitempty"` + + // The grace time for pod to perform connection draining before termination. The unit is in seconds. + // (Optional) defaults to 360 seconds + TerminationGracePeriod int64 `json:"terminationGracePeriod,omitempty"` + + // KeepArchive is used by fetcher to determine if the extracted archive + // or unarchived file should be placed, which is then used by specialize handler. + // (This is mainly for the JVM environment because .jar is one kind of zip archive.) + KeepArchive bool `json:"keeparchive"` + } - result = multierror.Append(result, - validateMetadata("Recorder", r.Metadata), - r.Spec.Validate()) + AllowedFunctionsPerContainer string - return result.ErrorOrNil() -} + // + // Triggers + // + + // HTTPTriggerSpec is for router to expose user functions at the given URL path. + HTTPTriggerSpec struct { + // NOT USED NOW + Host string `json:"-"` //`json:"host"` + + // RelativeURL is the exposed URL for external client to access a function with. + RelativeURL string `json:"relativeurl"` + + // If CreateIngress is true, router will create a ingress definition. + CreateIngress bool `json:"createingress"` + + // HTTP method to access a function. + Method string `json:"method"` + + // FunctionReference is a reference to the target function. + FunctionReference FunctionReference `json:"functionref"` + } + + // KubernetesWatchTriggerSpec + KubernetesWatchTriggerSpec struct { + Namespace string `json:"namespace"` + + // Type of resource to watch (Pod, Service, etc.) + Type string `json:"type"` + + // Resource labels + LabelSelector map[string]string `json:"labelselector"` + + // The reference to a function for kubewatcher to invoke with + // when receiving events. + FunctionReference FunctionReference `json:"functionref"` + } + + // Type of message queue + MessageQueueType string + + // MessageQueueTriggerSpec defines a binding from a topic in a + // message queue to a function. + MessageQueueTriggerSpec struct { + // The reference to a function for message queue trigger to invoke with + // when receiving messages from subscribed topic. + FunctionReference FunctionReference `json:"functionref"` + + // Type of message queue (NATS, Kafka, AzureQueue) + MessageQueueType MessageQueueType `json:"messageQueueType"` + + // Subscribed topic + Topic string `json:"topic"` + + // Topic for message queue trigger to sent response from function. + ResponseTopic string `json:"respTopic,omitempty"` + + // Topic to collect error response sent from function + ErrorTopic string `json:"errorTopic"` + + // Maximum times for message queue trigger to retry + MaxRetries int `json:"maxRetries"` + + // Content type of payload + ContentType string `json:"contentType"` + } + + // RecorderSpec defines a policy for recording requests and responses + // to a function, that can be later inspected or replayed. + RecorderSpec struct { + // Name of recorder resource + Name string `json:"name"` + + // Function to collect requests/responses + Function string `json:"function"` + + // HTTP trigger to record the requests and responses. + Triggers []string `json:"triggers"` + RetentionPolicy string `json:"-"` // `json:"retentionPolicy"` + EvictionPolicy string `json:"-"` // `json:"evictionPolicy"` + Enabled bool `json:"enabled"` + } + + // TimeTrigger invokes the specific function at a time or + // times specified by a cron string. + TimeTriggerSpec struct { + // Cron schedule + Cron string `json:"cron"` + + // The reference to function + FunctionReference `json:"functionref"` + } + + FailureType string + + // Canary Config Spec + CanaryConfigSpec struct { + // HTTP trigger that this config references + Trigger string `json:"trigger"` + + // New version of the function + NewFunction string `json:"newfunction"` + + // Old stable version of the function + OldFunction string `json:"oldfunction"` + + // Weight increment step for function + WeightIncrement int `json:"weightincrement"` + + // Weight increment interval, string representation of time.Duration, ex : 1m, 2h, 2d (default: "2m") + WeightIncrementDuration string `json:"duration"` + + // Threshold in percentage beyond which the new version of the function is considered unstable + FailureThreshold int `json:"failurethreshold"` + FailureType FailureType `json:"failureType"` + } + + // CanaryConfig Status + CanaryConfigStatus struct { + Status string `json:"status"` + } +) diff --git a/pkg/apis/fission.io/v1/types_swagger_doc_generated.go b/pkg/apis/fission.io/v1/types_swagger_doc_generated.go new file mode 100644 index 0000000000..29cd8617fa --- /dev/null +++ b/pkg/apis/fission.io/v1/types_swagger_doc_generated.go @@ -0,0 +1,426 @@ +/* +Copyright 2019 The Fission Authors. + +Licensed 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. +*/ + +package v1 + +// This file contains a collection of methods that can be used from go-restful to +// generate Swagger API documentation for its models. Please read this PR for more +// information on the implementation: https://github.com/emicklei/go-restful/pull/215 +// +// TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if +// they are on one line! For multiple line or blocks that you want to ignore use ---. +// Any context after a --- is ignored. +// +// Those methods can be generated by using hack/update-generated-swagger-docs.sh + +// AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT. +var map_Archive = map[string]string{ + "": "Package contains or references a collection of source or binary files.", + "type": "Type defines how the package is specified: literal or URL. Available value:\n - literal\n - url", + "literal": "Literal contents of the package. Can be used for encoding packages below TODO (256KB?) size.", + "url": "URL references a package.", + "checksum": "Checksum ensures the integrity of packages refereced by URL. Ignored for literals.", +} + +func (Archive) SwaggerDoc() map[string]string { + return map_Archive +} + +var map_Builder = map[string]string{ + "": "Builder is the setting for environment builder.", + "image": "Image for containing the language compilation environment.", + "command": "(Optional) Default build command to run for this build environment.", + "container": "(Optional) Container allows the modification of the deployed builder container using the Kubernetes Container spec. Fission overrides the following fields: - Name - Image; set to the Builder.Image - Command; set to the Builder.Command - TerminationMessagePath - ImagePullPolicy - ReadinessProbe", +} + +func (Builder) SwaggerDoc() map[string]string { + return map_Builder +} + +var map_CanaryConfig = map[string]string{ + "": "CanaryConfig is for canary deployment of two functions.", +} + +func (CanaryConfig) SwaggerDoc() map[string]string { + return map_CanaryConfig +} + +var map_CanaryConfigList = map[string]string{ + "": "CanaryConfigList is a list of CanaryConfigs.", +} + +func (CanaryConfigList) SwaggerDoc() map[string]string { + return map_CanaryConfigList +} + +var map_CanaryConfigSpec = map[string]string{ + "": "Canary Config Spec", + "trigger": "HTTP trigger that this config references", + "newfunction": "New version of the function", + "oldfunction": "Old stable version of the function", + "weightincrement": "Weight increment step for function", + "duration": "Weight increment interval, string representation of time.Duration, ex : 1m, 2h, 2d (default: \"2m\")", + "failurethreshold": "Threshold in percentage beyond which the new version of the function is considered unstable", +} + +func (CanaryConfigSpec) SwaggerDoc() map[string]string { + return map_CanaryConfigSpec +} + +var map_CanaryConfigStatus = map[string]string{ + "": "CanaryConfig Status", +} + +func (CanaryConfigStatus) SwaggerDoc() map[string]string { + return map_CanaryConfigStatus +} + +var map_Checksum = map[string]string{ + "": "Checksum of package contents when the contents are stored outside the Package struct. Type is the checksum algorithm; \"sha256\" is the only currently supported one. Sum is hex encoded.", +} + +func (Checksum) SwaggerDoc() map[string]string { + return map_Checksum +} + +var map_ConfigMapReference = map[string]string{ + "": "ConfigMapReference is a reference to a kubernetes configmap.", +} + +func (ConfigMapReference) SwaggerDoc() map[string]string { + return map_ConfigMapReference +} + +var map_Environment = map[string]string{ + "": "Environment is environment for building and running user functions.", +} + +func (Environment) SwaggerDoc() map[string]string { + return map_Environment +} + +var map_EnvironmentList = map[string]string{ + "": "EnvironmentList is a list of Environments.", +} + +func (EnvironmentList) SwaggerDoc() map[string]string { + return map_EnvironmentList +} + +var map_EnvironmentReference = map[string]string{ + "": "EnvironmentReference is a reference to a environment.", +} + +func (EnvironmentReference) SwaggerDoc() map[string]string { + return map_EnvironmentReference +} + +var map_EnvironmentSpec = map[string]string{ + "": "EnvironmentSpec contains with builder, runtime and some other related environment settings.", + "version": "Version is the Environment API version\n\nVersion \"1\" allows user to run code snippet in a file and it's supported by most of environments except tensorflow-serving.\n\nVersion \"2\" supports downloading and compiling user function if source archive is not empty.\n\nVersion \"3\" is almost the same with v2, but you're able to control the size of pre-warm pool of the environment.", + "runtime": "Runtime is configuration for running function, like container image etc.", + "builder": "(Optional) Builder is configuration for builder manager to launch environment builder to build source code into deployable binary.", + "allowedFunctionsPerContainer": "(Optional) defaults to 'single'. Fission workflow uses 'infinite' to load multiple functions in one function pod. Available value: - single - infinite", + "allowAccessToExternalNetwork": "Istio default blocks all egress traffic for safety. To enable accessibility of external network for builder/function pod, set to 'true'. (Optional) defaults to 'false'", + "resources": "The request and limit CPU/MEM resource setting for poolmanager to set up pods in the pre-warm pool. (Optional) defaults to no limitation.", + "poolsize": "The initial pool size for environment", + "terminationGracePeriod": "The grace time for pod to perform connection draining before termination. The unit is in seconds. (Optional) defaults to 360 seconds", + "keeparchive": "KeepArchive is used by fetcher to determine if the extracted archive or unarchived file should be placed, which is then used by specialize handler. (This is mainly for the JVM environment because .jar is one kind of zip archive.)", +} + +func (EnvironmentSpec) SwaggerDoc() map[string]string { + return map_EnvironmentSpec +} + +var map_ExecutionStrategy = map[string]string{ + "": "ExecutionStrategy specifies low-level parameters for function execution, such as the number of instances.\n\nMinScale affects the cold start behaviour for a function. If MinScale is 0 then the deployment is created on first invocation of function and is good for requests of asynchronous nature. If MinScale is greater than 0 then MinScale number of pods are created at the time of creation of function. This ensures faster response during first invocation at the cost of consuming resources.\n\nMaxScale is the maximum number of pods that function will scale to based on TargetCPUPercent and resources allocated to the function pod.", + "ExecutorType": "ExecutorType is the executor type of a function used. Defaults to \"poolmgr\".\n\nAvailable value:\n - poolmgr\n - newdeploy", + "MinScale": "This is only for newdeploy to set up minimum replicas of deployment.", + "MaxScale": "This is only for newdeploy to set up maximum replicas of deployment.", + "TargetCPUPercent": "This is only for newdeploy to set up target CPU utilization of HPA.", +} + +func (ExecutionStrategy) SwaggerDoc() map[string]string { + return map_ExecutionStrategy +} + +var map_Function = map[string]string{ + "": "Function is function runs within environment runtime with given package and secrets/configmaps.", +} + +func (Function) SwaggerDoc() map[string]string { + return map_Function +} + +var map_FunctionList = map[string]string{ + "": "FunctionList is a list of Functions.", +} + +func (FunctionList) SwaggerDoc() map[string]string { + return map_FunctionList +} + +var map_FunctionPackageRef = map[string]string{ + "": "FunctionPackageRef includes the reference to the package also the entrypoint of package.", + "packageref": "Package reference", + "functionName": "FunctionName specifies a specific function within the package. This allows functions to share packages, by having different functions within the same package.\n\nFission itself does not interpret this path. It is passed verbatim to build and runtime environments.\n\nThis is optional: if unspecified, the environment has a default name.", +} + +func (FunctionPackageRef) SwaggerDoc() map[string]string { + return map_FunctionPackageRef +} + +var map_FunctionReference = map[string]string{ + "type": "Type indicates whether this function reference is by name or selector. For now, the only supported reference type is by \"name\". Future reference types:\n * Function by label or annotation\n * Branch or tag of a versioned function\n * A \"rolling upgrade\" from one version of a function to another\nAvailable value: - name - function-weights", + "name": "Name of the function.", + "functionweights": "Function Reference by weight. this map contains function name as key and its weight as the value. This is for canary upgrade purpose.", +} + +func (FunctionReference) SwaggerDoc() map[string]string { + return map_FunctionReference +} + +var map_FunctionSpec = map[string]string{ + "": "FunctionSpec describes the contents of the function.", + "environment": "Environment is the build and runtime environment that this function is associated with. An Environment with this name should exist, otherwise the function cannot be invoked.", + "package": "Reference to a package containing deployment and optionally the source.", + "secrets": "Reference to a list of secrets.", + "configmaps": "Reference to a list of configmaps.", + "resources": "cpu and memory resources as per K8S standards This is only for newdeploy to set up resource limitation when creating deployment for a function.", + "InvokeStrategy": "InvokeStrategy is a set of controls which affect how function executes", +} + +func (FunctionSpec) SwaggerDoc() map[string]string { + return map_FunctionSpec +} + +var map_HTTPTrigger = map[string]string{ + "": "HTTPTrigger is the trigger invokes user functions when receiving HTTP requests.", +} + +func (HTTPTrigger) SwaggerDoc() map[string]string { + return map_HTTPTrigger +} + +var map_HTTPTriggerList = map[string]string{ + "": "HTTPTriggerList is a list of HTTPTriggers", +} + +func (HTTPTriggerList) SwaggerDoc() map[string]string { + return map_HTTPTriggerList +} + +var map_HTTPTriggerSpec = map[string]string{ + "": "HTTPTriggerSpec is for router to expose user functions at the given URL path.", + "relativeurl": "RelativeURL is the exposed URL for external client to access a function with.", + "createingress": "If CreateIngress is true, router will create a ingress definition.", + "method": "HTTP method to access a function.", + "functionref": "FunctionReference is a reference to the target function.", +} + +func (HTTPTriggerSpec) SwaggerDoc() map[string]string { + return map_HTTPTriggerSpec +} + +var map_InvokeStrategy = map[string]string{ + "": "InvokeStrategy is a set of controls over how the function executes. It affects the performance and resource usage of the function.\n\nAn InvokeStrategy is of one of two types: ExecutionStrategy, which controls low-level parameters such as which ExecutorType to use, when to autoscale, minimum and maximum number of running instances, etc. A higher-level AbstractInvokeStrategy will also be supported; this strategy would specify the target request rate of the function, the target latency statistics, and the target cost (in terms of compute resources).", + "ExecutionStrategy": "ExecutionStrategy specifies low-level parameters for function execution, such as the number of instances.", + "StrategyType": "StrategyType is the strategy type of a function. Now it only supports 'execution'.", +} + +func (InvokeStrategy) SwaggerDoc() map[string]string { + return map_InvokeStrategy +} + +var map_KubernetesWatchTrigger = map[string]string{ + "": "KubernetesWatchTrigger watches kubernetes resource events and invokes functions.", +} + +func (KubernetesWatchTrigger) SwaggerDoc() map[string]string { + return map_KubernetesWatchTrigger +} + +var map_KubernetesWatchTriggerList = map[string]string{ + "": "KubernetesWatchTriggerList is a list of KubernetesWatchTriggers", +} + +func (KubernetesWatchTriggerList) SwaggerDoc() map[string]string { + return map_KubernetesWatchTriggerList +} + +var map_KubernetesWatchTriggerSpec = map[string]string{ + "": "KubernetesWatchTriggerSpec", + "type": "Type of resource to watch (Pod, Service, etc.)", + "labelselector": "Resource labels", + "functionref": "The reference to a function for kubewatcher to invoke with when receiving events.", +} + +func (KubernetesWatchTriggerSpec) SwaggerDoc() map[string]string { + return map_KubernetesWatchTriggerSpec +} + +var map_MessageQueueTrigger = map[string]string{ + "": "MessageQueueTrigger invokes functions when messages arrive to certain topic that trigger subscribes to.", +} + +func (MessageQueueTrigger) SwaggerDoc() map[string]string { + return map_MessageQueueTrigger +} + +var map_MessageQueueTriggerList = map[string]string{ + "": "MessageQueueTriggerList is a list of MessageQueueTriggers.", +} + +func (MessageQueueTriggerList) SwaggerDoc() map[string]string { + return map_MessageQueueTriggerList +} + +var map_MessageQueueTriggerSpec = map[string]string{ + "": "MessageQueueTriggerSpec defines a binding from a topic in a message queue to a function.", + "functionref": "The reference to a function for message queue trigger to invoke with when receiving messages from subscribed topic.", + "messageQueueType": "Type of message queue (NATS, Kafka, AzureQueue)", + "topic": "Subscribed topic", + "respTopic": "Topic for message queue trigger to sent response from function.", + "errorTopic": "Topic to collect error response sent from function", + "maxRetries": "Maximum times for message queue trigger to retry", + "contentType": "Content type of payload", +} + +func (MessageQueueTriggerSpec) SwaggerDoc() map[string]string { + return map_MessageQueueTriggerSpec +} + +var map_Package = map[string]string{ + "": "Packages. Think of these as function-level images.", + "status": "Status indicates the build status of package.", +} + +func (Package) SwaggerDoc() map[string]string { + return map_Package +} + +var map_PackageList = map[string]string{ + "": "PackageList is a list of Packages.", +} + +func (PackageList) SwaggerDoc() map[string]string { + return map_PackageList +} + +var map_PackageRef = map[string]string{ + "": "PackageRef is a reference to the package.", + "resourceversion": "Including resource version in the reference forces the function to be updated on package update, making it possible to cache the function based on its metadata.", +} + +func (PackageRef) SwaggerDoc() map[string]string { + return map_PackageRef +} + +var map_PackageSpec = map[string]string{ + "": "PackageSpec includes source/deploy archives and the reference of environment to build the package.", + "environment": "Environment is a reference to the environment for building source archive.", + "source": "Source is the archive contains source code and dependencies file. If the package status is in PENDING state, builder manager will then notify builder to compile source and save the result as deployable archive.", + "deployment": "Deployment is the deployable archive that environment runtime used to run user function.", + "buildcmd": "BuildCommand is a custom build command that builder used to build the source archive.", +} + +func (PackageSpec) SwaggerDoc() map[string]string { + return map_PackageSpec +} + +var map_PackageStatus = map[string]string{ + "": "PackageStatus contains the build status of a package also the build log for examination.", + "buildstatus": "BuildStatus is the package build status.", + "buildlog": "BuildLog stores build log during the compilation.", +} + +func (PackageStatus) SwaggerDoc() map[string]string { + return map_PackageStatus +} + +var map_Recorder = map[string]string{ + "": "Recorder allows user to record all traffic payload to a certain function.", +} + +func (Recorder) SwaggerDoc() map[string]string { + return map_Recorder +} + +var map_RecorderList = map[string]string{ + "": "RecorderList is a list of Recorders.", +} + +func (RecorderList) SwaggerDoc() map[string]string { + return map_RecorderList +} + +var map_RecorderSpec = map[string]string{ + "": "RecorderSpec defines a policy for recording requests and responses to a function, that can be later inspected or replayed.", + "name": "Name of recorder resource", + "function": "Function to collect requests/responses", + "triggers": "HTTP trigger to record the requests and responses.", +} + +func (RecorderSpec) SwaggerDoc() map[string]string { + return map_RecorderSpec +} + +var map_Runtime = map[string]string{ + "": "Runtime is the setting for environment runtime.", + "image": "Image for containing the language runtime.", + "container": "(Optional) Container allows the modification of the deployed runtime container using the Kubernetes Container spec. Fission overrides the following fields: - Name - Image; set to the Runtime.Image - TerminationMessagePath - ImagePullPolicy\n\nYou can set either PodSpec or Container, but not both.", + "podspec": "(Optional) Podspec allows modification of deployed runtime pod with Kubernetes PodSpec The merging logic is briefly described below and detailed MergePodSpec function - Volumes mounts and env variables for function and fetcher container are appended - All additional containers and init containers are appended - Volume definitions are appended - Lists such as tolerations, ImagePullSecrets, HostAliases are appended - Structs are merged and variables from pod spec take precedence\n\nYou can set either PodSpec or Container, but not both.", +} + +func (Runtime) SwaggerDoc() map[string]string { + return map_Runtime +} + +var map_SecretReference = map[string]string{ + "": "SecretReference is a reference to a kubernetes secret.", +} + +func (SecretReference) SwaggerDoc() map[string]string { + return map_SecretReference +} + +var map_TimeTrigger = map[string]string{ + "": "TimeTrigger invokes functions based on given cron schedule.", +} + +func (TimeTrigger) SwaggerDoc() map[string]string { + return map_TimeTrigger +} + +var map_TimeTriggerList = map[string]string{ + "": "TimeTriggerList is a list of TimeTriggers.", +} + +func (TimeTriggerList) SwaggerDoc() map[string]string { + return map_TimeTriggerList +} + +var map_TimeTriggerSpec = map[string]string{ + "": "TimeTrigger invokes the specific function at a time or times specified by a cron string.", + "cron": "Cron schedule", + "functionref": "The reference to function", +} + +func (TimeTriggerSpec) SwaggerDoc() map[string]string { + return map_TimeTriggerSpec +} + +// AUTO-GENERATED FUNCTIONS END HERE diff --git a/pkg/controller/api.go b/pkg/controller/api.go index 37db06a332..97cefab173 100644 --- a/pkg/controller/api.go +++ b/pkg/controller/api.go @@ -270,6 +270,8 @@ func (api *API) Serve(port int) { r.HandleFunc("/proxy/workflows-apiserver/{path:.*}", api.WorkflowApiserverProxy) r.HandleFunc("/proxy/svcname", api.GetSvcName).Queries("application", "").Methods("GET") + r.Handle("/v2/apidocs.json", openAPI()).Methods("GET") + address := fmt.Sprintf(":%v", port) api.logger.Info("server started", zap.Int("port", port)) diff --git a/pkg/controller/canaryConfigApi.go b/pkg/controller/canaryConfigApi.go index 7aa44a67b6..ffe4e6e269 100644 --- a/pkg/controller/canaryConfigApi.go +++ b/pkg/controller/canaryConfigApi.go @@ -22,6 +22,9 @@ import ( "io/ioutil" "net/http" + "github.com/emicklei/go-restful" + restfulspec "github.com/emicklei/go-restful-openapi" + "github.com/go-openapi/spec" "github.com/gorilla/mux" "go.uber.org/zap" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -31,6 +34,73 @@ import ( config "github.com/fission/fission/pkg/featureconfig" ) +func RegisterCanaryConfigRoute(ws *restful.WebService) { + tags := []string{"CanaryConfig"} + specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "CanaryConfig", Description: "CanaryConfig Operation"}}) + + ws.Route( + ws.GET("/v2/canaryconfigs"). + Doc("List all canary configs"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.QueryParameter("namespace", "Namespace of canaryConfig").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes([]fv1.CanaryConfig{}). + Returns(http.StatusOK, "List of canaryConfigs", []fv1.CanaryConfig{})) + + ws.Route( + ws.POST("/v2/canaryconfigs"). + Doc("Create canary config"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Produces(restful.MIME_JSON). + Reads(fv1.CanaryConfig{}). + Writes(metav1.ObjectMeta{}). + Returns(http.StatusCreated, "Metadata of created canaryConfig", metav1.ObjectMeta{})) + + ws.Route( + ws.GET("/v2/canaryconfigs/{canaryConfig}"). + Doc("Get detail of canary config"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("canaryConfig", "CanaryConfig name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of canaryConfig").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes(fv1.CanaryConfig{}). // on the response + Returns(http.StatusOK, "A canaryConfig", fv1.CanaryConfig{})) + + ws.Route( + ws.PUT("/v2/canaryconfigs/{canaryConfig}"). + Doc("Update canary config"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("canaryConfig", "CanaryConfig name").DataType("string").DefaultValue("").Required(true)). + Produces(restful.MIME_JSON). + Reads(fv1.CanaryConfig{}). + Writes(metav1.ObjectMeta{}). // on the response + Returns(http.StatusOK, "Metadata of updated canaryConfig", metav1.ObjectMeta{})) + + ws.Route( + ws.DELETE("/v2/canaryconfigs/{canaryConfig}"). + Doc("Delete canary config"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("canaryConfig", "CanaryConfig name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of canaryConfig").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Returns(http.StatusOK, "Only HTTP status returned", nil)) +} + func (a *API) CanaryConfigApiCreate(w http.ResponseWriter, r *http.Request) { featureErr := a.featureStatus[config.CanaryFeature] if len(featureErr) > 0 { diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 93ece2567e..c3c8fb1925 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -49,6 +49,9 @@ func Start(logger *zap.Logger, port int, unitTestFlag bool) { } defer cancel() + // openapi service + //go openAPI(cLogger) + api, err := MakeAPI(cLogger, featureStatus) if err != nil { cLogger.Fatal("failed to start controller", zap.Error(err)) diff --git a/pkg/controller/environmentApi.go b/pkg/controller/environmentApi.go index 656cf86772..2396c1db85 100644 --- a/pkg/controller/environmentApi.go +++ b/pkg/controller/environmentApi.go @@ -21,6 +21,9 @@ import ( "io/ioutil" "net/http" + "github.com/emicklei/go-restful" + restfulspec "github.com/emicklei/go-restful-openapi" + "github.com/go-openapi/spec" "github.com/gorilla/mux" "go.uber.org/zap" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -29,6 +32,73 @@ import ( ferror "github.com/fission/fission/pkg/error" ) +func RegisterEnvironmentRoute(ws *restful.WebService) { + tags := []string{"Environment"} + specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "Environment", Description: "Environment Operation"}}) + + ws.Route( + ws.GET("/v2/environments"). + Doc("List all environments"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.QueryParameter("namespace", "Namespace of environment").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes([]fv1.Environment{}). + Returns(http.StatusOK, "List of environments", []fv1.Environment{})) + + ws.Route( + ws.POST("/v2/environments"). + Doc("Create environment"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Produces(restful.MIME_JSON). + Reads(fv1.Environment{}). + Writes(metav1.ObjectMeta{}). + Returns(http.StatusCreated, "Metadata of created environment", metav1.ObjectMeta{})) + + ws.Route( + ws.GET("/v2/environments/{environment}"). + Doc("Get detail of environment"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("environment", "Environment name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of environment").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes(fv1.Environment{}). // on the response + Returns(http.StatusOK, "A environment", fv1.Environment{})) + + ws.Route( + ws.PUT("/v2/environments/{environment}"). + Doc("Update environment"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("environment", "Environment name").DataType("string").DefaultValue("").Required(true)). + Produces(restful.MIME_JSON). + Reads(fv1.Environment{}). + Writes(metav1.ObjectMeta{}). // on the response + Returns(http.StatusOK, "Metadata of updated environment", metav1.ObjectMeta{})) + + ws.Route( + ws.DELETE("/v2/environments/{environment}"). + Doc("Delete environment"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("environment", "Environment name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of environment").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Returns(http.StatusOK, "Only HTTP status returned", nil)) +} + func (a *API) EnvironmentApiList(w http.ResponseWriter, r *http.Request) { ns := a.extractQueryParamFromRequest(r, "namespace") if len(ns) == 0 { diff --git a/pkg/controller/functionApi.go b/pkg/controller/functionApi.go index b25a8e2e34..a886b8829d 100644 --- a/pkg/controller/functionApi.go +++ b/pkg/controller/functionApi.go @@ -26,6 +26,9 @@ import ( "net/url" "sort" + "github.com/emicklei/go-restful" + restfulspec "github.com/emicklei/go-restful-openapi" + "github.com/go-openapi/spec" "github.com/gorilla/mux" "go.uber.org/zap" apiv1 "k8s.io/api/core/v1" @@ -36,6 +39,73 @@ import ( ferror "github.com/fission/fission/pkg/error" ) +func RegisterFunctionRoute(ws *restful.WebService) { + tags := []string{"Function"} + specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "Function", Description: "Function Operation"}}) + + ws.Route( + ws.GET("/v2/functions"). + Doc("List all functions"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.QueryParameter("namespace", "Namespace of function").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes([]fv1.Function{}). + Returns(http.StatusOK, "List of functions", []fv1.Function{})) + + ws.Route( + ws.POST("/v2/functions"). + Doc("Create function"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Produces(restful.MIME_JSON). + Reads(fv1.Function{}). + Writes(metav1.ObjectMeta{}). + Returns(http.StatusOK, "Metadata of created function", metav1.ObjectMeta{})) + + ws.Route( + ws.GET("/v2/functions/{function}"). + Doc("Get detail of function"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("function", "Function name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of function").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes(fv1.Function{}). // on the response + Returns(http.StatusOK, "A function", fv1.Function{})) + + ws.Route( + ws.PUT("/v2/functions/{function}"). + Doc("Update function"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("function", "Function name").DataType("string").DefaultValue("").Required(true)). + Produces(restful.MIME_JSON). + Reads(fv1.Function{}). + Writes(metav1.ObjectMeta{}). // on the response + Returns(http.StatusOK, "Metadata of updated function", metav1.ObjectMeta{})) + + ws.Route( + ws.DELETE("/v2/functions/{function}"). + Doc("Delete function"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("function", "Function name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of function").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Returns(http.StatusOK, "Only HTTP status returned", nil)) +} + func (a *API) getIstioServiceLabels(fnName string) map[string]string { return map[string]string{ "functionName": fnName, diff --git a/pkg/controller/httpTriggerApi.go b/pkg/controller/httpTriggerApi.go index f23856fd67..75cbdd181c 100644 --- a/pkg/controller/httpTriggerApi.go +++ b/pkg/controller/httpTriggerApi.go @@ -22,6 +22,9 @@ import ( "io/ioutil" "net/http" + "github.com/emicklei/go-restful" + restfulspec "github.com/emicklei/go-restful-openapi" + "github.com/go-openapi/spec" "github.com/gorilla/mux" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -29,6 +32,73 @@ import ( ferror "github.com/fission/fission/pkg/error" ) +func RegisterHTTPTriggerRoute(ws *restful.WebService) { + tags := []string{"HTTPTrigger"} + specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "HTTPTrigger", Description: "HTTPTrigger Operation"}}) + + ws.Route( + ws.GET("/v2/triggers/http"). + Doc("List all HTTP triggers"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.QueryParameter("namespace", "Namespace of httpTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes([]fv1.HTTPTrigger{}). + Returns(http.StatusOK, "List of httpTriggers", []fv1.HTTPTrigger{})) + + ws.Route( + ws.POST("/v2/triggers/http"). + Doc("Create HTTP trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Produces(restful.MIME_JSON). + Reads(fv1.HTTPTrigger{}). + Writes(metav1.ObjectMeta{}). + Returns(http.StatusCreated, "Metadata of created httpTrigger", metav1.ObjectMeta{})) + + ws.Route( + ws.GET("/v2/triggers/http/{httpTrigger}"). + Doc("Get detail of HTTP trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("httpTrigger", "HTTPTrigger name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of httpTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes(fv1.HTTPTrigger{}). // on the response + Returns(http.StatusOK, "A httpTrigger", fv1.HTTPTrigger{})) + + ws.Route( + ws.PUT("/v2/triggers/http/{httpTrigger}"). + Doc("Update HTTP trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("httpTrigger", "HTTPTrigger name").DataType("string").DefaultValue("").Required(true)). + Produces(restful.MIME_JSON). + Reads(fv1.HTTPTrigger{}). + Writes(metav1.ObjectMeta{}). // on the response + Returns(http.StatusOK, "Metadata of updated httpTrigger", metav1.ObjectMeta{})) + + ws.Route( + ws.DELETE("/v2/triggers/http/{httpTrigger}"). + Doc("Delete HTTP trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("httpTrigger", "HTTPTrigger name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of httpTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Returns(http.StatusOK, "Only HTTP status returned", nil)) +} + func (a *API) HTTPTriggerApiList(w http.ResponseWriter, r *http.Request) { ns := a.extractQueryParamFromRequest(r, "namespace") if len(ns) == 0 { diff --git a/pkg/controller/mqTriggerApi.go b/pkg/controller/mqTriggerApi.go index b5941d806c..9f43ea3593 100644 --- a/pkg/controller/mqTriggerApi.go +++ b/pkg/controller/mqTriggerApi.go @@ -21,6 +21,9 @@ import ( "io/ioutil" "net/http" + "github.com/emicklei/go-restful" + restfulspec "github.com/emicklei/go-restful-openapi" + "github.com/go-openapi/spec" "github.com/gorilla/mux" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -28,6 +31,73 @@ import ( ferror "github.com/fission/fission/pkg/error" ) +func RegisterMessageQueueTriggerRoute(ws *restful.WebService) { + tags := []string{"MessageQueueTrigger"} + specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "MessageQueueTrigger", Description: "MessageQueueTrigger Operation"}}) + + ws.Route( + ws.GET("/v2/triggers/messagequeue"). + Doc("List all message queue triggers"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.QueryParameter("namespace", "Namespace of messageQueueTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes([]fv1.MessageQueueTrigger{}). + Returns(http.StatusOK, "List of messageQueueTriggers", []fv1.MessageQueueTrigger{})) + + ws.Route( + ws.POST("/v2/triggers/messagequeue"). + Doc("Create message queue trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Produces(restful.MIME_JSON). + Reads(fv1.MessageQueueTrigger{}). + Writes(metav1.ObjectMeta{}). + Returns(http.StatusCreated, "Metadata of created messageQueueTrigger", metav1.ObjectMeta{})) + + ws.Route( + ws.GET("/v2/triggers/messagequeue/{mqTrigger}"). + Doc("Get detail of message queue trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("mqTrigger", "MessageQueueTriggers name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of messageQueueTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes(fv1.MessageQueueTrigger{}). // on the response + Returns(http.StatusOK, "A messageQueueTrigger", fv1.MessageQueueTrigger{})) + + ws.Route( + ws.PUT("/v2/triggers/messagequeue/{mqTrigger}"). + Doc("Update message queue trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("mqTrigger", "MessageQueueTrigger name").DataType("string").DefaultValue("").Required(true)). + Produces(restful.MIME_JSON). + Reads(fv1.MessageQueueTrigger{}). + Writes(metav1.ObjectMeta{}). // on the response + Returns(http.StatusOK, "Metadata of updated messageQueueTrigger", metav1.ObjectMeta{})) + + ws.Route( + ws.DELETE("/v2/triggers/messagequeue/{mqTrigger}"). + Doc("Delete message queue trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("mqTrigger", "MessageQueueTrigger name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of messageQueueTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Returns(http.StatusOK, "Only HTTP status returned", nil)) +} + func (a *API) MessageQueueTriggerApiList(w http.ResponseWriter, r *http.Request) { //mqType := r.FormValue("mqtype") // ignored for now ns := a.extractQueryParamFromRequest(r, "namespace") diff --git a/pkg/controller/openapi.go b/pkg/controller/openapi.go new file mode 100644 index 0000000000..b6e1d4d703 --- /dev/null +++ b/pkg/controller/openapi.go @@ -0,0 +1,78 @@ +/* +Copyright 2019 The Fission Authors. + +Licensed 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. +*/ + +package controller + +import ( + "net/http" + + "github.com/emicklei/go-restful" + restfulspec "github.com/emicklei/go-restful-openapi" + "github.com/go-openapi/spec" +) + +var specTag []spec.Tag + +func openAPI() http.Handler { + restful.DefaultContainer.Add(openAPIWebService()) + + config := restfulspec.Config{ + WebServices: restful.RegisteredWebServices(), + APIPath: "/v2/apidocs.json", + PostBuildSwaggerObjectHandler: enrichSwaggerObject} + + restful.DefaultContainer.Add(restfulspec.NewOpenAPIService(config)) + + return restful.DefaultContainer +} + +func openAPIWebService() *restful.WebService { + ws := new(restful.WebService) + + // CRD resource + RegisterEnvironmentRoute(ws) + RegisterFunctionRoute(ws) + RegisterHTTPTriggerRoute(ws) + RegisterMessageQueueTriggerRoute(ws) + RegisterPackageRoute(ws) + RegisterWatchRoute(ws) + RegisterTimeTriggerRoute(ws) + RegisterCanaryConfigRoute(ws) + + // proxy + RegisterStorageServiceProxyRoute(ws) + + return ws +} + +func enrichSwaggerObject(swo *spec.Swagger) { + swo.Info = &spec.Info{ + InfoProps: spec.InfoProps{ + Title: "Fission OpenAPI 2.0", + Description: openapiDescription, + Version: "v1", + }, + } + swo.Tags = specTag +} + +var openapiDescription = ` +OpenAPI 2.0 document for fission controller +* Metadata (v1.ObjectMeta) should be empty when creating a CRD resource. Kubernetes will assign it automatically. +* Following semantic errors are known issues and won't affect the API accessibility. + - Operations must have unique operationIds. + - All scale semantic errors. (Due to go-restful exposes inner fields of k8s struct). +` diff --git a/pkg/controller/packageApi.go b/pkg/controller/packageApi.go index 00420ff30d..cea3c84e36 100644 --- a/pkg/controller/packageApi.go +++ b/pkg/controller/packageApi.go @@ -23,7 +23,10 @@ import ( "net/http" "github.com/dustin/go-humanize" + "github.com/emicklei/go-restful" + restfulspec "github.com/emicklei/go-restful-openapi" "github.com/fission/fission/pkg/types" + "github.com/go-openapi/spec" "github.com/gorilla/mux" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -31,6 +34,73 @@ import ( ferror "github.com/fission/fission/pkg/error" ) +func RegisterPackageRoute(ws *restful.WebService) { + tags := []string{"Package"} + specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "Package", Description: "Package Operation"}}) + + ws.Route( + ws.GET("/v2/packages"). + Doc("List all packages"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.QueryParameter("namespace", "Namespace of package").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes([]fv1.Package{}). + Returns(http.StatusOK, "List of packages", []fv1.Package{})) + + ws.Route( + ws.POST("/v2/packages"). + Doc("Create package"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Produces(restful.MIME_JSON). + Reads(fv1.Package{}). + Writes(metav1.ObjectMeta{}). + Returns(http.StatusCreated, "Metadata of created package", metav1.ObjectMeta{})) + + ws.Route( + ws.GET("/v2/packages/{package}"). + Doc("Get detail of package"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("package", "Package name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of package").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes(fv1.Package{}). // on the response + Returns(http.StatusOK, "A package", fv1.Package{})) + + ws.Route( + ws.PUT("/v2/packages/{package}"). + Doc("Update package"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("package", "Package name").DataType("string").DefaultValue("").Required(true)). + Produces(restful.MIME_JSON). + Reads(fv1.Package{}). + Writes(metav1.ObjectMeta{}). // on the response + Returns(http.StatusOK, "Metadata of updated package", metav1.ObjectMeta{})) + + ws.Route( + ws.DELETE("/v2/packages/{package}"). + Doc("Delete package"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("package", "Package name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of package").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Returns(http.StatusOK, "Only HTTP status returned", nil)) +} + func (a *API) PackageApiList(w http.ResponseWriter, r *http.Request) { ns := a.extractQueryParamFromRequest(r, "namespace") if len(ns) == 0 { diff --git a/pkg/controller/storagesvc.go b/pkg/controller/storagesvc.go index 647c8b06ba..a587fd25a6 100644 --- a/pkg/controller/storagesvc.go +++ b/pkg/controller/storagesvc.go @@ -22,9 +22,40 @@ import ( "net/http/httputil" "net/url" + "github.com/emicklei/go-restful" + restfulspec "github.com/emicklei/go-restful-openapi" + "github.com/go-openapi/spec" "go.uber.org/zap" ) +func RegisterStorageServiceProxyRoute(ws *restful.WebService) { + tags := []string{"StorageServiceProxy"} + specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "StorageServiceProxy", Description: "StorageServiceProxy Operation"}}) + + // workaround as go-restful has to set HTTP method explicitly. + ws.Route( + ws.POST("/proxy/storage/v1/archive"). + Doc("Create archive"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + })) + ws.Route( + ws.GET("/proxy/storage/v1/archive"). + Doc("Get archive"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + })) + ws.Route( + ws.DELETE("/proxy/storage/v1/archive"). + Doc("Delete archive"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + })) +} + func (api *API) StorageServiceProxy(w http.ResponseWriter, r *http.Request) { u := api.storageServiceUrl ssUrl, err := url.Parse(u) diff --git a/pkg/controller/timeTriggerApi.go b/pkg/controller/timeTriggerApi.go index b7e157b873..0df4388131 100644 --- a/pkg/controller/timeTriggerApi.go +++ b/pkg/controller/timeTriggerApi.go @@ -21,6 +21,9 @@ import ( "io/ioutil" "net/http" + "github.com/emicklei/go-restful" + restfulspec "github.com/emicklei/go-restful-openapi" + "github.com/go-openapi/spec" "github.com/gorilla/mux" "github.com/robfig/cron" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -29,6 +32,73 @@ import ( ferror "github.com/fission/fission/pkg/error" ) +func RegisterTimeTriggerRoute(ws *restful.WebService) { + tags := []string{"TimeTrigger"} + specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "TimeTrigger", Description: "TimeTrigger Operation"}}) + + ws.Route( + ws.GET("/v2/triggers/time"). + Doc("List all time trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.QueryParameter("namespace", "Namespace of timeTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes([]fv1.TimeTrigger{}). + Returns(http.StatusOK, "List of timeTriggers", []fv1.TimeTrigger{})) + + ws.Route( + ws.POST("/v2/triggers/time"). + Doc("Create time trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Produces(restful.MIME_JSON). + Reads(fv1.TimeTrigger{}). + Writes(metav1.ObjectMeta{}). + Returns(http.StatusCreated, "Metadata of created timeTrigger", metav1.ObjectMeta{})) + + ws.Route( + ws.GET("/v2/triggers/time/{timeTrigger}"). + Doc("Get detail of time trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("timeTrigger", "TimeTrigger name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of timeTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes(fv1.TimeTrigger{}). // on the response + Returns(http.StatusOK, "A timeTrigger", fv1.TimeTrigger{})) + + ws.Route( + ws.PUT("/v2/triggers/time/{timeTrigger}"). + Doc("Update time trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("timeTrigger", "TimeTrigger name").DataType("string").DefaultValue("").Required(true)). + Produces(restful.MIME_JSON). + Reads(fv1.TimeTrigger{}). + Writes(metav1.ObjectMeta{}). // on the response + Returns(http.StatusOK, "Metadata of updated timeTrigger", metav1.ObjectMeta{})) + + ws.Route( + ws.DELETE("/v2/triggers/time/{timeTrigger}"). + Doc("Delete time trigger"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("timeTrigger", "TimeTrigger name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of timeTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Returns(http.StatusOK, "Only HTTP status returned", nil)) +} + func (a *API) TimeTriggerApiList(w http.ResponseWriter, r *http.Request) { ns := a.extractQueryParamFromRequest(r, "namespace") if len(ns) == 0 { diff --git a/pkg/controller/watchApi.go b/pkg/controller/watchApi.go index 205d54751f..94a66cd6e6 100644 --- a/pkg/controller/watchApi.go +++ b/pkg/controller/watchApi.go @@ -21,6 +21,9 @@ import ( "io/ioutil" "net/http" + "github.com/emicklei/go-restful" + restfulspec "github.com/emicklei/go-restful-openapi" + "github.com/go-openapi/spec" "github.com/gorilla/mux" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -28,6 +31,73 @@ import ( ferror "github.com/fission/fission/pkg/error" ) +func RegisterWatchRoute(ws *restful.WebService) { + tags := []string{"KubernetesWatch"} + specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "KubernetesWatch", Description: "KubernetesWatch Operation"}}) + + ws.Route( + ws.GET("/v2/watches"). + Doc("List all kubernetes watch"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.QueryParameter("namespace", "Namespace of kubernetesWatch").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes([]fv1.KubernetesWatchTrigger{}). + Returns(http.StatusOK, "List of kubernetesWatchs", []fv1.KubernetesWatchTrigger{})) + + ws.Route( + ws.POST("/v2/watches"). + Doc("Create kubernetes watch"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Produces(restful.MIME_JSON). + Reads(fv1.KubernetesWatchTrigger{}). + Writes(metav1.ObjectMeta{}). + Returns(http.StatusCreated, "Metadata of created kubernetesWatch", metav1.ObjectMeta{})) + + ws.Route( + ws.GET("/v2/watches/{watch}"). + Doc("Get detail of kubernetes watch"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("watch", "KubernetesWatch name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of kubernetesWatch").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Writes(fv1.KubernetesWatchTrigger{}). // on the response + Returns(http.StatusOK, "A kubernetesWatch", fv1.KubernetesWatchTrigger{})) + + ws.Route( + ws.PUT("/v2/watches/{watch}"). + Doc("Update kubernetes watch"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("watch", "KubernetesWatch name").DataType("string").DefaultValue("").Required(true)). + Produces(restful.MIME_JSON). + Reads(fv1.KubernetesWatchTrigger{}). + Writes(metav1.ObjectMeta{}). // on the response + Returns(http.StatusOK, "Metadata of updated kubernetesWatch", metav1.ObjectMeta{})) + + ws.Route( + ws.DELETE("/v2/watches/{watch}"). + Doc("Delete kubernetes watch"). + Metadata(restfulspec.KeyOpenAPITags, tags). + To(func(req *restful.Request, resp *restful.Response) { + resp.ResponseWriter.WriteHeader(http.StatusOK) + }). + Param(ws.PathParameter("watch", "KubernetesWatch name").DataType("string").DefaultValue("").Required(true)). + Param(ws.QueryParameter("namespace", "Namespace of kubernetesWatch").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)). + Produces(restful.MIME_JSON). + Returns(http.StatusOK, "Only HTTP status returned", nil)) +} + func (a *API) WatchApiList(w http.ResponseWriter, r *http.Request) { ns := a.extractQueryParamFromRequest(r, "namespace") if len(ns) == 0 { diff --git a/pkg/fission-cli/mqtrigger.go b/pkg/fission-cli/mqtrigger.go index a481a318f8..8d949d8e97 100644 --- a/pkg/fission-cli/mqtrigger.go +++ b/pkg/fission-cli/mqtrigger.go @@ -5,7 +5,7 @@ Licensed 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 - tttp://www.apache.org/licenses/LICENSE-2.0 + 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, diff --git a/pkg/fission-cli/recorder.go b/pkg/fission-cli/recorder.go index 3c7ad96850..da3200a907 100644 --- a/pkg/fission-cli/recorder.go +++ b/pkg/fission-cli/recorder.go @@ -5,7 +5,7 @@ Licensed 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 - tttp://www.apache.org/licenses/LICENSE-2.0 + 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, diff --git a/pkg/fission-cli/records.go b/pkg/fission-cli/records.go index 2fa7bda14f..879a31dceb 100644 --- a/pkg/fission-cli/records.go +++ b/pkg/fission-cli/records.go @@ -5,7 +5,7 @@ Licensed 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 - tttp://www.apache.org/licenses/LICENSE-2.0 + 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, diff --git a/pkg/fission-cli/timetrigger.go b/pkg/fission-cli/timetrigger.go index 3881a52717..f58822e502 100644 --- a/pkg/fission-cli/timetrigger.go +++ b/pkg/fission-cli/timetrigger.go @@ -5,7 +5,7 @@ Licensed 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 - tttp://www.apache.org/licenses/LICENSE-2.0 + 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,