This is an automated email from the ASF dual-hosted git repository.

msciabarra pushed a commit to branch 0.1.0
in repository https://gitbox.apache.org/repos/asf/openserverless-task.git


The following commit(s) were added to refs/heads/0.1.0 by this push:
     new 1cbae59  sync to main
1cbae59 is described below

commit 1cbae59d6c6e5f235801d742fa3456cf9dfcc8ec
Author: Michele Sciabarra <“[email protected]”>
AuthorDate: Thu Mar 26 09:42:55 2026 +0000

    sync to main
---
 ide/deploy/bun.lockb               | Bin
 ide/deploy/deploy.js               |   5 +-
 ide/docopts.md                     |   3 +-
 ide/opsfile.yml                    |  29 +++++--
 opsroot.json                       |  39 ++++++---
 setup/devcontainer/deployment.yaml | 110 ++++++++++++++++++++++++
 setup/devcontainer/opsfile.yml     | 167 +++++++++++++++++++++++++++++++++++++
 setup/docker/kind.yaml             |  10 ++-
 setup/docker/opsfile.yml           |  25 ++++--
 setup/kubernetes/DEBUG.txt         |  25 ++++++
 setup/kubernetes/operator.yaml     |   5 +-
 setup/kubernetes/opsfile.yml       |  41 +++++----
 setup/opsfile.yml                  |   2 +-
 util/docopts.md                    |   5 +-
 util/freeze/findimages.js          |  50 +++++++++++
 util/freeze/opsfile.yml            |  42 +++++++---
 util/opsfile.yml                   |   7 ++
 util/stdtext.js                    |  23 +++++
 18 files changed, 530 insertions(+), 58 deletions(-)

diff --git a/ide/deploy/bun.lockb b/ide/deploy/bun.lockb
old mode 100755
new mode 100644
diff --git a/ide/deploy/deploy.js b/ide/deploy/deploy.js
index 28f16bc..628814a 100644
--- a/ide/deploy/deploy.js
+++ b/ide/deploy/deploy.js
@@ -41,7 +41,10 @@ async function exec(cmd) {
     cwd: process.env.OPS_PWD,
     stdio: ["inherit", "inherit", "inherit"],
   });
-  await proc.exited;
+  const code = await proc.exited;
+  if (code !== 0) {
+    throw new Error(`command failed (${code}): ${cmd}`);
+  }
 }
 
 async function extractArgs(files) {
diff --git a/ide/docopts.md b/ide/docopts.md
index 8b35feb..1c157ef 100644
--- a/ide/docopts.md
+++ b/ide/docopts.md
@@ -24,7 +24,7 @@ OpenServerless Ide Development Utilities.
 
 ```text
 Usage:
-    ide login [<username>] [<apihost>] [--pin]
+    ide login [<username>] [<apihost>] [--pin] [--mode=<mode>]
     ide devel [--fast] [--dry-run]
     ide deploy [<action>|--packages|--web] [--dry-run]
     ide undeploy [<action>] [--dry-run]
@@ -65,4 +65,5 @@ Usage:
 --web           Only deploy web folder, skip packages
 --fast          Skip the initial deployment step and go in incremental update 
mode
 --pin           Pin the current auth in the .env to check you are not 
deploying on the wrong user
+--mode          this will load from .env.<mode> after .env
 ```
diff --git a/ide/opsfile.yml b/ide/opsfile.yml
index 75d28e8..2d6e65c 100644
--- a/ide/opsfile.yml
+++ b/ide/opsfile.yml
@@ -43,7 +43,7 @@ tasks:
     silent: true
     vars:
       MSG: |
-            This command must be run inside a devcontainer.
+            This command on windows requires a devcontainr
             Please use 'ops ide devcontainer' to create a configuration and 
enter in a devcontainer.
             You can then use 'ops ide devel' and 'ops ide deploy'.
             You can also reopen the project with VSCode and use the command 
'Reopen in Container'.
@@ -137,7 +137,7 @@ tasks:
 
 
   login:
-    silent: false
+    silent: true
     desc: login in you OpenServerless host
     cmds:
       - |
@@ -145,6 +145,11 @@ tasks:
         if test -e "$OPS_PWD/.env"
         then source "$OPS_PWD/.env"
         fi
+        if [ -n "{{.__mode}}" ] && [ -e "$OPS_PWD/.env.{{.__mode}}" ]
+        then
+          echo "Loading .env.{{.__mode}}"
+          source "$OPS_PWD/.env.{{.__mode}}"
+        fi
         if test -n "$OPS_USERNAME"
         then echo "Please use OPS_USER, OPS_USERNAME is deprecated"
         fi
@@ -164,10 +169,8 @@ tasks:
             fi
         else
             export OPSDEV_USERNAME="{{._username_}}"
-            if test -e "$OPS_PWD/.env.{{._username_}}"
-            then source "$OPS_PWD/.env.{{._username_}}"
-            fi
         fi
+
         if test -z "{{._apihost_}}"
         then
             if test -z "$OPS_APIHOST"
@@ -188,21 +191,29 @@ tasks:
         then
           OPSDEV_HOST_PROT="$(echo "$OPSDEV_APIHOST" | awk -F '://' '{print 
$1}')"
           OPSDEV_HOST_URL="$(echo "$OPSDEV_APIHOST" | awk -F '://' '{print 
