flant / shell-operator

Shell-operator is a tool for running event-driven scripts in a Kubernetes cluster
https://flant.github.io/shell-operator/
Apache License 2.0
2.39k stars 214 forks source link

mutating webhook error: cannot get config for hook /hooks/mutating.sh: exec format error #580

Open lbvffvbl opened 7 months ago

lbvffvbl commented 7 months ago

Expected behavior (what you expected to happen): Hi I was try to use mutating webhook with your example

Actual behavior (what actually happened): After run deployment I got error

{"cmd":"/hooks/mutating.sh --config","hook":"mutating.sh","level":"debug","msg":"Executing hook in /hooks","time":"2024-01-16T05:52:32Z"}
{"level":"debug","msg":"Executing command '/hooks/mutating.sh --config' in '/hooks' dir","time":"2024-01-16T05:52:32Z"}
{"hook":"mutating.sh","level":"error","msg":"Hook config output:\n","phase":"config","time":"2024-01-16T05:52:32Z"}
{"level":"error","msg":"MAIN Fatal: initialize hook manager: cannot get config for hook '/hooks/mutating.sh': fork/exec /hooks/mutating.sh: exec format error\n","time":"2024-01-16T05:52:32Z"}
{"level":"error","msg":"Fatal: initialize HookManager fail: cannot get config for hook '/hooks/mutating.sh': fork/exec /hooks/mutating.sh: exec format error","time":"2024-01-16T05:52:32Z"}

But if I run hook -- config in pod by hand i see config:

shell-operator-86c49d495c-7gwnc:/# /hooks/mutating.sh --config
configVersion: v1
kubernetesMutating:
- name: change.crontab.resources
  namespace:
    labelSelector:
      matchLabels:
        # helm adds a 'name' label to a namespace it creates
        name: example-206
  rules:
  - apiGroups:   ["stable.example.com"]
    apiVersions: ["v1"]
    operations:  ["CREATE", "UPDATE"]
    resources:   ["crontabs"]
    scope:       "Namespaced"

Steps to reproduce:

  1. Just use hook from example

Environment:

Anything else we should know?: manifests

apiVersion: v1
kind: ConfigMap
metadata:
  name: zoo-mutation-hooks
data:
  mutating.sh: |

    #!/usr/bin/env bash

    source /shell_lib.sh

    function __config__(){
        cat <<EOF
    configVersion: v1
    kubernetesMutating:
    - name: change.crontab.resources
      namespace:
        labelSelector:
          matchLabels:
            # helm adds a 'name' label to a namespace it creates
            name: example-206
      rules:
      - apiGroups:   ["stable.example.com"]
        apiVersions: ["v1"]
        operations:  ["CREATE", "UPDATE"]
        resources:   ["crontabs"]
        scope:       "Namespaced"
    EOF
    }

    function __main__() {
      context::jq -r '.review.request'
    #  image=$(context::jq -r '.review.request.object.spec.image')
    #  echo "Got image: $image"

    #  if [[ $image == repo.example.com* ]] ; then
      PATCH=$( echo '[{"op": "add", "path": "/spec/replicas", "value": 333 }]' | base64 )
        cat <<EOF > $VALIDATING_RESPONSE_PATH
    {"allowed":true, "patch": "$PATCH"}
    EOF
    #  else
    #    cat <<EOF > $VALIDATING_RESPONSE_PATH
    #{"allowed":false, "message":"Only images from repo.example.com are allowed"}
    #EOF
    #  fi
    }

    hook::run $@

---
# Source: 206-mutating-webhook/templates/rbac.yaml
# Create and update ValidatingWebhookConfiguration
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: zoo-mutation
  labels:
    heritage: zoo-mutation
rules:
- apiGroups: ["admissionregistration.k8s.io"]
  resources: ["mutatingwebhookconfigurations"]
  verbs: ["create", "list", "update"]
---
# Source: 206-mutating-webhook/templates/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: zoo-mutation
  labels:
    heritage: zoo-mutation
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: zoo-mutation
subjects:
  - kind: ServiceAccount
    name: zoo-mutation-acc
    namespace: altinity-cloud-system
---
# Source: 206-mutating-webhook/templates/webhook-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: zoo-mutation-mutating-service
  labels:
    heritage: zoo-mutation
spec:
#  type: LoadBalancer
#  externalTrafficPolicy: Local
  ports:
    - name: webhook
      port: 443
      targetPort: 9680
      protocol: TCP
  selector:
    app: shell-operator-zoo-mutation
---
# Source: 206-mutating-webhook/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: shell-operator
  labels:
    heritage: zoo-mutation
    app: shell-operator-zoo-mutation
