Improve executor bootstrap speed (#1446)
This commit is contained in:
@@ -18,7 +18,6 @@ package v1
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
EXECUTOR_INSTANCEID_LABEL string = "executorInstanceId"
|
EXECUTOR_INSTANCEID_LABEL string = "executorInstanceId"
|
||||||
POOLMGR_INSTANCEID_LABEL string = "poolmgrInstanceId"
|
|
||||||
DEFAULT_FUNCTION_TIMEOUT int = 60
|
DEFAULT_FUNCTION_TIMEOUT int = 60
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import (
|
|||||||
"github.com/fission/fission/pkg/executor/executortype/poolmgr"
|
"github.com/fission/fission/pkg/executor/executortype/poolmgr"
|
||||||
"github.com/fission/fission/pkg/executor/fscache"
|
"github.com/fission/fission/pkg/executor/fscache"
|
||||||
"github.com/fission/fission/pkg/executor/reaper"
|
"github.com/fission/fission/pkg/executor/reaper"
|
||||||
|
"github.com/fission/fission/pkg/executor/util"
|
||||||
fetcherConfig "github.com/fission/fission/pkg/fetcher/config"
|
fetcherConfig "github.com/fission/fission/pkg/fetcher/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -74,6 +75,12 @@ func MakeExecutor(logger *zap.Logger, cms *cms.ConfigSecretController,
|
|||||||
requestChan: make(chan *createFuncServiceRequest),
|
requestChan: make(chan *createFuncServiceRequest),
|
||||||
fsCreateWg: make(map[string]*sync.WaitGroup),
|
fsCreateWg: make(map[string]*sync.WaitGroup),
|
||||||
}
|
}
|
||||||
|
for _, et := range types {
|
||||||
|
go func(et executortype.ExecutorType) {
|
||||||
|
et.Run(context.Background())
|
||||||
|
}(et)
|
||||||
|
}
|
||||||
|
go cms.Run(context.Background())
|
||||||
go executor.serveCreateFuncServices()
|
go executor.serveCreateFuncServices()
|
||||||
|
|
||||||
return executor, nil
|
return executor, nil
|
||||||
@@ -241,21 +248,20 @@ func StartExecutor(logger *zap.Logger, functionNamespace string, envBuilderNames
|
|||||||
go func(et executortype.ExecutorType) {
|
go func(et executortype.ExecutorType) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
et.AdoptOrphanResources()
|
et.AdoptOrphanResources()
|
||||||
et.Run(context.Background())
|
|
||||||
}(et)
|
}(et)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
// set hard timeout for resource adoption
|
||||||
|
util.WaitTimeout(wg, 30*time.Second)
|
||||||
|
|
||||||
cms := cms.MakeConfigSecretController(logger, fissionClient, kubernetesClient, executorTypes)
|
cms := cms.MakeConfigSecretController(logger, fissionClient, kubernetesClient, executorTypes)
|
||||||
cms.Run(context.Background())
|
|
||||||
|
|
||||||
api, err := MakeExecutor(logger, cms, fissionClient, executorTypes)
|
api, err := MakeExecutor(logger, cms, fissionClient, executorTypes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go reaper.CleanupRoleBindings(logger, kubernetesClient, fissionClient, functionNamespace, envBuilderNamespace, time.Minute*30)
|
|
||||||
go reaper.CleanupOldExecutorObjects(logger, kubernetesClient, executorInstanceID)
|
go reaper.CleanupOldExecutorObjects(logger, kubernetesClient, executorInstanceID)
|
||||||
|
go reaper.CleanupRoleBindings(logger, kubernetesClient, fissionClient, functionNamespace, envBuilderNamespace, time.Minute*30)
|
||||||
go api.Serve(port)
|
go api.Serve(port)
|
||||||
go serveMetric(logger)
|
go serveMetric(logger)
|
||||||
|
|
||||||
|
|||||||
@@ -44,22 +44,22 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (deploy *NewDeploy) createOrGetDeployment(fn *fv1.Function, env *fv1.Environment,
|
func (deploy *NewDeploy) createOrGetDeployment(fn *fv1.Function, env *fv1.Environment,
|
||||||
deployName string, deployLabels map[string]string, deployAnnotations map[string]string, deployNamespace string, firstcreate bool) (*appsv1.Deployment, error) {
|
deployName string, deployLabels map[string]string, deployAnnotations map[string]string, deployNamespace string) (*appsv1.Deployment, error) {
|
||||||
|
|
||||||
minScale := int32(fn.Spec.InvokeStrategy.ExecutionStrategy.MinScale)
|
|
||||||
specializationTimeout := int(fn.Spec.InvokeStrategy.ExecutionStrategy.SpecializationTimeout)
|
specializationTimeout := int(fn.Spec.InvokeStrategy.ExecutionStrategy.SpecializationTimeout)
|
||||||
|
minScale := int32(fn.Spec.InvokeStrategy.ExecutionStrategy.MinScale)
|
||||||
|
|
||||||
// If it's not the first time creation and minscale is 0 means that all pods for function were recycled,
|
// Always scale to at least one pod when createOrGetDeployment
|
||||||
// in such cases we need set minscale to 1 for router to serve requests.
|
// is called. The idleObjectReaper will scale-in the deployment
|
||||||
if !firstcreate && minScale <= 0 {
|
// later if no requests to the function.
|
||||||
|
if minScale <= 0 {
|
||||||
minScale = 1
|
minScale = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForDeploy := minScale > 0
|
|
||||||
|
|
||||||
existingDepl, err := deploy.kubernetesClient.AppsV1().Deployments(deployNamespace).Get(deployName, metav1.GetOptions{})
|
existingDepl, err := deploy.kubernetesClient.AppsV1().Deployments(deployNamespace).Get(deployName, metav1.GetOptions{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if existingDepl.Labels[fv1.EXECUTOR_INSTANCEID_LABEL] != deploy.instanceID {
|
// Try to adopt orphan deployment created by the old executor.
|
||||||
|
if existingDepl.Annotations[fv1.EXECUTOR_INSTANCEID_LABEL] != deploy.instanceID {
|
||||||
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%v":"%v"}}}`, types.EXECUTOR_INSTANCEID_LABEL, deploy.instanceID)
|
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%v":"%v"}}}`, types.EXECUTOR_INSTANCEID_LABEL, deploy.instanceID)
|
||||||
existingDepl, err = deploy.kubernetesClient.AppsV1().Deployments(deployNamespace).Patch(deployName, k8sTypes.StrategicMergePatchType, []byte(patch))
|
existingDepl, err = deploy.kubernetesClient.AppsV1().Deployments(deployNamespace).Patch(deployName, k8sTypes.StrategicMergePatchType, []byte(patch))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -67,19 +67,21 @@ func (deploy *NewDeploy) createOrGetDeployment(fn *fv1.Function, env *fv1.Enviro
|
|||||||
zap.String("deploy", deployName), zap.String("ns", deployNamespace))
|
zap.String("deploy", deployName), zap.String("ns", deployNamespace))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// In this case, we just return without waiting for it for fast bootstraping.
|
||||||
|
return existingDepl, nil
|
||||||
}
|
}
|
||||||
if waitForDeploy {
|
|
||||||
if *existingDepl.Spec.Replicas < minScale {
|
if *existingDepl.Spec.Replicas < minScale {
|
||||||
err = deploy.scaleDeployment(existingDepl.Namespace, existingDepl.Name, minScale)
|
err = deploy.scaleDeployment(existingDepl.Namespace, existingDepl.Name, minScale)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
deploy.logger.Error("error scaling up function deployment", zap.Error(err), zap.String("function", fn.Metadata.Name))
|
deploy.logger.Error("error scaling up function deployment", zap.Error(err), zap.String("function", fn.Metadata.Name))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
|
||||||
}
|
|
||||||
if existingDepl.Status.AvailableReplicas < minScale {
|
|
||||||
existingDepl, err = deploy.waitForDeploy(existingDepl, minScale, specializationTimeout)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if existingDepl.Status.AvailableReplicas < minScale {
|
||||||
|
existingDepl, err = deploy.waitForDeploy(existingDepl, minScale, specializationTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
return existingDepl, err
|
return existingDepl, err
|
||||||
} else if k8s_err.IsNotFound(err) {
|
} else if k8s_err.IsNotFound(err) {
|
||||||
err := deploy.setupRBACObjs(deployNamespace, fn)
|
err := deploy.setupRBACObjs(deployNamespace, fn)
|
||||||
@@ -87,7 +89,7 @@ func (deploy *NewDeploy) createOrGetDeployment(fn *fv1.Function, env *fv1.Enviro
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
deployment, err := deploy.getDeploymentSpec(fn, env, deployName, deployNamespace, deployLabels, deployAnnotations)
|
deployment, err := deploy.getDeploymentSpec(fn, env, &minScale, deployName, deployNamespace, deployLabels, deployAnnotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -102,7 +104,7 @@ func (deploy *NewDeploy) createOrGetDeployment(fn *fv1.Function, env *fv1.Enviro
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if waitForDeploy {
|
if minScale > 0 {
|
||||||
depl, err = deploy.waitForDeploy(depl, minScale, specializationTimeout)
|
depl, err = deploy.waitForDeploy(depl, minScale, specializationTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,10 +170,13 @@ func (deploy *NewDeploy) deleteDeployment(ns string, name string) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (deploy *NewDeploy) getDeploymentSpec(fn *fv1.Function, env *fv1.Environment,
|
func (deploy *NewDeploy) getDeploymentSpec(fn *fv1.Function, env *fv1.Environment, targetReplicas *int32,
|
||||||
deployName string, deployNamespace string, deployLabels map[string]string, deployAnnotations map[string]string) (*appsv1.Deployment, error) {
|
deployName string, deployNamespace string, deployLabels map[string]string, deployAnnotations map[string]string) (*appsv1.Deployment, error) {
|
||||||
|
|
||||||
replicas := int32(fn.Spec.InvokeStrategy.ExecutionStrategy.MinScale)
|
replicas := int32(fn.Spec.InvokeStrategy.ExecutionStrategy.MinScale)
|
||||||
|
if targetReplicas != nil {
|
||||||
|
replicas = *targetReplicas
|
||||||
|
}
|
||||||
|
|
||||||
gracePeriodSeconds := int64(6 * 60)
|
gracePeriodSeconds := int64(6 * 60)
|
||||||
if env.Spec.TerminationGracePeriod > 0 {
|
if env.Spec.TerminationGracePeriod > 0 {
|
||||||
@@ -351,7 +356,7 @@ func (deploy *NewDeploy) createOrGetHpa(hpaName string, execStrategy *fv1.Execut
|
|||||||
|
|
||||||
existingHpa, err := deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(depl.ObjectMeta.Namespace).Get(hpaName, metav1.GetOptions{})
|
existingHpa, err := deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(depl.ObjectMeta.Namespace).Get(hpaName, metav1.GetOptions{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if existingHpa.Labels[fv1.EXECUTOR_INSTANCEID_LABEL] != deploy.instanceID {
|
if existingHpa.Annotations[fv1.EXECUTOR_INSTANCEID_LABEL] != deploy.instanceID {
|
||||||
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%v":"%v"}}}`, types.EXECUTOR_INSTANCEID_LABEL, deploy.instanceID)
|
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%v":"%v"}}}`, types.EXECUTOR_INSTANCEID_LABEL, deploy.instanceID)
|
||||||
existingHpa, err = deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(depl.ObjectMeta.Namespace).Patch(hpaName, k8sTypes.StrategicMergePatchType, []byte(patch))
|
existingHpa, err = deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(depl.ObjectMeta.Namespace).Patch(hpaName, k8sTypes.StrategicMergePatchType, []byte(patch))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -407,7 +412,7 @@ func (deploy *NewDeploy) deleteHpa(ns string, name string) error {
|
|||||||
func (deploy *NewDeploy) createOrGetSvc(deployLabels map[string]string, deployAnnotations map[string]string, svcName string, svcNamespace string) (*apiv1.Service, error) {
|
func (deploy *NewDeploy) createOrGetSvc(deployLabels map[string]string, deployAnnotations map[string]string, svcName string, svcNamespace string) (*apiv1.Service, error) {
|
||||||
existingSvc, err := deploy.kubernetesClient.CoreV1().Services(svcNamespace).Get(svcName, metav1.GetOptions{})
|
existingSvc, err := deploy.kubernetesClient.CoreV1().Services(svcNamespace).Get(svcName, metav1.GetOptions{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if existingSvc.Labels[fv1.EXECUTOR_INSTANCEID_LABEL] != deploy.instanceID {
|
if existingSvc.Annotations[fv1.EXECUTOR_INSTANCEID_LABEL] != deploy.instanceID {
|
||||||
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%v":"%v"}}}`, types.EXECUTOR_INSTANCEID_LABEL, deploy.instanceID)
|
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%v":"%v"}}}`, types.EXECUTOR_INSTANCEID_LABEL, deploy.instanceID)
|
||||||
existingSvc, err = deploy.kubernetesClient.CoreV1().Services(svcNamespace).Patch(svcName, k8sTypes.StrategicMergePatchType, []byte(patch))
|
existingSvc, err = deploy.kubernetesClient.CoreV1().Services(svcNamespace).Patch(svcName, k8sTypes.StrategicMergePatchType, []byte(patch))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ func (deploy *NewDeploy) GetFuncSvc(ctx context.Context, fn *fv1.Function) (*fsc
|
|||||||
// TODO: client-go doesn't support to pass in context.
|
// TODO: client-go doesn't support to pass in context.
|
||||||
// Once it supports context, we should change the signature of method.
|
// Once it supports context, we should change the signature of method.
|
||||||
// https://github.com/kubernetes/kubernetes/issues/46503
|
// https://github.com/kubernetes/kubernetes/issues/46503
|
||||||
return deploy.createFunction(fn, false)
|
return deploy.createFunction(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (deploy *NewDeploy) GetFuncSvcFromCache(fn *fv1.Function) (*fscache.FuncSvc, error) {
|
func (deploy *NewDeploy) GetFuncSvcFromCache(fn *fv1.Function) (*fscache.FuncSvc, error) {
|
||||||
@@ -249,24 +249,21 @@ func (deploy *NewDeploy) AdoptOrphanResources() {
|
|||||||
podList, err := deploy.kubernetesClient.CoreV1().Pods(metav1.NamespaceAll).List(metav1.ListOptions{
|
podList, err := deploy.kubernetesClient.CoreV1().Pods(metav1.NamespaceAll).List(metav1.ListOptions{
|
||||||
LabelSelector: labels.Set(l).AsSelector().String(),
|
LabelSelector: labels.Set(l).AsSelector().String(),
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
deploy.logger.Error("error getting pod list", zap.Error(err))
|
deploy.logger.Error("error getting pod list", zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
podWG := &sync.WaitGroup{}
|
// Unlike poolmanager manages the lifecycle of function pod directly,
|
||||||
|
// newdeploy is only responsible to create the deployment and Kubernetes
|
||||||
|
// will handle the rest. Hence we don't need to wait for the pod patching
|
||||||
|
// process to finish.
|
||||||
for i := range podList.Items {
|
for i := range podList.Items {
|
||||||
pod := &podList.Items[i]
|
pod := &podList.Items[i]
|
||||||
if !utils.IsReadyPod(pod) {
|
if !utils.IsReadyPod(pod) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
podWG.Add(1)
|
|
||||||
go func() {
|
go func() {
|
||||||
defer podWG.Done()
|
|
||||||
|
|
||||||
// avoid too many requests arrive Kubernetes API server at the same time.
|
// avoid too many requests arrive Kubernetes API server at the same time.
|
||||||
time.Sleep(time.Duration(rand.Intn(30)) * time.Millisecond)
|
time.Sleep(time.Duration(rand.Intn(30)) * time.Millisecond)
|
||||||
|
|
||||||
@@ -278,7 +275,6 @@ func (deploy *NewDeploy) AdoptOrphanResources() {
|
|||||||
zap.String("pod", pod.Name), zap.String("ns", pod.Namespace))
|
zap.String("pod", pod.Name), zap.String("ns", pod.Namespace))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
deploy.logger.Info("adopt newdeploy function pod",
|
deploy.logger.Info("adopt newdeploy function pod",
|
||||||
zap.String("pod", pod.Name), zap.Any("labels", pod.Labels), zap.Any("annotations", pod.Annotations))
|
zap.String("pod", pod.Name), zap.Any("labels", pod.Labels), zap.Any("annotations", pod.Annotations))
|
||||||
}()
|
}()
|
||||||
@@ -290,16 +286,16 @@ func (deploy *NewDeploy) AdoptOrphanResources() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
deployWG := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
|
|
||||||
for i := range fnList.Items {
|
for i := range fnList.Items {
|
||||||
fn := &fnList.Items[i]
|
fn := &fnList.Items[i]
|
||||||
if fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType == fv1.ExecutorTypeNewdeploy {
|
if fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType == fv1.ExecutorTypeNewdeploy {
|
||||||
deployWG.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer deployWG.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
_, err = deploy.fnCreate(fn, true)
|
_, err = deploy.fnCreate(fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
deploy.logger.Warn("failed to adopt resources for function", zap.Error(err))
|
deploy.logger.Warn("failed to adopt resources for function", zap.Error(err))
|
||||||
return
|
return
|
||||||
@@ -309,8 +305,7 @@ func (deploy *NewDeploy) AdoptOrphanResources() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
podWG.Wait()
|
wg.Wait()
|
||||||
deployWG.Wait()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (deploy *NewDeploy) initFuncController() (k8sCache.Store, k8sCache.Controller) {
|
func (deploy *NewDeploy) initFuncController() (k8sCache.Store, k8sCache.Controller) {
|
||||||
@@ -324,7 +319,7 @@ func (deploy *NewDeploy) initFuncController() (k8sCache.Store, k8sCache.Controll
|
|||||||
go func() {
|
go func() {
|
||||||
fn := obj.(*fv1.Function)
|
fn := obj.(*fv1.Function)
|
||||||
deploy.logger.Debug("create deployment for function", zap.Any("fn", fn.Metadata), zap.Any("fnspec", fn.Spec))
|
deploy.logger.Debug("create deployment for function", zap.Any("fn", fn.Metadata), zap.Any("fnspec", fn.Spec))
|
||||||
_, err := deploy.createFunction(fn, true)
|
_, err := deploy.createFunction(fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
deploy.logger.Error("error eager creating function",
|
deploy.logger.Error("error eager creating function",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
@@ -406,14 +401,14 @@ func (deploy *NewDeploy) getEnvFunctions(m *metav1.ObjectMeta) []fv1.Function {
|
|||||||
return relatedFunctions
|
return relatedFunctions
|
||||||
}
|
}
|
||||||
|
|
||||||
func (deploy *NewDeploy) createFunction(fn *fv1.Function, firstcreate bool) (*fscache.FuncSvc, error) {
|
func (deploy *NewDeploy) createFunction(fn *fv1.Function) (*fscache.FuncSvc, error) {
|
||||||
if fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType != fv1.ExecutorTypeNewdeploy {
|
if fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType != fv1.ExecutorTypeNewdeploy {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fsvcObj, err := deploy.throttler.RunOnce(string(fn.Metadata.UID), func(ableToCreate bool) (interface{}, error) {
|
fsvcObj, err := deploy.throttler.RunOnce(string(fn.Metadata.UID), func(ableToCreate bool) (interface{}, error) {
|
||||||
if ableToCreate {
|
if ableToCreate {
|
||||||
return deploy.fnCreate(fn, firstcreate)
|
return deploy.fnCreate(fn)
|
||||||
}
|
}
|
||||||
return deploy.fsCache.GetByFunctionUID(fn.Metadata.UID)
|
return deploy.fsCache.GetByFunctionUID(fn.Metadata.UID)
|
||||||
})
|
})
|
||||||
@@ -446,7 +441,7 @@ func (deploy *NewDeploy) deleteFunction(fn *fv1.Function) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (deploy *NewDeploy) fnCreate(fn *fv1.Function, firstcreate bool) (*fscache.FuncSvc, error) {
|
func (deploy *NewDeploy) fnCreate(fn *fv1.Function) (*fscache.FuncSvc, error) {
|
||||||
env, err := deploy.fissionClient.
|
env, err := deploy.fissionClient.
|
||||||
Environments(fn.Spec.Environment.Namespace).
|
Environments(fn.Spec.Environment.Namespace).
|
||||||
Get(fn.Spec.Environment.Name)
|
Get(fn.Spec.Environment.Name)
|
||||||
@@ -478,7 +473,7 @@ func (deploy *NewDeploy) fnCreate(fn *fv1.Function, firstcreate bool) (*fscache.
|
|||||||
}
|
}
|
||||||
svcAddress := fmt.Sprintf("%v.%v", svc.Name, svc.Namespace)
|
svcAddress := fmt.Sprintf("%v.%v", svc.Name, svc.Namespace)
|
||||||
|
|
||||||
depl, err := deploy.createOrGetDeployment(fn, env, objName, deployLabels, deployAnnotations, ns, firstcreate)
|
depl, err := deploy.createOrGetDeployment(fn, env, objName, deployLabels, deployAnnotations, ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
deploy.logger.Error("error creating deployment", zap.Error(err), zap.String("deployment", objName))
|
deploy.logger.Error("error creating deployment", zap.Error(err), zap.String("deployment", objName))
|
||||||
go deploy.cleanupNewdeploy(ns, objName)
|
go deploy.cleanupNewdeploy(ns, objName)
|
||||||
@@ -567,7 +562,7 @@ func (deploy *NewDeploy) updateFunction(oldFn *fv1.Function, newFn *fv1.Function
|
|||||||
deploy.logger.Info("function type changed to new deployment, creating resources",
|
deploy.logger.Info("function type changed to new deployment, creating resources",
|
||||||
zap.Any("old_function", oldFn.Metadata),
|
zap.Any("old_function", oldFn.Metadata),
|
||||||
zap.Any("new_function", newFn.Metadata))
|
zap.Any("new_function", newFn.Metadata))
|
||||||
_, err := deploy.createFunction(newFn, true)
|
_, err := deploy.createFunction(newFn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
deploy.updateStatus(oldFn, err, "error changing the function's type to newdeploy")
|
deploy.updateStatus(oldFn, err, "error changing the function's type to newdeploy")
|
||||||
}
|
}
|
||||||
@@ -686,7 +681,14 @@ func (deploy *NewDeploy) updateFuncDeployment(fn *fv1.Function, env *fv1.Environ
|
|||||||
ns = fn.Metadata.Namespace
|
ns = fn.Metadata.Namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
newDeployment, err := deploy.getDeploymentSpec(fn, env, fnObjName, ns, deployLabels, deploy.getDeployAnnotations(fn.Metadata))
|
existingDepl, err := deploy.kubernetesClient.AppsV1().Deployments(ns).Get(fnObjName, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// use current replicas instead of minscale in the ExecutionStrategy.
|
||||||
|
newDeployment, err := deploy.getDeploymentSpec(fn, env,
|
||||||
|
existingDepl.Spec.Replicas, fnObjName, ns, deployLabels, deploy.getDeployAnnotations(fn.Metadata))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
deploy.updateStatus(fn, err, "failed to get new deployment spec while updating function")
|
deploy.updateStatus(fn, err, "failed to get new deployment spec while updating function")
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -456,20 +456,20 @@ func (gp *GenericPool) createPool() error {
|
|||||||
deployment.Spec.Template.Spec = *newPodSpec
|
deployment.Spec.Template.Spec = *newPodSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = gp.kubernetesClient.AppsV1().Deployments(gp.namespace).Get(deployment.Name, metav1.GetOptions{})
|
depl, err := gp.kubernetesClient.AppsV1().Deployments(gp.namespace).Get(deployment.Name, metav1.GetOptions{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%v":"%v"}}}`, fv1.EXECUTOR_INSTANCEID_LABEL, gp.instanceId)
|
if depl.Annotations[fv1.EXECUTOR_INSTANCEID_LABEL] != gp.instanceId {
|
||||||
depl, err := gp.kubernetesClient.AppsV1().Deployments(gp.namespace).Patch(deployment.Name, k8sTypes.StrategicMergePatchType, []byte(patch))
|
patch := fmt.Sprintf(`{"metadata":{"annotations":{"%v":"%v"}}}`, fv1.EXECUTOR_INSTANCEID_LABEL, gp.instanceId)
|
||||||
if err == nil {
|
depl, err = gp.kubernetesClient.AppsV1().Deployments(gp.namespace).Patch(deployment.Name, k8sTypes.StrategicMergePatchType, []byte(patch))
|
||||||
gp.deployment = depl
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
gp.deployment = depl
|
||||||
|
return err
|
||||||
} else if !k8sErrs.IsNotFound(err) {
|
} else if !k8sErrs.IsNotFound(err) {
|
||||||
gp.logger.Error("error getting deployment in kubernetes", zap.Error(err), zap.String("deployment", deployment.Name))
|
gp.logger.Error("error getting deployment in kubernetes", zap.Error(err), zap.String("deployment", deployment.Name))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
depl, err := gp.kubernetesClient.AppsV1().Deployments(gp.namespace).Create(deployment)
|
depl, err = gp.kubernetesClient.AppsV1().Deployments(gp.namespace).Create(deployment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gp.logger.Error("error creating deployment in kubernetes", zap.Error(err), zap.String("deployment", deployment.Name))
|
gp.logger.Error("error creating deployment in kubernetes", zap.Error(err), zap.String("deployment", deployment.Name))
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -251,15 +251,15 @@ func (gpm *GenericPoolManager) AdoptOrphanResources() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
envMap := make(map[string]fv1.Environment, len(envs.Items))
|
envMap := make(map[string]fv1.Environment, len(envs.Items))
|
||||||
envWG := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
|
|
||||||
for i := range envs.Items {
|
for i := range envs.Items {
|
||||||
env := envs.Items[i]
|
env := envs.Items[i]
|
||||||
|
|
||||||
if gpm.getEnvPoolsize(&env) > 0 {
|
if gpm.getEnvPoolsize(&env) > 0 {
|
||||||
envWG.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer envWG.Done()
|
defer wg.Done()
|
||||||
_, err := gpm.getPool(&env)
|
_, err := gpm.getPool(&env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gpm.logger.Error("adopt pool failed", zap.Error(err))
|
gpm.logger.Error("adopt pool failed", zap.Error(err))
|
||||||
@@ -285,17 +285,15 @@ func (gpm *GenericPoolManager) AdoptOrphanResources() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
podWG := &sync.WaitGroup{}
|
|
||||||
|
|
||||||
for i := range podList.Items {
|
for i := range podList.Items {
|
||||||
pod := &podList.Items[i]
|
pod := &podList.Items[i]
|
||||||
if !utils.IsReadyPod(pod) {
|
if !utils.IsReadyPod(pod) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
podWG.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer podWG.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
// avoid too many requests arrive Kubernetes API server at the same time.
|
// avoid too many requests arrive Kubernetes API server at the same time.
|
||||||
time.Sleep(time.Duration(rand.Intn(30)) * time.Millisecond)
|
time.Sleep(time.Duration(rand.Intn(30)) * time.Millisecond)
|
||||||
@@ -324,7 +322,7 @@ func (gpm *GenericPoolManager) AdoptOrphanResources() {
|
|||||||
env, ok8 := envMap[fmt.Sprintf("%v/%v", envNS, envName)]
|
env, ok8 := envMap[fmt.Sprintf("%v/%v", envNS, envName)]
|
||||||
|
|
||||||
if !(ok1 && ok2 && ok3 && ok4 && ok5 && ok6 && ok7 && ok8) {
|
if !(ok1 && ok2 && ok3 && ok4 && ok5 && ok6 && ok7 && ok8) {
|
||||||
gpm.logger.Warn("failed to adopt pod for function due to lack necessary information",
|
gpm.logger.Warn("failed to adopt pod for function due to lack of necessary information",
|
||||||
zap.String("pod", pod.Name), zap.Any("labels", pod.Labels), zap.Any("annotations", pod.Annotations),
|
zap.String("pod", pod.Name), zap.Any("labels", pod.Labels), zap.Any("annotations", pod.Annotations),
|
||||||
zap.String("env", env.Metadata.Name))
|
zap.String("env", env.Metadata.Name))
|
||||||
return
|
return
|
||||||
@@ -355,16 +353,14 @@ func (gpm *GenericPoolManager) AdoptOrphanResources() {
|
|||||||
Atime: time.Now(),
|
Atime: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// If fsvc already exists we just skip the duplicate one. And let reaper to recycle the duplicate pod.
|
|
||||||
// This is for the case that there are multiple function pods for the same function due to unknown reason.
|
|
||||||
_, err := gpm.fsCache.GetByFunction(fsvc.Function)
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = gpm.fsCache.Add(fsvc)
|
_, err = gpm.fsCache.Add(fsvc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gpm.logger.Warn("failed to adopt pod for function", zap.Error(err), zap.String("pod", pod.Name))
|
// If fsvc already exists we just skip the duplicate one. And let reaper to recycle the duplicate pods.
|
||||||
|
// This is for the case that there are multiple function pods for the same function due to unknown reason.
|
||||||
|
if !fscache.IsNameExistError(err) {
|
||||||
|
gpm.logger.Warn("failed to adopt pod for function", zap.Error(err), zap.String("pod", pod.Name))
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,8 +369,7 @@ func (gpm *GenericPoolManager) AdoptOrphanResources() {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
envWG.Wait()
|
wg.Wait()
|
||||||
podWG.Wait()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gpm *GenericPoolManager) service() {
|
func (gpm *GenericPoolManager) service() {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fission/fission/pkg/utils"
|
"github.com/hashicorp/go-multierror"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@@ -29,6 +29,7 @@ import (
|
|||||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||||
"github.com/fission/fission/pkg/crd"
|
"github.com/fission/fission/pkg/crd"
|
||||||
"github.com/fission/fission/pkg/types"
|
"github.com/fission/fission/pkg/types"
|
||||||
|
"github.com/fission/fission/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -38,45 +39,39 @@ var (
|
|||||||
|
|
||||||
// CleanupOldExecutorObjects cleans up resources created by old executor instances
|
// CleanupOldExecutorObjects cleans up resources created by old executor instances
|
||||||
func CleanupOldExecutorObjects(logger *zap.Logger, kubernetesClient *kubernetes.Clientset, instanceId string) {
|
func CleanupOldExecutorObjects(logger *zap.Logger, kubernetesClient *kubernetes.Clientset, instanceId string) {
|
||||||
err := cleanup(logger, kubernetesClient, instanceId)
|
errs := &multierror.Error{}
|
||||||
if err != nil {
|
|
||||||
// TODO retry reaper; logged and ignored for now
|
|
||||||
logger.Error("Failed to cleanup old executor objects", zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cleanup(logger *zap.Logger, client *kubernetes.Clientset, instanceId string) error {
|
err := cleanupHpa(logger, kubernetesClient, instanceId)
|
||||||
// Pods might still be running user functions, so we give them
|
if err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cleanupDeployments(logger, kubernetesClient, instanceId)
|
||||||
|
if err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pods might be running user functions, so we give them
|
||||||
// a few minutes before terminating them. This time is the
|
// a few minutes before terminating them. This time is the
|
||||||
// maximum function runtime, plus the time a router might
|
// maximum function runtime, plus the time a router might
|
||||||
// still route to an old instance, i.e. router cache expiry
|
// still route to an old instance, i.e. router cache expiry
|
||||||
// time.
|
// time.
|
||||||
time.Sleep(6 * time.Minute)
|
time.Sleep(6 * time.Minute)
|
||||||
|
|
||||||
err := cleanupServices(logger, client, instanceId)
|
err = cleanupServices(logger, kubernetesClient, instanceId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
errs = multierror.Append(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cleanupHpa(logger, client, instanceId)
|
err = cleanupPods(logger, kubernetesClient, instanceId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
errs = multierror.Append(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deployments are used for idle pools and can be cleaned up
|
if errs.ErrorOrNil() != nil {
|
||||||
// immediately. (We should "adopt" these instead of creating
|
// TODO retry reaper; logged and ignored for now
|
||||||
// a new pool.)
|
logger.Error("Failed to cleanup old executor objects", zap.Error(err))
|
||||||
err = cleanupDeployments(logger, client, instanceId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cleanupPods(logger, client, instanceId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CleanupKubeObject deletes given kubernetes object
|
// CleanupKubeObject deletes given kubernetes object
|
||||||
@@ -119,20 +114,11 @@ func cleanupDeployments(logger *zap.Logger, client *kubernetes.Clientset, instan
|
|||||||
}
|
}
|
||||||
for _, dep := range deploymentList.Items {
|
for _, dep := range deploymentList.Items {
|
||||||
id, ok := dep.ObjectMeta.Annotations[types.EXECUTOR_INSTANCEID_LABEL]
|
id, ok := dep.ObjectMeta.Annotations[types.EXECUTOR_INSTANCEID_LABEL]
|
||||||
if ok && id != instanceId {
|
if !ok {
|
||||||
logger.Debug("cleaning up deployment", zap.String("deployment", dep.ObjectMeta.Name))
|
// Backward compatibility with older label name
|
||||||
err := client.AppsV1().Deployments(dep.ObjectMeta.Namespace).Delete(dep.ObjectMeta.Name, &delOpt)
|
id, ok = dep.ObjectMeta.Labels[types.EXECUTOR_INSTANCEID_LABEL]
|
||||||
if err != nil {
|
|
||||||
logger.Error("error cleaning up deployment",
|
|
||||||
zap.Error(err),
|
|
||||||
zap.String("deployment_name", dep.ObjectMeta.Name),
|
|
||||||
zap.String("deployment_namespace", dep.ObjectMeta.Namespace))
|
|
||||||
}
|
|
||||||
// ignore err
|
|
||||||
}
|
}
|
||||||
// Backward compatibility with older label name
|
if ok && id != instanceId {
|
||||||
pid, pok := dep.ObjectMeta.Annotations[types.POOLMGR_INSTANCEID_LABEL]
|
|
||||||
if pok && pid != instanceId {
|
|
||||||
logger.Debug("cleaning up deployment", zap.String("deployment", dep.ObjectMeta.Name))
|
logger.Debug("cleaning up deployment", zap.String("deployment", dep.ObjectMeta.Name))
|
||||||
err := client.AppsV1().Deployments(dep.ObjectMeta.Namespace).Delete(dep.ObjectMeta.Name, &delOpt)
|
err := client.AppsV1().Deployments(dep.ObjectMeta.Namespace).Delete(dep.ObjectMeta.Name, &delOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -154,6 +140,10 @@ func cleanupPods(logger *zap.Logger, client *kubernetes.Clientset, instanceId st
|
|||||||
}
|
}
|
||||||
for _, pod := range podList.Items {
|
for _, pod := range podList.Items {
|
||||||
id, ok := pod.ObjectMeta.Annotations[types.EXECUTOR_INSTANCEID_LABEL]
|
id, ok := pod.ObjectMeta.Annotations[types.EXECUTOR_INSTANCEID_LABEL]
|
||||||
|
if !ok {
|
||||||
|
// Backward compatibility with older label name
|
||||||
|
id, ok = pod.ObjectMeta.Labels[types.EXECUTOR_INSTANCEID_LABEL]
|
||||||
|
}
|
||||||
if ok && id != instanceId {
|
if ok && id != instanceId {
|
||||||
logger.Debug("cleaning up pod", zap.String("pod", pod.ObjectMeta.Name))
|
logger.Debug("cleaning up pod", zap.String("pod", pod.ObjectMeta.Name))
|
||||||
err := client.CoreV1().Pods(pod.ObjectMeta.Namespace).Delete(pod.ObjectMeta.Name, nil)
|
err := client.CoreV1().Pods(pod.ObjectMeta.Namespace).Delete(pod.ObjectMeta.Name, nil)
|
||||||
@@ -165,18 +155,6 @@ func cleanupPods(logger *zap.Logger, client *kubernetes.Clientset, instanceId st
|
|||||||
}
|
}
|
||||||
// ignore err
|
// ignore err
|
||||||
}
|
}
|
||||||
// Backward compatibility with older label name
|
|
||||||
pid, pok := pod.ObjectMeta.Annotations[types.POOLMGR_INSTANCEID_LABEL]
|
|
||||||
if pok && pid != instanceId {
|
|
||||||
logger.Debug("cleaning up pod", zap.String("pod", pod.ObjectMeta.Name))
|
|
||||||
err := client.CoreV1().Pods(pod.ObjectMeta.Namespace).Delete(pod.ObjectMeta.Name, nil)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("error cleaning up pod",
|
|
||||||
zap.Error(err),
|
|
||||||
zap.String("pod_name", pod.ObjectMeta.Name),
|
|
||||||
zap.String("pod_namespace", pod.ObjectMeta.Namespace))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -188,6 +166,10 @@ func cleanupServices(logger *zap.Logger, client *kubernetes.Clientset, instanceI
|
|||||||
}
|
}
|
||||||
for _, svc := range svcList.Items {
|
for _, svc := range svcList.Items {
|
||||||
id, ok := svc.ObjectMeta.Annotations[types.EXECUTOR_INSTANCEID_LABEL]
|
id, ok := svc.ObjectMeta.Annotations[types.EXECUTOR_INSTANCEID_LABEL]
|
||||||
|
if !ok {
|
||||||
|
// Backward compatibility with older label name
|
||||||
|
id, ok = svc.ObjectMeta.Labels[types.EXECUTOR_INSTANCEID_LABEL]
|
||||||
|
}
|
||||||
if ok && id != instanceId {
|
if ok && id != instanceId {
|
||||||
logger.Debug("cleaning up service", zap.String("service", svc.ObjectMeta.Name))
|
logger.Debug("cleaning up service", zap.String("service", svc.ObjectMeta.Name))
|
||||||
err := client.CoreV1().Services(svc.ObjectMeta.Namespace).Delete(svc.ObjectMeta.Name, nil)
|
err := client.CoreV1().Services(svc.ObjectMeta.Namespace).Delete(svc.ObjectMeta.Name, nil)
|
||||||
@@ -211,6 +193,10 @@ func cleanupHpa(logger *zap.Logger, client *kubernetes.Clientset, instanceId str
|
|||||||
|
|
||||||
for _, hpa := range hpaList.Items {
|
for _, hpa := range hpaList.Items {
|
||||||
id, ok := hpa.ObjectMeta.Annotations[types.EXECUTOR_INSTANCEID_LABEL]
|
id, ok := hpa.ObjectMeta.Annotations[types.EXECUTOR_INSTANCEID_LABEL]
|
||||||
|
if !ok {
|
||||||
|
// Backward compatibility with older label name
|
||||||
|
id, ok = hpa.ObjectMeta.Labels[types.EXECUTOR_INSTANCEID_LABEL]
|
||||||
|
}
|
||||||
if ok && id != instanceId {
|
if ok && id != instanceId {
|
||||||
logger.Debug("cleaning up HPA", zap.String("hpa", hpa.ObjectMeta.Name))
|
logger.Debug("cleaning up HPA", zap.String("hpa", hpa.ObjectMeta.Name))
|
||||||
err := client.AutoscalingV1().HorizontalPodAutoscalers(hpa.ObjectMeta.Namespace).Delete(hpa.ObjectMeta.Name, nil)
|
err := client.AutoscalingV1().HorizontalPodAutoscalers(hpa.ObjectMeta.Namespace).Delete(hpa.ObjectMeta.Name, nil)
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ limitations under the License.
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,3 +34,15 @@ func ApplyImagePullSecret(secret string, podspec apiv1.PodSpec) *apiv1.PodSpec {
|
|||||||
podspec.ImagePullSecrets = []apiv1.LocalObjectReference{{Name: secret}}
|
podspec.ImagePullSecrets = []apiv1.LocalObjectReference{{Name: secret}}
|
||||||
return &podspec
|
return &podspec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WaitTimeout(wg *sync.WaitGroup, timeout time.Duration) {
|
||||||
|
waitCh := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer close(waitCh)
|
||||||
|
wg.Wait()
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-waitCh:
|
||||||
|
case <-time.After(timeout):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const EXECUTOR_INSTANCEID_LABEL = fv1.EXECUTOR_INSTANCEID_LABEL
|
const EXECUTOR_INSTANCEID_LABEL = fv1.EXECUTOR_INSTANCEID_LABEL
|
||||||
const POOLMGR_INSTANCEID_LABEL = fv1.POOLMGR_INSTANCEID_LABEL
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ChecksumTypeSHA256 = fv1.ChecksumTypeSHA256
|
ChecksumTypeSHA256 = fv1.ChecksumTypeSHA256
|
||||||
|
|||||||
Reference in New Issue
Block a user