Repository: skupperproject/skupper
Pull request #1844 (2024-12-13 12:42:43)

Change waiting message when  status condition is false
With a timeout of 30 seconds by default, sometimes the waiting status by default (ready) is reached but the condition is not true at the moment. After checking the status, the site is ready without any type of error, so with this PR the wait status message will change for one that is less alarming to the user and more accurate.


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index b442e31f..280143e2 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -3,6 +3,7 @@ orbs:
     docker: circleci/docker@1.0.1
     kube-orb: circleci/kubernetes@0.11.0
     go: circleci/go@1.7.1
+    helm: circleci/helm@3.1.0
 
 executors:
   go_cimg:
@@ -203,6 +204,22 @@ jobs:
           paths:
             - skupper-manifest
 
+  generate-skupper-setup:
+    executor:
+      name: go_cimg
+    steps:
+      - checkout
+      - go/mod-download-cached
+      - helm/install
+      - run: make generate-skupper-deployment-cluster-scoped
+      - run: make generate-skupper-deployment-namespace-scoped
+      - run: mkdir skupper-setup
+      - run: cp ./skupper-setup-*-scope.yaml skupper-setup
+      - persist_to_workspace:
+          root: .
+          paths:
+            - skupper-setup
+
   build-oci-images:
     executor: local_cluster_test_executor
     parameters:
@@ -341,6 +358,7 @@ jobs:
             done
             cd ${BASEDIR}
             cp "${BASEDIR}/skupper-manifest/manifest.json" "${BASEDIR}/archives"
+            cp "${BASEDIR}/skupper-setup/*.yaml" "${BASEDIR}/archives"
             ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -replace -prerelease -draft ${VERSION} "${BASEDIR}/archives"
 
   publish-github-prerelease-artifacts:
diff --git a/.gitignore b/.gitignore
index 88d33a1c..31adc73b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,5 @@ vendor/
 # Generated files
 manifest.json
 oci-archives/
+skupper-setup-cluster-scope.yaml
+skupper-setup-namespace-scope.yaml
diff --git a/Makefile b/Makefile
index 181d68d8..d2ba627e 100644
--- a/Makefile
+++ b/Makefile
@@ -119,6 +119,12 @@ generate-doc: build-doc-generator
 update-helm-crd:
 	./scripts/update-helm-crds.sh
 
+generate-skupper-deployment-cluster-scoped:
+	helm template ./charts/skupper-setup  --include-crds --set scope=cluster > skupper-setup-cluster-scope.yaml
+
+generate-skupper-deployment-namespace-scoped:
+	helm template ./charts/skupper-setup  --include-crds --set scope=namespace > skupper-setup-namespace-scope.yaml
+
 clean:
 	rm -rf skupper controller kube-adaptor \
 		network-observer generate-doc \
diff --git a/deployments/helm/Chart.yaml b/charts/skupper-setup/Chart.yaml
similarity index 66%
rename from deployments/helm/Chart.yaml
rename to charts/skupper-setup/Chart.yaml
index 31e77b1b..767500d3 100644
--- a/deployments/helm/Chart.yaml
+++ b/charts/skupper-setup/Chart.yaml
@@ -1,4 +1,5 @@
 apiVersion: v2
 name: skupper-setup
 description:  Helm chart for setting up Skupper.