$2}')"
+          OPSDEV_STREAM="${OPSDEV_APIHOST/\/\////stream.}"
+          OPSDEV_S3="${OPSDEV_APIHOST/\/\////s3.}"
+          OPSDEV_HOST="$OPSDEV_HOST_PROT://$OPSDEV_USERNAME.$OPSDEV_HOST_URL"
           config OPSDEV_APIHOST="$OPSDEV_APIHOST"
           config OPSDEV_USERNAME="$OPSDEV_USERNAME"
-          config 
OPSDEV_HOST="$OPSDEV_HOST_PROT://$OPSDEV_USERNAME.$OPSDEV_HOST_URL"
+          config OPSDEV_HOST="$OPSDEV_HOST"
+          config OPSDEV_S3="$OPSDEV_S3"
+          config OPSDEV_STREAM="$OPSDEV_STREAM"
+          config VITE_OPSDEV_STREAM="$OPSDEV_STREAM"
+          config VITE_OPSDEV_S3="$OPSDEV_S3"
+          config VITE_OPSDEV_HOST="$OPSDEV_HOST"
+          config VITE_OPSDEV_APIHOST="$OPSDEV_APIHOST"
           source ~/.wskprops
         fi
         if {{.__pin}}
         then
           touch $OPS_PWD/.env
           mv $OPS_PWD/.env $OPS_PWD/.env.$$
-          cat $OPS_PWD/.env.$$ | rg -v "AUTH_CHECK=" >$OPS_PWD/.env || true
+          rg -v "AUTH_CHECK=" >$OPS_PWD/.env $OPS_PWD/.env.$$
           echo "AUTH_CHECK=$AUTH" >>$OPS_PWD/.env
+          rm $OPS_PWD/.env.$$
         fi
 
-
-
   poll:
     silent: true
     desc: poll activation logs
