Update Fn: Executor New Deployment (#504)
Enables updating functions of executor type new deployment and switching between executor types for a function.
This commit is contained in:
+258
-184
@@ -26,8 +26,10 @@ import (
|
||||
"time"
|
||||
|
||||
k8s_err "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/client-go/pkg/api/v1"
|
||||
apiv1 "k8s.io/client-go/pkg/api/v1"
|
||||
asv1 "k8s.io/client-go/pkg/apis/autoscaling/v1"
|
||||
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
||||
@@ -54,9 +56,6 @@ func (deploy *NewDeploy) createOrGetDeployment(fn *crd.Function, env *crd.Enviro
|
||||
if replicas == 0 {
|
||||
replicas = 1
|
||||
}
|
||||
targetFilename := "user"
|
||||
|
||||
var gracePeriodSeconds int64 = 6 * 60
|
||||
|
||||
existingDepl, err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(deploy.namespace).Get(deployName, metav1.GetOptions{})
|
||||
if err == nil && existingDepl.Status.ReadyReplicas >= replicas {
|
||||
@@ -64,190 +63,12 @@ func (deploy *NewDeploy) createOrGetDeployment(fn *crd.Function, env *crd.Enviro
|
||||
}
|
||||
|
||||
if err != nil && k8s_err.IsNotFound(err) {
|
||||
fetchReq := &fetcher.FetchRequest{
|
||||
FetchType: fetcher.FETCH_DEPLOYMENT,
|
||||
Package: metav1.ObjectMeta{
|
||||
Namespace: fn.Spec.Package.PackageRef.Namespace,
|
||||
Name: fn.Spec.Package.PackageRef.Name,
|
||||
},
|
||||
Filename: targetFilename,
|
||||
Secrets: fn.Spec.Secrets,
|
||||
ConfigMaps: fn.Spec.ConfigMaps,
|
||||
}
|
||||
|
||||
loadReq := fission.FunctionLoadRequest{
|
||||
FilePath: filepath.Join(deploy.sharedMountPath, targetFilename),
|
||||
FunctionName: fn.Spec.Package.FunctionName,
|
||||
FunctionMetadata: &fn.Metadata,
|
||||
}
|
||||
|
||||
fetchPayload, err := json.Marshal(fetchReq)
|
||||
deployment, err := deploy.getDeploymentSpec(fn, env, deployName, deployLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loadPayload, err := json.Marshal(loadReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fetcherResources, err := util.GetFetcherResources()
|
||||
if err != nil {
|
||||
log.Printf("Error while parsing fetcher resources: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
podAnnotation := make(map[string]string)
|
||||
if deploy.useIstio && env.Spec.AllowAccessToExternalNetwork {
|
||||
podAnnotation["sidecar.istio.io/inject"] = "false"
|
||||
}
|
||||
|
||||
deployment := &v1beta1.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: deployLabels,
|
||||
Name: deployName,
|
||||
},
|
||||
Spec: v1beta1.DeploymentSpec{
|
||||
Replicas: &replicas,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: deployLabels,
|
||||
},
|
||||
Template: apiv1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: deployLabels,
|
||||
Annotations: podAnnotation,
|
||||
},
|
||||
Spec: apiv1.PodSpec{
|
||||
Volumes: []apiv1.Volume{
|
||||
{
|
||||
Name: fission.SharedVolumeUserfunc,
|
||||
VolumeSource: apiv1.VolumeSource{
|
||||
EmptyDir: &apiv1.EmptyDirVolumeSource{},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeSecrets,
|
||||
VolumeSource: apiv1.VolumeSource{
|
||||
EmptyDir: &apiv1.EmptyDirVolumeSource{},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeConfigmaps,
|
||||
VolumeSource: apiv1.VolumeSource{
|
||||
EmptyDir: &apiv1.EmptyDirVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []apiv1.Container{
|
||||
{
|
||||
Name: fn.Metadata.Name,
|
||||
Image: env.Spec.Runtime.Image,
|
||||
ImagePullPolicy: apiv1.PullIfNotPresent,
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
VolumeMounts: []apiv1.VolumeMount{
|
||||
{
|
||||
Name: fission.SharedVolumeUserfunc,
|
||||
MountPath: deploy.sharedMountPath,
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeSecrets,
|
||||
MountPath: deploy.sharedSecretPath,
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeConfigmaps,
|
||||
MountPath: deploy.sharedCfgMapPath,
|
||||
},
|
||||
},
|
||||
Resources: env.Spec.Resources,
|
||||
Lifecycle: &apiv1.Lifecycle{
|
||||
PreStop: &apiv1.Handler{
|
||||
Exec: &apiv1.ExecAction{
|
||||
Command: []string{
|
||||
"sleep",
|
||||
fmt.Sprintf("%v", gracePeriodSeconds),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "fetcher",
|
||||
Image: deploy.fetcherImg,
|
||||
ImagePullPolicy: deploy.fetcherImagePullPolicy,
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
VolumeMounts: []apiv1.VolumeMount{
|
||||
{
|
||||
Name: fission.SharedVolumeUserfunc,
|
||||
MountPath: deploy.sharedMountPath,
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeSecrets,
|
||||
MountPath: deploy.sharedSecretPath,
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeConfigmaps,
|
||||
MountPath: deploy.sharedCfgMapPath,
|
||||
},
|
||||
},
|
||||
Command: []string{"/fetcher", "-specialize-on-startup",
|
||||
"-fetch-request", string(fetchPayload),
|
||||
"-load-request", string(loadPayload),
|
||||
"-secret-dir", deploy.sharedSecretPath,
|
||||
"-cfgmap-dir", deploy.sharedCfgMapPath,
|
||||
deploy.sharedMountPath},
|
||||
Lifecycle: &apiv1.Lifecycle{
|
||||
PreStop: &apiv1.Handler{
|
||||
Exec: &apiv1.ExecAction{
|
||||
Command: []string{
|
||||
"sleep",
|
||||
fmt.Sprintf("%v", gracePeriodSeconds),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Env: []apiv1.EnvVar{
|
||||
{
|
||||
Name: envVersion,
|
||||
Value: strconv.Itoa(env.Spec.Version),
|
||||
},
|
||||
},
|
||||
// TBD Use smaller default resources, for now needed to make HPA work
|
||||
Resources: fetcherResources,
|
||||
ReadinessProbe: &apiv1.Probe{
|
||||
InitialDelaySeconds: 1,
|
||||
PeriodSeconds: 1,
|
||||
FailureThreshold: 30,
|
||||
Handler: apiv1.Handler{
|
||||
HTTPGet: &apiv1.HTTPGetAction{
|
||||
Path: "/healthz",
|
||||
Port: intstr.IntOrString{
|
||||
Type: intstr.Int,
|
||||
IntVal: 8000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
LivenessProbe: &apiv1.Probe{
|
||||
InitialDelaySeconds: 35,
|
||||
PeriodSeconds: 5,
|
||||
Handler: apiv1.Handler{
|
||||
HTTPGet: &apiv1.HTTPGetAction{
|
||||
Path: "/healthz",
|
||||
Port: intstr.IntOrString{
|
||||
Type: intstr.Int,
|
||||
IntVal: 8000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServiceAccountName: "fission-fetcher",
|
||||
TerminationGracePeriodSeconds: &gracePeriodSeconds,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
depl, err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(deploy.namespace).Create(deployment)
|
||||
if err != nil {
|
||||
log.Printf("Error while creating deployment: %v", err)
|
||||
@@ -272,8 +93,20 @@ func (deploy *NewDeploy) createOrGetDeployment(fn *crd.Function, env *crd.Enviro
|
||||
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) getDeployment(fn *crd.Function) (*v1beta1.Deployment, error) {
|
||||
deployName := deploy.getObjName(fn)
|
||||
return deploy.kubernetesClient.ExtensionsV1beta1().Deployments(deploy.namespace).Get(deployName, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) updateDeployment(deployment *v1beta1.Deployment) error {
|
||||
_, err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(deploy.namespace).Update(deployment)
|
||||
return err
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) deleteDeployment(ns string, name string) error {
|
||||
deletePropagation := metav1.DeletePropagationForeground
|
||||
// DeletePropagationBackground deletes the object immediately and dependent are deleted later
|
||||
// DeletePropagationForeground not advisable; it markes for deleteion and API can still serve those objects
|
||||
deletePropagation := metav1.DeletePropagationBackground
|
||||
err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(ns).Delete(name, &metav1.DeleteOptions{
|
||||
PropagationPolicy: &deletePropagation,
|
||||
})
|
||||
@@ -283,6 +116,237 @@ func (deploy *NewDeploy) deleteDeployment(ns string, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) getDeploymentSpec(fn *crd.Function, env *crd.Environment,
|
||||
deployName string, deployLabels map[string]string) (*v1beta1.Deployment, error) {
|
||||
|
||||
replicas := int32(fn.Spec.InvokeStrategy.ExecutionStrategy.MinScale)
|
||||
if replicas == 0 {
|
||||
replicas = 1
|
||||
}
|
||||
targetFilename := "user"
|
||||
var gracePeriodSeconds int64 = 6 * 60
|
||||
|
||||
fetchReq := &fetcher.FetchRequest{
|
||||
FetchType: fetcher.FETCH_DEPLOYMENT,
|
||||
Package: metav1.ObjectMeta{
|
||||
Namespace: fn.Spec.Package.PackageRef.Namespace,
|
||||
Name: fn.Spec.Package.PackageRef.Name,
|
||||
},
|
||||
Filename: targetFilename,
|
||||
Secrets: fn.Spec.Secrets,
|
||||
ConfigMaps: fn.Spec.ConfigMaps,
|
||||
}
|
||||
|
||||
loadReq := fission.FunctionLoadRequest{
|
||||
FilePath: filepath.Join(deploy.sharedMountPath, targetFilename),
|
||||
FunctionName: fn.Spec.Package.FunctionName,
|
||||
FunctionMetadata: &fn.Metadata,
|
||||
}
|
||||
|
||||
fetchPayload, err := json.Marshal(fetchReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loadPayload, err := json.Marshal(loadReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fetcherResources, err := util.GetFetcherResources()
|
||||
if err != nil {
|
||||
log.Printf("Error while parsing fetcher resources: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
podAnnotation := make(map[string]string)
|
||||
if deploy.useIstio && env.Spec.AllowAccessToExternalNetwork {
|
||||
podAnnotation["sidecar.istio.io/inject"] = "false"
|
||||
}
|
||||
resources := deploy.getResources(env, fn)
|
||||
|
||||
deployment := &v1beta1.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: deployLabels,
|
||||
Name: deployName,
|
||||
},
|
||||
Spec: v1beta1.DeploymentSpec{
|
||||
Replicas: &replicas,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: deployLabels,
|
||||
},
|
||||
Template: apiv1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: deployLabels,
|
||||
Annotations: podAnnotation,
|
||||
},
|
||||
Spec: apiv1.PodSpec{
|
||||
Volumes: []apiv1.Volume{
|
||||
{
|
||||
Name: fission.SharedVolumeUserfunc,
|
||||
VolumeSource: apiv1.VolumeSource{
|
||||
EmptyDir: &apiv1.EmptyDirVolumeSource{},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeSecrets,
|
||||
VolumeSource: apiv1.VolumeSource{
|
||||
EmptyDir: &apiv1.EmptyDirVolumeSource{},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeConfigmaps,
|
||||
VolumeSource: apiv1.VolumeSource{
|
||||
EmptyDir: &apiv1.EmptyDirVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []apiv1.Container{
|
||||
{
|
||||
Name: fn.Metadata.Name,
|
||||
Image: env.Spec.Runtime.Image,
|
||||
ImagePullPolicy: apiv1.PullIfNotPresent,
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
VolumeMounts: []apiv1.VolumeMount{
|
||||
{
|
||||
Name: fission.SharedVolumeUserfunc,
|
||||
MountPath: deploy.sharedMountPath,
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeSecrets,
|
||||
MountPath: deploy.sharedSecretPath,
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeConfigmaps,
|
||||
MountPath: deploy.sharedCfgMapPath,
|
||||
},
|
||||
},
|
||||
Lifecycle: &apiv1.Lifecycle{
|
||||
PreStop: &apiv1.Handler{
|
||||
Exec: &apiv1.ExecAction{
|
||||
Command: []string{
|
||||
"sleep",
|
||||
fmt.Sprintf("%v", gracePeriodSeconds),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Resources: resources,
|
||||
},
|
||||
{
|
||||
Name: "fetcher",
|
||||
Image: deploy.fetcherImg,
|
||||
ImagePullPolicy: deploy.fetcherImagePullPolicy,
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
VolumeMounts: []apiv1.VolumeMount{
|
||||
{
|
||||
Name: fission.SharedVolumeUserfunc,
|
||||
MountPath: deploy.sharedMountPath,
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeSecrets,
|
||||
MountPath: deploy.sharedSecretPath,
|
||||
},
|
||||
{
|
||||
Name: fission.SharedVolumeConfigmaps,
|
||||
MountPath: deploy.sharedCfgMapPath,
|
||||
},
|
||||
},
|
||||
Command: []string{"/fetcher", "-specialize-on-startup",
|
||||
"-fetch-request", string(fetchPayload),
|
||||
"-load-request", string(loadPayload),
|
||||
"-secret-dir", deploy.sharedSecretPath,
|
||||
"-cfgmap-dir", deploy.sharedCfgMapPath,
|
||||
deploy.sharedMountPath},
|
||||
Lifecycle: &apiv1.Lifecycle{
|
||||
PreStop: &apiv1.Handler{
|
||||
Exec: &apiv1.ExecAction{
|
||||
Command: []string{
|
||||
"sleep",
|
||||
fmt.Sprintf("%v", gracePeriodSeconds),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Env: []apiv1.EnvVar{
|
||||
{
|
||||
Name: envVersion,
|
||||
Value: strconv.Itoa(env.Spec.Version),
|
||||
},
|
||||
},
|
||||
Resources: fetcherResources,
|
||||
ReadinessProbe: &apiv1.Probe{
|
||||
InitialDelaySeconds: 1,
|
||||
PeriodSeconds: 1,
|
||||
FailureThreshold: 30,
|
||||
Handler: apiv1.Handler{
|
||||
HTTPGet: &apiv1.HTTPGetAction{
|
||||
Path: "/healthz",
|
||||
Port: intstr.IntOrString{
|
||||
Type: intstr.Int,
|
||||
IntVal: 8000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
LivenessProbe: &apiv1.Probe{
|
||||
InitialDelaySeconds: 35,
|
||||
PeriodSeconds: 5,
|
||||
Handler: apiv1.Handler{
|
||||
HTTPGet: &apiv1.HTTPGetAction{
|
||||
Path: "/healthz",
|
||||
Port: intstr.IntOrString{
|
||||
Type: intstr.Int,
|
||||
IntVal: 8000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServiceAccountName: "fission-fetcher",
|
||||
TerminationGracePeriodSeconds: &gracePeriodSeconds,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return deployment, nil
|
||||
}
|
||||
|
||||
// getResources overrides only the resources which are overridden at function level otherwise
|
||||
// default to resources specified at environment level
|
||||
func (deploy *NewDeploy) getResources(env *crd.Environment, fn *crd.Function) v1.ResourceRequirements {
|
||||
resources := env.Spec.Resources
|
||||
if resources.Requests == nil {
|
||||
resources.Requests = make(map[v1.ResourceName]resource.Quantity)
|
||||
}
|
||||
if resources.Limits == nil {
|
||||
resources.Limits = make(map[v1.ResourceName]resource.Quantity)
|
||||
}
|
||||
// Only override the once specified at function, rest default to values from env.
|
||||
_, ok := fn.Spec.Resources.Requests[v1.ResourceCPU]
|
||||
if ok {
|
||||
resources.Requests[v1.ResourceCPU] = fn.Spec.Resources.Requests[v1.ResourceCPU]
|
||||
}
|
||||
|
||||
_, ok = fn.Spec.Resources.Requests[v1.ResourceMemory]
|
||||
if ok {
|
||||
resources.Requests[v1.ResourceMemory] = fn.Spec.Resources.Requests[v1.ResourceMemory]
|
||||
}
|
||||
|
||||
_, ok = fn.Spec.Resources.Limits[v1.ResourceCPU]
|
||||
if ok {
|
||||
resources.Limits[v1.ResourceCPU] = fn.Spec.Resources.Limits[v1.ResourceCPU]
|
||||
}
|
||||
|
||||
_, ok = fn.Spec.Resources.Limits[v1.ResourceMemory]
|
||||
if ok {
|
||||
resources.Limits[v1.ResourceMemory] = fn.Spec.Resources.Limits[v1.ResourceMemory]
|
||||
}
|
||||
|
||||
return resources
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) createOrGetHpa(hpaName string, execStrategy *fission.ExecutionStrategy, depl *v1beta1.Deployment) (*asv1.HorizontalPodAutoscaler, error) {
|
||||
|
||||
minRepl := int32(execStrategy.MinScale)
|
||||
@@ -331,7 +395,17 @@ func (deploy *NewDeploy) createOrGetHpa(hpaName string, execStrategy *fission.Ex
|
||||
|
||||
}
|
||||
|
||||
func (deploy NewDeploy) deleteHpa(ns string, name string) error {
|
||||
func (deploy *NewDeploy) getHpa(fn *crd.Function) (*asv1.HorizontalPodAutoscaler, error) {
|
||||
hpaName := deploy.getObjName(fn)
|
||||
return deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(deploy.namespace).Get(hpaName, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) updateHpa(hpa *asv1.HorizontalPodAutoscaler) error {
|
||||
_, err := deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(deploy.namespace).Update(hpa)
|
||||
return err
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) deleteHpa(ns string, name string) error {
|
||||
err := deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(ns).Delete(name, &metav1.DeleteOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -24,9 +24,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
"github.com/fission/fission/executor/fscache"
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
@@ -34,6 +32,10 @@ import (
|
||||
apiv1 "k8s.io/client-go/pkg/api/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
k8sCache "k8s.io/client-go/tools/cache"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
"github.com/fission/fission/executor/fscache"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -76,7 +78,6 @@ type (
|
||||
const (
|
||||
FnCreate requestType = iota
|
||||
FnDelete
|
||||
FnUpdate
|
||||
)
|
||||
|
||||
func MakeNewDeploy(
|
||||
@@ -152,8 +153,10 @@ func (deploy *NewDeploy) initFuncController() (k8sCache.Store, k8sCache.Controll
|
||||
fn := obj.(*crd.Function)
|
||||
deploy.deleteFunction(fn)
|
||||
},
|
||||
UpdateFunc: func(newObj interface{}, oldObj interface{}) {
|
||||
//TBD
|
||||
UpdateFunc: func(oldObj interface{}, newObj interface{}) {
|
||||
oldFn := oldObj.(*crd.Function)
|
||||
newFn := newObj.(*crd.Function)
|
||||
deploy.fnUpdate(oldFn, newFn)
|
||||
},
|
||||
})
|
||||
return store, controller
|
||||
@@ -170,8 +173,6 @@ func (deploy *NewDeploy) service() {
|
||||
fSvc: fsvc,
|
||||
}
|
||||
continue
|
||||
case FnUpdate:
|
||||
// TBD
|
||||
case FnDelete:
|
||||
_, err := deploy.fnDelete(req.fn)
|
||||
req.responseChannel <- &fnResponse{
|
||||
@@ -179,6 +180,7 @@ func (deploy *NewDeploy) service() {
|
||||
fSvc: nil,
|
||||
}
|
||||
continue
|
||||
// Update needs two inputs and will be called directly by controller
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,14 +254,7 @@ func (deploy *NewDeploy) fnCreate(fn *crd.Function) (*fscache.FuncSvc, error) {
|
||||
|
||||
objName := deploy.getObjName(fn)
|
||||
|
||||
deployLabels := map[string]string{
|
||||
"environmentName": env.Metadata.Name,
|
||||
"environmentUid": string(env.Metadata.UID),
|
||||
"functionName": fn.Metadata.Name,
|
||||
"functionUid": string(fn.Metadata.UID),
|
||||
fission.EXECUTOR_INSTANCEID_LABEL: deploy.instanceID,
|
||||
"executorType": fission.ExecutorTypeNewdeploy,
|
||||
}
|
||||
deployLabels := deploy.getDeployLabels(fn, env)
|
||||
|
||||
// Envoy(istio-proxy) returns 404 directly before istio pilot
|
||||
// propagates latest Envoy-specific configuration.
|
||||
@@ -281,8 +276,7 @@ func (deploy *NewDeploy) fnCreate(fn *crd.Function) (*fscache.FuncSvc, error) {
|
||||
|
||||
hpa, err := deploy.createOrGetHpa(objName, &fn.Spec.InvokeStrategy.ExecutionStrategy, depl)
|
||||
if err != nil {
|
||||
log.Printf("Error creating the HPA %v: %v", objName, err)
|
||||
return fsvc, err
|
||||
return fsvc, errors.Wrap(err, fmt.Sprintf("error creating the HPA %v:", objName))
|
||||
}
|
||||
|
||||
kubeObjRefs := []api.ObjectReference{
|
||||
@@ -330,6 +324,124 @@ func (deploy *NewDeploy) fnCreate(fn *crd.Function) (*fscache.FuncSvc, error) {
|
||||
return fsvc, nil
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) fnUpdate(oldFn *crd.Function, newFn *crd.Function) {
|
||||
|
||||
if oldFn.Metadata.ResourceVersion == newFn.Metadata.ResourceVersion {
|
||||
return
|
||||
}
|
||||
|
||||
// Ignoring updates to functions which are not of NewDeployment type
|
||||
if newFn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType != fission.ExecutorTypeNewdeploy &&
|
||||
oldFn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType != fission.ExecutorTypeNewdeploy {
|
||||
return
|
||||
}
|
||||
|
||||
changed := false
|
||||
|
||||
if oldFn.Spec.InvokeStrategy != newFn.Spec.InvokeStrategy {
|
||||
|
||||
// Executor type is no longer New Deployment
|
||||
if newFn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType != fission.ExecutorTypeNewdeploy &&
|
||||
oldFn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType == fission.ExecutorTypeNewdeploy {
|
||||
log.Printf("function does not use new deployment executor anymore, deleting resources: %v", newFn)
|
||||
// IMP - pass the oldFn, as the new/modified function is not in cache
|
||||
deploy.fnDelete(oldFn)
|
||||
return
|
||||
}
|
||||
|
||||
// Executor type changed to New Deployment from something else
|
||||
if oldFn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType != fission.ExecutorTypeNewdeploy &&
|
||||
newFn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType == fission.ExecutorTypeNewdeploy {
|
||||
log.Printf("function type changed to new deployment, creating resources: %v", newFn)
|
||||
_, err := deploy.fnCreate(newFn)
|
||||
if err != nil {
|
||||
updateStatus(oldFn, err, "error changing the function's type to newdeploy")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
hpa, err := deploy.getHpa(newFn)
|
||||
if err != nil {
|
||||
updateStatus(oldFn, err, "error getting HPA while updating function")
|
||||
return
|
||||
}
|
||||
|
||||
if newFn.Spec.InvokeStrategy.ExecutionStrategy.MinScale != oldFn.Spec.InvokeStrategy.ExecutionStrategy.MinScale {
|
||||
replicas := int32(newFn.Spec.InvokeStrategy.ExecutionStrategy.MinScale)
|
||||
hpa.Spec.MinReplicas = &replicas
|
||||
changed = true // Will start deployment update
|
||||
}
|
||||
|
||||
if newFn.Spec.InvokeStrategy.ExecutionStrategy.MaxScale != oldFn.Spec.InvokeStrategy.ExecutionStrategy.MaxScale {
|
||||
hpa.Spec.MaxReplicas = int32(newFn.Spec.InvokeStrategy.ExecutionStrategy.MaxScale)
|
||||
}
|
||||
|
||||
if newFn.Spec.InvokeStrategy.ExecutionStrategy.TargetCPUPercent != oldFn.Spec.InvokeStrategy.ExecutionStrategy.TargetCPUPercent {
|
||||
targetCpupercent := int32(newFn.Spec.InvokeStrategy.ExecutionStrategy.TargetCPUPercent)
|
||||
hpa.Spec.TargetCPUUtilizationPercentage = &targetCpupercent
|
||||
}
|
||||
|
||||
err = deploy.updateHpa(hpa)
|
||||
if err != nil {
|
||||
updateStatus(oldFn, err, "error updating HPA while updating function")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if oldFn.Spec.Environment != newFn.Spec.Environment {
|
||||
changed = true
|
||||
}
|
||||
|
||||
if oldFn.Spec.Package.PackageRef != newFn.Spec.Package.PackageRef {
|
||||
changed = true
|
||||
}
|
||||
|
||||
// If length of slice has changed then no need to check individual elements
|
||||
if len(oldFn.Spec.Secrets) != len(newFn.Spec.Secrets) {
|
||||
changed = true
|
||||
} else {
|
||||
for i, newSecret := range newFn.Spec.Secrets {
|
||||
if newSecret != oldFn.Spec.Secrets[i] {
|
||||
changed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(oldFn.Spec.ConfigMaps) != len(newFn.Spec.ConfigMaps) {
|
||||
changed = true
|
||||
} else {
|
||||
for i, newConfig := range newFn.Spec.ConfigMaps {
|
||||
if newConfig != oldFn.Spec.ConfigMaps[i] {
|
||||
changed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if changed == true {
|
||||
env, err := deploy.fissionClient.Environments(newFn.Spec.Environment.Namespace).
|
||||
Get(newFn.Spec.Environment.Name)
|
||||
if err != nil {
|
||||
updateStatus(oldFn, err, "failed to get environment while updating function")
|
||||
return
|
||||
}
|
||||
deployName := deploy.getObjName(oldFn)
|
||||
deployLabels := deploy.getDeployLabels(oldFn, env)
|
||||
log.Printf("updating deployment due to function update")
|
||||
newDeployment, err := deploy.getDeploymentSpec(newFn, env, deployName, deployLabels)
|
||||
if err != nil {
|
||||
updateStatus(oldFn, err, "failed to get new deployment spec while updating function")
|
||||
return
|
||||
}
|
||||
err = deploy.updateDeployment(newDeployment)
|
||||
if err != nil {
|
||||
updateStatus(oldFn, err, "failed to update deployment while updating function")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) fnDelete(fn *crd.Function) (*fscache.FuncSvc, error) {
|
||||
|
||||
var delError error
|
||||
@@ -338,12 +450,13 @@ func (deploy *NewDeploy) fnDelete(fn *crd.Function) (*fscache.FuncSvc, error) {
|
||||
if err != nil {
|
||||
log.Printf("fsvc not fonud in cache: %v", fn.Metadata)
|
||||
delError = err
|
||||
} else {
|
||||
_, err = deploy.fsCache.DeleteOld(fsvc, time.Second*0)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting the function from cache: %v", fsvc)
|
||||
delError = err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = deploy.fsCache.DeleteOld(fsvc, time.Second*0)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting the function from cache: %v", fsvc)
|
||||
delError = err
|
||||
}
|
||||
objName := fsvc.Name
|
||||
|
||||
@@ -376,3 +489,20 @@ func (deploy *NewDeploy) getObjName(fn *crd.Function) string {
|
||||
fn.Metadata.Name,
|
||||
deploy.instanceID)
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) getDeployLabels(fn *crd.Function, env *crd.Environment) map[string]string {
|
||||
return map[string]string{
|
||||
"environmentName": env.Metadata.Name,
|
||||
"environmentUid": string(env.Metadata.UID),
|
||||
"functionName": fn.Metadata.Name,
|
||||
"functionUid": string(fn.Metadata.UID),
|
||||
fission.EXECUTOR_INSTANCEID_LABEL: deploy.instanceID,
|
||||
"executorType": fission.ExecutorTypeNewdeploy,
|
||||
}
|
||||
}
|
||||
|
||||
// updateStatus is a function which updates status of update.
|
||||
// Current implementation only logs messages, in future it will update function status
|
||||
func updateStatus(fn *crd.Function, err error, message string) {
|
||||
log.Printf(message, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user