Canary deployments for fission functions. (#892)
This commit is contained in:
@@ -73,8 +73,25 @@ const (
|
||||
// reference is simply by function name.
|
||||
FunctionReferenceTypeFunctionName = "name"
|
||||
|
||||
FunctionReferenceTypeFunctionWeights = "function-weights"
|
||||
|
||||
// Other function reference types we'd like to support:
|
||||
// Versioned function, latest version
|
||||
// Versioned function. by semver "latest compatible"
|
||||
// Set of function references (recursively), by percentage of traffic
|
||||
)
|
||||
|
||||
const (
|
||||
// failure type currently supported is http status code. This could be extended
|
||||
// in the future.
|
||||
FailureTypeStatusCode FailureType = "status-code"
|
||||
|
||||
// Status of canary config can be one of the following
|
||||
CanaryConfigStatusPending = "pending"
|
||||
CanaryConfigStatusSucceeded = "succeeded"
|
||||
CanaryConfigStatusFailed = "failed"
|
||||
CanaryConfigStatusAborted = "aborted"
|
||||
|
||||
// set a max number for iterations to prevent infinite processing of canary config
|
||||
MaxIterationsForCanaryConfig = 10
|
||||
)
|
||||
|
||||
@@ -185,6 +185,10 @@ 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"`
|
||||
}
|
||||
|
||||
//
|
||||
@@ -328,4 +332,22 @@ type (
|
||||
Cron string `json:"cron"`
|
||||
FunctionReference `json:"functionref"`
|
||||
}
|
||||
|
||||
FailureType string
|
||||
|
||||
// Canary Config Spec
|
||||
CanaryConfigSpec struct {
|
||||
Trigger string `json:"trigger"`
|
||||
FunctionN string `json:"funcn"`
|
||||
FunctionNminus1 string `json:"funcn-1"`
|
||||
WeightIncrement int `json:"weightincrement"`
|
||||
WeightIncrementDuration string `json:"duration"`
|
||||
FailureThreshold int `json:"failurethreshold"`
|
||||
FailureType FailureType `json:"failureType"`
|
||||
}
|
||||
|
||||
// CanaryConfig Status
|
||||
CanaryConfigStatus struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
)
|
||||
|
||||
@@ -167,6 +167,22 @@ type (
|
||||
|
||||
Items []Recorder `json:"items"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
CanaryConfig struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
Metadata metav1.ObjectMeta `json:"metadata"`
|
||||
Spec CanaryConfigSpec `json:"spec"`
|
||||
Status CanaryConfigStatus `json:"status"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
CanaryConfigList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
Metadata metav1.ListMeta `json:"metadata"`
|
||||
|
||||
Items []CanaryConfig `json:"items"`
|
||||
}
|
||||
)
|
||||
|
||||
// Each CRD type needs:
|
||||
@@ -199,6 +215,9 @@ func (m *MessageQueueTrigger) GetObjectKind() schema.ObjectKind {
|
||||
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
|
||||
@@ -225,6 +244,9 @@ func (m *MessageQueueTrigger) GetObjectMeta() metav1.Object {
|
||||
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
|
||||
@@ -255,6 +277,10 @@ 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
|
||||
}
|
||||
@@ -276,10 +302,15 @@ func (ml *MessageQueueTriggerList) GetListMeta() metav1.ListInterface {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -329,11 +329,14 @@ func (ref FunctionReference) Validate() error {
|
||||
|
||||
switch ref.Type {
|
||||
case FunctionReferenceTypeFunctionName: // no op
|
||||
case FunctionReferenceTypeFunctionWeights: // no op
|
||||
default:
|
||||
result = multierror.Append(result, MakeValidationErr(ErrorUnsupportedType, "FunctionReference.Type", ref.Type, "not a valid function reference type"))
|
||||
}
|
||||
|
||||
result = multierror.Append(result, ValidateKubeName("FunctionReference.Name", ref.Name))
|
||||
if ref.Type == FunctionReferenceTypeFunctionName {
|
||||
result = multierror.Append(result, ValidateKubeName("FunctionReference.Name", ref.Name))
|
||||
}
|
||||
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ limitations under the License.
|
||||
package v1
|
||||
|
||||
import (
|
||||
core_v1 "k8s.io/api/core/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
@@ -52,12 +52,8 @@ func (in *Builder) DeepCopyInto(out *Builder) {
|
||||
*out = *in
|
||||
if in.Container != nil {
|
||||
in, out := &in.Container, &out.Container
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(core_v1.Container)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
*out = new(corev1.Container)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -72,6 +68,99 @@ func (in *Builder) DeepCopy() *Builder {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CanaryConfig) DeepCopyInto(out *CanaryConfig) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.Metadata.DeepCopyInto(&out.Metadata)
|
||||
out.Spec = in.Spec
|
||||
out.Status = in.Status
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryConfig.
|
||||
func (in *CanaryConfig) DeepCopy() *CanaryConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CanaryConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CanaryConfig) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CanaryConfigList) DeepCopyInto(out *CanaryConfigList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.Metadata = in.Metadata
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]CanaryConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryConfigList.
|
||||
func (in *CanaryConfigList) DeepCopy() *CanaryConfigList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CanaryConfigList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CanaryConfigList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CanaryConfigSpec) DeepCopyInto(out *CanaryConfigSpec) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryConfigSpec.
|
||||
func (in *CanaryConfigSpec) DeepCopy() *CanaryConfigSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CanaryConfigSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CanaryConfigStatus) DeepCopyInto(out *CanaryConfigStatus) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryConfigStatus.
|
||||
func (in *CanaryConfigStatus) DeepCopy() *CanaryConfigStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CanaryConfigStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Checksum) DeepCopyInto(out *Checksum) {
|
||||
*out = *in
|
||||
@@ -295,6 +384,13 @@ func (in *FunctionPackageRef) DeepCopy() *FunctionPackageRef {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *FunctionReference) DeepCopyInto(out *FunctionReference) {
|
||||
*out = *in
|
||||
if in.FunctionWeights != nil {
|
||||
in, out := &in.FunctionWeights, &out.FunctionWeights
|
||||
*out = make(map[string]int, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -343,7 +439,7 @@ func (in *HTTPTrigger) DeepCopyInto(out *HTTPTrigger) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.Metadata.DeepCopyInto(&out.Metadata)
|
||||
out.Spec = in.Spec
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -401,7 +497,7 @@ func (in *HTTPTriggerList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPTriggerSpec) DeepCopyInto(out *HTTPTriggerSpec) {
|
||||
*out = *in
|
||||
out.FunctionReference = in.FunctionReference
|
||||
in.FunctionReference.DeepCopyInto(&out.FunctionReference)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -502,7 +598,7 @@ func (in *KubernetesWatchTriggerSpec) DeepCopyInto(out *KubernetesWatchTriggerSp
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
out.FunctionReference = in.FunctionReference
|
||||
in.FunctionReference.DeepCopyInto(&out.FunctionReference)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -521,7 +617,7 @@ func (in *MessageQueueTrigger) DeepCopyInto(out *MessageQueueTrigger) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.Metadata.DeepCopyInto(&out.Metadata)
|
||||
out.Spec = in.Spec
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -579,7 +675,7 @@ func (in *MessageQueueTriggerList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MessageQueueTriggerSpec) DeepCopyInto(out *MessageQueueTriggerSpec) {
|
||||
*out = *in
|
||||
out.FunctionReference = in.FunctionReference
|
||||
in.FunctionReference.DeepCopyInto(&out.FunctionReference)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -791,12 +887,8 @@ func (in *Runtime) DeepCopyInto(out *Runtime) {
|
||||
*out = *in
|
||||
if in.Container != nil {
|
||||
in, out := &in.Container, &out.Container
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(core_v1.Container)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
*out = new(corev1.Container)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -832,7 +924,7 @@ func (in *TimeTrigger) DeepCopyInto(out *TimeTrigger) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.Metadata.DeepCopyInto(&out.Metadata)
|
||||
out.Spec = in.Spec
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -890,7 +982,7 @@ func (in *TimeTriggerList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TimeTriggerSpec) DeepCopyInto(out *TimeTriggerSpec) {
|
||||
*out = *in
|
||||
out.FunctionReference = in.FunctionReference
|
||||
in.FunctionReference.DeepCopyInto(&out.FunctionReference)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user