-version: 0.1.0
\ No newline at end of file
+version: 0.1.0-devel
+appVersion: v2-latest
\ No newline at end of file
diff --git a/deployments/helm/README.md b/charts/skupper-setup/README.md
similarity index 100%
rename from deployments/helm/README.md
rename to charts/skupper-setup/README.md
diff --git a/deployments/helm/crds/skupper_access_grant_crd.yaml b/charts/skupper-setup/crds/skupper_access_grant_crd.yaml
similarity index 100%
rename from deployments/helm/crds/skupper_access_grant_crd.yaml
rename to charts/skupper-setup/crds/skupper_access_grant_crd.yaml
diff --git a/deployments/helm/crds/skupper_access_token_crd.yaml b/charts/skupper-setup/crds/skupper_access_token_crd.yaml
similarity index 100%
rename from deployments/helm/crds/skupper_access_token_crd.yaml
rename to charts/skupper-setup/crds/skupper_access_token_crd.yaml
diff --git a/deployments/helm/crds/skupper_attached_connector_binding_crd.yaml b/charts/skupper-setup/crds/skupper_attached_connector_binding_crd.yaml
similarity index 100%
rename from deployments/helm/crds/skupper_attached_connector_binding_crd.yaml
rename to charts/skupper-setup/crds/skupper_attached_connector_binding_crd.yaml
diff --git a/deployments/helm/crds/skupper_attached_connector_crd.yaml b/charts/skupper-setup/crds/skupper_attached_connector_crd.yaml
similarity index 100%
rename from deployments/helm/crds/skupper_attached_connector_crd.yaml
rename to charts/skupper-setup/crds/skupper_attached_connector_crd.yaml
diff --git a/deployments/helm/crds/skupper_certificate_crd.yaml b/charts/skupper-setup/crds/skupper_certificate_crd.yaml
similarity index 100%
rename from deployments/helm/crds/skupper_certificate_crd.yaml
rename to charts/skupper-setup/crds/skupper_certificate_crd.yaml
diff --git a/deployments/helm/crds/skupper_connector_crd.yaml b/charts/skupper-setup/crds/skupper_connector_crd.yaml
similarity index 100%
rename from deployments/helm/crds/skupper_connector_crd.yaml
rename to charts/skupper-setup/crds/skupper_connector_crd.yaml
diff --git a/deployments/helm/crds/skupper_link_crd.yaml b/charts/skupper-setup/crds/skupper_link_crd.yaml
similarity index 100%
rename from deployments/helm/crds/skupper_link_crd.yaml
rename to charts/skupper-setup/crds/skupper_link_crd.yaml
diff --git a/deployments/helm/crds/skupper_listener_crd.yaml b/charts/skupper-setup/crds/skupper_listener_crd.yaml
similarity index 100%
rename from deployments/helm/crds/skupper_listener_crd.yaml
rename to charts/skupper-setup/crds/skupper_listener_crd.yaml
diff --git a/deployments/helm/crds/skupper_router_access_crd.yaml b/charts/skupper-setup/crds/skupper_router_access_crd.yaml
similarity index 100%
rename from deployments/helm/crds/skupper_router_access_crd.yaml
rename to charts/skupper-setup/crds/skupper_router_access_crd.yaml
diff --git a/deployments/helm/crds/skupper_secured_access_crd.yaml b/charts/skupper-setup/crds/skupper_secured_access_crd.yaml
similarity index 100%
rename from deployments/helm/crds/skupper_secured_access_crd.yaml
rename to charts/skupper-setup/crds/skupper_secured_access_crd.yaml
diff --git a/deployments/helm/crds/skupper_site_crd.yaml b/charts/skupper-setup/crds/skupper_site_crd.yaml
similarity index 100%
rename from deployments/helm/crds/skupper_site_crd.yaml
rename to charts/skupper-setup/crds/skupper_site_crd.yaml
diff --git a/deployments/helm/templates/deploy_controller.yaml b/charts/skupper-setup/templates/deploy_controller.yaml
similarity index 100%
rename from deployments/helm/templates/deploy_controller.yaml
rename to charts/skupper-setup/templates/deploy_controller.yaml
diff --git a/deployments/helm/values.yaml b/charts/skupper-setup/values.yaml
similarity index 100%
rename from deployments/helm/values.yaml
rename to charts/skupper-setup/values.yaml
diff --git a/cmd/controller/deploy_cluster_scope.yaml b/cmd/controller/deploy_cluster_scope.yaml
index aef4ab13..e69de29b 100644
--- a/cmd/controller/deploy_cluster_scope.yaml
+++ b/cmd/controller/deploy_cluster_scope.yaml
@@ -1,234 +0,0 @@
----
-apiVersion: v1
-kind: Namespace
-metadata:
-  name: skupper
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: skupper-controller
-  namespace: skupper
-  labels:
-    application: skupper-controller
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
-  labels:
-    application: skupper-controller
-  name: skupper-controller
-rules:
-- apiGroups:
-  - ""
-  resources:
-  - nodes
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - ""
-  resources:
-  - configmaps
-  - pods
-  - pods/exec
-  - services
-  - secrets
-  - serviceaccounts
-  - events
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - update
-  - delete
-  - patch
-- apiGroups:
-  - apps
-  resources:
-  - deployments
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - update
-  - delete
-  - patch
-- apiGroups:
-  - route.openshift.io
-  resources:
-  - routes
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-- apiGroups:
-    - apps.openshift.io
-  resources:
-    - deploymentconfigs
-  verbs:
-    - get
-    - list
-    - watch
-- apiGroups:
-  - networking.k8s.io
-  resources:
-  - ingresses
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-- apiGroups:
-  - projectcontour.io
-  resources:
-  - httpproxies
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-- apiGroups:
-  - gateway.networking.k8s.io
-  resources:
-  - gateways
-  - tlsroutes
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-  - patch
-- apiGroups:
-  - coordination.k8s.io
-  resources:
-  - leases
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-- apiGroups:
-  - rbac.authorization.k8s.io
-  resources:
-  - rolebindings
-  - roles
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-- apiGroups:
-  - skupper.io
-  resources:
-  - sites
-  - sites/status
-  - links
-  - links/status
-  - accesstokens
-  - accesstokens/status
-  - accessgrants
-  - accessgrants/status
-  - listeners
-  - listeners/status
-  - connectors
-  - connectors/status
-  - attachedconnectors
-  - attachedconnectors/status
-  - attachedconnectorbindings
-  - attachedconnectorbindings/status
-  - routeraccesses
-  - routeraccesses/status
-  - securedaccesses
-  - securedaccesses/status
-  - certificates
-  - certificates/status
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - update
-  - delete
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
-  labels:
-    application: skupper-controller
-  name: skupper-controller
-subjects:
-- kind: ServiceAccount
-  name: skupper-controller
-  namespace: skupper
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: skupper-controller
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: skupper-controller
-  namespace: skupper
-spec:
-  replicas: 1
-  selector:
-    matchLabels:
-      application: skupper-controller
-  template:
-    metadata:
-      labels:
-        app.kubernetes.io/part-of: skupper
-        application: skupper-controller
-    spec:
-      serviceAccountName: skupper-controller
-      # Prevent kubernetes from injecting env vars for grant service
-      # as these then collide with those that actually configure the
-      # controller:
-      enableServiceLinks: false
-      # Please ensure that you can use SeccompProfile and do not use
-      # if your project must work on old Kubernetes
-      # versions < 1.19 or on vendors versions which
-      # do NOT support this field by default
-      securityContext:
-        runAsNonRoot: true
-        seccompProfile:
-          type: RuntimeDefault
-      containers:
-      - name: controller
-        image: quay.io/skupper/controller:v2-latest
-        imagePullPolicy: Always
-        command: ["/app/controller"]
-        args: ["-enable-grants", "-grant-server-autoconfigure"]
-        env:
-        - name: SKUPPER_ADAPTOR_IMAGE
-          value: quay.io/skupper/kube-adaptor:v2-latest
-        securityContext:
-          capabilities:
-            drop:
-            - ALL
-          runAsNonRoot: true
-          allowPrivilegeEscalation: false
-        volumeMounts:
-        - name: tls-credentials
-          mountPath: /etc/controller
-      volumes:
-      - name: tls-credentials
-        emptyDir: {}
diff --git a/cmd/controller/deploy_namespace_scope.yaml b/cmd/controller/deploy_namespace_scope.yaml
index f8d238cc..e69de29b 100644
--- a/cmd/controller/deploy_namespace_scope.yaml
+++ b/cmd/controller/deploy_namespace_scope.yaml
@@ -1,226 +0,0 @@
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: skupper-controller
-  labels:
-    application: skupper-controller
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
-  labels:
-    application: skupper-controller
-  name: skupper-controller
-rules:
-- apiGroups:
-  - ""
-  resources:
-  - nodes
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - ""
-  resources:
-  - configmaps
-  - pods
-  - pods/exec
-  - services
-  - secrets
-  - serviceaccounts
-  - events
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - update
-  - delete
-  - patch
-- apiGroups:
-  - apps
-  resources:
-  - deployments
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - update
-  - delete
-  - patch
-- apiGroups:
-  - route.openshift.io
-  resources:
-  - routes
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-- apiGroups:
-    - apps.openshift.io
-  resources:
-    - deploymentconfigs
-  verbs:
-    - get
-    - list
-    - watch
-- apiGroups:
-  - networking.k8s.io
-  resources:
-  - ingresses
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-- apiGroups:
-  - projectcontour.io
-  resources:
-  - httpproxies
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-- apiGroups:
-  - gateway.networking.k8s.io
-  resources:
-  - gateways
-  - tlsroutes
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-  - patch
-- apiGroups:
-  - coordination.k8s.io
-  resources:
-  - leases
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-- apiGroups:
-  - rbac.authorization.k8s.io
-  resources:
-  - rolebindings
-  - roles
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - delete
-  - update
-- apiGroups:
-  - skupper.io
-  resources:
-  - sites
-  - sites/status
-  - links
-  - links/status
-  - accesstokens
-  - accesstokens/status
-  - accessgrants
-  - accessgrants/status
-  - listeners
-  - listeners/status
-  - connectors
-  - connectors/status
-  - attachedconnectors
-  - attachedconnectors/status
-  - attachedconnectorbindings
-  - attachedconnectorbindings/status
-  - routeraccesses
-  - routeraccesses/status
-  - securedaccesses
-  - securedaccesses/status
-  - certificates
-  - certificates/status
-  verbs:
-  - get
-  - list
-  - watch
-  - create
-  - update
-  - delete
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
-  labels:
-    application: skupper-controller
-  name: skupper-controller
-subjects:
-- kind: ServiceAccount
-  name: skupper-controller
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: Role
-  name: skupper-controller
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: skupper-controller
-spec:
-  replicas: 1
-  selector:
-    matchLabels:
-      application: skupper-controller
-  template:
-    metadata:
-      labels:
-        app.kubernetes.io/part-of: skupper
-        application: skupper-controller
-    spec:
-      serviceAccountName: skupper-controller
-      # Prevent kubernetes from injecting env vars for grant service
-      # as these then collide with those that actually configure the
-      # controller:
-      enableServiceLinks: false
-      securityContext:
-        runAsNonRoot: true
-        seccompProfile:
-          type: RuntimeDefault
-      containers:
-      - name: controller
-        image: quay.io/skupper/controller:v2-latest
-        imagePullPolicy: Always
-        command: ["/app/controller"]
-        args: ["-enable-grants", "-grant-server-autoconfigure"]
-        env:
-        - name: SKUPPER_ADAPTOR_IMAGE
-          value: quay.io/skupper/kube-adaptor:v2-latest
-        - name: WATCH_NAMESPACE
-          valueFrom:
-             fieldRef:
-               fieldPath: metadata.namespace
-        securityContext:
-          capabilities:
-            drop:
-            - ALL
-          runAsNonRoot: true
-          allowPrivilegeEscalation: false
-        volumeMounts:
-        - name: tls-credentials
-          mountPath: /etc/controller
-      volumes:
-      - name: tls-credentials
-        emptyDir: {}
diff --git a/cmd/network-observer/internal/api/types_gen.go b/cmd/network-observer/internal/api/types_gen.go
index 0a890a81..2c0197bb 100644
--- a/cmd/network-observer/internal/api/types_gen.go
+++ b/cmd/network-observer/internal/api/types_gen.go
@@ -114,6 +114,8 @@ type ApplicationFlowRecord struct {
 	// Identity The unique identifier for the record.
 	Identity          string `json:"identity"`
 	Method            string `json:"method"`
+	Octets            uint64 `json:"octets"`
+	OctetsReverse     uint64 `json:"octetsReverse"`
 	Protocol          string `json:"protocol"`
 	RoutingKey        string `json:"routingKey"`
 	SourceProcessId   string `json:"sourceProcessId"`
diff --git a/cmd/network-observer/internal/server/views/flows.go b/cmd/network-observer/internal/server/views/flows.go
index f8ce4fef..1098b60f 100644
--- a/cmd/network-observer/internal/server/views/flows.go
+++ b/cmd/network-observer/internal/server/views/flows.go
@@ -26,6 +26,7 @@ func NewConnectionsSliceProvider(stor store.Interface) func([]store.Entry) []api
 		return results
 	}
 }
