console v0.4.5: русификация UI, Go/TF предупреждения, handler.go в preferred
This commit is contained in:
+128
-11
@@ -58,6 +58,7 @@ type server struct {
|
||||
|
||||
type createFunctionRequest struct {
|
||||
Name string `json:"name"`
|
||||
Language string `json:"language"`
|
||||
Environment string `json:"environment"`
|
||||
Code string `json:"code"`
|
||||
Entrypoint string `json:"entrypoint"`
|
||||
@@ -65,6 +66,20 @@ type createFunctionRequest struct {
|
||||
Methods []string `json:"methods"`
|
||||
}
|
||||
|
||||
type langEnvDef struct {
|
||||
Image string
|
||||
BuilderImage string
|
||||
}
|
||||
|
||||
var langEnvMap = map[string]langEnvDef{
|
||||
"python": {Image: "ghcr.io/fission/python-env"},
|
||||
"nodejs": {Image: "ghcr.io/fission/node-env"},
|
||||
"go": {Image: "ghcr.io/fission/go-env", BuilderImage: "ghcr.io/fission/go-builder"},
|
||||
"php": {Image: "ghcr.io/fission/php-env"},
|
||||
"ruby": {Image: "ghcr.io/fission/ruby-env"},
|
||||
"perl": {Image: "ghcr.io/fission/perl-env"},
|
||||
}
|
||||
|
||||
type updateCodeRequest struct {
|
||||
Code string `json:"code"`
|
||||
}
|
||||
@@ -202,13 +217,38 @@ func (s *server) handleCreateFunction(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
req.Name = strings.TrimSpace(req.Name)
|
||||
req.Language = strings.TrimSpace(req.Language)
|
||||
req.Environment = strings.TrimSpace(req.Environment)
|
||||
req.Code = strings.TrimSpace(req.Code)
|
||||
req.Entrypoint = strings.TrimSpace(req.Entrypoint)
|
||||
req.Route = strings.TrimSpace(req.Route)
|
||||
|
||||
// Resolve language → environment (auto-create if needed)
|
||||
if req.Language != "" {
|
||||
langDef, ok := langEnvMap[req.Language]
|
||||
if !ok {
|
||||
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("unsupported language: %q", req.Language))
|
||||
return
|
||||
}
|
||||
envName := "console-" + req.Language + "-env"
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
_, err := s.dyn.Resource(environmentGVR).Namespace(s.ns).Get(ctx, envName, metav1.GetOptions{})
|
||||
if apierrors.IsNotFound(err) {
|
||||
env := s.buildLangEnvironment(envName, langDef)
|
||||
if _, err := s.dyn.Resource(environmentGVR).Namespace(s.ns).Create(ctx, env, metav1.CreateOptions{}); err != nil {
|
||||
writeJSONError(w, http.StatusBadGateway, fmt.Sprintf("create environment %q: %v", envName, err))
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
writeJSONError(w, http.StatusBadGateway, fmt.Sprintf("check environment: %v", err))
|
||||
return
|
||||
}
|
||||
req.Environment = envName
|
||||
}
|
||||
|
||||
if req.Name == "" || req.Environment == "" || req.Code == "" {
|
||||
writeJSONError(w, http.StatusBadRequest, "name, environment and code are required")
|
||||
writeJSONError(w, http.StatusBadRequest, "name, environment/language and code are required")
|
||||
return
|
||||
}
|
||||
if req.Entrypoint == "" {
|
||||
@@ -237,15 +277,30 @@ func (s *server) handleCreateFunction(w http.ResponseWriter, r *http.Request) {
|
||||
methodValues = append(methodValues, method)
|
||||
}
|
||||
|
||||
literal := base64.StdEncoding.EncodeToString([]byte(req.Code))
|
||||
pkg := &unstructured.Unstructured{Object: map[string]any{
|
||||
"apiVersion": "fission.io/v1",
|
||||
"kind": "Package",
|
||||
"metadata": map[string]any{
|
||||
"name": pkgName,
|
||||
"namespace": s.ns,
|
||||
},
|
||||
"spec": map[string]any{
|
||||
// Build the package spec: Go uses source archive (builder), others use literal deployment
|
||||
var pkgSpec map[string]any
|
||||
if req.Language == "go" {
|
||||
srcZip, err := s.buildGoSourceZip(req.Code)
|
||||
if err != nil {
|
||||
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("build go source archive: %v", err))
|
||||
return
|
||||
}
|
||||
literal := base64.StdEncoding.EncodeToString(srcZip)
|
||||
pkgSpec = map[string]any{
|
||||
"source": map[string]any{
|
||||
"type": "literal",
|
||||
"literal": literal,
|
||||
},
|
||||
"deployment": map[string]any{},
|
||||
"environment": map[string]any{
|
||||
"name": req.Environment,
|
||||
"namespace": s.ns,
|
||||
},
|
||||
"buildcommand": "build",
|
||||
}
|
||||
} else {
|
||||
literal := base64.StdEncoding.EncodeToString([]byte(req.Code))
|
||||
pkgSpec = map[string]any{
|
||||
"deployment": map[string]any{
|
||||
"type": "literal",
|
||||
"literal": literal,
|
||||
@@ -255,7 +310,17 @@ func (s *server) handleCreateFunction(w http.ResponseWriter, r *http.Request) {
|
||||
"namespace": s.ns,
|
||||
},
|
||||
"source": map[string]any{},
|
||||
}
|
||||
}
|
||||
|
||||
pkg := &unstructured.Unstructured{Object: map[string]any{
|
||||
"apiVersion": "fission.io/v1",
|
||||
"kind": "Package",
|
||||
"metadata": map[string]any{
|
||||
"name": pkgName,
|
||||
"namespace": s.ns,
|
||||
},
|
||||
"spec": pkgSpec,
|
||||
}}
|
||||
|
||||
if _, err := s.dyn.Resource(packageGVR).Namespace(s.ns).Create(ctx, pkg, metav1.CreateOptions{}); err != nil {
|
||||
@@ -325,6 +390,58 @@ func (s *server) handleCreateFunction(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *server) buildLangEnvironment(name string, def langEnvDef) *unstructured.Unstructured {
|
||||
spec := map[string]any{
|
||||
"version": int64(3),
|
||||
"runtime": map[string]any{
|
||||
"image": def.Image,
|
||||
},
|
||||
"poolsize": int64(1),
|
||||
}
|
||||
if def.BuilderImage != "" {
|
||||
spec["builder"] = map[string]any{
|
||||
"image": def.BuilderImage,
|
||||
"command": "build",
|
||||
}
|
||||
}
|
||||
return &unstructured.Unstructured{Object: map[string]any{
|
||||
"apiVersion": "fission.io/v1",
|
||||
"kind": "Environment",
|
||||
"metadata": map[string]any{
|
||||
"name": name,
|
||||
"namespace": s.ns,
|
||||
},
|
||||
"spec": spec,
|
||||
}}
|
||||
}
|
||||
|
||||
func (s *server) buildGoSourceZip(code string) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
zw := zip.NewWriter(&buf)
|
||||
|
||||
fw, err := zw.Create("handler.go")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := fw.Write([]byte(code)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
goMod := "module github.com/user/fn\n\ngo 1.23\n"
|
||||
fw2, err := zw.Create("go.mod")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := fw2.Write([]byte(goMod)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := zw.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (s *server) handleGetFunction(w http.ResponseWriter, r *http.Request, name string) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
@@ -851,7 +968,7 @@ func decodeZipSource(zipBytes []byte) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
preferred := []string{"main.py", "main.js", "main.go"}
|
||||
preferred := []string{"main.py", "main.js", "main.go", "handler.go", "handler.js", "handler.py"}
|
||||
for _, name := range preferred {
|
||||
for _, file := range reader.File {
|
||||
if strings.EqualFold(file.Name, name) {
|
||||
|
||||
Reference in New Issue
Block a user