feat: patch Deployment env vars directly via k8s API (v1.3.78)
Fission newdeploy executor does NOT apply fn.Spec.PodSpec when building Deployment spec - it only uses env.Spec.Runtime.Container and podSpecPatch. Fix: after updating Function CRD, also directly patch the newdeploy Deployment via Kubernetes API using StrategicMergePatch, searching by labels functionName/functionNamespace/executorType=newdeploy. This ensures env vars immediately appear in the container and survive pod scaling events (scale to 0 / scale back to 1).
This commit is contained in:
@@ -55,7 +55,7 @@ spec:
|
||||
serviceAccountName: fission-console
|
||||
containers:
|
||||
- name: console
|
||||
image: naeel/fission-console:v1.3.77
|
||||
image: naeel/fission-console:v1.3.78
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8090
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// handleGetFunction возвращает детали функции: код, environment, route, methods.
|
||||
@@ -395,9 +396,9 @@ func (s *Server) handlePutFunctionEnvVars(w http.ResponseWriter, r *http.Request
|
||||
// Переключаем на newdeploy (только он поддерживает podspec env)
|
||||
if err := unstructured.SetNestedField(fn.Object, map[string]any{
|
||||
"ExecutionStrategy": map[string]any{
|
||||
"ExecutorType": "newdeploy",
|
||||
"MinScale": int64(0),
|
||||
"MaxScale": int64(1),
|
||||
"ExecutorType": "newdeploy",
|
||||
"MinScale": int64(0),
|
||||
"MaxScale": int64(1),
|
||||
"SpecializationTimeout": int64(120),
|
||||
},
|
||||
"StrategyType": "execution",
|
||||
@@ -426,6 +427,18 @@ func (s *Server) handlePutFunctionEnvVars(w http.ResponseWriter, r *http.Request
|
||||
return
|
||||
}
|
||||
|
||||
// Fission newdeploy НЕ применяет fn.Spec.PodSpec при построении Deployment.
|
||||
// Поэтому напрямую патчим существующий Deployment через Kubernetes API.
|
||||
if len(req.EnvVars) > 0 && s.kube != nil {
|
||||
envName, _, _ := unstructured.NestedString(fn.Object, "spec", "environment", "name")
|
||||
if envName != "" {
|
||||
if err := s.patchDeploymentEnvVars(ctx, ns, name, envName, req.EnvVars); err != nil {
|
||||
// Не фатальная ошибка — CRD обновлён, Deployment будет обновлён позже
|
||||
s.log.Sugar().Warnf("patch deployment env vars: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
executor := "poolmgr"
|
||||
if len(req.EnvVars) > 0 {
|
||||
executor = "newdeploy"
|
||||
@@ -450,3 +463,51 @@ func extractEnvVars(fn *unstructured.Unstructured) []map[string]string {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// patchDeploymentEnvVars находит Deployment newdeploy для функции и патчит его env vars.
|
||||
// Fission не применяет fn.Spec.PodSpec при построении Deployment, поэтому патчим напрямую.
|
||||
// Поиск по labels: functionName=<name>, functionNamespace=<ns>, executorType=newdeploy
|
||||
func (s *Server) patchDeploymentEnvVars(ctx context.Context, ns, fnName, envContainerName string, envVars []map[string]string) error {
|
||||
selector := fmt.Sprintf("functionName=%s,functionNamespace=%s,executorType=newdeploy", fnName, ns)
|
||||
deplList, err := s.kube.AppsV1().Deployments(ns).List(ctx, metav1.ListOptions{LabelSelector: selector})
|
||||
if err != nil {
|
||||
return fmt.Errorf("list deployments: %w", err)
|
||||
}
|
||||
if len(deplList.Items) == 0 {
|
||||
return nil // Deployment ещё не создан Fission — ничего страшного
|
||||
}
|
||||
|
||||
// Строим env vars для patch (StrategicMergePatch мержит по "name")
|
||||
envItems := make([]map[string]string, 0, len(envVars))
|
||||
for _, ev := range envVars {
|
||||
envItems = append(envItems, map[string]string{"name": ev["name"], "value": ev["value"]})
|
||||
}
|
||||
|
||||
patch := map[string]any{
|
||||
"spec": map[string]any{
|
||||
"template": map[string]any{
|
||||
"spec": map[string]any{
|
||||
"containers": []any{
|
||||
map[string]any{
|
||||
"name": envContainerName,
|
||||
"env": envItems,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
patchBytes, err := json.Marshal(patch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal patch: %w", err)
|
||||
}
|
||||
|
||||
for _, depl := range deplList.Items {
|
||||
if _, err := s.kube.AppsV1().Deployments(ns).Patch(
|
||||
ctx, depl.Name, k8stypes.StrategicMergePatchType, patchBytes, metav1.PatchOptions{},
|
||||
); err != nil {
|
||||
return fmt.Errorf("patch deployment %s: %w", depl.Name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
<div class="nubes">NUBES</div>
|
||||
<div class="product">FISSION CONSOLE</div>
|
||||
</div>
|
||||
<div style="font-size:0.65rem; color:var(--text-secondary); margin-left:10px; align-self:center; opacity:0.7;">v1.3.77</div>
|
||||
<div style="font-size:0.65rem; color:var(--text-secondary); margin-left:10px; align-self:center; opacity:0.7;">v1.3.78</div>
|
||||
</div>
|
||||
<div class="row" style="margin:0;">
|
||||
<button class="btn ghost" onclick="reloadAll()">Refresh</button>
|
||||
@@ -510,7 +510,7 @@
|
||||
</div>
|
||||
|
||||
<div class="actions" style="justify-content:space-between; align-items:center;">
|
||||
<span style="font-size:0.75rem; color:var(--text-secondary);">v1.3.77</span>
|
||||
<span style="font-size:0.75rem; color:var(--text-secondary);">v1.3.78</span>
|
||||
<button class="btn ghost" onclick="closeHelp()">Закрыть</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user