+
 func NewConnectionsProvider(stor store.Interface) func(collector.ConnectionRecord) (api.ConnectionRecord, bool) {
 	traceProvider := newTraceProvider(stor)
 	return func(conn collector.ConnectionRecord) (api.ConnectionRecord, bool) {
@@ -199,6 +200,8 @@ func NewRequestProvider(stor store.Interface) func(collector.RequestRecord) (api
 		out.StartTime, out.EndTime = vanflowTimes(record.BaseRecord)
 		setOpt(&out.Method, record.Method)
 		setOpt(&out.Status, record.Result)
+		setOpt(&out.Octets, record.Octets)
+		setOpt(&out.OctetsReverse, record.OctetsReverse)
 
 		if record.EndTime != nil && record.StartTime != nil && record.EndTime.After(record.StartTime.Time) {
 			if record.EndTime != nil && record.StartTime != nil {
diff --git a/cmd/network-observer/spec/openapi.yaml b/cmd/network-observer/spec/openapi.yaml
index 4f657497..dfb35d1b 100644
--- a/cmd/network-observer/spec/openapi.yaml
+++ b/cmd/network-observer/spec/openapi.yaml
@@ -1378,6 +1378,8 @@ components:
             - status
             - traceRouters
             - traceSites
+            - octets
+            - octetsReverse
           properties:
             connectionId:
               type: string
@@ -1412,6 +1414,12 @@ components:
             status:
               type: string
               example: 200
+            octets:
+              type: integer
+              format: uint64
+            octetsReverse:
+              type: integer
+              format: uint64
             traceRouters:
               type: array
               description: Ordered array of the names of routers involved in proxying the connection
diff --git a/cmd/skupper/README.md b/cmd/skupper/README.md
index 9fdcf93c..1392cdd2 100644
--- a/cmd/skupper/README.md
+++ b/cmd/skupper/README.md
@@ -5,26 +5,8 @@ kubectl create namespace skupper
 kubectl config set-context --current --namespace skupper
 ```
 
-Apply the CRDs in the cluster:
+Apply the CRDs in the cluster and deploy the skupper controller ([instructions](../../charts/skupper-setup/README.md)):
 
-```
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/api/types/crds/skupper_access_grant_crd.yaml
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/api/types/crds/skupper_access_token_crd.yaml
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/api/types/crds/skupper_attached_connector_anchor_crd.yaml
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/api/types/crds/skupper_attached_connector_crd.yaml
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/api/types/crds/skupper_certificate_crd.yaml
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/api/types/crds/skupper_connector_crd.yaml
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/api/types/crds/skupper_link_crd.yaml
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/api/types/crds/skupper_listener_crd.yaml
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/api/types/crds/skupper_router_access_crd.yaml
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/api/types/crds/skupper_secured_access_crd.yaml
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/api/types/crds/skupper_site_crd.yaml
-```
-
-Deploy the Skupper controller in the cluster:
-```
-kubectl apply -f https://raw.githubusercontent.com/skupperproject/skupper/v2/cmd/controller/deploy_cluster_scope.yaml
-```
 
 # Deploy application in two namespaces (or contexts)
 
diff --git a/internal/cmd/skupper/common/flags.go b/internal/cmd/skupper/common/flags.go
index a36e89e1..383ed2b4 100644
--- a/internal/cmd/skupper/common/flags.go
+++ b/internal/cmd/skupper/common/flags.go
@@ -82,6 +82,10 @@ for other Kubernetes flavors, loadbalancer is the default.`
 	FlagNameWait       = "wait"
 	FlagDescWait       = "Wait for the given status before exiting. Choices: configured, ready, none"
 	FlagDescDeleteWait = "Wait for deletion to complete before exiting"
+
+	FlagNameAll       = "all"
+	FlagDescAll       = "delete all skupper resources in current namespace"
+	FlagDescDeleteAll = "delete all skupper resources associated with site in current namespace"
 )
 
 type CommandSiteCreateFlags struct {
@@ -109,6 +113,7 @@ type CommandSiteUpdateFlags struct {
 }
 
 type CommandSiteDeleteFlags struct {
+	All     bool
 	Timeout time.Duration
 	Wait    bool
 }
diff --git a/internal/cmd/skupper/connector/kube/connector_create.go b/internal/cmd/skupper/connector/kube/connector_create.go
index c2d3c5e7..72827154 100644
--- a/internal/cmd/skupper/connector/kube/connector_create.go
+++ b/internal/cmd/skupper/connector/kube/connector_create.go
@@ -326,9 +326,9 @@ func (cmd *CmdConnectorCreate) WaitUntil() error {
 	})
 
 	if err != nil && connectorCondition == nil {
-		return fmt.Errorf("Connector %q is not %s yet, check the status for more information\n", cmd.name, cmd.status)
+		return fmt.Errorf("Connector %q is not yet %s, check the status for more information\n", cmd.name, cmd.status)
 	} else if err != nil && connectorCondition.Status == metav1.ConditionFalse {
-		return fmt.Errorf("Connector %q is %s with errors, check the status for more information\n", cmd.name, cmd.status)
+		return fmt.Errorf("Connector %q is not yet %s: %s\n", cmd.name, cmd.status, connectorCondition.Message)
 	}
 
 	fmt.Printf("Connector %q is %s.\n", cmd.name, cmd.status)
diff --git a/internal/cmd/skupper/connector/kube/connector_update.go b/internal/cmd/skupper/connector/kube/connector_update.go
index b15a2360..14d14f60 100644
--- a/internal/cmd/skupper/connector/kube/connector_update.go
+++ b/internal/cmd/skupper/connector/kube/connector_update.go
@@ -330,9 +330,9 @@ func (cmd *CmdConnectorUpdate) WaitUntil() error {
 	})
 
 	if err != nil && connectorCondition == nil {
-		return fmt.Errorf("Connector %q is not %s yet, check the status for more information\n", cmd.name, cmd.status)
+		return fmt.Errorf("Connector %q is not yet %s, check the status for more information\n", cmd.name, cmd.status)
 	} else if err != nil && connectorCondition.Status == metav1.ConditionFalse {
-		return fmt.Errorf("Connector %q is %s with errors, check the status for more information\n", cmd.name, cmd.status)
+		return fmt.Errorf("Connector %q is not yet %s: %s\n", cmd.name, cmd.status, connectorCondition.Message)
 	}
 
 	fmt.Printf("Connector %q is %s.\n", cmd.name, cmd.status)
diff --git a/internal/cmd/skupper/link/kube/link_update.go b/internal/cmd/skupper/link/kube/link_update.go
index 2ba3d753..5da082f6 100644
--- a/internal/cmd/skupper/link/kube/link_update.go
+++ b/internal/cmd/skupper/link/kube/link_update.go
@@ -216,9 +216,9 @@ func (cmd *CmdLinkUpdate) WaitUntil() error {
 	})
 
 	if err != nil && linkCondition == nil {
-		return fmt.Errorf("Link %q is not %s yet, check the status for more information\n", cmd.linkName, cmd.status)
+		return fmt.Errorf("Link %q is not yet %s, check the status for more information\n", cmd.linkName, cmd.status)
 	} else if err != nil && linkCondition.Status == metav1.ConditionFalse {
-		return fmt.Errorf("Link %q is %s with errors, check the status for more information\n", cmd.linkName, cmd.status)
+		return fmt.Errorf("Link %q is not yet %s: %s\n", cmd.linkName, cmd.status, linkCondition.Message)
 	}
 
 	fmt.Printf("Link %q is updated\n", cmd.linkName)
diff --git a/internal/cmd/skupper/listener/kube/listener_create.go b/internal/cmd/skupper/listener/kube/listener_create.go
index 6574f923..c847be93 100644
--- a/internal/cmd/skupper/listener/kube/listener_create.go
+++ b/internal/cmd/skupper/listener/kube/listener_create.go
@@ -239,9 +239,9 @@ func (cmd *CmdListenerCreate) WaitUntil() error {
 	})
 
 	if err != nil && listenerCondition == nil {
-		return fmt.Errorf("Listener %q is not %s yet, check the status for more information\n", cmd.name, cmd.status)
+		return fmt.Errorf("Listener %q is not yet %s, check the status for more information\n", cmd.name, cmd.status)
 	} else if err != nil && listenerCondition.Status == metav1.ConditionFalse {
-		return fmt.Errorf("Listener %q is %s with errors, check the status for more information\n", cmd.name, cmd.status)
+		return fmt.Errorf("Listener %q is not yet %s: %s\n", cmd.name, cmd.status, listenerCondition.Message)
 	}
 
 	fmt.Printf("Listener %q is %s.\n", cmd.name, cmd.status)
diff --git a/internal/cmd/skupper/listener/kube/listener_update.go b/internal/cmd/skupper/listener/kube/listener_update.go
index ca829296..d6672644 100644
--- a/internal/cmd/skupper/listener/kube/listener_update.go
+++ b/internal/cmd/skupper/listener/kube/listener_update.go
@@ -232,9 +232,9 @@ func (cmd *CmdListenerUpdate) WaitUntil() error {
 	})
 
 	if err != nil && listenerCondition == nil {
-		return fmt.Errorf("Listener %q is not %s yet, check the status for more information\n", cmd.name, cmd.status)
+		return fmt.Errorf("Listener %q is not yet %s, check the status for more information\n", cmd.name, cmd.status)
 	} else if err != nil && listenerCondition.Status == metav1.ConditionFalse {
-		return fmt.Errorf("Listener %q is %s with errors, check the status for more information\n", cmd.name, cmd.status)
+		return fmt.Errorf("Listener %q is not yet %s: %s\n", cmd.name, cmd.status, listenerCondition.Message)
 	}
 
 	fmt.Printf("Listener %q is updated\n", cmd.name)
