Add swagger (OpenAPI 2.0) support (#1245)

* Add swagger (OpenAPI 2.0) support
* Gererate swagger_doc before building bundle image
This commit is contained in:
Ta-Ching Chen
2019-08-21 15:49:41 +08:00
committed by GitHub
parent 9c63975497
commit b9997b2ece
27 changed files with 1710 additions and 659 deletions
+7
View File
@@ -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
```
@@ -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.
*/
+67
View File
@@ -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 <<EOF
// 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.
EOF
} > "${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"
}
@@ -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)
}
}
}
@@ -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
+291
View File
@@ -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()
}
-364
View File
@@ -1,364 +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
SpecializationTimeout 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"`
}
)
+495 -289
View File
@@ -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,472 @@ type (
Items []CanaryConfig `json:"items"`
}
//
// 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.
// 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"`
}
// EnvironmentReference is a reference to a environment.
EnvironmentReference struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
}
// SecretReference is a reference to a kubernetes secret.
SecretReference struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
}
// ConfigMapReference is a reference to a kubernetes configmap.
ConfigMapReference struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
}
// 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"`
// 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"`
// Deployment is the deployable archive that environment runtime used to run user function.
Deployment Archive `json:"deployment,omitempty"`
// 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
}
// 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"`
// BuildLog stores build log during the compilation.
BuildLog string `json:"buildlog,omitempty"` // output of the build (errors etc)
}
// PackageRef is a reference to the package.
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 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
// This is the timeout setting for executor to wait for pod specialization.
// Currently, only newdeploy utilizes this value.
SpecializationTimeout 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"`
}
AllowedFunctionsPerContainer string
//
// 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"`
}
)
// 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()
}
+2
View File
@@ -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))
+70
View File
@@ -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 {
+3
View File
@@ -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))
+70
View File
@@ -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 {
+70
View File
@@ -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,
+70
View File
@@ -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 {
+70
View File
@@ -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")
+78
View File
@@ -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).
`
+70
View File
@@ -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 {
+31
View File
@@ -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)
+70
View File
@@ -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 {
+70
View File
@@ -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 {
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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,