Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go? Bash! Meet the Shell-operator

flant
August 20, 2020

Go? Bash! Meet the Shell-operator

Andrey Klimentyev and Dmitry Stolyarov from Flant (https://flant.com/) tell why and how our company has simplified the process of creating Kubernetes operators — thanks to shell-operator.

* Article: https://medium.com/flant-com/meet-the-shell-operator-kubecon-36c14ba2f8fe?source=friends_link&sk=a545f75ddb2e4787fd95da61f0bd241c
* Video: https://www.youtube.com/watch?v=we0s4ETUBLc

GitHub for:
* shell-operator: https://github.com/flant/shell-operator
* addon-operator: https://github.com/flant/addon-operator

flant

August 20, 2020
Tweet

More Decks by flant

Other Decks in Programming

Transcript

  1. Go? Bash! Meet the Shell-operator backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod GET

    backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml Simple HTTP API
  2. Go? Bash! Meet the Shell-operator backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod PUT

    backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml GET Simple HTTP API
  3. Go? Bash! Meet the Shell-operator okay backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod

    PUT backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml GET Simple HTTP API
  4. Go? Bash! Meet the Shell-operator NO! backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod

    PUT backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml GET Simple HTTP API
  5. Go? Bash! Meet the Shell-operator backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH

    backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml GET PUT Simple HTTP API
  6. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  7. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  8. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  9. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  10. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  11. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  12. Go? Bash! Meet the Shell-operator backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod GET

    PUT WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml Simple HTTP API
  13. Go? Bash! Meet the Shell-operator backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod backend.yaml

    frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml External world type #1 type #2
  14. Go? Bash! Meet the Shell-operator Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml

    backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod ReplicaSet Controller
  15. Go? Bash! Meet the Shell-operator ReplicaSet Controller Deployment Controller User

    Scheduler backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod
  16. Go? Bash! Meet the Shell-operator ReplicaSet Controller Deployment Controller User

    Scheduler node-x node-y backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod
  17. Go? Bash! Meet the Shell-operator ReplicaSet Controller Scheduler node-x node-y

    Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod Kubelet Kubelet
  18. Go? Bash! Meet the Shell-operator ReplicaSet Controller Scheduler node-x node-y

    Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod Kubelet Kubelet
  19. Go? Bash! Meet the Shell-operator ReplicaSet Controller Scheduler node-x node-y

    Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod Kubelet Kubelet Docker Docker
  20. Go? Bash! Meet the Shell-operator ReplicaSet Controller Scheduler node-x node-y

    Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod Kubelet Kubelet Docker Docker
  21. Go? Bash! Meet the Shell-operator ReplicaSet Controller Scheduler node-x node-y

    Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod Kubelet Kubelet Docker Docker
  22. Go? Bash! Meet the Shell-operator Kubelet Kubelet Docker Docker Scheduler

    node-x node-y Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod ReplicaSet Controller
  23. Go? Bash! Meet the Shell-operator Kubelet Kubelet Docker Docker Scheduler

    node-x node-y Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod ReplicaSet Controller
  24. Go? Bash! Meet the Shell-operator User Kubelet Kubelet Docker Docker

    ReplicaSet Controller Scheduler node-x node-y Deployment Controller backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod
  25. Go? Bash! Meet the Shell-operator User Kubelet Kubelet Docker Docker

    ReplicaSet Controller Scheduler node-x node-y Deployment Controller backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod
  26. Go? Bash! Meet the Shell-operator Kubelet Kubelet Docker Docker ReplicaSet

    Controller Scheduler node-x node-y Deployment Controller backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod User
  27. Go? Bash! Meet the Shell-operator default foo qux quux garply

    mysecret secret:yes secret:yes secret:yes kubernetes
  28. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    garply mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  29. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  30. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes secret:yes mysecret secret:yes
  31. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes mysecret secret:yes
  32. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes mysecret secret:yes
  33. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes mysecret
  34. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes mysecret
  35. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  36. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  37. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  38. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  39. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  40. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret secret:yes secret:yes mysecret secret:yes
  41. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  42. Go? Bash! Meet the Shell-operator Configuration Hook is executed with

    --config arg. 1 Hook should output YAML with its configuration. 2 Normal execution Hook is executed with no args. 1 Hook receives binding context. 2 once, on startup many times, on events
  43. Go? Bash! Meet the Shell-operator #!/bin/bash source /shell_lib.sh function __config__()

    { cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF } function __main__() { #THE LOGIC } hook::run "$@" cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF
  44. Go? Bash! Meet the Shell-operator #!/bin/bash source /shell_lib.sh function __config__()

    { cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF } function __main__() { #THE LOGIC } hook::run "$@" #THE LOGIC
  45. Go? Bash! Meet the Shell-operator #!/bin/bash source /shell_lib.sh function __config__()

    { cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF } function __main__() { #THE LOGIC } hook::run "$@"
  46. Go? Bash! Meet the Shell-operator default foo qux quux quuz

    garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes kubernetes
  47. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  48. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  49. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  50. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  51. Go? Bash! Meet the Shell-operator #!/bin/bash source /shell_lib.sh function __config__()

    { cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF } function __main__() { } hook::run "$@" cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF Binding configuration
  52. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 # BINDING CONFIGURATION EOF Binding configuration
  53. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  54. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  55. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  56. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  57. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  58. Go? Bash! Meet the Shell-operator snapshots: src_secret: - object: apiVersion:

    v1 kind: Secret metadata: { … } data: { … } function __config__() { } cat << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding context Binding configuration
  59. Go? Bash! Meet the Shell-operator snapshots: src_secret: - object: apiVersion:

    v1 kind: Secret metadata: { … } data: { … } function __config__() { } cat << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding context Binding configuration
  60. Go? Bash! Meet the Shell-operator snapshots: src_secret: - object: apiVersion:

    v1 kind: Secret metadata: { … } data: { … } function __config__() { } cat << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding context Binding configuration
  61. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  62. Go? Bash! Meet the Shell-operator - name: namespaces group: main

    apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding configuration
  63. Go? Bash! Meet the Shell-operator - name: namespaces group: main

    apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding configuration
  64. Go? Bash! Meet the Shell-operator - name: namespaces group: main

    apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding configuration
  65. Go? Bash! Meet the Shell-operator # kubectl get ns foo

    -o json | jq '{ > "name": .metadata.name, > "hasLabel": ( .metadata.labels // {} | contains({"secret": "yes"}) ) > }' { "name": "kube-system", "hasLabel": true }
  66. Go? Bash! Meet the Shell-operator - name: namespaces group: main

    apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding configuration Binding configuration
  67. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  68. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  69. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  70. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  71. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true object: apiVersion: v1 kind: Namespace metadata: { … } - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  72. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true object: apiVersion: v1 kind: Namespace metadata: { … } - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  73. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true object: apiVersion: v1 kind: Namespace metadata: { … } - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  74. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  75. Go? Bash! Meet the Shell-operator - name: dst_secrets apiVersion: v1

    kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .metadata.annotations.resourceVersion } group: main keepFullObjectsInMemory: false Binding configuration
  76. Go? Bash! Meet the Shell-operator - name: dst_secrets apiVersion: v1

    kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .metadata.annotations.resourceVersion } group: main keepFullObjectsInMemory: false Binding configuration
  77. Go? Bash! Meet the Shell-operator - name: dst_secrets apiVersion: v1

    kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .metadata.annotations.resourceVersion } group: main keepFullObjectsInMemory: false Binding configuration
  78. Go? Bash! Meet the Shell-operator snapshots: dst_secrets: - filterResult: namespace:

    foo resourceVersion: 123456 - name: dst_secrets apiVersion: v1 kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .metadata.annotations.resourceVersion } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  79. Go? Bash! Meet the Shell-operator snapshots: dst_secrets: - filterResult: namespace:

    foo resourceVersion: 123456 - name: dst_secrets apiVersion: v1 kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .metadata.annotations.resourceVersion } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  80. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  81. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  82. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  83. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  84. Go? Bash! Meet the Shell-operator Is in sync with ?

    do nothing yes kubectl create or replace no dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … } namespaces: - filterResult: namespace: foo hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ...
  85. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  86. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  87. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  88. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... Does exist? kubectl delete yes do nothing no dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  89. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.namespaces | length) - 1')"); do ns_name="$(context::jq -r '.snapshots.namespaces['"$i"'].filterResult.name')" if context::jq -e '.snapshots.namespaces['"$i"'].filterResult.hasLabel'; then sync_secret "$ns_name" else delete_secret "$ns_name" fi done }
  90. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.namespaces | length) - 1')"); do ns_name="$(context::jq -r '.snapshots.namespaces['"$i"'].filterResult.name')" if context::jq -e '.snapshots.namespaces['"$i"'].filterResult.hasLabel'; then sync_secret "$ns_name" else delete_secret "$ns_name" fi done }
  91. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.namespaces | length) - 1')"); do ns_name="$(context::jq -r '.snapshots.namespaces['"$i"'].filterResult.name')" if context::jq -e '.snapshots.namespaces['"$i"'].filterResult.hasLabel'; then sync_secret "$ns_name" else delete_secret "$ns_name" fi done }
  92. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.namespaces | length) - 1')"); do ns_name="$(context::jq -r '.snapshots.namespaces['"$i"'].filterResult.name')" if context::jq -e '.snapshots.namespaces['"$i"'].filterResult.hasLabel'; then sync_secret "$ns_name" else delete_secret "$ns_name" fi done }
  93. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi }
  94. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi }
  95. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi }
  96. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  97. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  98. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  99. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  100. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  101. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  102. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  103. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  104. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  105. Go? Bash! Meet the Shell-operator 35 lines in yaml configVersion:

    v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main - name: dst_secrets apiVersion: v1 kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .annotations."resourceVersion" } group: main keepFullObjectsInMemory: false - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { name: .metadata.name, hasLabel: (.metadata.labels // {} | contains({"secret": "yes"})) } group: main keepFullObjectsInMemory: false 20 lines in bash #! + + shell-operator function __main__() { for i in $(seq 0 "$(context::jq -r '(.snapshots.namespaces | length) - 1')"); do ns_name="$(context::jq -r '.snapshots.namespaces['"$i"'].filterResult.name')" if context::jq -e '.snapshots.namespaces['"$i"'].filterResult.hasLabel'; then sync_secret "$ns_name" else delete_secret "$ns_name" fi done } function delete_secret() { if context::jq -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi } kubernetes default foo qux quux quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  106. Go? Bash! Meet the Shell-operator apiVersion: apps/v1 kind: Deployment metadata:

    name: foo spec: template: spec: containers: - name: bar image: registry.example.com/myapp:v1.0.0 env: - name: DB_USER valueFrom: configMapKeyRef: name: foo key: db_user - name: DB_PASSWORD valueFrom: configMapKeyRef: name: foo key: db_password ENV
  107. Go? Bash! Meet the Shell-operator apiVersion: apps/v1 kind: Deployment metadata:

    name: foo spec: template: spec: containers: - name: bar image: registry.example.com/myapp:v1.0.0 volumeMounts: - mountPath: /etc/config name: config volumes: - name: config configMap: name: foo items: - key: config.yaml path: config.yaml Mount
  108. Go? Bash! Meet the Shell-operator apiVersion: apps/v1 kind: Deployment metadata:

    name: foo spec: template: spec: containers: - name: bar image: registry.example.com/myapp:v1.0.0 env: - name: DB_USER valueFrom: configMapKeyRef: name: foo key: db_user - name: DB_PASSWORD valueFrom: configMapKeyRef: name: foo key: db_password
  109. Go? Bash! Meet the Shell-operator apiVersion: apps/v1 kind: Deployment metadata:

    name: foo spec: template: spec: containers: - name: bar image: registry.example.com/myapp:v1.0.0 env: - name: DB_USER valueFrom: configMapKeyRef: name: foo key: db_user - name: DB_PASSWORD valueFrom: configMapKeyRef: name: foo key: db_password
  110. Go? Bash! Meet the Shell-operator apiVersion: apps/v1 kind: Deployment metadata:

    name: foo spec: template: metadata: annotations: config/checksum: b4d6b660fffb798dcaca5b8a spec: containers: - name: bar image: registry.example.com/myapp:v1.0.0 env: - name: DB_USER valueFrom: configMapKeyRef: name: foo key: db_user - name: DB_PASSWORD valueFrom: configMapKeyRef: name: foo key: db_password
  111. Go? Bash! Meet the Shell-operator backend.yaml Deployment backend-689bc4d4d5.yaml ReplicaSet backend-689bc4d4d5-rv4rq.yaml

    Pod backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml a-users.yaml MysqlDatabase a-archive.yaml Custom Resource Definitions
  112. Go? Bash! Meet the Shell-operator kubernetes server foo main bar

    main baz main qux main another #! foo.main bar.main baz.main baz.another qux.main
  113. Go? Bash! Meet the Shell-operator configVersion: v1 kubernetes: - name:

    nodes apiVersion: v1 kind: Node jqFilter: | { name: .metadata.name, ip: ( .status.addresses[] | select(.type == "InternalIP") | .address ) } group: main keepFullObjectsInMemory: false
  114. Go? Bash! Meet the Shell-operator configVersion: v1 kubernetes: - name:

    nodes apiVersion: v1 kind: Node jqFilter: | { name: .metadata.name, ip: ( .status.addresses[] | select(.type == "InternalIP") | .address ) } group: main keepFullObjectsInMemory: false
  115. Go? Bash! Meet the Shell-operator configVersion: v1 kubernetes: - name:

    nodes apiVersion: v1 kind: Node jqFilter: | { name: .metadata.name, ip: ( .status.addresses[] | select(.type == "InternalIP") | .address ) } group: main keepFullObjectsInMemory: false
  116. Go? Bash! Meet the Shell-operator configVersion: v1 kubernetes: - name:

    nodes apiVersion: v1 kind: Node jqFilter: | { name: .metadata.name, ip: ( .status.addresses[] | select(.type == "InternalIP") | .address ) } group: main keepFullObjectsInMemory: false executeHookOnEvent: []
  117. Go? Bash! Meet the Shell-operator configVersion: v1 kubernetes: - name:

    nodes apiVersion: v1 kind: Node jqFilter: | { name: .metadata.name, ip: ( .status.addresses[] | select(.type == "InternalIP") | .address ) } group: main keepFullObjectsInMemory: false executeHookOnEvent: [] schedule: - name: every_minute group: main crontab: "* * * * *"
  118. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  119. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  120. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  121. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  122. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  123. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  124. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  125. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  126. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  127. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  128. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  129. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main queue: "some_name" EOF Binding configuration
  130. Go? Bash! Meet the Shell-operator #! + shell-operator addon-operator =

    #! hooks + events + helm = #! hooks + events
  131. Go? Bash! Meet the Shell-operator Thank you! Like? Try! And

    don’t forget to star on GitHub Dmitry Stolyarov CTO & Co-founder twitter.com/dmistol linkedin.com/in/distol Flant Running your production 24×7×365 medium.com/flant-com youtube.com/c/flant_com flant.com #! + shell-operator github.com/flant/shell-operator addon-operator github.com/flant/addon-operator Andrey Klimentyev Solutions Engineer