diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index f432188..88e9527 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -64,6 +64,25 @@ ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout= Коммитить и пушить после каждого завершённого этапа. +### Версионирование тегами + +После каждого коммита с изменениями — поднимать версию тега: + +```bash +# Посмотреть текущий тег +git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0" + +# Поднять patch-версию (v0.1.0 → v0.1.1, v0.1.1 → v0.1.2 и т.д.) +git tag vX.Y.Z && git push origin vX.Y.Z +``` + +**Правила:** +- Patch (Z) — любое изменение: правка кода, новая функция, фикс +- Minor (Y) — новая фича/компонент (новый ресурс провайдера, новый модуль консоли) +- Major (X) — breaking change +- Тег ставить ПОСЛЕ успешного коммита и пуша +- Формат: `vMAJOR.MINOR.PATCH` (например `v0.2.3`) + --- ## Как создать и задеплоить новую Fission-функцию через Terraform diff --git a/examples/auto-funcs/code/bigdata/main.py b/examples/auto-funcs/code/bigdata/main.py new file mode 100644 index 0000000..1adb79f --- /dev/null +++ b/examples/auto-funcs/code/bigdata/main.py @@ -0,0 +1,5 @@ +def main(): + lines = [] + for i in range(500): + lines.append(f"line-{i}: {'x' * 80}") + return "\n".join(lines) diff --git a/examples/auto-funcs/code/chain/main.py b/examples/auto-funcs/code/chain/main.py new file mode 100644 index 0000000..f82e396 --- /dev/null +++ b/examples/auto-funcs/code/chain/main.py @@ -0,0 +1,9 @@ +import hashlib +import json + +def main(): + data = {"step": 1, "value": "start"} + for i in range(2, 6): + h = hashlib.sha256(json.dumps(data).encode()).hexdigest()[:8] + data = {"step": i, "prev_hash": h, "value": f"chain-{i}"} + return json.dumps(data) diff --git a/examples/auto-funcs/code/cpu.py b/examples/auto-funcs/code/cpu.py new file mode 100644 index 0000000..7ebb2a8 --- /dev/null +++ b/examples/auto-funcs/code/cpu.py @@ -0,0 +1,5 @@ +def main(): + s = 0 + for i in range(1, 100000): + s += (i * i) % 97 + return f"cpu-load:{s}" \ No newline at end of file diff --git a/examples/auto-funcs/code/cpu/main.py b/examples/auto-funcs/code/cpu/main.py new file mode 100644 index 0000000..a28b8cf --- /dev/null +++ b/examples/auto-funcs/code/cpu/main.py @@ -0,0 +1,5 @@ +def main(): + s = 0 + for i in range(1, 100000): + s += (i * i) % 97 + return f"cpu-load:{s}" diff --git a/examples/auto-funcs/code/echo.py b/examples/auto-funcs/code/echo.py new file mode 100644 index 0000000..94a2514 --- /dev/null +++ b/examples/auto-funcs/code/echo.py @@ -0,0 +1,4 @@ +def main(): + import os + msg = os.environ.get("FISSION_INPUT", "echo-default") + return f"echo:{msg}" \ No newline at end of file diff --git a/examples/auto-funcs/code/echo/main.py b/examples/auto-funcs/code/echo/main.py new file mode 100644 index 0000000..7148fce --- /dev/null +++ b/examples/auto-funcs/code/echo/main.py @@ -0,0 +1,5 @@ +import os + +def main(): + msg = os.environ.get("FISSION_INPUT", "echo-default") + return f"echo:{msg}" diff --git a/examples/auto-funcs/code/encoding/main.py b/examples/auto-funcs/code/encoding/main.py new file mode 100644 index 0000000..cac9723 --- /dev/null +++ b/examples/auto-funcs/code/encoding/main.py @@ -0,0 +1,5 @@ +def main(): + emoji = "\U0001f680\U0001f525\u2764\ufe0f" + cyrillic = "\u041f\u0440\u0438\u0432\u0435\u0442 \u043c\u0438\u0440!" + chinese = "\u4f60\u597d\u4e16\u754c" + return f"emoji:{emoji} cyr:{cyrillic} zh:{chinese}" diff --git a/examples/auto-funcs/code/error.py b/examples/auto-funcs/code/error.py new file mode 100644 index 0000000..b27585c --- /dev/null +++ b/examples/auto-funcs/code/error.py @@ -0,0 +1,2 @@ +def main(): + raise Exception("auto-error-test") \ No newline at end of file diff --git a/examples/auto-funcs/code/error/main.py b/examples/auto-funcs/code/error/main.py new file mode 100644 index 0000000..65f4f65 --- /dev/null +++ b/examples/auto-funcs/code/error/main.py @@ -0,0 +1,2 @@ +def main(): + raise Exception("auto-error-test") diff --git a/examples/auto-funcs/code/jsonout/main.py b/examples/auto-funcs/code/jsonout/main.py new file mode 100644 index 0000000..0b4260c --- /dev/null +++ b/examples/auto-funcs/code/jsonout/main.py @@ -0,0 +1,9 @@ +import json + +def main(): + data = { + "status": "ok", + "items": [{"id": i, "value": i * i} for i in range(10)], + "count": 10 + } + return json.dumps(data) diff --git a/examples/auto-funcs/code/math/main.py b/examples/auto-funcs/code/math/main.py new file mode 100644 index 0000000..a3d909e --- /dev/null +++ b/examples/auto-funcs/code/math/main.py @@ -0,0 +1,12 @@ +import math + +def main(): + results = { + "pi": round(math.pi, 10), + "e": round(math.e, 10), + "sqrt2": round(math.sqrt(2), 10), + "factorial20": math.factorial(20), + "log1000": round(math.log(1000), 10), + } + parts = [f"{k}={v}" for k, v in results.items()] + return "; ".join(parts) diff --git a/examples/auto-funcs/code/memory/main.py b/examples/auto-funcs/code/memory/main.py new file mode 100644 index 0000000..c5332a6 --- /dev/null +++ b/examples/auto-funcs/code/memory/main.py @@ -0,0 +1,6 @@ +import sys + +def main(): + big_list = list(range(500000)) + size_mb = sys.getsizeof(big_list) / (1024 * 1024) + return f"memory-alloc:{size_mb:.2f}MB len={len(big_list)}" diff --git a/examples/auto-funcs/code/multiline/main.py b/examples/auto-funcs/code/multiline/main.py new file mode 100644 index 0000000..df7554e --- /dev/null +++ b/examples/auto-funcs/code/multiline/main.py @@ -0,0 +1,5 @@ +def main(): + return """line1 +line2 +line3 +Конец (кириллица)""" diff --git a/examples/auto-funcs/code/nested/main.py b/examples/auto-funcs/code/nested/main.py new file mode 100644 index 0000000..404d41b --- /dev/null +++ b/examples/auto-funcs/code/nested/main.py @@ -0,0 +1,9 @@ +def main(): + try: + a = 1 / 0 + except ZeroDivisionError: + try: + raise ValueError("nested after div-by-zero") + except ValueError as e: + return f"caught-nested:{e}" + return "unreachable" diff --git a/examples/auto-funcs/code/ok.py b/examples/auto-funcs/code/ok.py new file mode 100644 index 0000000..0066b01 --- /dev/null +++ b/examples/auto-funcs/code/ok.py @@ -0,0 +1,2 @@ +def main(): + return "ok-auto-func" \ No newline at end of file diff --git a/examples/auto-funcs/code/ok/main.py b/examples/auto-funcs/code/ok/main.py new file mode 100644 index 0000000..962d505 --- /dev/null +++ b/examples/auto-funcs/code/ok/main.py @@ -0,0 +1,2 @@ +def main(): + return "ok-auto-func-UPDATED-v2" diff --git a/examples/auto-funcs/code/recurse/main.py b/examples/auto-funcs/code/recurse/main.py new file mode 100644 index 0000000..ae3afcd --- /dev/null +++ b/examples/auto-funcs/code/recurse/main.py @@ -0,0 +1,8 @@ +def fib(n): + if n <= 1: + return n + return fib(n - 1) + fib(n - 2) + +def main(): + result = fib(30) + return f"fib(30)={result}" diff --git a/examples/auto-funcs/code/slow.py b/examples/auto-funcs/code/slow.py new file mode 100644 index 0000000..46e3947 --- /dev/null +++ b/examples/auto-funcs/code/slow.py @@ -0,0 +1,4 @@ +import time +def main(): + time.sleep(2) + return "slow-done" \ No newline at end of file diff --git a/examples/auto-funcs/code/slow/main.py b/examples/auto-funcs/code/slow/main.py new file mode 100644 index 0000000..da21a0c --- /dev/null +++ b/examples/auto-funcs/code/slow/main.py @@ -0,0 +1,5 @@ +import time + +def main(): + time.sleep(2) + return "slow-done" diff --git a/examples/auto-funcs/code/timestamp/main.py b/examples/auto-funcs/code/timestamp/main.py new file mode 100644 index 0000000..379fca2 --- /dev/null +++ b/examples/auto-funcs/code/timestamp/main.py @@ -0,0 +1,5 @@ +import datetime + +def main(): + now = datetime.datetime.utcnow().isoformat() + return f"timestamp:{now}Z" diff --git a/examples/auto-funcs/main.tf b/examples/auto-funcs/main.tf new file mode 100644 index 0000000..61047d3 --- /dev/null +++ b/examples/auto-funcs/main.tf @@ -0,0 +1,309 @@ +terraform { + required_providers { + fission = { + source = "nail/fission" + version = "~> 0.1.0" + } + } +} + +provider "fission" { + kubeconfig_path = "/home/naeel/.kube/config" + namespace = "default" +} + +resource "fission_environment" "python" { + name = "tf-auto-env" + image = "ghcr.io/fission/python-env" + version = 3 +} + +# ok function +resource "fission_package" "ok" { + name = "tf-auto-ok-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/ok" + code_hash = "v2" +} +resource "fission_function" "ok" { + name = "tf-auto-ok-fn" + environment = fission_environment.python.name + package_name = fission_package.ok.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "ok" { + name = "tf-auto-ok-route" + function = fission_function.ok.name + url = "/auto/ok" + methods = ["GET"] +} + +# echo function +resource "fission_package" "echo" { + name = "tf-auto-echo-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/echo" +} +resource "fission_function" "echo" { + name = "tf-auto-echo-fn" + environment = fission_environment.python.name + package_name = fission_package.echo.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "echo" { + name = "tf-auto-echo-route" + function = fission_function.echo.name + url = "/auto/echo" + methods = ["GET"] +} + +# error function +resource "fission_package" "error" { + name = "tf-auto-error-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/error" +} +resource "fission_function" "error" { + name = "tf-auto-error-fn" + environment = fission_environment.python.name + package_name = fission_package.error.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "error" { + name = "tf-auto-error-route" + function = fission_function.error.name + url = "/auto/error" + methods = ["GET"] +} + +# cpu function +resource "fission_package" "cpu" { + name = "tf-auto-cpu-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/cpu" +} +resource "fission_function" "cpu" { + name = "tf-auto-cpu-fn" + environment = fission_environment.python.name + package_name = fission_package.cpu.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "cpu" { + name = "tf-auto-cpu-route" + function = fission_function.cpu.name + url = "/auto/cpu" + methods = ["GET"] +} + +# slow function +resource "fission_package" "slow" { + name = "tf-auto-slow-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/slow" +} +resource "fission_function" "slow" { + name = "tf-auto-slow-fn" + environment = fission_environment.python.name + package_name = fission_package.slow.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "slow" { + name = "tf-auto-slow-route" + function = fission_function.slow.name + url = "/auto/slow" + methods = ["GET"] +} + +# --- BATCH 2 --- + +# jsonout: возвращает сложный JSON +resource "fission_package" "jsonout" { + name = "tf-auto-jsonout-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/jsonout" +} +resource "fission_function" "jsonout" { + name = "tf-auto-jsonout-fn" + environment = fission_environment.python.name + package_name = fission_package.jsonout.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "jsonout" { + name = "tf-auto-jsonout-route" + function = fission_function.jsonout.name + url = "/auto/jsonout" + methods = ["GET"] +} + +# recurse: рекурсивный Фибоначчи (нагрузка на стек) +resource "fission_package" "recurse" { + name = "tf-auto-recurse-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/recurse" +} +resource "fission_function" "recurse" { + name = "tf-auto-recurse-fn" + environment = fission_environment.python.name + package_name = fission_package.recurse.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "recurse" { + name = "tf-auto-recurse-route" + function = fission_function.recurse.name + url = "/auto/recurse" + methods = ["GET"] +} + +# bigdata: большой ответ (~45KB текста) +resource "fission_package" "bigdata" { + name = "tf-auto-bigdata-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/bigdata" +} +resource "fission_function" "bigdata" { + name = "tf-auto-bigdata-fn" + environment = fission_environment.python.name + package_name = fission_package.bigdata.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "bigdata" { + name = "tf-auto-bigdata-route" + function = fission_function.bigdata.name + url = "/auto/bigdata" + methods = ["GET"] +} + +# math: математические вычисления +resource "fission_package" "math" { + name = "tf-auto-math-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/math" +} +resource "fission_function" "math" { + name = "tf-auto-math-fn" + environment = fission_environment.python.name + package_name = fission_package.math.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "math" { + name = "tf-auto-math-route" + function = fission_function.math.name + url = "/auto/math" + methods = ["GET"] +} + +# timestamp: текущее время UTC +resource "fission_package" "timestamp" { + name = "tf-auto-timestamp-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/timestamp" +} +resource "fission_function" "timestamp" { + name = "tf-auto-timestamp-fn" + environment = fission_environment.python.name + package_name = fission_package.timestamp.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "timestamp" { + name = "tf-auto-timestamp-route" + function = fission_function.timestamp.name + url = "/auto/timestamp" + methods = ["GET"] +} + +# --- BATCH 3 --- + +# multiline: многострочный вывод с кириллицей +resource "fission_package" "multiline" { + name = "tf-auto-multiline-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/multiline" +} +resource "fission_function" "multiline" { + name = "tf-auto-multiline-fn" + environment = fission_environment.python.name + package_name = fission_package.multiline.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "multiline" { + name = "tf-auto-multiline-route" + function = fission_function.multiline.name + url = "/auto/multiline" + methods = ["GET"] +} + +# encoding: unicode/emoji/кириллица/китайский +resource "fission_package" "encoding" { + name = "tf-auto-encoding-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/encoding" +} +resource "fission_function" "encoding" { + name = "tf-auto-encoding-fn" + environment = fission_environment.python.name + package_name = fission_package.encoding.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "encoding" { + name = "tf-auto-encoding-route" + function = fission_function.encoding.name + url = "/auto/encoding" + methods = ["GET"] +} + +# nested: вложенные try/except +resource "fission_package" "nested" { + name = "tf-auto-nested-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/nested" +} +resource "fission_function" "nested" { + name = "tf-auto-nested-fn" + environment = fission_environment.python.name + package_name = fission_package.nested.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "nested" { + name = "tf-auto-nested-route" + function = fission_function.nested.name + url = "/auto/nested" + methods = ["GET"] +} + +# memory: аллокация памяти (500k элементов) +resource "fission_package" "memory" { + name = "tf-auto-memory-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/memory" +} +resource "fission_function" "memory" { + name = "tf-auto-memory-fn" + environment = fission_environment.python.name + package_name = fission_package.memory.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "memory" { + name = "tf-auto-memory-route" + function = fission_function.memory.name + url = "/auto/memory" + methods = ["GET"] +} + +# chain: хеш-цепочка (имитация блокчейна) +resource "fission_package" "chain" { + name = "tf-auto-chain-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code/chain" +} +resource "fission_function" "chain" { + name = "tf-auto-chain-fn" + environment = fission_environment.python.name + package_name = fission_package.chain.name + entrypoint = "main.main" +} +resource "fission_http_trigger" "chain" { + name = "tf-auto-chain-route" + function = fission_function.chain.name + url = "/auto/chain" + methods = ["GET"] +} diff --git a/examples/destroy-test/code/main.py b/examples/destroy-test/code/main.py new file mode 100644 index 0000000..282c218 --- /dev/null +++ b/examples/destroy-test/code/main.py @@ -0,0 +1,2 @@ +def main(): + return "destroy-test-alive" diff --git a/examples/destroy-test/main.tf b/examples/destroy-test/main.tf new file mode 100644 index 0000000..b035ecd --- /dev/null +++ b/examples/destroy-test/main.tf @@ -0,0 +1,39 @@ +terraform { + required_providers { + fission = { + source = "nail/fission" + version = "~> 0.1.0" + } + } +} + +provider "fission" { + kubeconfig_path = "/home/naeel/.kube/config" + namespace = "default" +} + +resource "fission_environment" "python" { + name = "tf-destroy-test-env" + image = "ghcr.io/fission/python-env" + version = 3 +} + +resource "fission_package" "pkg" { + name = "tf-destroy-test-pkg" + environment = fission_environment.python.name + source_dir = "${path.module}/code" +} + +resource "fission_function" "fn" { + name = "tf-destroy-test-fn" + environment = fission_environment.python.name + package_name = fission_package.pkg.name + entrypoint = "main.main" +} + +resource "fission_http_trigger" "route" { + name = "tf-destroy-test-route" + function = fission_function.fn.name + url = "/destroy-test" + methods = ["GET"] +}