diff --git a/calico/calico-arm64.tgz b/calico/calico-arm64.tgz deleted file mode 100644 index 02024d5..0000000 Binary files a/calico/calico-arm64.tgz and /dev/null differ diff --git a/calico/calico-upgrade-arm64.tgz b/calico/calico-upgrade-arm64.tgz deleted file mode 100644 index 34f3ccd..0000000 Binary files a/calico/calico-upgrade-arm64.tgz and /dev/null differ diff --git a/calico/calico-upgrade.tgz b/calico/calico-upgrade.tgz deleted file mode 100644 index d647ee0..0000000 Binary files a/calico/calico-upgrade.tgz and /dev/null differ diff --git a/calico/calico.tgz b/calico/calico.tgz deleted file mode 100644 index 031a87e..0000000 Binary files a/calico/calico.tgz and /dev/null differ diff --git a/coredns/venv/__pycache__/oci_image.cpython-38.pyc b/coredns/venv/__pycache__/oci_image.cpython-38.pyc new file mode 100644 index 0000000..031a742 Binary files /dev/null and b/coredns/venv/__pycache__/oci_image.cpython-38.pyc differ diff --git a/coredns/venv/ops/__pycache__/__init__.cpython-38.pyc b/coredns/venv/ops/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..c37336c Binary files /dev/null and b/coredns/venv/ops/__pycache__/__init__.cpython-38.pyc differ diff --git a/coredns/venv/ops/__pycache__/charm.cpython-38.pyc b/coredns/venv/ops/__pycache__/charm.cpython-38.pyc new file mode 100644 index 0000000..0cdaada Binary files /dev/null and b/coredns/venv/ops/__pycache__/charm.cpython-38.pyc differ diff --git a/coredns/venv/ops/__pycache__/framework.cpython-38.pyc b/coredns/venv/ops/__pycache__/framework.cpython-38.pyc new file mode 100644 index 0000000..37a070e Binary files /dev/null and b/coredns/venv/ops/__pycache__/framework.cpython-38.pyc differ diff --git a/coredns/venv/ops/__pycache__/jujuversion.cpython-38.pyc b/coredns/venv/ops/__pycache__/jujuversion.cpython-38.pyc new file mode 100644 index 0000000..be159fd Binary files /dev/null and b/coredns/venv/ops/__pycache__/jujuversion.cpython-38.pyc differ diff --git a/coredns/venv/ops/__pycache__/log.cpython-38.pyc b/coredns/venv/ops/__pycache__/log.cpython-38.pyc new file mode 100644 index 0000000..83de3b9 Binary files /dev/null and b/coredns/venv/ops/__pycache__/log.cpython-38.pyc differ diff --git a/coredns/venv/ops/__pycache__/main.cpython-38.pyc b/coredns/venv/ops/__pycache__/main.cpython-38.pyc new file mode 100644 index 0000000..f4f10a5 Binary files /dev/null and b/coredns/venv/ops/__pycache__/main.cpython-38.pyc differ diff --git a/coredns/venv/ops/__pycache__/model.cpython-38.pyc b/coredns/venv/ops/__pycache__/model.cpython-38.pyc new file mode 100644 index 0000000..db6dc9e Binary files /dev/null and b/coredns/venv/ops/__pycache__/model.cpython-38.pyc differ diff --git a/coredns/venv/ops/__pycache__/storage.cpython-38.pyc b/coredns/venv/ops/__pycache__/storage.cpython-38.pyc new file mode 100644 index 0000000..1bb4a07 Binary files /dev/null and b/coredns/venv/ops/__pycache__/storage.cpython-38.pyc differ diff --git a/coredns/venv/ops/__pycache__/testing.cpython-38.pyc b/coredns/venv/ops/__pycache__/testing.cpython-38.pyc new file mode 100644 index 0000000..2d9cb29 Binary files /dev/null and b/coredns/venv/ops/__pycache__/testing.cpython-38.pyc differ diff --git a/coredns/venv/ops/__pycache__/version.cpython-38.pyc b/coredns/venv/ops/__pycache__/version.cpython-38.pyc new file mode 100644 index 0000000..1be0b7a Binary files /dev/null and b/coredns/venv/ops/__pycache__/version.cpython-38.pyc differ diff --git a/coredns/venv/ops/lib/__pycache__/__init__.cpython-38.pyc b/coredns/venv/ops/lib/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..f06f4b5 Binary files /dev/null and b/coredns/venv/ops/lib/__pycache__/__init__.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/__init__.cpython-38.pyc b/coredns/venv/yaml/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..18da437 Binary files /dev/null and b/coredns/venv/yaml/__pycache__/__init__.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/composer.cpython-38.pyc b/coredns/venv/yaml/__pycache__/composer.cpython-38.pyc new file mode 100644 index 0000000..483755e Binary files /dev/null and b/coredns/venv/yaml/__pycache__/composer.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/constructor.cpython-38.pyc b/coredns/venv/yaml/__pycache__/constructor.cpython-38.pyc new file mode 100644 index 0000000..b0e3021 Binary files /dev/null and b/coredns/venv/yaml/__pycache__/constructor.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/cyaml.cpython-38.pyc b/coredns/venv/yaml/__pycache__/cyaml.cpython-38.pyc new file mode 100644 index 0000000..0e4fdf0 Binary files /dev/null and b/coredns/venv/yaml/__pycache__/cyaml.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/dumper.cpython-38.pyc b/coredns/venv/yaml/__pycache__/dumper.cpython-38.pyc new file mode 100644 index 0000000..0f2c1e6 Binary files /dev/null and b/coredns/venv/yaml/__pycache__/dumper.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/emitter.cpython-38.pyc b/coredns/venv/yaml/__pycache__/emitter.cpython-38.pyc new file mode 100644 index 0000000..fbe86dd Binary files /dev/null and b/coredns/venv/yaml/__pycache__/emitter.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/error.cpython-38.pyc b/coredns/venv/yaml/__pycache__/error.cpython-38.pyc new file mode 100644 index 0000000..481c6cf Binary files /dev/null and b/coredns/venv/yaml/__pycache__/error.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/events.cpython-38.pyc b/coredns/venv/yaml/__pycache__/events.cpython-38.pyc new file mode 100644 index 0000000..ee8ca1b Binary files /dev/null and b/coredns/venv/yaml/__pycache__/events.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/loader.cpython-38.pyc b/coredns/venv/yaml/__pycache__/loader.cpython-38.pyc new file mode 100644 index 0000000..ed7fdcf Binary files /dev/null and b/coredns/venv/yaml/__pycache__/loader.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/nodes.cpython-38.pyc b/coredns/venv/yaml/__pycache__/nodes.cpython-38.pyc new file mode 100644 index 0000000..7766e80 Binary files /dev/null and b/coredns/venv/yaml/__pycache__/nodes.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/parser.cpython-38.pyc b/coredns/venv/yaml/__pycache__/parser.cpython-38.pyc new file mode 100644 index 0000000..7047475 Binary files /dev/null and b/coredns/venv/yaml/__pycache__/parser.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/reader.cpython-38.pyc b/coredns/venv/yaml/__pycache__/reader.cpython-38.pyc new file mode 100644 index 0000000..d1c3b1b Binary files /dev/null and b/coredns/venv/yaml/__pycache__/reader.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/representer.cpython-38.pyc b/coredns/venv/yaml/__pycache__/representer.cpython-38.pyc new file mode 100644 index 0000000..c4544e2 Binary files /dev/null and b/coredns/venv/yaml/__pycache__/representer.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/resolver.cpython-38.pyc b/coredns/venv/yaml/__pycache__/resolver.cpython-38.pyc new file mode 100644 index 0000000..ec45829 Binary files /dev/null and b/coredns/venv/yaml/__pycache__/resolver.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/scanner.cpython-38.pyc b/coredns/venv/yaml/__pycache__/scanner.cpython-38.pyc new file mode 100644 index 0000000..70d13ce Binary files /dev/null and b/coredns/venv/yaml/__pycache__/scanner.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/serializer.cpython-38.pyc b/coredns/venv/yaml/__pycache__/serializer.cpython-38.pyc new file mode 100644 index 0000000..e4ce884 Binary files /dev/null and b/coredns/venv/yaml/__pycache__/serializer.cpython-38.pyc differ diff --git a/coredns/venv/yaml/__pycache__/tokens.cpython-38.pyc b/coredns/venv/yaml/__pycache__/tokens.cpython-38.pyc new file mode 100644 index 0000000..2ad8c48 Binary files /dev/null and b/coredns/venv/yaml/__pycache__/tokens.cpython-38.pyc differ diff --git a/easyrsa/easyrsa.tar.gz b/easyrsa/easyrsa.tar.gz deleted file mode 100644 index 65b2ebb..0000000 Binary files a/easyrsa/easyrsa.tar.gz and /dev/null differ diff --git a/kata/.build.manifest b/kata/.build.manifest new file mode 100644 index 0000000..5589d6b --- /dev/null +++ b/kata/.build.manifest @@ -0,0 +1,531 @@ +{ + "layers": [ + { + "branch": "refs/heads/master\nrefs/heads/stable", + "rev": "fcdcea4e5de3e1556c24e6704607862d0ba00a56", + "url": "layer:options" + }, + { + "branch": "refs/heads/master\nrefs/heads/stable", + "rev": "a3ff62c32c993d80417f6e093e3ef95e42f62083", + "url": "layer:basic" + }, + { + "branch": "refs/heads/master\nrefs/heads/stable", + "rev": "527dd64fc4b9a6b0f8d80a3c2c0b865155050275", + "url": "layer:debug" + }, + { + "branch": "refs/heads/master\nrefs/heads/stable", + "rev": "a7d7b6423db37a47611310039e6ed1929c0a2eab", + "url": "layer:status" + }, + { + "branch": "refs/heads/stable", + "rev": "b2fa345285b14fe339084fd35865973ca05eefbf", + "url": "kata" + }, + { + "branch": "refs/heads/master\nrefs/heads/stable", + "rev": "6f927f10b97f45c566481cf57a29d433f17373e1", + "url": "interface:container-runtime" + }, + { + "branch": "refs/heads/master\nrefs/heads/stable", + "rev": "b59ce0c44bc52c789175750ce18b42f76c9a4578", + "url": "interface:untrusted-container-runtime" + } + ], + "signatures": { + ".build.manifest": [ + "build", + "dynamic", + "unchecked" + ], + ".github/workflows/main.yml": [ + "layer:basic", + "static", + "96a48a981ceb2a96f427a6b5226d2da6d7191981793804055d70a88ca1987473" + ], + ".gitignore": [ + "kata", + "static", + "589384c900fb8e573ae6939a9efa0813087ea526761ba661d96aa2526a494eef" + ], + ".travis.yml": [ + "kata", + "static", + "714ed5453bd5a053676efb64370194a7c130f426ec11acba7d1509d558dc979c" + ], + "CONTRIBUTING.md": [ + "kata", + "static", + "c44755a6800e330bd939b7a27a4bb75adaef3a1ccdc15df62cb5533a3ea6252f" + ], + "LICENSE": [ + "kata", + "static", + "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4" + ], + "Makefile": [ + "layer:basic", + "static", + "b7ab3a34e5faf79b96a8632039a0ad0aa87f2a9b5f0ba604e007cafb22190301" + ], + "README.md": [ + "kata", + "static", + "ac3b4f06b6e4a23f80a12f898645c4d4c2daedf961e72a2d851cf9c4b37d538a" + ], + "actions.yaml": [ + "layer:debug", + "dynamic", + "cea290e28bc78458ea4a56dcad39b9a880c67e4ba53b774ac46bd8778618c7b9" + ], + "actions/debug": [ + "layer:debug", + "static", + "db0a42dae4c5045b2c06385bf22209dfe0e2ded55822ef847d84b01d9ff2b046" + ], + "bin/charm-env": [ + "layer:basic", + "static", + "fb6a20fac4102a6a4b6ffe903fcf666998f9a95a3647e6f9af7a1eeb44e58fd5" + ], + "bin/layer_option": [ + "layer:options", + "static", + "e959bf29da4c5edff28b2602c24113c4df9e25cdc9f2aa3b5d46c8577b2a40cc" + ], + "copyright": [ + "layer:status", + "static", + "7c0e36e618a8544faaaa3f8e0533c2f1f4a18bcacbdd8b99b537742e6b587d58" + ], + "copyright.layer-basic": [ + "layer:basic", + "static", + "f6740d66fd60b60f2533d9fcb53907078d1e20920a0219afce7182e2a1c97629" + ], + "copyright.layer-options": [ + "layer:options", + "static", + "f6740d66fd60b60f2533d9fcb53907078d1e20920a0219afce7182e2a1c97629" + ], + "debug-scripts/charm-unitdata": [ + "layer:debug", + "static", + "c952b9d31f3942e4e722cb3e70f5119707b69b8e76cc44e2e906bc6d9aef49b7" + ], + "debug-scripts/filesystem": [ + "layer:debug", + "static", + "d29cc8687f4422d024001c91b1ac756ee6bf8a2a125bc98db1199ba775eb8fd7" + ], + "debug-scripts/juju-logs": [ + "layer:debug", + "static", + "d260b35753a917368cb8c64c1312546a0a40ef49cba84c75bc6369549807c55e" + ], + "debug-scripts/juju-network-get": [ + "layer:debug", + "static", + "6d849a1f8e6569bd0d5ea38299f7937cb8b36a5f505e3532f6c756eabeb8b6c5" + ], + "debug-scripts/network": [ + "layer:debug", + "static", + "714afae5dcb45554ff1f05285501e3b7fcc656c8de51217e263b93dab25a9d2e" + ], + "debug-scripts/packages": [ + "layer:debug", + "static", + "e8177102dc2ca853cb9272c1257cf2cfd5253d2a074e602d07c8bc4ea8e27c75" + ], + "debug-scripts/sysctl": [ + "layer:debug", + "static", + "990035b320e09cc2228e1f2f880e795d51118b2959339eacddff9cbb74349c6a" + ], + "debug-scripts/systemd": [ + "layer:debug", + "static", + "23ddf533198bf5b1ce723acde31ada806aab8539292b514c721d8ec08af74106" + ], + "docs/status.md": [ + "layer:status", + "static", + "975dec9f8c938196e102e954a80226bda293407c4e5ae857c118bf692154702a" + ], + "hooks/config-changed": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/containerd-relation-broken": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/containerd-relation-changed": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/containerd-relation-created": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/containerd-relation-departed": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/containerd-relation-joined": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/hook.template": [ + "layer:basic", + "static", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/install": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/leader-elected": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/leader-settings-changed": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/post-series-upgrade": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/pre-series-upgrade": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/relations/container-runtime/.gitignore": [ + "interface:container-runtime", + "static", + "a2ebfecdb6c1b58267fbe97e6e2ac02c2b963df7673fc1047270f0f0cff16732" + ], + "hooks/relations/container-runtime/LICENSE": [ + "interface:container-runtime", + "static", + "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4" + ], + "hooks/relations/container-runtime/README.md": [ + "interface:container-runtime", + "static", + "44273265818229d2c858c3af0e0eee3a7df05aaa9ab20d28c3872190d4b48611" + ], + "hooks/relations/container-runtime/__init__.py": [ + "interface:container-runtime", + "static", + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ], + "hooks/relations/container-runtime/interface.yaml": [ + "interface:container-runtime", + "static", + "e5343dcb11a6817a6050df4ea1c463eeaa0dd4777098566d4e27b056775426c6" + ], + "hooks/relations/container-runtime/provides.py": [ + "interface:container-runtime", + "static", + "4e818da222f507604179a828629787a1250083c847277f6b5b8e028cfbbb6d06" + ], + "hooks/relations/container-runtime/requires.py": [ + "interface:container-runtime", + "static", + "95285168b02f1f70be15c03098833a85e60fa1658ed72a46acd42e8e85ded761" + ], + "hooks/relations/untrusted-container-runtime/.gitignore": [ + "interface:untrusted-container-runtime", + "static", + "a2ebfecdb6c1b58267fbe97e6e2ac02c2b963df7673fc1047270f0f0cff16732" + ], + "hooks/relations/untrusted-container-runtime/LICENSE": [ + "interface:untrusted-container-runtime", + "static", + "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4" + ], + "hooks/relations/untrusted-container-runtime/README.md": [ + "interface:untrusted-container-runtime", + "static", + "e3dc7db9ee98b716cb9a3a281fad88ca313bc11888a0da2f4b63c4306d91b64f" + ], + "hooks/relations/untrusted-container-runtime/__init__.py": [ + "interface:untrusted-container-runtime", + "static", + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ], + "hooks/relations/untrusted-container-runtime/interface.yaml": [ + "interface:untrusted-container-runtime", + "static", + "1fcb0305295206dc2b9926bf1870cae2c6cd8eee6eef72b6060c85e4f2109a45" + ], + "hooks/relations/untrusted-container-runtime/provides.py": [ + "interface:untrusted-container-runtime", + "static", + "05a52be7ad18df5cac9fb5dcc27c2ab24fe12e65fa809e0ea4d395dbcb36e6f2" + ], + "hooks/relations/untrusted-container-runtime/requires.py": [ + "interface:untrusted-container-runtime", + "static", + "958e03e254ee27bee761a6af3e032a273204b356dc51438489cde726b1a6e060" + ], + "hooks/start": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/stop": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/untrusted-relation-broken": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/untrusted-relation-changed": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/untrusted-relation-created": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/untrusted-relation-departed": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/untrusted-relation-joined": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/update-status": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "hooks/upgrade-charm": [ + "layer:basic", + "dynamic", + "2b693cb2a11594a80cc91235c2dc219a0a6303ae62bee8aa87eb35781f7158f7" + ], + "icon.svg": [ + "kata", + "static", + "d20624e9389af6506a8d8a69ac9bba4d41709601b624c0875fd7d6717b395088" + ], + "layer.yaml": [ + "kata", + "dynamic", + "599574e1d3dda3bf1d63047ac0b152caffcf22058e2f61370a37c8bb89317e4c" + ], + "lib/charms/layer/__init__.py": [ + "layer:basic", + "static", + "dfe0d26c6bf409767de6e2546bc648f150e1b396243619bad3aa0553ab7e0e6f" + ], + "lib/charms/layer/basic.py": [ + "layer:basic", + "static", + "98b47134770ed6e4c0b2d4aad73cd5bc200bec84aa9c1c4e075fd70c3222a0c9" + ], + "lib/charms/layer/execd.py": [ + "layer:basic", + "static", + "fda8bd491032db1db8ddaf4e99e7cc878c6fb5432efe1f91cadb5b34765d076d" + ], + "lib/charms/layer/options.py": [ + "layer:options", + "static", + "8ae7a07d22542fc964f2d2bee8219d1c78a68dace70a1b38d36d4aea47b1c3b2" + ], + "lib/charms/layer/status.py": [ + "layer:status", + "static", + "d560a5e07b2e5f2b0f25f30e1f0278b06f3f90c01e4dbad5c83d71efc79018c6" + ], + "lib/debug_script.py": [ + "layer:debug", + "static", + "a4d56f2d3e712b1b5cadb657c7195c6268d0aac6d228991049fd769e0ddaf453" + ], + "make_docs": [ + "layer:status", + "static", + "c990f55c8e879793a62ed8464ee3d7e0d7d2225fdecaf17af24b0df0e2daa8c1" + ], + "metadata.yaml": [ + "kata", + "dynamic", + "883f95d6180166d507365b3374b733fde27e0eb988d9532e88bb66e002c3fd68" + ], + "pydocmd.yml": [ + "layer:status", + "static", + "11d9293901f32f75f4256ae4ac2073b92ce1d7ef7b6c892ba9fbb98690a0b330" + ], + "reactive/__init__.py": [ + "layer:basic", + "static", + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ], + "reactive/kata.py": [ + "kata", + "static", + "7863484c83034271ea1f7a645c9f904405047db1be0fd7857f80008f47e073bf" + ], + "reactive/status.py": [ + "layer:status", + "static", + "30207fc206f24e91def5252f1c7f7c8e23c0aed0e93076babf5e03c05296d207" + ], + "requirements.txt": [ + "layer:basic", + "static", + "a00f75d80849e5b4fc5ad2e7536f947c25b1a4044b341caa8ee87a92d3a4c804" + ], + "tests/conftest.py": [ + "kata", + "static", + "fd53e0c38b4dda0c18096167889cd0d85b98b0a13225f9f8853261241e94078c" + ], + "tests/test_kata_reactive.py": [ + "kata", + "static", + "24d714d03b6f2c2faa67ecdbd7d102f700087973eb5c98d7b9c8e5542d61541c" + ], + "tox.ini": [ + "kata", + "static", + "b04898a3c4de3bf48ca4363751048ec83ed185bc27af7d956ae799d88d3827ab" + ], + "version": [ + "kata", + "dynamic", + "f6c325fd13ee5c726bc2e631996963198f2cfbaa50599b4962b151630fa86cf4" + ], + "wheelhouse.txt": [ + "kata", + "dynamic", + "425000e4406bf00f663cf41789c409e7980e4bd4a1b557b0470770502f71ed09" + ], + "wheelhouse/Jinja2-2.10.1.tar.gz": [ + "layer:basic", + "dynamic", + "065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013" + ], + "wheelhouse/MarkupSafe-1.1.1.tar.gz": [ + "layer:basic", + "dynamic", + "29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b" + ], + "wheelhouse/PyYAML-5.2.tar.gz": [ + "layer:basic", + "dynamic", + "c0ee8eca2c582d29c3c2ec6e2c4f703d1b7f1fb10bc72317355a746057e7346c" + ], + "wheelhouse/Tempita-0.5.2.tar.gz": [ + "__pip__", + "dynamic", + "cacecf0baa674d356641f1d406b8bff1d756d739c46b869a54de515d08e6fc9c" + ], + "wheelhouse/certifi-2021.10.8.tar.gz": [ + "__pip__", + "dynamic", + "78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872" + ], + "wheelhouse/charmhelpers-0.20.23.tar.gz": [ + "layer:basic", + "dynamic", + "59a9776594e91cd3e3e000043f8668b4d7b279422dbb17e320f01dc16385b80e" + ], + "wheelhouse/charms.reactive-1.4.1.tar.gz": [ + "layer:basic", + "dynamic", + "bba21b4fd40b26c240c9ef2aa10c6fdf73592031c68591da4e7ccc46ca9cb616" + ], + "wheelhouse/charset-normalizer-2.0.7.tar.gz": [ + "__pip__", + "dynamic", + "e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0" + ], + "wheelhouse/idna-3.3.tar.gz": [ + "__pip__", + "dynamic", + "9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + ], + "wheelhouse/netaddr-0.7.19.tar.gz": [ + "layer:basic", + "dynamic", + "38aeec7cdd035081d3a4c306394b19d677623bf76fa0913f6695127c7753aefd" + ], + "wheelhouse/pbr-5.6.0.tar.gz": [ + "__pip__", + "dynamic", + "42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd" + ], + "wheelhouse/pip-18.1.tar.gz": [ + "layer:basic", + "dynamic", + "c0a292bd977ef590379a3f05d7b7f65135487b67470f6281289a94e015650ea1" + ], + "wheelhouse/pyaml-21.10.1.tar.gz": [ + "__pip__", + "dynamic", + "c6519fee13bf06e3bb3f20cacdea8eba9140385a7c2546df5dbae4887f768383" + ], + "wheelhouse/requests-2.26.0.tar.gz": [ + "kata", + "dynamic", + "b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" + ], + "wheelhouse/setuptools-41.6.0.zip": [ + "layer:basic", + "dynamic", + "6afa61b391dcd16cb8890ec9f66cc4015a8a31a6e1c2b4e0c464514be1a3d722" + ], + "wheelhouse/setuptools_scm-1.17.0.tar.gz": [ + "layer:basic", + "dynamic", + "70a4cf5584e966ae92f54a764e6437af992ba42ac4bca7eb37cc5d02b98ec40a" + ], + "wheelhouse/six-1.16.0.tar.gz": [ + "__pip__", + "dynamic", + "1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926" + ], + "wheelhouse/urllib3-1.26.7.tar.gz": [ + "__pip__", + "dynamic", + "4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece" + ], + "wheelhouse/wheel-0.33.6.tar.gz": [ + "layer:basic", + "dynamic", + "10c9da68765315ed98850f8e048347c3eb06dd81822dc2ab1d4fde9dc9702646" + ] + } +} \ No newline at end of file diff --git a/kata/.github/workflows/main.yml b/kata/.github/workflows/main.yml new file mode 100644 index 0000000..565bfaf --- /dev/null +++ b/kata/.github/workflows/main.yml @@ -0,0 +1,50 @@ +name: Test Suite +on: [pull_request] + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + strategy: + matrix: + python: [3.5, 3.6, 3.7, 3.8, 3.9] + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + - name: Install Dependencies + run: | + pip install tox + - name: Run lint + run: tox -e flake8 + functional-test: + name: Functional test with LXD + runs-on: ubuntu-latest + timeout-minutes: 360 + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install Dependencies + run: | + pip install tox + - name: Setup operator environment + uses: charmed-kubernetes/actions-operator@master + - name: Run test + run: tox -e func + - name: Show Status + if: ${{ always() }} + run: | + model=$(juju models --format yaml|grep "^- name:.*zaza"|cut -f2 -d/); + juju status -m "$model" + - name: Show Error Logs + if: ${{ always() }} + run: | + model=$(juju models --format yaml|grep "^- name:.*zaza"|cut -f2 -d/); + juju debug-log -m "$model" --replay --no-tail --level ERROR diff --git a/kata/.gitignore b/kata/.gitignore new file mode 100644 index 0000000..8003a31 --- /dev/null +++ b/kata/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +.coverage +.tox/ +.venv/ diff --git a/kata/.travis.yml b/kata/.travis.yml new file mode 100644 index 0000000..694ddcb --- /dev/null +++ b/kata/.travis.yml @@ -0,0 +1,11 @@ +dist: bionic +language: python +python: + - "3.5" + - "3.6" + - "3.7" + - "3.8" +install: + - pip install tox-travis +script: + - tox diff --git a/kata/CONTRIBUTING.md b/kata/CONTRIBUTING.md new file mode 100644 index 0000000..7a8f252 --- /dev/null +++ b/kata/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# Contributor Guide + +This Juju charm is open source ([Apache License 2.0](./LICENSE)) and we actively seek any community contibutions +for code, suggestions and documentation. +This page details a few notes, workflows and suggestions for how to make contributions most effective and help us +all build a better charm - please give them a read before working on any contributions. + +## Licensing + +This charm has been created under the [Apache License 2.0](./LICENSE), which will cover any contributions you may +make to this project. Please familiarise yourself with the terms of the license. + +Additionally, this charm uses the Harmony CLA agreement. It’s the easiest way for you to give us permission to +use your contributions. +In effect, you’re giving us a license, but you still own the copyright — so you retain the right to modify your +code and use it in other projects. Please [sign the CLA here](https://ubuntu.com/legal/contributors/agreement) before +making any contributions. + +## Code of conduct + +We have adopted the Ubuntu code of Conduct. You can read this in full [here](https://ubuntu.com/community/code-of-conduct). + +## Contributing code + +To contribute code to this project, please use the following workflow: + +1. [Submit a bug][bug] to explain the need for and track the change. +2. Create a branch on your fork of the repo with your changes, including a unit test covering the new or modified code. +3. Submit a PR. The PR description should include a link to the bug on Launchpad. +4. Update the Launchpad bug to include a link to the PR and the `review-needed` tag. +5. Once reviewed and merged, the change will become available on the edge channel and assigned to an appropriate milestone + for further release according to priority. + +## Documentation + +Documentation for this charm is currently maintained as part of the Charmed Kubernetes docs. +See [this page][docs] + + +[bug]: https://bugs.launchpad.net/charm-kata/+filebug +[docs]: https://github.com/charmed-kubernetes/kubernetes-docs/blob/master/pages/k8s/charm-kata.md \ No newline at end of file diff --git a/kata/LICENSE b/kata/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/kata/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/kata/Makefile b/kata/Makefile new file mode 100644 index 0000000..a1ad3a5 --- /dev/null +++ b/kata/Makefile @@ -0,0 +1,24 @@ +#!/usr/bin/make + +all: lint unit_test + + +.PHONY: clean +clean: + @rm -rf .tox + +.PHONY: apt_prereqs +apt_prereqs: + @# Need tox, but don't install the apt version unless we have to (don't want to conflict with pip) + @which tox >/dev/null || (sudo apt-get install -y python-pip && sudo pip install tox) + +.PHONY: lint +lint: apt_prereqs + @tox --notest + @PATH=.tox/py34/bin:.tox/py35/bin flake8 $(wildcard hooks reactive lib unit_tests tests) + @charm proof + +.PHONY: unit_test +unit_test: apt_prereqs + @echo Starting tests... + tox diff --git a/kata/README.md b/kata/README.md new file mode 100644 index 0000000..39cb53b --- /dev/null +++ b/kata/README.md @@ -0,0 +1,7 @@ +# Charm for Kata Containers + +This subordinate charm deploys the [Kata](https://katacontainers.io/) +untrusted container runtime within a running Juju charm model. + +This charm is maintained along with the components of Charmed Kubernetes. +For full information, please visit the official [Charmed Kubernetes docs](https://ubuntu.com/kubernetes/docs/charm-kata). diff --git a/kata/actions.yaml b/kata/actions.yaml new file mode 100644 index 0000000..8712b6b --- /dev/null +++ b/kata/actions.yaml @@ -0,0 +1,2 @@ +"debug": + "description": "Collect debug data" diff --git a/kata/actions/debug b/kata/actions/debug new file mode 100755 index 0000000..8ba160e --- /dev/null +++ b/kata/actions/debug @@ -0,0 +1,102 @@ +#!/usr/local/sbin/charm-env python3 + +import os +import subprocess +import tarfile +import tempfile +import traceback +from contextlib import contextmanager +from datetime import datetime +from charmhelpers.core.hookenv import action_set, local_unit + +archive_dir = None +log_file = None + + +@contextmanager +def archive_context(): + """ Open a context with a new temporary directory. + + When the context closes, the directory is archived, and the archive + location is added to Juju action output. """ + global archive_dir + global log_file + with tempfile.TemporaryDirectory() as temp_dir: + name = "debug-" + datetime.now().strftime("%Y%m%d%H%M%S") + archive_dir = os.path.join(temp_dir, name) + os.makedirs(archive_dir) + with open("%s/debug.log" % archive_dir, "w") as log_file: + yield + os.chdir(temp_dir) + tar_path = "/home/ubuntu/%s.tar.gz" % name + with tarfile.open(tar_path, "w:gz") as f: + f.add(name) + action_set({ + "path": tar_path, + "command": "juju scp %s:%s ." % (local_unit(), tar_path), + "message": " ".join([ + "Archive has been created on unit %s." % local_unit(), + "Use the juju scp command to copy it to your local machine." + ]) + }) + + +def log(msg): + """ Log a message that will be included in the debug archive. + + Must be run within archive_context """ + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + for line in str(msg).splitlines(): + log_file.write(timestamp + " | " + line.rstrip() + "\n") + + +def run_script(script): + """ Run a single script. Must be run within archive_context """ + log("Running script: " + script) + script_dir = os.path.join(archive_dir, script) + os.makedirs(script_dir) + env = os.environ.copy() + env["PYTHONPATH"] = "lib" # allow same imports as reactive code + env["DEBUG_SCRIPT_DIR"] = script_dir + with open(script_dir + "/stdout", "w") as stdout: + with open(script_dir + "/stderr", "w") as stderr: + process = subprocess.Popen( + "debug-scripts/" + script, + stdout=stdout, stderr=stderr, env=env + ) + try: + exit_code = process.wait(timeout=300) + except subprocess.TimeoutExpired: + log("ERROR: still running, terminating") + process.terminate() + try: + exit_code = process.wait(timeout=10) + except subprocess.TimeoutExpired: + log("ERROR: still running, killing") + process.kill() + exit_code = process.wait(timeout=10) + if exit_code != 0: + log("ERROR: %s failed with exit code %d" % (script, exit_code)) + + +def run_all_scripts(): + """ Run all scripts. For the sake of robustness, log and ignore any + exceptions that occur. + + Must be run within archive_context """ + scripts = os.listdir("debug-scripts") + for script in scripts: + try: + run_script(script) + except: + log(traceback.format_exc()) + + +def main(): + """ Open an archive context and run all scripts. """ + with archive_context(): + run_all_scripts() + + +if __name__ == "__main__": + main() diff --git a/kata/bin/charm-env b/kata/bin/charm-env new file mode 100755 index 0000000..d211ce9 --- /dev/null +++ b/kata/bin/charm-env @@ -0,0 +1,107 @@ +#!/bin/bash + +VERSION="1.0.0" + + +find_charm_dirs() { + # Hopefully, $JUJU_CHARM_DIR is set so which venv to use in unambiguous. + if [[ -n "$JUJU_CHARM_DIR" || -n "$CHARM_DIR" ]]; then + if [[ -z "$JUJU_CHARM_DIR" ]]; then + # accept $CHARM_DIR to be more forgiving + export JUJU_CHARM_DIR="$CHARM_DIR" + fi + if [[ -z "$CHARM_DIR" ]]; then + # set CHARM_DIR as well to help with backwards compatibility + export CHARM_DIR="$JUJU_CHARM_DIR" + fi + return + fi + # Try to guess the value for JUJU_CHARM_DIR by looking for a non-subordinate + # (because there's got to be at least one principle) charm directory; + # if there are several, pick the first by alpha order. + agents_dir="/var/lib/juju/agents" + if [[ -d "$agents_dir" ]]; then + desired_charm="$1" + found_charm_dir="" + if [[ -n "$desired_charm" ]]; then + for charm_dir in $(/bin/ls -d "$agents_dir"/unit-*/charm); do + charm_name="$(grep -o '^['\''"]\?name['\''"]\?:.*' $charm_dir/metadata.yaml 2> /dev/null | sed -e 's/.*: *//' -e 's/['\''"]//g')" + if [[ "$charm_name" == "$desired_charm" ]]; then + if [[ -n "$found_charm_dir" ]]; then + >&2 echo "Ambiguous possibilities for JUJU_CHARM_DIR matching '$desired_charm'; please run within a Juju hook context" + exit 1 + fi + found_charm_dir="$charm_dir" + fi + done + if [[ -z "$found_charm_dir" ]]; then + >&2 echo "Unable to determine JUJU_CHARM_DIR matching '$desired_charm'; please run within a Juju hook context" + exit 1 + fi + export JUJU_CHARM_DIR="$found_charm_dir" + export CHARM_DIR="$found_charm_dir" + return + fi + # shellcheck disable=SC2126 + non_subordinates="$(grep -L 'subordinate"\?:.*true' "$agents_dir"/unit-*/charm/metadata.yaml | wc -l)" + if [[ "$non_subordinates" -gt 1 ]]; then + >&2 echo 'Ambiguous possibilities for JUJU_CHARM_DIR; please use --charm or run within a Juju hook context' + exit 1 + elif [[ "$non_subordinates" -eq 1 ]]; then + for charm_dir in $(/bin/ls -d "$agents_dir"/unit-*/charm); do + if grep -q 'subordinate"\?:.*true' "$charm_dir/metadata.yaml"; then + continue + fi + export JUJU_CHARM_DIR="$charm_dir" + export CHARM_DIR="$charm_dir" + return + done + fi + fi + >&2 echo 'Unable to determine JUJU_CHARM_DIR; please run within a Juju hook context' + exit 1 +} + +try_activate_venv() { + if [[ -d "$JUJU_CHARM_DIR/../.venv" ]]; then + . "$JUJU_CHARM_DIR/../.venv/bin/activate" + fi +} + +find_wrapped() { + PATH="${PATH/\/usr\/local\/sbin:}" which "$(basename "$0")" +} + + +if [[ "$1" == "--version" || "$1" == "-v" ]]; then + echo "$VERSION" + exit 0 +fi + + +# allow --charm option to hint which JUJU_CHARM_DIR to choose when ambiguous +# NB: --charm option must come first +# NB: option must be processed outside find_charm_dirs to modify $@ +charm_name="" +if [[ "$1" == "--charm" ]]; then + charm_name="$2" + shift; shift +fi + +find_charm_dirs "$charm_name" +try_activate_venv +export PYTHONPATH="$JUJU_CHARM_DIR/lib:$PYTHONPATH" + +if [[ "$(basename "$0")" == "charm-env" ]]; then + # being used as a shebang + exec "$@" +elif [[ "$0" == "$BASH_SOURCE" ]]; then + # being invoked as a symlink wrapping something to find in the venv + exec "$(find_wrapped)" "$@" +elif [[ "$(basename "$BASH_SOURCE")" == "charm-env" ]]; then + # being sourced directly; do nothing + /bin/true +else + # being sourced for wrapped bash helpers + . "$(find_wrapped)" +fi diff --git a/kata/bin/layer_option b/kata/bin/layer_option new file mode 100755 index 0000000..3253ef8 --- /dev/null +++ b/kata/bin/layer_option @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +import sys +import argparse +from charms import layer + + +parser = argparse.ArgumentParser(description='Access layer options.') +parser.add_argument('section', + help='the section, or layer, the option is from') +parser.add_argument('option', + help='the option to access') + +args = parser.parse_args() +value = layer.options.get(args.section, args.option) +if isinstance(value, bool): + sys.exit(0 if value else 1) +elif isinstance(value, list): + for val in value: + print(val) +else: + print(value) diff --git a/kata/copyright b/kata/copyright new file mode 100644 index 0000000..a91bdf1 --- /dev/null +++ b/kata/copyright @@ -0,0 +1,16 @@ +Format: http://dep.debian.net/deps/dep5/ + +Files: * +Copyright: Copyright 2018, Canonical Ltd., All Rights Reserved. +License: Apache License 2.0 + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + http://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/kata/copyright.layer-basic b/kata/copyright.layer-basic new file mode 100644 index 0000000..d4fdd18 --- /dev/null +++ b/kata/copyright.layer-basic @@ -0,0 +1,16 @@ +Format: http://dep.debian.net/deps/dep5/ + +Files: * +Copyright: Copyright 2015-2017, Canonical Ltd., All Rights Reserved. +License: Apache License 2.0 + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + http://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/kata/copyright.layer-options b/kata/copyright.layer-options new file mode 100644 index 0000000..d4fdd18 --- /dev/null +++ b/kata/copyright.layer-options @@ -0,0 +1,16 @@ +Format: http://dep.debian.net/deps/dep5/ + +Files: * +Copyright: Copyright 2015-2017, Canonical Ltd., All Rights Reserved. +License: Apache License 2.0 + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + http://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/kata/debug-scripts/charm-unitdata b/kata/debug-scripts/charm-unitdata new file mode 100755 index 0000000..d2aac60 --- /dev/null +++ b/kata/debug-scripts/charm-unitdata @@ -0,0 +1,12 @@ +#!/usr/local/sbin/charm-env python3 + +import debug_script +import json +from charmhelpers.core import unitdata + +kv = unitdata.kv() +data = kv.getrange("") + +with debug_script.open_file("unitdata.json", "w") as f: + json.dump(data, f, indent=2) + f.write("\n") diff --git a/kata/debug-scripts/filesystem b/kata/debug-scripts/filesystem new file mode 100755 index 0000000..c5ec6d8 --- /dev/null +++ b/kata/debug-scripts/filesystem @@ -0,0 +1,17 @@ +#!/bin/sh +set -ux + +# report file system disk space usage +df -hT > $DEBUG_SCRIPT_DIR/df-hT +# estimate file space usage +du -h / 2>&1 > $DEBUG_SCRIPT_DIR/du-h +# list the mounted filesystems +mount > $DEBUG_SCRIPT_DIR/mount +# list the mounted systems with ascii trees +findmnt -A > $DEBUG_SCRIPT_DIR/findmnt +# list block devices +lsblk > $DEBUG_SCRIPT_DIR/lsblk +# list open files +lsof 2>&1 > $DEBUG_SCRIPT_DIR/lsof +# list local system locks +lslocks > $DEBUG_SCRIPT_DIR/lslocks diff --git a/kata/debug-scripts/juju-logs b/kata/debug-scripts/juju-logs new file mode 100755 index 0000000..d27c458 --- /dev/null +++ b/kata/debug-scripts/juju-logs @@ -0,0 +1,4 @@ +#!/bin/sh +set -ux + +cp -v /var/log/juju/* $DEBUG_SCRIPT_DIR diff --git a/kata/debug-scripts/juju-network-get b/kata/debug-scripts/juju-network-get new file mode 100755 index 0000000..983c8c4 --- /dev/null +++ b/kata/debug-scripts/juju-network-get @@ -0,0 +1,21 @@ +#!/usr/local/sbin/charm-env python3 + +import os +import subprocess +import yaml +import debug_script + +with open('metadata.yaml') as f: + metadata = yaml.load(f) + +relations = [] +for key in ['requires', 'provides', 'peers']: + relations += list(metadata.get(key, {}).keys()) + +os.mkdir(os.path.join(debug_script.dir, 'relations')) + +for relation in relations: + path = 'relations/' + relation + with debug_script.open_file(path, 'w') as f: + cmd = ['network-get', relation] + subprocess.call(cmd, stdout=f, stderr=subprocess.STDOUT) diff --git a/kata/debug-scripts/network b/kata/debug-scripts/network new file mode 100755 index 0000000..944a355 --- /dev/null +++ b/kata/debug-scripts/network @@ -0,0 +1,11 @@ +#!/bin/sh +set -ux + +ifconfig -a > $DEBUG_SCRIPT_DIR/ifconfig +cp -v /etc/resolv.conf $DEBUG_SCRIPT_DIR/resolv.conf +cp -v /etc/network/interfaces $DEBUG_SCRIPT_DIR/interfaces +netstat -planut > $DEBUG_SCRIPT_DIR/netstat +route -n > $DEBUG_SCRIPT_DIR/route +iptables-save > $DEBUG_SCRIPT_DIR/iptables-save +dig google.com > $DEBUG_SCRIPT_DIR/dig-google +ping -w 2 -i 0.1 google.com > $DEBUG_SCRIPT_DIR/ping-google diff --git a/kata/debug-scripts/packages b/kata/debug-scripts/packages new file mode 100755 index 0000000..b60a9cf --- /dev/null +++ b/kata/debug-scripts/packages @@ -0,0 +1,7 @@ +#!/bin/sh +set -ux + +dpkg --list > $DEBUG_SCRIPT_DIR/dpkg-list +snap list > $DEBUG_SCRIPT_DIR/snap-list +pip2 list > $DEBUG_SCRIPT_DIR/pip2-list +pip3 list > $DEBUG_SCRIPT_DIR/pip3-list diff --git a/kata/debug-scripts/sysctl b/kata/debug-scripts/sysctl new file mode 100755 index 0000000..a86a6c8 --- /dev/null +++ b/kata/debug-scripts/sysctl @@ -0,0 +1,4 @@ +#!/bin/sh +set -ux + +sysctl -a > $DEBUG_SCRIPT_DIR/sysctl diff --git a/kata/debug-scripts/systemd b/kata/debug-scripts/systemd new file mode 100755 index 0000000..8bb9b6f --- /dev/null +++ b/kata/debug-scripts/systemd @@ -0,0 +1,9 @@ +#!/bin/sh +set -ux + +systemctl --all > $DEBUG_SCRIPT_DIR/systemctl +journalctl > $DEBUG_SCRIPT_DIR/journalctl +systemd-analyze time > $DEBUG_SCRIPT_DIR/systemd-analyze-time +systemd-analyze blame > $DEBUG_SCRIPT_DIR/systemd-analyze-blame +systemd-analyze critical-chain > $DEBUG_SCRIPT_DIR/systemd-analyze-critical-chain +systemd-analyze dump > $DEBUG_SCRIPT_DIR/systemd-analyze-dump diff --git a/kata/docs/status.md b/kata/docs/status.md new file mode 100644 index 0000000..c6cceab --- /dev/null +++ b/kata/docs/status.md @@ -0,0 +1,91 @@ +