diff --git a/opsroot.json b/opsroot.json
index 677fac3..1c8a1d9 100644
--- a/opsroot.json
+++ b/opsroot.json
@@ -1,15 +1,30 @@
 {
-    "version": "0.1.0-2409121919.dev",
-    "config": {
-       "ops": {
-            "coreutils": "arch b2sum b3sum base32 basename basenc cat chgrp 
chmod chown chroot cksum comm cp csplit cut date dd df dir dircolors dirname du 
env expand expr factor fmt fold groups hashsum head hostid hostname id install 
join kill link ln logname ls md5sum mkdir mkfifo mknod mktemp more mv nice nl 
nohup nproc numfmt od paste pathchk pinky pr printenv printf ptx pwd readlink 
realpath rm rmdir seq sha1sum sha224sum sha256sum sha3-224sum sha3-256sum 
sha3-384sum sha3-512sum sha384sum [...]
-       },
-       "images": {
-         "operator": 
"registry.hub.docker.com/apache/openserverless-operator:0.1.0-incubating.2512151437",
-         "controller": 
"ghcr.io/nuvolaris/openwhisk-controller:3.1.0-mastrogpt.2402101445",
-         "invoker": 
"ghcr.io/nuvolaris/openwhisk-invoker:3.1.0-mastrogpt.2402101445",
-         "streamer": 
"registry.hub.docker.com/apache/openserverless-streamer:0.1.0-incubating.2505031325",
-         "systemapi": 
"registry.hub.docker.com/apache/openserverless-admin-api:0.1.0-incubating.2512101357"
-        }
+  "version": "0.1.0-2409121919.dev",
+  "config": {
+    "ops": {
+      "coreutils": "arch b2sum b3sum base32 basename basenc cat chgrp chmod 
chown chroot cksum comm cp csplit cut date dd df dir dircolors dirname du env 
expand expr factor fmt fold groups hashsum head hostid hostname id install join 
kill link ln logname ls md5sum mkdir mkfifo mknod mktemp more mv nice nl nohup 
nproc numfmt od paste pathchk pinky pr printenv printf ptx pwd readlink 
realpath rm rmdir seq sha1sum sha224sum sha256sum sha3-224sum sha3-256sum 
sha3-384sum sha3-512sum sha384sum [...]
+    },
+    "images": {
+      "standalone": 
"ghcr.io/nuvolaris/openwhisk-controller:3.1.0-mastrogpt.2402101445",
+      "operator": 
"registry.hub.docker.com/apache/openserverless-operator:0.1.0-incubating.2603190945",
+      "controller": 
"ghcr.io/nuvolaris/openwhisk-controller:3.1.0-mastrogpt.2402101445",
+      "invoker": 
"ghcr.io/nuvolaris/openwhisk-invoker:3.1.0-mastrogpt.2402101445",
+      "streamer": 
"registry.hub.docker.com/apache/openserverless-streamer:0.1.0-incubating.2505031325",
+      "systemapi": 
"registry.hub.docker.com/apache/openserverless-admin-api:0.1.0-incubating.2512101357",
+      "devcontainer": 
"apache/openserverless-devcontainer:0.1.0-incubating.2603111653",
+      "ingress": "registry.k8s.io/ingress-nginx/controller:v1.7.0",
+      "couchdb": "docker.io/apache/couchdb:2.3",
+      "etcd": "docker.io/bitnamilegacy/etcd:3.5.17-debian-12-r0",
+      "redis": "docker.io/bitnamilegacy/redis:8.2.1",
+      "seaweedfs": "docker.io/chrislusf/seaweedfs:3.97",
+      "busybox":"docker.io/library/busybox:1.36.0",
+      "registry": "docker.io/library/registry:3.0.0",
+      "milvus": "docker.io/milvusdb/milvus:v2.5.2",
+      "nginx": "docker.io/nginxinc/nginx-unprivileged:1.24",
+      "pgvector": "docker.io/pgvector/pgvector:pg16",
+      "kubegres": "docker.io/reactivetechio/kubegres:1.18",
+      "ferretdb": "ghcr.io/nuvolaris/ferretdb:1.6.0",
+      "rbacproxy": "registry.k8s.io/kubebuilder/kube-rbac-proxy:v0.14.1"
     }
+  }
 }
diff --git a/setup/devcontainer/deployment.yaml 
b/setup/devcontainer/deployment.yaml
new file mode 100644
index 0000000..c231209
--- /dev/null
+++ b/setup/devcontainer/deployment.yaml
@@ -0,0 +1,110 @@
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: ssh-devcontainer
+  namespace: nuvolaris
+  labels:
+    app: ssh-devcontainer
+spec:
+  serviceName: ssh-devcontainer
+  replicas: 1
+  selector:
+    matchLabels:
+      app: ssh-devcontainer
+  template:
+    metadata:
+      labels:
+        app: ssh-devcontainer
+    spec:
+      hostname: ssh-devcontainer
+      volumes:
+      - name: workspace
+        hostPath:
+          path: /workspace
+      - name: nginx-config
+        configMap:
+          name: nginx-proxy-config
+      containers:
+      - name: devcontainer
+        image: $IMAGE
+        ports:
+        - containerPort: 2222
+          name: ssh
+          protocol: TCP
+        securityContext:
+          runAsUser: $USERID
+          runAsGroup: $USERID
+        volumeMounts:
+        - name: workspace
+          mountPath: /home/workspace
+        env:
+        - name: OPS_USER
+          value: $OPS_USER
+        - name: OPS_PASSWORD
+          value: $OPS_PASSWORD
+        - name: OPS_APIHOST
+          value: $OPS_APIHOST
+        - name: DEBIAN_FRONTEND
+          value: noninteractive
+        - name: SSHKEY
+          valueFrom:
+            secretKeyRef:
+              name: ssh-secret
+              key: authorized_keys
+      - name: reverse-proxy
+        image: nginx:alpine
+        ports:
+        - containerPort: 80
+          name: http
+          protocol: TCP
+        command: ["nginx", "-g", "daemon off;"]
+        volumeMounts:
+        - name: nginx-config
+          mountPath: /etc/nginx/nginx.conf
+          subPath: nginx.conf
+          readOnly: true
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: nginx-proxy-config
+  namespace: nuvolaris
+data:
+  nginx.conf: |
+    events {
+        worker_connections 1024;
+    }
+    http {
+        client_max_body_size 1g;
+
+        server {
+            listen 80;
+            server_name miniops.me *.miniops.me;
+
+            location / {
+                proxy_pass 
http://ingress-nginx-controller.ingress-nginx.svc.cluster.local;
+                proxy_set_header Host $$host;
+                proxy_set_header X-Real-IP $$remote_addr;
+                proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
+                proxy_set_header X-Forwarded-Proto http;
+            }
+        }
+    }
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: ssh-devcontainer
+  namespace: nuvolaris
+  labels:
+    app: ssh-devcontainer
+spec:
+  type: NodePort
+  selector:
+    app: ssh-devcontainer
+  ports:
+  - port: 2222
+    targetPort: 2222
+    nodePort: 30222
+    protocol: TCP
+    name: ssh
diff --git a/setup/devcontainer/opsfile.yml b/setup/devcontainer/opsfile.yml
new file mode 100644
index 0000000..0c862ea
--- /dev/null
+++ b/setup/devcontainer/opsfile.yml
@@ -0,0 +1,167 @@
+version: "3"
+
+vars:
+  UID:
+    sh: 'echo {{ if eq OS "windows" }}1000{{ else }}$(id -u){{ end }}'
+  GID:
+    sh: 'echo {{ if eq OS "windows" }}1000{{ else }}$(id -g){{ end }}'
+  SSHDIR:
+    sh: echo ~/.ssh | replace -s \\ -r / --stdin
+  SSHKEY:
+     sh: echo {{.SSHDIR}}/id_miniops
+  DRY: ""
+  EXTRA: ""
+
+
+env:
+  KUBECONFIG:
+    sh: |-
+      if test -e "$OPS_TMP/kubeconfig"
+      then echo "$OPS_TMP/kubeconfig"
+      else echo ~/.kube/config
+      fi
+
+tasks:
+
+  vars:
+
+  gen-key:
+    silent: true
+    desc: generating an internal ssh key
+    cmds:
+    - |
+      if ! test -e "{{.SSHKEY}}"
+      then mkdir -p "{{.SSHDIR}}"
+        echo Generating key {{.SSHKEY}}
+        ssh-keygen -q -a 100 -t ed25519 -a 100 -N '' -f "{{.SSHKEY}}" -C 
"miniops key"
+      else
+        echo Using {{.SSHKEY}}
+      fi
+    - |
+      touch "{{.SSHDIR}}/config"
+      if ! rg "Host miniops" ~/.ssh/config >/dev/null
+      then  echo Adding miniops entry in ssh config
+        echo -e "\nHost miniops\n  Hostname localhost\n  Port 2222\n  User 
devel\n  StrictHostKeyChecking no\n  UserKnownHostsFile=/dev/null\n  
IdentityFile ~/.ssh/id_miniops\n" >> ~/.ssh/config
+      else
+        echo Found miniops entry in ssh config
+      fi
+    - |
+      if rg "miniops key"  "{{.SSHDIR}}/authorized_keys" 2>/dev/null >/dev/null
+      then
+        echo Access already added
+      else
+        cat "{{.SSHKEY}}.pub" >>"{{.SSHDIR}}/authorized_keys"
+        echo Added key for external Access
+        {{if ne OS "windows"}}
+        chmod 0700 "{{.SSHDIR}}"
+        chmod 0600 "{{.SSHDIR}}/authorized_keys"
+        {{end}}
+      fi
+
+  deploy:
+    silent: true
+    desc: deploy the devcontainer in kubernetes
+    env:
+      OPS_APIHOST: http://miniops.me
+      OPS_USER: devel
+      OPS_PASSWORD:
+        sh: cat ~/.ops/devel.password
+    cmds:
+      - ops util apihost | rg miniops.me || die "devcontainer requires 
miniops.me"
+      - task: gen-key
+      - >
+          kubectl -n nuvolaris create secret generic ssh-secret
+          --from-literal=authorized_keys="$(cat {{.SSHKEY}}.pub)" 2>/dev/null 
|| die "devcontainer already exists"
+      - |
+        export IMAGE="{{.IMAGES_DEVCONTAINER}}"
+        envsubst < deployment.yaml >_deployment.yaml
+        kubectl apply -f _deployment.yaml
+      - ops setup kubernetes wait-pod SELECTOR="-l app=ssh-devcontainer" 
COND=false FILE=_devcontainer
+      - >
+        retry -t 100 -m 600 ssh miniops exit 2>&1
+        | awk '{s=""; for(i=1;i<=NR;i++) s=s"#"; printf "\rwaiting for ssh: 
[%s]", s; fflush()}'
+      - echo -e "\nyou can now connect to the devcontainer with 'ssh miniops'"
+
+  undeploy:
+    silent: true
+    desc: undeploy the devcontainer in kubernetes
+    cmds:
+      - kubectl -n nuvolaris delete sts/ssh-devcontainer secret/ssh-secret
+      - echo Please remove the Host miniops entry from your ~/.ssh/config file 
if present
+
+  kind-load:
+    silent: true
+    desc: load the devcontainer image from docker to kind to avoid pulling 
from outside
+    cmds:
+    - kind load docker-image {{.IMAGES_DEVCONTAINER}} --name nuvolaris
+
+  docker-run:
+    desc: run the ssh-devcontainer in docker with W=<workspace absolute path>
+    silent: true
+    requires: { vars: [W]}
+    vars:
+      EXTRA: #"--entrypoint=/bin/bash -ti"
+    cmds:
+      - test -e "$OPS_PWD/workspace/package.json" || die "mising workdpace 
folder with starter"
+      - test -e ~/.ssh/id_rsa.pub || die "please generate an ssh key with 
'ssk-keygen -t rsa'"
+      - echo "{{.W}}" | rg '^/' || die "W=<absolute path> required"
+      - docker rm -f ssh-devcontainer 2>/dev/null
+      - >
+        {{.DRY}} docker run
+        --hostname ssh-devcontainer
+        --name ssh-devcontainer --rm
+        -e SSHKEY="$(cat "{{.SSHKEY}}")"
+        -e USERID={{.UID}}
+        --mount "type=bind,src={{.W}},dst=/home/workspace"
+        -p 2223:2222
+        {{.EXTRA}}
+        {{.IMAGES_DEVCONTAINER}}
+
+  connect:
+    silent: true
+    desc: specify U=<user> and H=<host> to connect a remote devcontainer
+    requires:
+      vars: [H,U]
+    cmds:
+    - echo Connecting to {{.U}}@{{.H}}
+    - |
+      if ! test -e "{{.SSHKEY}}.pub"
+      then scp "{{.U}}@{{.H}}:.ssh/id_miniops" "{{.SSHKEY}}" && ssh-keygen -f 
"{{.SSHKEY}}" -y >"{{.SSHKEY}}.pub"
+      fi
+      if test -e "{{.SSHKEY}}.pub"
+      then echo Found "{{.SSHKEY}}"
+      else echo "Remote user has not a miniops configured" ; exit 1
+      fi
+    - |
+      if ! rg '^Host miniops$' "{{.SSHDIR}}/config" >/dev/null
+      then cat <<EOF >>"{{.SSHDIR}}/config"
+
+      Host miniops
+        ProxyJump remote-miniops
+        HostName localhost
+        Port 2222
+        User devel
+        IdentityFile ~/.ssh/id_miniops
+        StrictHostKeyChecking no
+        UserKnownHostsFile /dev/null
+      EOF
+      else
+        echo Found ssh config miniops
+      fi
+    - |
+      if ! rg '^Host remote-miniops$' "{{.SSHDIR}}/config" >/dev/null
+      then cat <<EOF >>"{{.SSHDIR}}/config"
+
+      Host remote-miniops
+        Hostname {{.H}}
+        User {{.U}}
+        IdentityFile ~/.ssh/id_miniops
+      EOF
+          echo Added ssh config remote-miniops
+      else
+          echo Found ssh config remote-miniops
+      fi
+
+    - echo "You can now reach devcontainer with ssh miniops"
+
+
diff --git a/setup/docker/kind.yaml b/setup/docker/kind.yaml
index 696eaa6..ae7c085 100644
--- a/setup/docker/kind.yaml
+++ b/setup/docker/kind.yaml
@@ -31,6 +31,14 @@ nodes:
     nodeRegistration:
       kubeletExtraArgs:
         node-labels: "ingress-ready=true,nuvolaris.io/kube=kind"
+  - |
+    kind: ClusterConfiguration
+    controlPlaneEndpoint: "nuvolaris-control-plane:6443"
+    apiServer:
+      certSANs:
+      - "nuvolaris-control-plane"
+      - "localhost"
+      - "127.0.0.1"
   extraPortMappings:
   - containerPort: 80
     hostPort: 80
@@ -62,5 +70,5 @@ nodes:
     containerPath: /zookeeper/log
   - hostPath: "$DATADIR/kafka"
     containerPath: /kafka
-  - hostPath: "$OPS_HOME/workspace"
+  - hostPath: "$WORKSPACE"
     containerPath: /workspace
diff --git a/setup/docker/opsfile.yml b/setup/docker/opsfile.yml
index e43b194..595220f 100644
--- a/setup/docker/opsfile.yml
+++ b/setup/docker/opsfile.yml
@@ -19,12 +19,14 @@ version: '3'
 vars:
   CLUSTER: nuvolaris
   INGRESS: 
"https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml";
+  HOMEDIR:
+    sh: echo ~ | replace --stdin -s \\ -r /
 
 env:
   DATADIR:
-    sh: echo "$OPS_TMP/kind"
+    sh: echo "$OPS_TMP/kind" | replace --stdin -s \\ -r /
   WORKSPACE:
-    sh: echo "$OPS_HOME/workspace"
+    sh: echo "{{.HOMEDIR}}/.ops-workspace"
   KUBECONFIG:
     sh: |-
         if test -e "$OPS_TMP/kubeconfig"
@@ -62,7 +64,7 @@ tasks:
   cluster:
     silent: true
     cmds:
-    - mkdir -p "$DATADIR" "$OPS_HOME/workspace"
+    - mkdir -p "$DATADIR" "$WORKSPACE"
     - envsubst -i kind.yaml -o _kind.yaml
     - >
       kind create cluster
@@ -79,9 +81,19 @@ tasks:
       EOF'
       docker exec nuvolaris-control-plane systemctl restart containerd
       kind export kubeconfig -n nuvolaris --kubeconfig "$OPS_TMP/kubeconfig"
-      echo "waiting for kind ready..."
-      retry -t 100 -m 600 test -e $OPS_TMP/kubeconfig
-      retry kubectl --kubeconfig $OPS_TMP/kubeconfig cluster-info
+    - task: wait-kube
+
+  wait-kube:
+    silent: true
+    desc: wait kubeconfig
+    cmds:
+    - |
+      while ! test -e $OPS_TMP/kubeconfig
+      do echo waiting  kubeconfig
+         sleep 1
+      done
+    - retry kubectl --kubeconfig $OPS_TMP/kubeconfig cluster-info
+
 
   ingress:
     silent: true
@@ -117,6 +129,7 @@ tasks:
         then kind export kubeconfig --name {{.CLUSTER}} --kubeconfig 
"$OPS_TMP/kubeconfig"
         else
            ops util freeze docker-load
+           ops util freeze kind-preload
            ops setup docker cluster
            ops util freeze kind-load
            ops setup docker ingress
diff --git a/setup/kubernetes/DEBUG.txt b/setup/kubernetes/DEBUG.txt
new file mode 100644
index 0000000..c49b2ce
--- /dev/null
+++ b/setup/kubernetes/DEBUG.txt
@@ -0,0 +1,25 @@
+# check pod status
+ops debug kube pod
+
+# delete a kuberenetes cluster
+ops setup kubernetes delete
+
+
+# create the entire cluster in the default kubernetes
+# kubeconfig shold be in ~/.ops/tmp/kubeconfig or in ~/.kube/config
+ops setup kubernetes create
+
+# watch what is happening in another terminal
+ops debug watch
+
+# step by step operator launch with standby
+ops setup kubernetes permission
+ops setup kubernetes pre-deploy
+ops setup kubernetes operator COMMAND="tail -f /dev/null"
+
+ops debug kube pod
+
+# enter
+ops util kubeconfig
+kubectl exec -ti -n nuvolaris nuvolaris-operator-0 -- bash
+
diff --git a/setup/kubernetes/operator.yaml b/setup/kubernetes/operator.yaml
index 121296b..74526e3 100644
--- a/setup/kubernetes/operator.yaml
+++ b/setup/kubernetes/operator.yaml
@@ -78,8 +78,11 @@ spec:
       containers:
         - name: nuvolaris-operator
           image: ${IMAGES_OPERATOR}
+          command:
+          - bash
+          - -c
+          - ${COMMAND}
           imagePullPolicy: IfNotPresent
-          command: ["./run.sh"]
           args: ["--verbose"]
           securityContext:
              capabilities:
diff --git a/setup/kubernetes/opsfile.yml b/setup/kubernetes/opsfile.yml
index 733eb8c..a09d817 100644
--- a/setup/kubernetes/opsfile.yml
+++ b/setup/kubernetes/opsfile.yml
@@ -21,6 +21,7 @@ vars:
   RETRY: 100
   TIMEOUT: 10s
   CONTEXT: ""
+  COMMAND: "./run.sh"
 
 env:
   KUBECONFIG:
@@ -90,9 +91,6 @@ env:
 
 tasks:
 
-  streamer:
-    desc: deploy streamer
-
   status:
     desc: show nuvolaris cluster status
     silent: true
@@ -114,14 +112,13 @@ tasks:
         kubectl version
 
   crd:
-    #desc get crd
+    desc: get crd
     silent: true
     cmds:
       - kubectl get wsk/controller -n nuvolaris -o yaml
 
-
   wait:
-    #desc: wait for an object to reach a condition
+    desc: wait for an object to reach a condition
     silent: true
     status:
       - test "{{.COND}}" != "true"
@@ -156,7 +153,7 @@ tasks:
         $RES
 
   wait-pod:
-    #desc: wait for a pod to be available - leave the result in FILE
+    desc: wait for a pod to be available - leave the result in FILE
     silent: true
     status:
       - test "{{.COND}}" != "true"
@@ -221,7 +218,7 @@ tasks:
           fi
 
   prepare:
-    #desc: prepare the environment
+    desc: prepare the environment
     ignore_error: true
     silent: true
     cmds:
@@ -237,8 +234,9 @@ tasks:
     cmds:
       - echo "export OPERATOR_VOLUME_STORAGE_CLASS={{.OP_VOL_STORAGE_CLASS}}"
 
+
   operator:
-    #desc: deploy operator
+    desc: deploy operator (use  COMMAND=your-start-command to change default 
./run.sh)
     silent: true
     status:
       - config SKIP_OPERATOR_LAUNCH
@@ -246,6 +244,7 @@ tasks:
       - |
         eval $(task storageclass-env)
         echo "Operator storage class is $OPERATOR_VOLUME_STORAGE_CLASS"
+        export COMMAND="{{.COMMAND}}"
         envsubst -i operator-pvc.yaml -o _operator-pvc.yaml
         envsubst -i operator.yaml -o _operator.yaml
       - "kubectl apply -f _operator-pvc.yaml -f _operator.yaml"
@@ -274,7 +273,7 @@ tasks:
 
   wait-openwhisk:
     silent: true
-    #desc: wait for openwhisk start
+    desc: wait for openwhisk start
     status:
       - config SKIP_OPERATOR_LAUNCH
     cmds:
@@ -291,7 +290,7 @@ tasks:
 
   wait-services:
     silent: true
-    #desc: wait for active services
+    desc: wait for active services
     status:
       - config SKIP_OPERATOR_LAUNCH
     cmds:
@@ -370,18 +369,30 @@ tasks:
     - task: create
     - config -r SKIP_OPERATOR_LAUNCH
 
-  deploy:
+
+  pre-deploy:
     silent: true
-    desc: deploy in namespace (use namespace admin)
+    desc: prepare deploy
     cmds:
       - task: context
       - task: secrets
       - task: runtimes
-      - task: operator
-      - task: instance
+
+  post-deploy:
+    desc: wait results
+    cmds:
       - task: wait-openwhisk
       - task: wait-services
 
+  deploy:
+    silent: true
+    desc: deploy in namespace (use namespace admin)
+    cmds:
+      - task: pre-deploy
+      - task: operator
+      - task: instance
+      - task: post-deploy
+
   delete:
     silent: true
     ignore_error: true
diff --git a/setup/opsfile.yml b/setup/opsfile.yml
index f4bd7f2..df0bab0 100644
--- a/setup/opsfile.yml
+++ b/setup/opsfile.yml
@@ -124,9 +124,9 @@ tasks:
       - ops config slim
       - ops config apihost '{{.DOMAIN}}' --protocol={{.PROTO}}
       - ops setup devcluster
+      - ops setup nuvolaris add-user
       - ops setup nuvolaris streamer deploy
       - ops setup nuvolaris system-api deploy
-      - ops setup nuvolaris add-user
 
   devcluster:
     vars:
diff --git a/util/docopts.md b/util/docopts.md
index 1ab1629..86aec9f 100644
--- a/util/docopts.md
+++ b/util/docopts.md
@@ -44,6 +44,7 @@ Usage:
   util ingress-type
   util edit [<plugin>]
   util link-plugin <plugin>
+  util stdtext <text>
 ```
 
 ## Commands
@@ -69,14 +70,16 @@ Usage:
 -  ingress-type            return the ingress type
 -  edit                    edit (with vscode) the current tasks or a plugin
 -  link-plugin             link the <plugin> in current directory to the 
global list
+-  stdtext                 standardize the text to the text convetions of the 
underlying platform (windows/unix)
 ```
 
 ## Options
 
 ```
-  --showhelp              Show configuration tool help.
+  --showhelp               Show configuration tool help.
   --override               Override the current configuration.
   --verbose                Provide more details.
   --clean                  Remove all files from the web bucket before upload.
   --batchsize=<batchsize>  Number of concurrent web uploads
+  --dry                    Dry Run
 ```
\ No newline at end of file
diff --git a/util/freeze/findimages.js b/util/freeze/findimages.js
new file mode 100644
index 0000000..4d4ecbd
--- /dev/null
+++ b/util/freeze/findimages.js
@@ -0,0 +1,50 @@
+/*
+write a simple bun script with no deps that will list images to be preloaded
+assume IMAGE_DIR are available in process.env
+
+read all the component images from the section config.images
+in $OPS_ROOT/opsroot.json skip controller and invoker
+
+search the runtime images looking in $OPS_ROOT/runtimes.json
+pick only  entries with default true, skipping those with tag nightly or latest
+
+assemble image from the image sction using docker.io/<prefix>/<name>:tag
+
+for each image found:
+- if the file $IMAGE_DIR/<base64 of image> exists, skip the preloading
+- print the image to be preloaded
+
+*/
+const opsRoot = process.env.OPS_ROOT
+const imageDir = process.env.IMAGE_DIR
+
+const images = []
+
+// Component images from opsroot.json, skip controller and invoker
+const skipKeys = new Set(["controller", "invoker"])
+const opsroot = await Bun.file(`${opsRoot}/opsroot.json`).json()
+for (const [key, img] of Object.entries(opsroot.config.images)) {
+  if (skipKeys.has(key)) continue
+  images.push(img)
+}
+
+// Runtime images from runtimes.json, only defaults, skip nightly/latest tags
+const skipTags = new Set(["latest", "nightly"])
+const runtimes = await Bun.file(`${opsRoot}/runtimes.json`).json()
+for (const family of Object.values(runtimes.runtimes)) {
+  for (const runtime of family) {
+    if (!runtime.default || !runtime.image) continue
+    const { prefix, name, tag } = runtime.image
+    if (!tag || skipTags.has(tag)) continue
+    images.push(`docker.io/${prefix}/${name}:${tag}`)
+  }
+}
+
+// Print only images that need preloading
+for (const img of images) {
+  const marker = `${imageDir}/${btoa(img)}`
+  const found = await Bun.file(marker).exists()
+  if (!found) {
+    console.log(img)
+  }
+}
diff --git a/util/freeze/opsfile.yml b/util/freeze/opsfile.yml
index 5ebb6b4..541dd43 100644
--- a/util/freeze/opsfile.yml
+++ b/util/freeze/opsfile.yml
@@ -4,7 +4,7 @@ vars:
   CLUSTER: nuvolaris
   KIND_CLUSTER: '{{.CLUSTER}}-control-plane'
   BASE:
-    sh: echo ~/.ops
+    sh: echo ~/.ops | replace -s \\ -r / --stdin
   IMAGES:
      sh: >
         echo {{.BASE}}/{{OS}}-{{ARCH}}/images
@@ -44,15 +44,15 @@ tasks:
         file={{.IMAGES}}/docker/$(base64 -e "$img")
         if test -e "$file"
         then echo "already saved $img.{{ARCH}} "
-        else echo ">>> Saving: $img"
-             if docker pull --platform linux/{{ARCH}} "$img"
-             then echo "OK: save $file"
-             else echo "*** FAIL: pull $img"
-             fi
-             if docker save "$img" -o "$file"
-             then echo "OK: save $file"
-             else echo "*** FAIL: save $file"
-             fi
+        else  echo ">>> Saving: $img"
+              if docker pull --platform linux/{{ARCH}} "$img"
+              then echo "OK: save $file"
+              else echo "*** FAIL: pull $img"
+              fi
+              if docker save "$img" -o "$file"
+              then echo "OK: save $file"
+              else echo "*** FAIL: save $file"
+              fi
         fi
       done
 
@@ -67,6 +67,20 @@ tasks:
       docker exec -it "$CLU" crictl images 2>/dev/null
       | awk 'NR > 1  && 
!/^(registry.k8s.io\/(kube-|coredns|etc|pause|ingress-nginx)|docker.io\/kindest\/)/
 {print  $1 ":" $2 }'
       >> _kind.lst
+    - task: _kind-get-images
+
+  kind-preload:
+    desc: preload docker images from config
+    silent: true
+    env:
+      IMAGE_DIR: "{{.IMAGES}}/kind"
+    cmds:
+    - bun findimages.js >_kind.lst
+    - task: _kind-get-images
+
+  _kind-get-images:
+    silent: true
+    cmds:
     - mkdir -p {{.IMAGES}}/kind
     - |
       cat _kind.lst | while read img
@@ -85,6 +99,14 @@ tasks:
         fi
       done
 
+  kind-preload-one:
+    silent: true
+    desc: preload one specified image
+    cmds:
+    - test -n "{{.CLI_ARGS}}" || die "specify the image to preload"
+    - echo "{{.CLI_ARGS}}" >_kind.lst
+    - task: _kind-get-images
+
   image-save:
     desc: save images
     cmds:
diff --git a/util/opsfile.yml b/util/opsfile.yml
index 3d7e00e..3738ffa 100644
--- a/util/opsfile.yml
+++ b/util/opsfile.yml
@@ -264,6 +264,7 @@ tasks:
         fi
         code "$DIR"
 
+
   link-plugin:
     desc: link a plugin
     silent: true
@@ -282,3 +283,9 @@ tasks:
   freeze:
     desc: freeze util
 
+  stdtext:
+    desc: standardize text to the convetion of the platfom
+    silent: true
+    cmds:
+      - bun stdtext.js {{OS}} "{{._text_}}"
+
diff --git a/util/stdtext.js b/util/stdtext.js
new file mode 100644
index 0000000..700a0ab
--- /dev/null
+++ b/util/stdtext.js
@@ -0,0 +1,23 @@
+/*
+accept two args: "os" and "file"
+
+read the file, accepting either lf or crlf terminators
+
+and rewrite it with the platform's convention
+
+if the first arg is "windows" use crlf, otherwise use lf
+*/
+const fs = require("fs");
+
+const os = process.argv[2];
+const file = process.argv[3];
+
+if (!os || !file) {
+  console.error("Usage: stdtext.js <os> <file>");
+  process.exit(1);
+}
+
+const content = fs.readFileSync(file, "utf8");
+const lines = content.split(/\r?\n/);
+const eol = os === "windows" ? "\r\n" : "\n";
+fs.writeFileSync(file, lines.join(eol));
\ No newline at end of file

Reply via email to