diff --git a/internal/cmd/skupper/site/kube/site_create.go b/internal/cmd/skupper/site/kube/site_create.go
index 6e8f4571..8d8cc047 100644
--- a/internal/cmd/skupper/site/kube/site_create.go
+++ b/internal/cmd/skupper/site/kube/site_create.go
@@ -225,9 +225,9 @@ func (cmd *CmdSiteCreate) WaitUntil() error {
 	})
 
 	if err != nil && siteCondition == nil {
-		return fmt.Errorf("Site %q is not %s yet, check the status for more information\n", cmd.siteName, cmd.status)
+		return fmt.Errorf("Site %q is not yet %s, check the status for more information\n", cmd.siteName, cmd.status)
 	} else if err != nil && siteCondition.Status == metav1.ConditionFalse {
-		return fmt.Errorf("Site %q is %s with errors, check the status for more information\n", cmd.siteName, cmd.status)
+		return fmt.Errorf("Site %q is not yet %s: %s\n", cmd.siteName, cmd.status, siteCondition.Message)
 	}
 
 	fmt.Printf("Site %q is %s.\n", cmd.siteName, cmd.status)
diff --git a/internal/cmd/skupper/site/kube/site_delete.go b/internal/cmd/skupper/site/kube/site_delete.go
index 1779161d..6d731770 100644
--- a/internal/cmd/skupper/site/kube/site_delete.go
+++ b/internal/cmd/skupper/site/kube/site_delete.go
@@ -3,10 +3,11 @@ package kube
 import (
 	"context"
 	"fmt"
+	"time"
+
 	"github.com/skupperproject/skupper/internal/cmd/skupper/common"
 	"github.com/skupperproject/skupper/internal/cmd/skupper/common/utils"
 	"github.com/skupperproject/skupper/pkg/utils/validator"
-	"time"
 
 	"github.com/skupperproject/skupper/internal/kube/client"
 	skupperv2alpha1 "github.com/skupperproject/skupper/pkg/generated/client/clientset/versioned/typed/skupper/v2alpha1"
@@ -22,6 +23,7 @@ type CmdSiteDelete struct {
 	siteName  string
 	timeout   time.Duration
 	wait      bool
+	all       bool
 }
 
 func NewCmdSiteDelete() *CmdSiteDelete {
@@ -87,11 +89,120 @@ func (cmd *CmdSiteDelete) ValidateInput(args []string) []error {
 func (cmd *CmdSiteDelete) InputToOptions() {
 	cmd.timeout = cmd.Flags.Timeout
 	cmd.wait = cmd.Flags.Wait
+	cmd.all = cmd.Flags.All
 }
 
 func (cmd *CmdSiteDelete) Run() error {
+
 	err := cmd.Client.Sites(cmd.Namespace).Delete(context.TODO(), cmd.siteName, metav1.DeleteOptions{})
-	return err
+	if err != nil {
+		return err
+	}
+
+	// if delete all, also remove all the other resources
+	if cmd.all {
+		connectors, err := cmd.Client.Connectors(cmd.Namespace).List(context.TODO(), metav1.ListOptions{})
+		if err == nil && connectors != nil && len(connectors.Items) != 0 {
+			for _, connector := range connectors.Items {
+				err = cmd.Client.Connectors(cmd.Namespace).Delete(context.TODO(), connector.Name, metav1.DeleteOptions{})
+				if err != nil {
+					return err
+				}
+			}
+		}
+
+		listeners, err := cmd.Client.Listeners(cmd.Namespace).List(context.TODO(), metav1.ListOptions{})
+		if err == nil && listeners != nil && len(listeners.Items) != 0 {
+			for _, listener := range listeners.Items {
+				err = cmd.Client.Listeners(cmd.Namespace).Delete(context.TODO(), listener.Name, metav1.DeleteOptions{})
+				if err != nil {
+					return err
+				}
+			}
+		}
+
+		links, err := cmd.Client.Links(cmd.Namespace).List(context.TODO(), metav1.ListOptions{})
+		if err == nil && links != nil && len(links.Items) != 0 {
+			for _, link := range links.Items {
+				err = cmd.Client.Links(cmd.Namespace).Delete(context.TODO(), link.Name, metav1.DeleteOptions{})
+				if err != nil {
+					return err
+				}
+			}
+		}
+
+		accessTokens, err := cmd.Client.AccessTokens(cmd.Namespace).List(context.TODO(), metav1.ListOptions{})
+		if err == nil && accessTokens != nil && len(accessTokens.Items) != 0 {
+			for _, accessToken := range accessTokens.Items {
+				err = cmd.Client.AccessTokens(cmd.Namespace).Delete(context.TODO(), accessToken.Name, metav1.DeleteOptions{})
+				if err != nil {
+					return err
+				}
+			}
+		}
+
+		accessGrants, err := cmd.Client.AccessGrants(cmd.Namespace).List(context.TODO(), metav1.ListOptions{})
+		if err == nil && accessGrants != nil && len(accessGrants.Items) != 0 {
+			for _, accessGrant := range accessGrants.Items {
+				err = cmd.Client.AccessGrants(cmd.Namespace).Delete(context.TODO(), accessGrant.Name, metav1.DeleteOptions{})
+				if err != nil {
+					return err
+				}
+			}
+		}
+
+		routerAccesses, err := cmd.Client.RouterAccesses(cmd.Namespace).List(context.TODO(), metav1.ListOptions{})
+		if err == nil && routerAccesses != nil && len(routerAccesses.Items) != 0 {
+			for _, routerAccess := range routerAccesses.Items {
+				err = cmd.Client.RouterAccesses(cmd.Namespace).Delete(context.TODO(), routerAccess.Name, metav1.DeleteOptions{})
+				if err != nil {
+					return err
+				}
+			}
+		}
+
+		securedAccesses, err := cmd.Client.SecuredAccesses(cmd.Namespace).List(context.TODO(), metav1.ListOptions{})
+		if err == nil && securedAccesses != nil && len(securedAccesses.Items) != 0 {
+			for _, securedAccess := range securedAccesses.Items {
+				err = cmd.Client.SecuredAccesses(cmd.Namespace).Delete(context.TODO(), securedAccess.Name, metav1.DeleteOptions{})
+				if err != nil {
+					return err
+				}
+			}
+		}
+
+		certificates, err := cmd.Client.Certificates(cmd.Namespace).List(context.TODO(), metav1.ListOptions{})
+		if err == nil && certificates != nil && len(certificates.Items) != 0 {
+			for _, certificate := range certificates.Items {
+				err = cmd.Client.Certificates(cmd.Namespace).Delete(context.TODO(), certificate.Name, metav1.DeleteOptions{})
+				if err != nil {
+					return err
+				}
+			}
+		}
+
+		attachedConnectors, err := cmd.Client.AttachedConnectors(cmd.Namespace).List(context.TODO(), metav1.ListOptions{})
+		if err == nil && attachedConnectors != nil && len(attachedConnectors.Items) != 0 {
+			for _, attachedConnector := range attachedConnectors.Items {
+				err = cmd.Client.AttachedConnectors(cmd.Namespace).Delete(context.TODO(), attachedConnector.Name, metav1.DeleteOptions{})
+				if err != nil {
+					return err
+				}
+			}
+		}
+
+		attachedConnectorBindings, err := cmd.Client.AttachedConnectorBindings(cmd.Namespace).List(context.TODO(), metav1.ListOptions{})
+		if err == nil && attachedConnectorBindings != nil && len(attachedConnectorBindings.Items) != 0 {
+			for _, attachedConnectorBinding := range attachedConnectorBindings.Items {
+				err = cmd.Client.AttachedConnectorBindings(cmd.Namespace).Delete(context.TODO(), attachedConnectorBinding.Name, metav1.DeleteOptions{})
+				if err != nil {
+					return err
+				}
+			}
+		}
+	}
+
+	return nil
 }
 func (cmd *CmdSiteDelete) WaitUntil() error {
 
diff --git a/internal/cmd/skupper/site/kube/site_update.go b/internal/cmd/skupper/site/kube/site_update.go
index c5a22a2e..ab0a4bd3 100644
--- a/internal/cmd/skupper/site/kube/site_update.go
+++ b/internal/cmd/skupper/site/kube/site_update.go
@@ -244,9 +244,9 @@ func (cmd *CmdSiteUpdate) WaitUntil() error {
 	})
 
 	if err != nil && siteCondition == nil {
-		return fmt.Errorf("Site %q is not %s yet, check the status for more information\n", cmd.siteName, cmd.status)
+		return fmt.Errorf("Site %q is not yet %s, check the status for more information\n", cmd.siteName, cmd.status)
 	} else if err != nil && siteCondition.Status == metav1.ConditionFalse {
-		return fmt.Errorf("Site %q is %s with errors, check the status for more information\n", cmd.siteName, cmd.status)
+		return fmt.Errorf("Site %q is not yet %s: %s\n", cmd.siteName, cmd.status, siteCondition.Message)
 	}
 
 	fmt.Printf("Site %q is updated\n", cmd.siteName)
diff --git a/internal/cmd/skupper/site/site.go b/internal/cmd/skupper/site/site.go
index 8b5c2549..5c565219 100644
--- a/internal/cmd/skupper/site/site.go
+++ b/internal/cmd/skupper/site/site.go
@@ -148,6 +148,7 @@ skupper site delete --wait=false`,
 	cmd := common.ConfigureCobraCommand(configuredPlatform, cmdSiteDeleteDesc, kubeCommand, nonKubeCommand)
 	cmdFlags := common.CommandSiteDeleteFlags{}
 
+	cmd.Flags().BoolVar(&cmdFlags.All, common.FlagNameAll, false, common.FlagDescDeleteAll)
 	cmd.Flags().DurationVar(&cmdFlags.Timeout, common.FlagNameTimeout, 60*time.Second, common.FlagDescTimeout)
 	cmd.Flags().BoolVar(&cmdFlags.Wait, common.FlagNameWait, true, common.FlagDescDeleteWait)
 
diff --git a/pkg/vanflow/records.go b/pkg/vanflow/records.go
index 3fc56696..e0f33188 100644
--- a/pkg/vanflow/records.go
+++ b/pkg/vanflow/records.go
@@ -292,11 +292,13 @@ func (r TransportBiflowRecord) GetTypeMeta() TypeMeta {
 
 type AppBiflowRecord struct {
 	BaseRecord
-	Parent   *string `vflow:"2"`
-	Protocol *string `vflow:"16"`
-	Latency  *uint64 `vflow:"24"`
-	Method   *string `vflow:"27"`
-	Result   *string `vflow:"28"`
+	Parent        *string `vflow:"2"`
+	Protocol      *string `vflow:"16"`
+	Latency       *uint64 `vflow:"24"`
+	Method        *string `vflow:"27"`
+	Result        *string `vflow:"28"`
+	Octets        *uint64 `vflow:"23"`
+	OctetsReverse *uint64 `vflow:"58"`
 }
 
 func (r AppBiflowRecord) GetTypeMeta() TypeMeta {


Test patch:
diff --git a/internal/cmd/skupper/listener/kube/listener_update_test.go b/internal/cmd/skupper/listener/kube/listener_update_test.go
index 2fe680be..998a31a3 100644
--- a/internal/cmd/skupper/listener/kube/listener_update_test.go
+++ b/internal/cmd/skupper/listener/kube/listener_update_test.go
@@ -460,13 +460,13 @@ func TestCmdListenerUpdate_WaitUntil(t *testing.T) {
 				},
 			},
 			expectError:  true,
-			errorMessage: "Listener \"my-listener\" is not ready yet, check the status for more information\n",
+			errorMessage: "Listener \"my-listener\" is not yet ready, check the status for more information\n",
 		},
 		{
 			name:         "listener is not returned",
 			status:       "ready",
 			expectError:  true,
-			errorMessage: "Listener \"my-listener\" is not ready yet, check the status for more information\n",
+			errorMessage: "Listener \"my-listener\" is not yet ready, check the status for more information\n",
 		},
 		{
 			name:   "listener is ready",
@@ -588,7 +588,7 @@ func TestCmdListenerUpdate_WaitUntil(t *testing.T) {
 				},
 			},
 			expectError:  true,
-			errorMessage: "Listener \"my-listener\" is configured with errors, check the status for more information\n",
+			errorMessage: "Listener \"my-listener\" is not yet configured: Error\n",
 		},
 	}
 
diff --git a/internal/cmd/skupper/site/kube/site_delete_test.go b/internal/cmd/skupper/site/kube/site_delete_test.go
index 6006e550..6b87e055 100644
--- a/internal/cmd/skupper/site/kube/site_delete_test.go
+++ b/internal/cmd/skupper/site/kube/site_delete_test.go
@@ -1,11 +1,12 @@
 package kube
 
 import (
-	"github.com/skupperproject/skupper/internal/cmd/skupper/common"
-	"github.com/skupperproject/skupper/internal/cmd/skupper/common/utils"
 	"testing"
 	"time"
 
+	"github.com/skupperproject/skupper/internal/cmd/skupper/common"
+	"github.com/skupperproject/skupper/internal/cmd/skupper/common/utils"
+
 	fakeclient "github.com/skupperproject/skupper/internal/kube/client/fake"
 
 	"github.com/skupperproject/skupper/pkg/apis/skupper/v2alpha1"
@@ -251,6 +252,7 @@ func TestCmdSiteDelete_InputToOptions(t *testing.T) {
 		flags           *common.CommandSiteDeleteFlags
 		expectedTimeout time.Duration
 		expectedWait    bool
+		expectedAll     bool
 	}
 
 	testTable := []test{
@@ -264,6 +266,11 @@ func TestCmdSiteDelete_InputToOptions(t *testing.T) {
 			flags:        &common.CommandSiteDeleteFlags{Wait: true},
 			expectedWait: true,
 		},
+		{
+			name:        "all site resources",
+			flags:       &common.CommandSiteDeleteFlags{All: true},
+			expectedAll: true,
+		},
 	}
 
 	for _, test := range testTable {
@@ -276,6 +283,7 @@ func TestCmdSiteDelete_InputToOptions(t *testing.T) {
 
 			assert.Check(t, command.timeout == test.expectedTimeout)
 			assert.Check(t, command.wait == test.expectedWait)
+			assert.Check(t, command.all == test.expectedAll)
 		})
 	}
 }
@@ -288,6 +296,7 @@ func TestCmdSiteDelete_Run(t *testing.T) {
 		skupperError   string
 		siteName       string
 		errorMessage   string
+		all            bool
 	}
 
 	testTable := []test{
@@ -327,6 +336,101 @@ func TestCmdSiteDelete_Run(t *testing.T) {
 			siteName:       "my-site",
 			errorMessage:   "sites.skupper.io \"my-site\" not found",
 		},
+		{
+			name:       "deletes all",
+			all:        true,
+			k8sObjects: nil,
+			skupperObjects: []runtime.Object{
+				&v2alpha1.Site{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-site",
+						Namespace: "test",
+					},
+					Status: v2alpha1.SiteStatus{
+						Status: v2alpha1.Status{
+							Message: "OK",
+							Conditions: []v1.Condition{
+								{
+									Message:            "OK",
+									ObservedGeneration: 1,
+									Reason:             "OK",
+									Status:             "True",
+									Type:               "Configured",
+								},
+							},
+						},
+					},
+				},
+				&v2alpha1.AccessGrant{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-token",
+						Namespace: "test",
+					},
+				},
+				&v2alpha1.AccessToken{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-token",
+						Namespace: "test",
+					},
+				},
+				&v2alpha1.Connector{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-connector",
+						Namespace: "test",
+					},
+				},
+				&v2alpha1.Listener{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-listener",
+						Namespace: "test",
+					},
+				},
+				&v2alpha1.Site{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "the-site",
+						Namespace: "test",
+					},
+				},
+				&v2alpha1.Certificate{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "link-test",
+						Namespace: "test",
+					},
+				},
+				&v2alpha1.Link{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-link",
+						Namespace: "test",
+					},
+				},
+				&v2alpha1.AttachedConnectorBinding{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-attachedConnectorBinding",
+						Namespace: "test",
+					},
+				},
+				&v2alpha1.AttachedConnector{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-attachedConnector",
+						Namespace: "test",
+					},
+				},
+				&v2alpha1.RouterAccess{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-routerAccess",
+						Namespace: "test",
+					},
+				},
+				&v2alpha1.SecuredAccess{
+					ObjectMeta: v1.ObjectMeta{
+						Name:      "my-securedAccess",
+						Namespace: "test",
+					},
+				},
+			},
+			skupperError: "",
+			siteName:     "my-site",
+		},
 	}
 
 	for _, test := range testTable {
@@ -337,7 +441,7 @@ func TestCmdSiteDelete_Run(t *testing.T) {
 		fakeSkupperClient, err := fakeclient.NewFakeClient(command.Namespace, test.k8sObjects, test.skupperObjects, test.skupperError)
 		assert.Assert(t, err)
 		command.Client = fakeSkupperClient.GetSkupperClient().SkupperV2alpha1()
-
+		command.all = test.all
 		command.siteName = test.siteName
 
 		t.Run(test.name, func(t *testing.T) {
diff --git a/internal/cmd/skupper/site/kube/site_update_test.go b/internal/cmd/skupper/site/kube/site_update_test.go
index a85c6dba..a96da0ad 100644
--- a/internal/cmd/skupper/site/kube/site_update_test.go
+++ b/internal/cmd/skupper/site/kube/site_update_test.go
@@ -574,7 +574,7 @@ func TestCmdSiteUpdate_WaitUntil(t *testing.T) {
 			},
 			siteName:     "my-site",
 			skupperError: "",
-			errorMessage: "Site \"my-site\" is not ready yet, check the status for more information\n",
+			errorMessage: "Site \"my-site\" is not yet ready, check the status for more information\n",
 			expectError:  true,
 		},
 		{
@@ -662,7 +662,7 @@ func TestCmdSiteUpdate_WaitUntil(t *testing.T) {
 			siteName:     "my-site",
 			skupperError: "",
 			expectError:  true,
-			errorMessage: "Site \"my-site\" is configured with errors, check the status for more information\n",
+			errorMessage: "Site \"my-site\" is not yet configured: Error\n",
 		},
 	}
 
diff --git a/internal/cmd/skupper/site/site_test.go b/internal/cmd/skupper/site/site_test.go
index 53339e1a..9cbe32d2 100644
--- a/internal/cmd/skupper/site/site_test.go
+++ b/internal/cmd/skupper/site/site_test.go
@@ -1,12 +1,13 @@
 package site
 
 import (
+	"testing"
+
 	"github.com/skupperproject/skupper/api/types"
 	"github.com/skupperproject/skupper/internal/cmd/skupper/common"
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
 	"gotest.tools/v3/assert"
-	"testing"
 )
 
 func TestCmdSiteFactory(t *testing.T) {
@@ -51,6 +52,7 @@ func TestCmdSiteFactory(t *testing.T) {
 			expectedFlagsWithDefaultValue: map[string]interface{}{
 				common.FlagNameTimeout: "1m0s",
 				common.FlagNameWait:    "true",
+				common.FlagNameAll:     "false",
 			},
 			command: CmdSiteDeleteFactory(types.PlatformKubernetes),
 		},