WorkloadState

+ +```python +WorkloadState(self, /, *args, **kwargs) +``` + +Enum of the valid workload states. + +Valid options are: + + * `WorkloadState.MAINTENANCE` + * `WorkloadState.BLOCKED` + * `WorkloadState.WAITING` + * `WorkloadState.ACTIVE` + +

maintenance

+ +```python +maintenance(message) +``` + +Set the status to the `MAINTENANCE` state with the given operator message. + +__Parameters__ + +- __`message` (str)__: Message to convey to the operator. + +

maint

+ +```python +maint(message) +``` + +Shorthand alias for +[maintenance](status.md#charms.layer.status.maintenance). + +__Parameters__ + +- __`message` (str)__: Message to convey to the operator. + +

blocked

+ +```python +blocked(message) +``` + +Set the status to the `BLOCKED` state with the given operator message. + +__Parameters__ + +- __`message` (str)__: Message to convey to the operator. + +

waiting

+ +```python +waiting(message) +``` + +Set the status to the `WAITING` state with the given operator message. + +__Parameters__ + +- __`message` (str)__: Message to convey to the operator. + +

active

+ +```python +active(message) +``` + +Set the status to the `ACTIVE` state with the given operator message. + +__Parameters__ + +- __`message` (str)__: Message to convey to the operator. + +

status_set

+ +```python +status_set(workload_state, message) +``` + +Set the status to the given workload state with a message. + +__Parameters__ + +- __`workload_state` (WorkloadState or str)__: State of the workload. Should be + a [WorkloadState](status.md#charms.layer.status.WorkloadState) enum + member, or the string value of one of those members. +- __`message` (str)__: Message to convey to the operator. + diff --git a/kata/hooks/config-changed b/kata/hooks/config-changed new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/config-changed @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/containerd-relation-broken b/kata/hooks/containerd-relation-broken new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/containerd-relation-broken @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/containerd-relation-changed b/kata/hooks/containerd-relation-changed new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/containerd-relation-changed @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/containerd-relation-created b/kata/hooks/containerd-relation-created new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/containerd-relation-created @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/containerd-relation-departed b/kata/hooks/containerd-relation-departed new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/containerd-relation-departed @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/containerd-relation-joined b/kata/hooks/containerd-relation-joined new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/containerd-relation-joined @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/hook.template b/kata/hooks/hook.template new file mode 100644 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/hook.template @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/install b/kata/hooks/install new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/install @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/leader-elected b/kata/hooks/leader-elected new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/leader-elected @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/leader-settings-changed b/kata/hooks/leader-settings-changed new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/leader-settings-changed @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/post-series-upgrade b/kata/hooks/post-series-upgrade new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/post-series-upgrade @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/pre-series-upgrade b/kata/hooks/pre-series-upgrade new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/pre-series-upgrade @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/relations/container-runtime/.gitignore b/kata/hooks/relations/container-runtime/.gitignore new file mode 100644 index 0000000..894a44c --- /dev/null +++ b/kata/hooks/relations/container-runtime/.gitignore @@ -0,0 +1,104 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/kata/hooks/relations/container-runtime/LICENSE b/kata/hooks/relations/container-runtime/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/kata/hooks/relations/container-runtime/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/kata/hooks/relations/container-runtime/README.md b/kata/hooks/relations/container-runtime/README.md new file mode 100644 index 0000000..4620013 --- /dev/null +++ b/kata/hooks/relations/container-runtime/README.md @@ -0,0 +1,45 @@ +# interface-container-runtime + +## Overview + +This interface handles communication between subordinate charms, that provide a container runtime and charms requiring a container runtime. + +## Usage + +### Provides + +The providing side of the container interface provides a place for a container runtime to connect to. + +Your charm should respond to the `endpoint.{endpoint_name}.available` state, +which indicates that there is a container runtime connected. + +A trivial example of handling this interface would be: + +```python +@when('endpoint.containerd.joined') +def update_kubelet_config(containerd): + endpoint = endpoint_from_flag('endpoint.containerd.joined') + config = endpoint.get_config() + kubelet.config['container-runtime'] = \ + config['runtime'] +``` + +### Requires + +The requiring side of the container interface requires a place for a container runtime to connect to. + +Your charm should set `{endpoint_name}.available` state, +which indicates that the container is runtime connected. + +A trivial example of handling this interface would be: + +```python +@when('endpoint.containerd.joined') +def pubish_config(): + endpoint = endpoint_from_flag('endpoint.containerd.joined') + endpoint.set_config( + socket='unix:///var/run/containerd/containerd.sock', + runtime='remote', + nvidia_enabled=False + ) +``` diff --git a/calico/calico-node-image.tgz b/kata/hooks/relations/container-runtime/__init__.py similarity index 100% rename from calico/calico-node-image.tgz rename to kata/hooks/relations/container-runtime/__init__.py diff --git a/kata/hooks/relations/container-runtime/interface.yaml b/kata/hooks/relations/container-runtime/interface.yaml new file mode 100644 index 0000000..294be1e --- /dev/null +++ b/kata/hooks/relations/container-runtime/interface.yaml @@ -0,0 +1,4 @@ +name: container-runtime +summary: Interface for relating to container runtimes +version: 1 +maintainer: "Joe Borg " diff --git a/kata/hooks/relations/container-runtime/provides.py b/kata/hooks/relations/container-runtime/provides.py new file mode 100644 index 0000000..a9768a8 --- /dev/null +++ b/kata/hooks/relations/container-runtime/provides.py @@ -0,0 +1,55 @@ +from charms.reactive import ( + Endpoint, + toggle_flag +) + + +class ContainerRuntimeProvides(Endpoint): + def manage_flags(self): + toggle_flag(self.expand_name('endpoint.{endpoint_name}.available'), + self.is_joined) + + def _get_config(self, key): + """ + Get the published configuration for a given key. + + :param key: String dict key + :return: String value for given key + """ + return self.all_joined_units.received.get(key) + + def get_nvidia_enabled(self): + """ + Get the published nvidia config. + + :return: String + """ + return self._get_config(key='nvidia_enabled') + + def get_runtime(self): + """ + Get the published runtime config. + + :return: String + """ + return self._get_config(key='runtime') + + def get_socket(self): + """ + Get the published socket config. + + :return: String + """ + return self._get_config(key='socket') + + def set_config(self, sandbox_image=None): + """ + Set the configuration to be published. + + :param sandbox_image: String to optionally override the sandbox image + :return: None + """ + for relation in self.relations: + relation.to_publish.update({ + 'sandbox_image': sandbox_image + }) diff --git a/kata/hooks/relations/container-runtime/requires.py b/kata/hooks/relations/container-runtime/requires.py new file mode 100644 index 0000000..c461b68 --- /dev/null +++ b/kata/hooks/relations/container-runtime/requires.py @@ -0,0 +1,61 @@ +from charms.reactive import ( + Endpoint, + clear_flag, + data_changed, + is_data_changed, + toggle_flag +) + + +class ContainerRuntimeRequires(Endpoint): + def manage_flags(self): + toggle_flag(self.expand_name('endpoint.{endpoint_name}.available'), + self.is_joined) + toggle_flag(self.expand_name('endpoint.{endpoint_name}.reconfigure'), + self.is_joined and self._config_changed()) + + def _config_changed(self): + """ + Determine if our received data has changed. + + :return: Boolean + """ + # NB: this call should match whatever we're tracking in handle_remote_config + return is_data_changed('containerd.remote_config', + [self.get_sandbox_image()]) + + def handle_remote_config(self): + """ + Keep track of received data so we can know if it changes. + + :return: None + """ + clear_flag(self.expand_name('endpoint.{endpoint_name}.reconfigure')) + # Presently, we only care about one piece of remote config. Expand + # the list as needed. + data_changed('containerd.remote_config', + [self.get_sandbox_image()]) + + def get_sandbox_image(self): + """ + Get the sandbox image URI if a remote has published one. + + :return: String: remotely configured sandbox image + """ + return self.all_joined_units.received.get('sandbox_image') + + def set_config(self, socket, runtime, nvidia_enabled): + """ + Set the configuration to be published. + + :param socket: String uri to runtime socket + :param runtime: String runtime executable + :param nvidia_enabled: Boolean nvidia runtime enabled + :return: None + """ + for relation in self.relations: + relation.to_publish.update({ + 'socket': socket, + 'runtime': runtime, + 'nvidia_enabled': nvidia_enabled + }) diff --git a/kata/hooks/relations/untrusted-container-runtime/.gitignore b/kata/hooks/relations/untrusted-container-runtime/.gitignore new file mode 100644 index 0000000..894a44c --- /dev/null +++ b/kata/hooks/relations/untrusted-container-runtime/.gitignore @@ -0,0 +1,104 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/kata/hooks/relations/untrusted-container-runtime/LICENSE b/kata/hooks/relations/untrusted-container-runtime/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/kata/hooks/relations/untrusted-container-runtime/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/kata/hooks/relations/untrusted-container-runtime/README.md b/kata/hooks/relations/untrusted-container-runtime/README.md new file mode 100644 index 0000000..135dca5 --- /dev/null +++ b/kata/hooks/relations/untrusted-container-runtime/README.md @@ -0,0 +1,54 @@ +# interface-untrusted-container-runtime + +## Overview + +This interface handles communication between subordinate container runtimes +and this subordinate untrusted container runtime, such as `containerd` and +`kata-containers`. + +## Usage + +### Provides + +The providing side of the container interface provides a place for an +untrusted container runtime to connect to. + +Your charm should respond to the `endpoint.{endpoint_name}.available` state, +which indicates that there is an untrusted container runtime connected. + +A trivial example of handling this interface would be: + +```python +@when('endpoint.containerd.joined') +def update_kubelet_config(containerd): + endpoint = endpoint_from_flag('endpoint.containerd.joined') + config = endpoint.get_config() + + render( + 'config.toml', + { + 'runtime_name': config['name'], + 'runtime_binary': config['binary_path'] + } + ) +``` + +### Requires + +The requiring side of the untrusted container interface requires a place for +an untrusted container runtime to connect to. + +Your charm should set `{endpoint_name}.available` state, +which indicates that the container is runtime connected. + +A trivial example of handling this interface would be: + +```python +@when('endpoint.containerd.joined') +def pubish_config(): + endpoint = endpoint_from_flag('endpoint.containerd.joined') + endpoint.set_config( + 'name': 'kata', + 'binary_path': '/usr/bin/kata-runtime' + ) +``` diff --git a/kata/hooks/relations/untrusted-container-runtime/__init__.py b/kata/hooks/relations/untrusted-container-runtime/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kata/hooks/relations/untrusted-container-runtime/interface.yaml b/kata/hooks/relations/untrusted-container-runtime/interface.yaml new file mode 100644 index 0000000..d0d7dbc --- /dev/null +++ b/kata/hooks/relations/untrusted-container-runtime/interface.yaml @@ -0,0 +1,4 @@ +name: untrusted-container-runtime +summary: Interface for relating to untrusted container runtimes +version: 1 +maintainer: "Joe Borg " diff --git a/kata/hooks/relations/untrusted-container-runtime/provides.py b/kata/hooks/relations/untrusted-container-runtime/provides.py new file mode 100644 index 0000000..09deb26 --- /dev/null +++ b/kata/hooks/relations/untrusted-container-runtime/provides.py @@ -0,0 +1,28 @@ +from charms.reactive import ( + Endpoint, + set_flag, + clear_flag +) + +from charms.reactive import ( + when, + when_not +) + + +class ContainerRuntimeProvides(Endpoint): + @when('endpoint.{endpoint_name}.joined') + def joined(self): + set_flag(self.expand_name('endpoint.{endpoint_name}.available')) + + @when_not('endpoint.{endpoint_name}.joined') + def broken(self): + clear_flag(self.expand_name('endpoint.{endpoint_name}.available')) + + def get_config(self): + """ + Get the configuration published. + + :return: Dictionary configuration + """ + return self.all_joined_units.received diff --git a/kata/hooks/relations/untrusted-container-runtime/requires.py b/kata/hooks/relations/untrusted-container-runtime/requires.py new file mode 100644 index 0000000..f717ba6 --- /dev/null +++ b/kata/hooks/relations/untrusted-container-runtime/requires.py @@ -0,0 +1,34 @@ +from charms.reactive import ( + Endpoint, + set_flag, + clear_flag +) + +from charms.reactive import ( + when, + when_not +) + + +class ContainerRuntimeRequires(Endpoint): + @when('endpoint.{endpoint_name}.changed') + def changed(self): + set_flag(self.expand_name('endpoint.{endpoint_name}.available')) + + @when_not('endpoint.{endpoint_name}.joined') + def broken(self): + clear_flag(self.expand_name('endpoint.{endpoint_name}.available')) + + def set_config(self, name, binary_path): + """ + Set the configuration to be published. + + :param name: String name of runtime + :param binary_path: String runtime executable + :return: None + """ + for relation in self.relations: + relation.to_publish.update({ + 'name': name, + 'binary_path': binary_path + }) diff --git a/kata/hooks/start b/kata/hooks/start new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/start @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/stop b/kata/hooks/stop new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/stop @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/untrusted-relation-broken b/kata/hooks/untrusted-relation-broken new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/untrusted-relation-broken @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/untrusted-relation-changed b/kata/hooks/untrusted-relation-changed new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/untrusted-relation-changed @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/untrusted-relation-created b/kata/hooks/untrusted-relation-created new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/untrusted-relation-created @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/untrusted-relation-departed b/kata/hooks/untrusted-relation-departed new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/untrusted-relation-departed @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/untrusted-relation-joined b/kata/hooks/untrusted-relation-joined new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/untrusted-relation-joined @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/update-status b/kata/hooks/update-status new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/update-status @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/hooks/upgrade-charm b/kata/hooks/upgrade-charm new file mode 100755 index 0000000..9858c6b --- /dev/null +++ b/kata/hooks/upgrade-charm @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# Load modules from $JUJU_CHARM_DIR/lib +import sys +sys.path.append('lib') + +from charms.layer import basic # noqa +basic.bootstrap_charm_deps() + +from charmhelpers.core import hookenv # noqa +hookenv.atstart(basic.init_config_states) +hookenv.atexit(basic.clear_config_states) + + +# This will load and run the appropriate @hook and other decorated +# handlers from $JUJU_CHARM_DIR/reactive, $JUJU_CHARM_DIR/hooks/reactive, +# and $JUJU_CHARM_DIR/hooks/relations. +# +# See https://jujucharms.com/docs/stable/authors-charm-building +# for more information on this pattern. +from charms.reactive import main # noqa +main() diff --git a/kata/icon.svg b/kata/icon.svg new file mode 100644 index 0000000..96a5d0c --- /dev/null +++ b/kata/icon.svg @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/kata/layer.yaml b/kata/layer.yaml new file mode 100644 index 0000000..7dfb411 --- /dev/null +++ b/kata/layer.yaml @@ -0,0 +1,20 @@ +"includes": +- "layer:options" +- "layer:basic" +- "layer:debug" +- "interface:container-runtime" +- "interface:untrusted-container-runtime" +- "layer:status" +"exclude": [".travis.yml", "tests", "tox.ini", "test-requirements.txt", "unit_tests"] +"options": + "basic": + "packages": [] + "python_packages": [] + "use_venv": !!bool "true" + "include_system_packages": !!bool "false" + "debug": {} + "status": + "patch-hookenv": !!bool "true" + "kata": {} +"repo": "https://github.com/charmed-kubernetes/charm-kata" +"is": "kata" diff --git a/kata/lib/charms/layer/__init__.py b/kata/lib/charms/layer/__init__.py new file mode 100644 index 0000000..a8e0c64 --- /dev/null +++ b/kata/lib/charms/layer/__init__.py @@ -0,0 +1,60 @@ +import sys +from importlib import import_module +from pathlib import Path + + +def import_layer_libs(): + """ + Ensure that all layer libraries are imported. + + This makes it possible to do the following: + + from charms import layer + + layer.foo.do_foo_thing() + + Note: This function must be called after bootstrap. + """ + for module_file in Path('lib/charms/layer').glob('*'): + module_name = module_file.stem + if module_name in ('__init__', 'basic', 'execd') or not ( + module_file.suffix == '.py' or module_file.is_dir() + ): + continue + import_module('charms.layer.{}'.format(module_name)) + + +# Terrible hack to support the old terrible interface. +# Try to get people to call layer.options.get() instead so +# that we can remove this garbage. +# Cribbed from https://stackoverfLow.com/a/48100440/4941864 +class OptionsBackwardsCompatibilityHack(sys.modules[__name__].__class__): + def __call__(self, section=None, layer_file=None): + if layer_file is None: + return self.get(section=section) + else: + return self.get(section=section, + layer_file=Path(layer_file)) + + +def patch_options_interface(): + from charms.layer import options + if sys.version_info.minor >= 5: + options.__class__ = OptionsBackwardsCompatibilityHack + else: + # Py 3.4 doesn't support changing the __class__, so we have to do it + # another way. The last line is needed because we already have a + # reference that doesn't get updated with sys.modules. + name = options.__name__ + hack = OptionsBackwardsCompatibilityHack(name) + hack.get = options.get + sys.modules[name] = hack + sys.modules[__name__].options = hack + + +try: + patch_options_interface() +except ImportError: + # This may fail if pyyaml hasn't been installed yet. But in that + # case, the bootstrap logic will try it again once it has. + pass diff --git a/kata/lib/charms/layer/basic.py b/kata/lib/charms/layer/basic.py new file mode 100644 index 0000000..bbdd074 --- /dev/null +++ b/kata/lib/charms/layer/basic.py @@ -0,0 +1,501 @@ +import os +import sys +import re +import shutil +from distutils.version import LooseVersion +from pkg_resources import Requirement +from glob import glob +from subprocess import check_call, check_output, CalledProcessError +from time import sleep + +from charms import layer +from charms.layer.execd import execd_preinstall + + +def _get_subprocess_env(): + env = os.environ.copy() + env['LANG'] = env.get('LANG', 'C.UTF-8') + return env + + +def get_series(): + """ + Return series for a few known OS:es. + Tested as of 2019 november: + * centos6, centos7, rhel6. + * bionic + """ + series = "" + + # Looking for content in /etc/os-release + # works for ubuntu + some centos + if os.path.isfile('/etc/os-release'): + d = {} + with open('/etc/os-release', 'r') as rel: + for l in rel: + if not re.match(r'^\s*$', l): + k, v = l.split('=') + d[k.strip()] = v.strip().replace('"', '') + series = "{ID}{VERSION_ID}".format(**d) + + # Looking for content in /etc/redhat-release + # works for redhat enterprise systems + elif os.path.isfile('/etc/redhat-release'): + with open('/etc/redhat-release', 'r') as redhatlsb: + # CentOS Linux release 7.7.1908 (Core) + line = redhatlsb.readline() + release = int(line.split("release")[1].split()[0][0]) + series = "centos" + str(release) + + # Looking for content in /etc/lsb-release + # works for ubuntu + elif os.path.isfile('/etc/lsb-release'): + d = {} + with open('/etc/lsb-release', 'r') as lsb: + for l in lsb: + k, v = l.split('=') + d[k.strip()] = v.strip() + series = d['DISTRIB_CODENAME'] + + # This is what happens if we cant figure out the OS. + else: + series = "unknown" + return series + + +def bootstrap_charm_deps(): + """ + Set up the base charm dependencies so that the reactive system can run. + """ + # execd must happen first, before any attempt to install packages or + # access the network, because sites use this hook to do bespoke + # configuration and install secrets so the rest of this bootstrap + # and the charm itself can actually succeed. This call does nothing + # unless the operator has created and populated $JUJU_CHARM_DIR/exec.d. + execd_preinstall() + # ensure that $JUJU_CHARM_DIR/bin is on the path, for helper scripts + + series = get_series() + + # OMG?! is build-essentials needed? + ubuntu_packages = ['python3-pip', + 'python3-setuptools', + 'python3-yaml', + 'python3-dev', + 'python3-wheel', + 'build-essential'] + + # I'm not going to "yum group info "Development Tools" + # omitting above madness + centos_packages = ['python3-pip', + 'python3-setuptools', + 'python3-devel', + 'python3-wheel'] + + packages_needed = [] + if 'centos' in series: + packages_needed = centos_packages + else: + packages_needed = ubuntu_packages + + charm_dir = os.environ['JUJU_CHARM_DIR'] + os.environ['PATH'] += ':%s' % os.path.join(charm_dir, 'bin') + venv = os.path.abspath('../.venv') + vbin = os.path.join(venv, 'bin') + vpip = os.path.join(vbin, 'pip') + vpy = os.path.join(vbin, 'python') + hook_name = os.path.basename(sys.argv[0]) + is_bootstrapped = os.path.exists('wheelhouse/.bootstrapped') + is_charm_upgrade = hook_name == 'upgrade-charm' + is_series_upgrade = hook_name == 'post-series-upgrade' + is_post_upgrade = os.path.exists('wheelhouse/.upgraded') + is_upgrade = (not is_post_upgrade and + (is_charm_upgrade or is_series_upgrade)) + if is_bootstrapped and not is_upgrade: + # older subordinates might have downgraded charm-env, so we should + # restore it if necessary + install_or_update_charm_env() + activate_venv() + # the .upgrade file prevents us from getting stuck in a loop + # when re-execing to activate the venv; at this point, we've + # activated the venv, so it's safe to clear it + if is_post_upgrade: + os.unlink('wheelhouse/.upgraded') + return + if os.path.exists(venv): + try: + # focal installs or upgrades prior to PR 160 could leave the venv + # in a broken state which would prevent subsequent charm upgrades + _load_installed_versions(vpip) + except CalledProcessError: + is_broken_venv = True + else: + is_broken_venv = False + if is_upgrade or is_broken_venv: + # All upgrades should do a full clear of the venv, rather than + # just updating it, to bring in updates to Python itself + shutil.rmtree(venv) + if is_upgrade: + if os.path.exists('wheelhouse/.bootstrapped'): + os.unlink('wheelhouse/.bootstrapped') + # bootstrap wheelhouse + if os.path.exists('wheelhouse'): + pre_eoan = series in ('ubuntu12.04', 'precise', + 'ubuntu14.04', 'trusty', + 'ubuntu16.04', 'xenial', + 'ubuntu18.04', 'bionic') + pydistutils_lines = [ + "[easy_install]\n", + "find_links = file://{}/wheelhouse/\n".format(charm_dir), + "no_index=True\n", + "index_url=\n", # deliberately nothing here; disables it. + ] + if pre_eoan: + pydistutils_lines.append("allow_hosts = ''\n") + with open('/root/.pydistutils.cfg', 'w') as fp: + # make sure that easy_install also only uses the wheelhouse + # (see https://github.com/pypa/pip/issues/410) + fp.writelines(pydistutils_lines) + if 'centos' in series: + yum_install(packages_needed) + else: + apt_install(packages_needed) + from charms.layer import options + cfg = options.get('basic') + # include packages defined in layer.yaml + if 'centos' in series: + yum_install(cfg.get('packages', [])) + else: + apt_install(cfg.get('packages', [])) + # if we're using a venv, set it up + if cfg.get('use_venv'): + if not os.path.exists(venv): + series = get_series() + if series in ('ubuntu12.04', 'precise', + 'ubuntu14.04', 'trusty'): + apt_install(['python-virtualenv']) + elif 'centos' in series: + yum_install(['python-virtualenv']) + else: + apt_install(['virtualenv']) + cmd = ['virtualenv', '-ppython3', '--never-download', venv] + if cfg.get('include_system_packages'): + cmd.append('--system-site-packages') + check_call(cmd, env=_get_subprocess_env()) + os.environ['PATH'] = ':'.join([vbin, os.environ['PATH']]) + pip = vpip + else: + pip = 'pip3' + # save a copy of system pip to prevent `pip3 install -U pip` + # from changing it + if os.path.exists('/usr/bin/pip'): + shutil.copy2('/usr/bin/pip', '/usr/bin/pip.save') + pre_install_pkgs = ['pip', 'setuptools', 'setuptools-scm'] + # we bundle these packages to work around bugs in older versions (such + # as https://github.com/pypa/pip/issues/56), but if the system already + # provided a newer version, downgrading it can cause other problems + _update_if_newer(pip, pre_install_pkgs) + # install the rest of the wheelhouse deps (extract the pkg names into + # a set so that we can ignore the pre-install packages and let pip + # choose the best version in case there are multiple from layer + # conflicts) + _versions = _load_wheelhouse_versions() + _pkgs = _versions.keys() - set(pre_install_pkgs) + # add back the versions such that each package in pkgs is + # ==. + # This ensures that pip 20.3.4+ will install the packages from the + # wheelhouse without (erroneously) flagging an error. + pkgs = _add_back_versions(_pkgs, _versions) + reinstall_flag = '--force-reinstall' + if not cfg.get('use_venv', True) and pre_eoan: + reinstall_flag = '--ignore-installed' + check_call([pip, 'install', '-U', reinstall_flag, '--no-index', + '--no-cache-dir', '-f', 'wheelhouse'] + list(pkgs), + env=_get_subprocess_env()) + # re-enable installation from pypi + os.remove('/root/.pydistutils.cfg') + + # install pyyaml for centos7, since, unlike the ubuntu image, the + # default image for centos doesn't include pyyaml; see the discussion: + # https://discourse.jujucharms.com/t/charms-for-centos-lets-begin + if 'centos' in series: + check_call([pip, 'install', '-U', 'pyyaml'], + env=_get_subprocess_env()) + + # install python packages from layer options + if cfg.get('python_packages'): + check_call([pip, 'install', '-U'] + cfg.get('python_packages'), + env=_get_subprocess_env()) + if not cfg.get('use_venv'): + # restore system pip to prevent `pip3 install -U pip` + # from changing it + if os.path.exists('/usr/bin/pip.save'): + shutil.copy2('/usr/bin/pip.save', '/usr/bin/pip') + os.remove('/usr/bin/pip.save') + # setup wrappers to ensure envs are used for scripts + install_or_update_charm_env() + for wrapper in ('charms.reactive', 'charms.reactive.sh', + 'chlp', 'layer_option'): + src = os.path.join('/usr/local/sbin', 'charm-env') + dst = os.path.join('/usr/local/sbin', wrapper) + if not os.path.exists(dst): + os.symlink(src, dst) + if cfg.get('use_venv'): + shutil.copy2('bin/layer_option', vbin) + else: + shutil.copy2('bin/layer_option', '/usr/local/bin/') + # re-link the charm copy to the wrapper in case charms + # call bin/layer_option directly (as was the old pattern) + os.remove('bin/layer_option') + os.symlink('/usr/local/sbin/layer_option', 'bin/layer_option') + # flag us as having already bootstrapped so we don't do it again + open('wheelhouse/.bootstrapped', 'w').close() + if is_upgrade: + # flag us as having already upgraded so we don't do it again + open('wheelhouse/.upgraded', 'w').close() + # Ensure that the newly bootstrapped libs are available. + # Note: this only seems to be an issue with namespace packages. + # Non-namespace-package libs (e.g., charmhelpers) are available + # without having to reload the interpreter. :/ + reload_interpreter(vpy if cfg.get('use_venv') else sys.argv[0]) + + +def _load_installed_versions(pip): + pip_freeze = check_output([pip, 'freeze']).decode('utf8') + versions = {} + for pkg_ver in pip_freeze.splitlines(): + try: + req = Requirement.parse(pkg_ver) + except ValueError: + continue + versions.update({ + req.project_name: LooseVersion(ver) + for op, ver in req.specs if op == '==' + }) + return versions + + +def _load_wheelhouse_versions(): + versions = {} + for wheel in glob('wheelhouse/*'): + pkg, ver = os.path.basename(wheel).rsplit('-', 1) + # nb: LooseVersion ignores the file extension + versions[pkg.replace('_', '-')] = LooseVersion(ver) + return versions + + +def _add_back_versions(pkgs, versions): + """Add back the version strings to each of the packages. + + The versions are LooseVersion() from _load_wheelhouse_versions(). This + function strips the ".zip" or ".tar.gz" from the end of the version string + and adds it back to the package in the form of == + + If a package name is not a key in the versions dictionary, then it is + returned in the list unchanged. + + :param pkgs: A list of package names + :type pkgs: List[str] + :param versions: A map of package to LooseVersion + :type versions: Dict[str, LooseVersion] + :returns: A list of (maybe) versioned packages + :rtype: List[str] + """ + def _strip_ext(s): + """Strip an extension (if it exists) from the string + + :param s: the string to strip an extension off if it exists + :type s: str + :returns: string without an extension of .zip or .tar.gz + :rtype: str + """ + for ending in [".zip", ".tar.gz"]: + if s.endswith(ending): + return s[:-len(ending)] + return s + + def _maybe_add_version(pkg): + """Maybe add back the version number to a package if it exists. + + Adds the version number, if the package exists in the lexically + captured `versions` dictionary, in the form ==. Strips + the extension if it exists. + + :param pkg: the package name to (maybe) add the version number to. + :type pkg: str + """ + try: + return "{}=={}".format(pkg, _strip_ext(str(versions[pkg]))) + except KeyError: + pass + return pkg + + return [_maybe_add_version(pkg) for pkg in pkgs] + + +def _update_if_newer(pip, pkgs): + installed = _load_installed_versions(pip) + wheelhouse = _load_wheelhouse_versions() + for pkg in pkgs: + if pkg not in installed or wheelhouse[pkg] > installed[pkg]: + check_call([pip, 'install', '-U', '--no-index', '-f', 'wheelhouse', + pkg], env=_get_subprocess_env()) + + +def install_or_update_charm_env(): + # On Trusty python3-pkg-resources is not installed + try: + from pkg_resources import parse_version + except ImportError: + apt_install(['python3-pkg-resources']) + from pkg_resources import parse_version + + try: + installed_version = parse_version( + check_output(['/usr/local/sbin/charm-env', + '--version']).decode('utf8')) + except (CalledProcessError, FileNotFoundError): + installed_version = parse_version('0.0.0') + try: + bundled_version = parse_version( + check_output(['bin/charm-env', + '--version']).decode('utf8')) + except (CalledProcessError, FileNotFoundError): + bundled_version = parse_version('0.0.0') + if installed_version < bundled_version: + shutil.copy2('bin/charm-env', '/usr/local/sbin/') + + +def activate_venv(): + """ + Activate the venv if enabled in ``layer.yaml``. + + This is handled automatically for normal hooks, but actions might + need to invoke this manually, using something like: + + # Load modules from $JUJU_CHARM_DIR/lib + import sys + sys.path.append('lib') + + from charms.layer.basic import activate_venv + activate_venv() + + This will ensure that modules installed in the charm's + virtual environment are available to the action. + """ + from charms.layer import options + venv = os.path.abspath('../.venv') + vbin = os.path.join(venv, 'bin') + vpy = os.path.join(vbin, 'python') + use_venv = options.get('basic', 'use_venv') + if use_venv and '.venv' not in sys.executable: + # activate the venv + os.environ['PATH'] = ':'.join([vbin, os.environ['PATH']]) + reload_interpreter(vpy) + layer.patch_options_interface() + layer.import_layer_libs() + + +def reload_interpreter(python): + """ + Reload the python interpreter to ensure that all deps are available. + + Newly installed modules in namespace packages sometimes seemt to + not be picked up by Python 3. + """ + os.execve(python, [python] + list(sys.argv), os.environ) + + +def apt_install(packages): + """ + Install apt packages. + + This ensures a consistent set of options that are often missed but + should really be set. + """ + if isinstance(packages, (str, bytes)): + packages = [packages] + + env = _get_subprocess_env() + + if 'DEBIAN_FRONTEND' not in env: + env['DEBIAN_FRONTEND'] = 'noninteractive' + + cmd = ['apt-get', + '--option=Dpkg::Options::=--force-confold', + '--assume-yes', + 'install'] + for attempt in range(3): + try: + check_call(cmd + packages, env=env) + except CalledProcessError: + if attempt == 2: # third attempt + raise + try: + # sometimes apt-get update needs to be run + check_call(['apt-get', 'update'], env=env) + except CalledProcessError: + # sometimes it's a dpkg lock issue + pass + sleep(5) + else: + break + + +def yum_install(packages): + """ Installs packages with yum. + This function largely mimics the apt_install function for consistency. + """ + if packages: + env = os.environ.copy() + cmd = ['yum', '-y', 'install'] + for attempt in range(3): + try: + check_call(cmd + packages, env=env) + except CalledProcessError: + if attempt == 2: + raise + try: + check_call(['yum', 'update'], env=env) + except CalledProcessError: + pass + sleep(5) + else: + break + else: + pass + + +def init_config_states(): + import yaml + from charmhelpers.core import hookenv + from charms.reactive import set_state + from charms.reactive import toggle_state + config = hookenv.config() + config_defaults = {} + config_defs = {} + config_yaml = os.path.join(hookenv.charm_dir(), 'config.yaml') + if os.path.exists(config_yaml): + with open(config_yaml) as fp: + config_defs = yaml.safe_load(fp).get('options', {}) + config_defaults = {key: value.get('default') + for key, value in config_defs.items()} + for opt in config_defs.keys(): + if config.changed(opt): + set_state('config.changed') + set_state('config.changed.{}'.format(opt)) + toggle_state('config.set.{}'.format(opt), config.get(opt)) + toggle_state('config.default.{}'.format(opt), + config.get(opt) == config_defaults[opt]) + + +def clear_config_states(): + from charmhelpers.core import hookenv, unitdata + from charms.reactive import remove_state + config = hookenv.config() + remove_state('config.changed') + for opt in config.keys(): + remove_state('config.changed.{}'.format(opt)) + remove_state('config.set.{}'.format(opt)) + remove_state('config.default.{}'.format(opt)) + unitdata.kv().flush() diff --git a/kata/lib/charms/layer/execd.py b/kata/lib/charms/layer/execd.py new file mode 100644 index 0000000..438d9a1 --- /dev/null +++ b/kata/lib/charms/layer/execd.py @@ -0,0 +1,114 @@ +# Copyright 2014-2016 Canonical Limited. +# +# This file is part of layer-basic, the reactive base layer for Juju. +# +# charm-helpers is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 as +# published by the Free Software Foundation. +# +# charm-helpers is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with charm-helpers. If not, see . + +# This module may only import from the Python standard library. +import os +import sys +import subprocess +import time + +''' +execd/preinstall + +Read the layer-basic docs for more info on how to use this feature. +https://charmsreactive.readthedocs.io/en/latest/layer-basic.html#exec-d-support +''' + + +def default_execd_dir(): + return os.path.join(os.environ['JUJU_CHARM_DIR'], 'exec.d') + + +def execd_module_paths(execd_dir=None): + """Generate a list of full paths to modules within execd_dir.""" + if not execd_dir: + execd_dir = default_execd_dir() + + if not os.path.exists(execd_dir): + return + + for subpath in os.listdir(execd_dir): + module = os.path.join(execd_dir, subpath) + if os.path.isdir(module): + yield module + + +def execd_submodule_paths(command, execd_dir=None): + """Generate a list of full paths to the specified command within exec_dir. + """ + for module_path in execd_module_paths(execd_dir): + path = os.path.join(module_path, command) + if os.access(path, os.X_OK) and os.path.isfile(path): + yield path + + +def execd_sentinel_path(submodule_path): + module_path = os.path.dirname(submodule_path) + execd_path = os.path.dirname(module_path) + module_name = os.path.basename(module_path) + submodule_name = os.path.basename(submodule_path) + return os.path.join(execd_path, + '.{}_{}.done'.format(module_name, submodule_name)) + + +def execd_run(command, execd_dir=None, stop_on_error=True, stderr=None): + """Run command for each module within execd_dir which defines it.""" + if stderr is None: + stderr = sys.stdout + for submodule_path in execd_submodule_paths(command, execd_dir): + # Only run each execd once. We cannot simply run them in the + # install hook, as potentially storage hooks are run before that. + # We cannot rely on them being idempotent. + sentinel = execd_sentinel_path(submodule_path) + if os.path.exists(sentinel): + continue + + try: + subprocess.check_call([submodule_path], stderr=stderr, + universal_newlines=True) + with open(sentinel, 'w') as f: + f.write('{} ran successfully {}\n'.format(submodule_path, + time.ctime())) + f.write('Removing this file will cause it to be run again\n') + except subprocess.CalledProcessError as e: + # Logs get the details. We can't use juju-log, as the + # output may be substantial and exceed command line + # length limits. + print("ERROR ({}) running {}".format(e.returncode, e.cmd), + file=stderr) + print("STDOUT<" +"description": | + Kata Containers is an open source community working to build a secure + container runtime with lightweight virtual machines that feel and perform + like containers, but provide stronger workload isolation using hardware + virtualization technology as a second layer of defense. +"tags": +- "misc" +- "containers" +"series": +- "focal" +- "bionic" +"requires": + "containerd": + "interface": "container-runtime" + "scope": "container" + "untrusted": + "interface": "untrusted-container-runtime" + "scope": "container" +"resources": + "kata-archive": + "type": "file" + "filename": "kata-archive.tar.gz" + "description": "Offline archive of kata" + +"subordinate": !!bool "true" diff --git a/kata/pydocmd.yml b/kata/pydocmd.yml new file mode 100644 index 0000000..ab3b2ef --- /dev/null +++ b/kata/pydocmd.yml @@ -0,0 +1,16 @@ +site_name: 'Status Management Layer' + +generate: + - status.md: + - charms.layer.status.WorkloadState + - charms.layer.status.maintenance + - charms.layer.status.maint + - charms.layer.status.blocked + - charms.layer.status.waiting + - charms.layer.status.active + - charms.layer.status.status_set + +pages: + - Status Management Layer: status.md + +gens_dir: docs diff --git a/kata/reactive/__init__.py b/kata/reactive/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kata/reactive/kata.py b/kata/reactive/kata.py new file mode 100644 index 0000000..e11c45f --- /dev/null +++ b/kata/reactive/kata.py @@ -0,0 +1,136 @@ +import os +import requests + +from subprocess import ( + check_call, + check_output +) + +from charmhelpers.core import host + +from charms.reactive import ( + when, + when_not, + set_state, + remove_state, + endpoint_from_flag, + hook, +) + +from charmhelpers.fetch import ( + apt_install, + apt_update, + apt_purge, + apt_autoremove, + import_key +) + +from charmhelpers.core.hookenv import ( + resource_get +) + +from charms.layer import status + + +KATA_PACKAGES = [ + 'kata-runtime', + 'kata-proxy', + 'kata-shim' +] + + +@when_not('kata.installed') +@when_not('endpoint.untrusted.departed') +def install_kata(): + """ + Install the Kata container runtime. + + :returns: None + """ + dist = host.lsb_release() + release = '{}_{}'.format( + dist['DISTRIB_ID'], + dist['DISTRIB_RELEASE'] + ) + + arch = check_output(['arch']).decode().strip() + + archive = resource_get('kata-archive') + + if not archive or os.path.getsize(archive) == 0: + status.maintenance('Installing Kata via apt') + gpg_key = requests.get( + 'http://download.opensuse.org/repositories/home:/katacontainers:/' + 'releases:/{}:/master/x{}/Release.key'.format(arch, release)).text + import_key(gpg_key) + + with open('/etc/apt/sources.list.d/kata-containers.list', 'w') as f: + f.write( + 'deb http://download.opensuse.org/repositories/home:/' + 'katacontainers:/releases:/{}:/master/x{}/ /' + .format(arch, release) + ) + + apt_update() + apt_install(KATA_PACKAGES) + + else: + status.maintenance('Installing Kata via resource') + unpack = '/tmp/kata-debs' + + if not os.path.isdir(unpack): + os.makedirs(unpack, exist_ok=True) + + check_call(['tar', '-xvf', archive, '-C', unpack]) + check_call('apt-get install -y {}/*.deb'.format(unpack), shell=True) + + status.active('Kata runtime available') + set_state('kata.installed') + + +@when('endpoint.untrusted.departed') +def purge_kata(): + """ + Purge Kata containers. + + :return: None + """ + status.maintenance('Purging Kata') + + apt_purge(KATA_PACKAGES, fatal=False) + + source = '/etc/apt/sources.list.d/kata-containers.list' + if os.path.isfile(source): + os.remove(source) + + apt_autoremove() + + remove_state('kata.installed') + + +@when('kata.installed') +@when('endpoint.untrusted.joined') +@when_not('endpoint.untrusted.departed') +def publish_config(): + """ + Pass configuration over the interface. + + :return: None + """ + endpoint = endpoint_from_flag('endpoint.untrusted.joined') + endpoint.set_config( + name='kata', + binary_path='/usr/bin/kata-runtime' + ) + + +@hook('pre-series-upgrade') +def pre_series_upgrade(): + """Set status during series upgrade.""" + status.blocked('Series upgrade in progress') + + +@hook('post-series-upgrade') +def post_series_upgrade(): + """Reset status to active after series upgrade.""" + status.active('Kata runtime available') diff --git a/kata/reactive/status.py b/kata/reactive/status.py new file mode 100644 index 0000000..2f33f3f --- /dev/null +++ b/kata/reactive/status.py @@ -0,0 +1,4 @@ +from charms import layer + + +layer.status._initialize() diff --git a/kata/requirements.txt b/kata/requirements.txt new file mode 100644 index 0000000..55543d9 --- /dev/null +++ b/kata/requirements.txt @@ -0,0 +1,3 @@ +mock +flake8 +pytest diff --git a/kata/revision b/kata/revision new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/kata/revision @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/kata/tests/conftest.py b/kata/tests/conftest.py new file mode 100644 index 0000000..a92e249 --- /dev/null +++ b/kata/tests/conftest.py @@ -0,0 +1,4 @@ +import charms.unit_test + + +charms.unit_test.patch_reactive() diff --git a/kata/tests/test_kata_reactive.py b/kata/tests/test_kata_reactive.py new file mode 100644 index 0000000..421b0dd --- /dev/null +++ b/kata/tests/test_kata_reactive.py @@ -0,0 +1,35 @@ +from reactive import kata + + +def test_packages_list(): + """Assert KATA_PACKAGES is a list of strings.""" + assert isinstance(kata.KATA_PACKAGES, list) + for item in kata.KATA_PACKAGES: + assert isinstance(item, str) + + +def test_install_kata(): + """Assert install_kata is a method.""" + assert callable(kata.install_kata) + + +def test_purge_kata(): + """Assert purge_kata is a method.""" + assert callable(kata.purge_kata) + + +def test_publist_config(): + """Assert publish_config is a method.""" + assert callable(kata.publish_config) + + +def test_series_upgrade(): + """Assert status is set during series upgrade.""" + assert kata.status.blocked.call_count == 0 + assert kata.status.active.call_count == 0 + kata.pre_series_upgrade() + assert kata.status.blocked.call_count == 1 + assert kata.status.active.call_count == 0 + kata.post_series_upgrade() + assert kata.status.blocked.call_count == 1 + assert kata.status.active.call_count == 1 diff --git a/kata/tox.ini b/kata/tox.ini new file mode 100644 index 0000000..0c9eaec --- /dev/null +++ b/kata/tox.ini @@ -0,0 +1,34 @@ +[flake8] +max-line-length = 120 +ignore = D100 + +[tox] +skipsdist = True +envlist = lint,py3 + +[tox:travis] +3.5: lint,py3 +3.6: lint, py3 +3.7: lint, py3 +3.8: lint, py3 + +[testenv] +basepython = python3 +setenv = + PYTHONPATH={toxinidir} +deps = + pyyaml + pytest + pytest-cov + flake8 + flake8-docstrings + requests + git+https://github.com/juju-solutions/charms.unit_test/#egg=charms.unit_test +commands = + pytest --cov-report term-missing \ + --cov reactive.kata --cov-fail-under 30 \ + --tb native -s {posargs} + +[testenv:lint] +envdir = {toxworkdir}/py3 +commands = flake8 {toxinidir}/reactive {toxinidir}/tests diff --git a/kata/version b/kata/version new file mode 100644 index 0000000..20817dd --- /dev/null +++ b/kata/version @@ -0,0 +1 @@ +ccfa68be \ No newline at end of file diff --git a/kata/wheelhouse.txt b/kata/wheelhouse.txt new file mode 100644 index 0000000..4413da7 --- /dev/null +++ b/kata/wheelhouse.txt @@ -0,0 +1,21 @@ +# layer:basic +# pip is pinned to <19.0 to avoid https://github.com/pypa/pip/issues/6164 +# even with installing setuptools before upgrading pip ends up with pip seeing +# the older setuptools at the system level if include_system_packages is true +pip>=18.1,<19.0 +# pin Jinja2, PyYAML and MarkupSafe to the last versions supporting python 3.5 +# for trusty +Jinja2<=2.10.1 +PyYAML<=5.2 +MarkupSafe<2.0.0 +setuptools<42 +setuptools-scm<=1.17.0 +charmhelpers>=0.4.0,<1.0.0 +charms.reactive>=0.1.0,<2.0.0 +wheel<0.34 +# pin netaddr to avoid pulling importlib-resources +netaddr<=0.7.19 + +# kata +requests + diff --git a/kata/wheelhouse/Jinja2-2.10.1.tar.gz b/kata/wheelhouse/Jinja2-2.10.1.tar.gz new file mode 100644 index 0000000..ffd1054 Binary files /dev/null and b/kata/wheelhouse/Jinja2-2.10.1.tar.gz differ diff --git a/kata/wheelhouse/MarkupSafe-1.1.1.tar.gz b/kata/wheelhouse/MarkupSafe-1.1.1.tar.gz new file mode 100644 index 0000000..a6dad8e Binary files /dev/null and b/kata/wheelhouse/MarkupSafe-1.1.1.tar.gz differ diff --git a/kata/wheelhouse/PyYAML-5.2.tar.gz b/kata/wheelhouse/PyYAML-5.2.tar.gz new file mode 100644 index 0000000..666d12a Binary files /dev/null and b/kata/wheelhouse/PyYAML-5.2.tar.gz differ diff --git a/kata/wheelhouse/Tempita-0.5.2.tar.gz b/kata/wheelhouse/Tempita-0.5.2.tar.gz new file mode 100644 index 0000000..755befc Binary files /dev/null and b/kata/wheelhouse/Tempita-0.5.2.tar.gz differ diff --git a/kata/wheelhouse/certifi-2021.10.8.tar.gz b/kata/wheelhouse/certifi-2021.10.8.tar.gz new file mode 100644 index 0000000..9e1581b Binary files /dev/null and b/kata/wheelhouse/certifi-2021.10.8.tar.gz differ diff --git a/kata/wheelhouse/charmhelpers-0.20.23.tar.gz b/kata/wheelhouse/charmhelpers-0.20.23.tar.gz new file mode 100644 index 0000000..8fbc8ec Binary files /dev/null and b/kata/wheelhouse/charmhelpers-0.20.23.tar.gz differ diff --git a/kata/wheelhouse/charms.reactive-1.4.1.tar.gz b/kata/wheelhouse/charms.reactive-1.4.1.tar.gz new file mode 100644 index 0000000..03bc1fe Binary files /dev/null and b/kata/wheelhouse/charms.reactive-1.4.1.tar.gz differ diff --git a/kata/wheelhouse/charset-normalizer-2.0.7.tar.gz b/kata/wheelhouse/charset-normalizer-2.0.7.tar.gz new file mode 100644 index 0000000..61df022 Binary files /dev/null and b/kata/wheelhouse/charset-normalizer-2.0.7.tar.gz differ diff --git a/kata/wheelhouse/idna-3.3.tar.gz b/kata/wheelhouse/idna-3.3.tar.gz new file mode 100644 index 0000000..ff2bcbf Binary files /dev/null and b/kata/wheelhouse/idna-3.3.tar.gz differ diff --git a/kata/wheelhouse/netaddr-0.7.19.tar.gz b/kata/wheelhouse/netaddr-0.7.19.tar.gz new file mode 100644 index 0000000..cc31d9d Binary files /dev/null and b/kata/wheelhouse/netaddr-0.7.19.tar.gz differ diff --git a/kata/wheelhouse/pbr-5.6.0.tar.gz b/kata/wheelhouse/pbr-5.6.0.tar.gz new file mode 100644 index 0000000..0d5c965 Binary files /dev/null and b/kata/wheelhouse/pbr-5.6.0.tar.gz differ diff --git a/kata/wheelhouse/pip-18.1.tar.gz b/kata/wheelhouse/pip-18.1.tar.gz new file mode 100644 index 0000000..a18192d Binary files /dev/null and b/kata/wheelhouse/pip-18.1.tar.gz differ diff --git a/kata/wheelhouse/pyaml-21.10.1.tar.gz b/kata/wheelhouse/pyaml-21.10.1.tar.gz new file mode 100644 index 0000000..b19aad3 Binary files /dev/null and b/kata/wheelhouse/pyaml-21.10.1.tar.gz differ diff --git a/kata/wheelhouse/requests-2.26.0.tar.gz b/kata/wheelhouse/requests-2.26.0.tar.gz new file mode 100644 index 0000000..101dc79 Binary files /dev/null and b/kata/wheelhouse/requests-2.26.0.tar.gz differ diff --git a/kata/wheelhouse/setuptools-41.6.0.zip b/kata/wheelhouse/setuptools-41.6.0.zip new file mode 100644 index 0000000..3345759 Binary files /dev/null and b/kata/wheelhouse/setuptools-41.6.0.zip differ diff --git a/kata/wheelhouse/setuptools_scm-1.17.0.tar.gz b/kata/wheelhouse/setuptools_scm-1.17.0.tar.gz new file mode 100644 index 0000000..43b16c7 Binary files /dev/null and b/kata/wheelhouse/setuptools_scm-1.17.0.tar.gz differ diff --git a/kata/wheelhouse/six-1.16.0.tar.gz b/kata/wheelhouse/six-1.16.0.tar.gz new file mode 100644 index 0000000..5bf3a27 Binary files /dev/null and b/kata/wheelhouse/six-1.16.0.tar.gz differ diff --git a/kata/wheelhouse/urllib3-1.26.7.tar.gz b/kata/wheelhouse/urllib3-1.26.7.tar.gz new file mode 100644 index 0000000..990abe6 Binary files /dev/null and b/kata/wheelhouse/urllib3-1.26.7.tar.gz differ diff --git a/kata/wheelhouse/wheel-0.33.6.tar.gz b/kata/wheelhouse/wheel-0.33.6.tar.gz new file mode 100644 index 0000000..c922c4e Binary files /dev/null and b/kata/wheelhouse/wheel-0.33.6.tar.gz differ diff --git a/kubernetes-master/cni-amd64.tar.gz b/kubernetes-master/cni-amd64.tar.gz deleted file mode 100644 index d144b41..0000000 Binary files a/kubernetes-master/cni-amd64.tar.gz and /dev/null differ diff --git a/kubernetes-master/cni-arm64.tar.gz b/kubernetes-master/cni-arm64.tar.gz deleted file mode 100644 index 3d3844c..0000000 Binary files a/kubernetes-master/cni-arm64.tar.gz and /dev/null differ diff --git a/kubernetes-master/cni-s390x.tar.gz b/kubernetes-master/cni-s390x.tar.gz deleted file mode 100644 index 5607993..0000000 Binary files a/kubernetes-master/cni-s390x.tar.gz and /dev/null differ