spec:
  replicas: 1
  selector:
    matchLabels:
      app: shell-operator-zoo-mutation
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        heritage: zoo-mutation
        app: shell-operator-zoo-mutation
      annotations:
        checksum/hook: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    spec:
      containers:
      - name: shell-operator
        image: "ghcr.io/flant/shell-operator:v1.4.5"
        securityContext:
          allowPrivilegeEscalation: false
          runAsUser: 0
        imagePullPolicy: Always
        env:
        - name: SHELL_OPERATOR_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: LOG_LEVEL
          value: Debug
        - name: VALIDATING_WEBHOOK_SERVICE_NAME
          value: "zoo-mutation-mutating-service"
        - name: VALIDATING_WEBHOOK_CONFIGURATION_NAME
          value: "zoo-mutation"
        livenessProbe:
          httpGet:
            port: 9680
            path: /healthz
            scheme: HTTPS
        volumeMounts:
        - name: validating-certs
          mountPath: /validating-certs/
          readOnly: true
        - name: hooks
          mountPath: /hooks/
          readOnly: false
      serviceAccountName: zoo-mutation-acc
      volumes:
      - name: validating-certs
        secret:
          secretName: zoo-mutation-certs
      - name: hooks
        configMap:
          name: zoo-mutation-hooks
          defaultMode: 0777

Additional information for debugging (if necessary):

Hook script

#!/usr/bin/env bash

source /shell_lib.sh

function __config__(){
    cat < $VALIDATING_RESPONSE_PATH
{"allowed":true, "patch": "$PATCH"}
EOF
}

hook::run $@

Logs
{"level":"info","msg":"shell-operator v1.4.5","time":"2024-01-16T05:52:32Z"}
{"level":"debug","msg":"jqFilter implementation: use embedded libjq-go","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Debug endpoint listen on /var/run/shell-operator/debug.socket","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric counter shell_operator_live_ticks","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric histogram shell_operator_tasks_queue_action_duration_seconds","operator.component":"metricsStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric gauge shell_operator_tasks_queue_length","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric gauge shell_operator_kube_snapshot_objects","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric histogram shell_operator_kube_jq_filter_duration_seconds","operator.component":"metricsStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric histogram shell_operator_kube_event_duration_seconds","operator.component":"metricsStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric counter shell_operator_kubernetes_client_watch_errors_total","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric histogram shell_operator_kubernetes_client_request_latency_seconds","operator.component":"metricsStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric counter shell_operator_kubernetes_client_request_result_total","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Kubernetes client is configured successfully with 'out-of-cluster' config","operator.component":"KubernetesAPIClient","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Kubernetes client is configured successfully with 'out-of-cluster' config","operator.component":"KubernetesAPIClient","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric gauge shell_operator_hook_enable_kubernetes_bindings_seconds","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric counter shell_operator_hook_enable_kubernetes_bindings_errors_total","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric gauge shell_operator_hook_enable_kubernetes_bindings_success","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric histogram shell_operator_hook_run_seconds","operator.component":"metricsStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric histogram shell_operator_hook_run_user_cpu_seconds","operator.component":"metricsStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric histogram shell_operator_hook_run_sys_cpu_seconds","operator.component":"metricsStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric gauge shell_operator_hook_run_max_rss_bytes","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric counter shell_operator_hook_run_errors_total","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric counter shell_operator_hook_run_allowed_errors_total","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric counter shell_operator_hook_run_success_total","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Create metric counter shell_operator_task_wait_in_queue_seconds_total","operator.component":"metricStorage","time":"2024-01-16T05:52:32Z"}
{"level":"info","msg":"Initialize hooks manager. Search for and load all hooks.","time":"2024-01-16T05:52:32Z"}
{"level":"debug","msg":"  Search hooks in this paths: [/hooks/mutating.sh]","time":"2024-01-16T05:52:32Z"}
{"hook":"mutating.sh","level":"info","msg":"Load config from '/hooks/mutating.sh'","phase":"config","time":"2024-01-16T05:52:32Z"}
{"cmd":"/hooks/mutating.sh --config","hook":"mutating.sh","level":"debug","msg":"Executing hook in /hooks","time":"2024-01-16T05:52:32Z"}
{"level":"debug","msg":"Executing command '/hooks/mutating.sh --config' in '/hooks' dir","time":"2024-01-16T05:52:32Z"}
{"hook":"mutating.sh","level":"error","msg":"Hook config output:\n","phase":"config","time":"2024-01-16T05:52:32Z"}
{"level":"error","msg":"MAIN Fatal: initialize hook manager: cannot get config for hook '/hooks/mutating.sh': fork/exec /hooks/mutating.sh: exec format error\n","time":"2024-01-16T05:52:32Z"}
{"level":"error","msg":"Fatal: initialize HookManager fail: cannot get config for hook '/hooks/mutating.sh': fork/exec /hooks/mutating.sh: exec format error","time":"2024-01-16T05:52:32Z"}

lbvffvbl commented 7 months ago

Also link to BINDING_MUTATING.md poined in example is broken and there are no documentation about mutating in doc folder