diff --git a/examples/deployment_create.py b/examples/deployment_create.py index ba13440ff8..e17af3b5c9 100644 --- a/examples/deployment_create.py +++ b/examples/deployment_create.py @@ -12,6 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +""" +Creates a deployment using AppsV1Api from file nginx-deployment.yaml. +""" + from os import path import yaml diff --git a/examples/dynamic-client/cluster_scoped_custom_resource.py b/examples/dynamic-client/cluster_scoped_custom_resource.py new file mode 100644 index 0000000000..532a763619 --- /dev/null +++ b/examples/dynamic-client/cluster_scoped_custom_resource.py @@ -0,0 +1,213 @@ +# Copyright 2021 The Kubernetes Authors. +# +# 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. + +""" +This example demonstrates the following: + - Creation of a custom resource definition (CRD) using dynamic-client + - Creation of cluster scoped custom resources (CR) using the above created CRD + - List, patch (update), delete the custom resources + - Delete the custom resource defintion (CRD) +""" + +from kubernetes import config, dynamic +from kubernetes.dynamic.exceptions import ResourceNotFoundError +from kubernetes.client import api_client +import time + + +def main(): + # Creating a dynamic client + client = dynamic.DynamicClient( + api_client.ApiClient(configuration=config.load_kube_config()) + ) + + # fetching the custom resource definition (CRD) api + crd_api = client.resources.get( + api_version="apiextensions.k8s.io/v1", kind="CustomResourceDefinition" + ) + + # Creating a Namespaced CRD named "ingressroutes.apps.example.com" + name = "ingressroutes.apps.example.com" + + crd_manifest = { + "apiVersion": "apiextensions.k8s.io/v1", + "kind": "CustomResourceDefinition", + "metadata": { + "name": name, + }, + "spec": { + "group": "apps.example.com", + "versions": [ + { + "name": "v1", + "schema": { + "openAPIV3Schema": { + "properties": { + "spec": { + "properties": { + "strategy": {"type": "string"}, + "virtualhost": { + "properties": { + "fqdn": {"type": "string"}, + "tls": { + "properties": { + "secretName": {"type": "string"} + }, + "type": "object", + }, + }, + "type": "object", + }, + }, + "type": "object", + } + }, + "type": "object", + } + }, + "served": True, + "storage": True, + } + ], + "scope": "Cluster", + "names": { + "plural": "ingressroutes", + "listKind": "IngressRouteList", + "singular": "ingressroute", + "kind": "IngressRoute", + "shortNames": ["ir"], + }, + }, + } + + crd_creation_response = crd_api.create(crd_manifest) + print( + "\n[INFO] custom resource definition `ingressroutes.apps.example.com` created\n" + ) + print("%s\t\t%s" % ("SCOPE", "NAME")) + print( + "%s\t\t%s\n" + % (crd_creation_response.spec.scope, crd_creation_response.metadata.name) + ) + + # Fetching the "ingressroutes" CRD api + + try: + ingressroute_api = client.resources.get( + api_version="apps.example.com/v1", kind="IngressRoute" + ) + except ResourceNotFoundError: + # Need to wait a sec for the discovery layer to get updated + time.sleep(2) + + ingressroute_api = client.resources.get( + api_version="apps.example.com/v1", kind="IngressRoute" + ) + + # Creating a custom resource (CR) `ingress-route-*`, using the above CRD `ingressroutes.apps.example.com` + + ingressroute_manifest_first = { + "apiVersion": "apps.example.com/v1", + "kind": "IngressRoute", + "metadata": { + "name": "ingress-route-first", + }, + "spec": { + "virtualhost": { + "fqdn": "www.google.com", + "tls": {"secretName": "google-tls"}, + }, + "strategy": "RoundRobin", + }, + } + + ingressroute_manifest_second = { + "apiVersion": "apps.example.com/v1", + "kind": "IngressRoute", + "metadata": { + "name": "ingress-route-second", + }, + "spec": { + "virtualhost": { + "fqdn": "www.yahoo.com", + "tls": {"secretName": "yahoo-tls"}, + }, + "strategy": "RoundRobin", + }, + } + + ingressroute_api.create(body=ingressroute_manifest_first) + ingressroute_api.create(body=ingressroute_manifest_second) + print("\n[INFO] custom resources `ingress-route-*` created\n") + + # Listing the `ingress-route-*` custom resources + + ingress_routes_list = ingressroute_api.get() + print("%s\t\t\t%s\t\t%s\t\t\t\t%s" % ("NAME", "FQDN", "TLS", "STRATEGY")) + for item in ingress_routes_list.items: + print( + "%s\t%s\t%s\t%s" + % ( + item.metadata.name, + item.spec.virtualhost.fqdn, + item.spec.virtualhost.tls, + item.spec.strategy, + ) + ) + + # Patching the ingressroutes custom resources + + ingressroute_manifest_first["spec"]["strategy"] = "Random" + ingressroute_manifest_second["spec"]["strategy"] = "WeightedLeastRequest" + + patch_ingressroute_first = ingressroute_api.patch( + body=ingressroute_manifest_first, content_type="application/merge-patch+json" + ) + patch_ingressroute_second = ingressroute_api.patch( + body=ingressroute_manifest_second, content_type="application/merge-patch+json" + ) + + print( + "\n[INFO] custom resources `ingress-route-*` patched to update the strategy\n" + ) + patched_ingress_routes_list = ingressroute_api.get() + print("%s\t\t\t%s\t\t%s\t\t\t\t%s" % ("NAME", "FQDN", "TLS", "STRATEGY")) + for item in patched_ingress_routes_list.items: + print( + "%s\t%s\t%s\t%s" + % ( + item.metadata.name, + item.spec.virtualhost.fqdn, + item.spec.virtualhost.tls, + item.spec.strategy, + ) + ) + + # Deleting the ingressroutes custom resources + + delete_ingressroute_first = ingressroute_api.delete(name="ingress-route-first") + delete_ingressroute_second = ingressroute_api.delete(name="ingress-route-second") + + print("\n[INFO] custom resources `ingress-route-*` deleted") + + # Deleting the ingressroutes.apps.example.com custom resource definition + + crd_api.delete(name=name) + print( + "\n[INFO] custom resource definition `ingressroutes.apps.example.com` deleted" + ) + + +if __name__ == "__main__": + main() diff --git a/examples/dynamic-client/configmap.py b/examples/dynamic-client/configmap.py new file mode 100644 index 0000000000..15094df6be --- /dev/null +++ b/examples/dynamic-client/configmap.py @@ -0,0 +1,85 @@ +# Copyright 2021 The Kubernetes Authors. +# +# 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. + +""" +This example demonstrates the following: + - Creation of a k8s configmap using dynamic-client + - List, patch(update), delete the configmap +""" + +from kubernetes import config, dynamic +from kubernetes.client import api_client + + +def main(): + # Creating a dynamic client + client = dynamic.DynamicClient( + api_client.ApiClient(configuration=config.load_kube_config()) + ) + + # fetching the configmap api + api = client.resources.get(api_version="v1", kind="ConfigMap") + + configmap_name = "test-configmap" + + configmap_manifest = { + "kind": "ConfigMap", + "apiVersion": "v1", + "metadata": { + "name": configmap_name, + "labels": { + "foo": "bar", + }, + }, + "data": { + "config.json": '{"command":"/usr/bin/mysqld_safe"}', + "frontend.cnf": "[mysqld]\nbind-address = 10.0.0.3\n", + }, + } + + # Creating configmap `test-configmap` in the `default` namespace + + configmap = api.create(body=configmap_manifest, namespace="default") + + print("\n[INFO] configmap `test-configmap` created\n") + + # Listing the configmaps in the `default` namespace + + configmap_list = api.get( + name=configmap_name, namespace="default", label_selector="foo=bar" + ) + + print("NAME:\n%s\n" % (configmap_list.metadata.name)) + print("DATA:\n%s\n" % (configmap_list.data)) + + # Updating the configmap's data, `config.json` + + configmap_manifest["data"]["config.json"] = "{}" + + configmap_patched = api.patch( + name=configmap_name, namespace="default", body=configmap_manifest + ) + + print("\n[INFO] configmap `test-configmap` patched\n") + print("NAME:\n%s\n" % (configmap_patched.metadata.name)) + print("DATA:\n%s\n" % (configmap_patched.data)) + + # Deleting configmap `test-configmap` from the `default` namespace + + configmap_deleted = api.delete(name=configmap_name, body={}, namespace="default") + print("\n[INFO] configmap `test-configmap` deleted\n") + + +if __name__ == "__main__": + main() diff --git a/examples/dynamic-client/namespaced_custom_resource.py b/examples/dynamic-client/namespaced_custom_resource.py new file mode 100644 index 0000000000..3c0a40e0f6 --- /dev/null +++ b/examples/dynamic-client/namespaced_custom_resource.py @@ -0,0 +1,225 @@ +# Copyright 2021 The Kubernetes Authors. +# +# 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. + +""" +This example demonstrates the following: + - Creation of a custom resource definition (CRD) using dynamic-client + - Creation of namespaced custom resources (CR) using the above CRD + - List, patch (update), delete the custom resources + - Delete the custom resource defintion (CRD) +""" + +from kubernetes import config, dynamic +from kubernetes.dynamic.exceptions import ResourceNotFoundError +from kubernetes.client import api_client +import time + + +def main(): + # Creating a dynamic client + client = dynamic.DynamicClient( + api_client.ApiClient(configuration=config.load_kube_config()) + ) + + # fetching the custom resource definition (CRD) api + crd_api = client.resources.get( + api_version="apiextensions.k8s.io/v1", kind="CustomResourceDefinition" + ) + + # Creating a Namespaced CRD named "ingressroutes.apps.example.com" + name = "ingressroutes.apps.example.com" + + crd_manifest = { + "apiVersion": "apiextensions.k8s.io/v1", + "kind": "CustomResourceDefinition", + "metadata": {"name": name, "namespace": "default"}, + "spec": { + "group": "apps.example.com", + "versions": [ + { + "name": "v1", + "schema": { + "openAPIV3Schema": { + "properties": { + "spec": { + "properties": { + "strategy": {"type": "string"}, + "virtualhost": { + "properties": { + "fqdn": {"type": "string"}, + "tls": { + "properties": { + "secretName": {"type": "string"} + }, + "type": "object", + }, + }, + "type": "object", + }, + }, + "type": "object", + } + }, + "type": "object", + } + }, + "served": True, + "storage": True, + } + ], + "scope": "Namespaced", + "names": { + "plural": "ingressroutes", + "listKind": "IngressRouteList", + "singular": "ingressroute", + "kind": "IngressRoute", + "shortNames": ["ir"], + }, + }, + } + + crd_creation_respone = crd_api.create(crd_manifest) + print( + "\n[INFO] custom resource definition `ingressroutes.apps.example.com` created\n" + ) + print("%s\t\t%s" % ("SCOPE", "NAME")) + print( + "%s\t%s\n" + % (crd_creation_respone.spec.scope, crd_creation_respone.metadata.name) + ) + + # Fetching the "ingressroutes" CRD api + + try: + ingressroute_api = client.resources.get( + api_version="apps.example.com/v1", kind="IngressRoute" + ) + except ResourceNotFoundError: + # Need to wait a sec for the discovery layer to get updated + time.sleep(2) + + ingressroute_api = client.resources.get( + api_version="apps.example.com/v1", kind="IngressRoute" + ) + + # Creating a custom resource (CR) `ingress-route-*`, using the above CRD `ingressroutes.apps.example.com` + + ingressroute_manifest_first = { + "apiVersion": "apps.example.com/v1", + "kind": "IngressRoute", + "metadata": { + "name": "ingress-route-first", + "namespace": "default", + }, + "spec": { + "virtualhost": { + "fqdn": "www.google.com", + "tls": {"secretName": "google-tls"}, + }, + "strategy": "RoundRobin", + }, + } + + ingressroute_manifest_second = { + "apiVersion": "apps.example.com/v1", + "kind": "IngressRoute", + "metadata": { + "name": "ingress-route-second", + "namespace": "default", + }, + "spec": { + "virtualhost": { + "fqdn": "www.yahoo.com", + "tls": {"secretName": "yahoo-tls"}, + }, + "strategy": "RoundRobin", + }, + } + + ingressroute_api.create(body=ingressroute_manifest_first, namespace="default") + ingressroute_api.create(body=ingressroute_manifest_second, namespace="default") + print("\n[INFO] custom resources `ingress-route-*` created\n") + + # Listing the `ingress-route-*` custom resources + + ingress_routes_list = ingressroute_api.get() + print( + "%s\t\t\t%s\t%s\t\t%s\t\t\t\t%s" + % ("NAME", "NAMESPACE", "FQDN", "TLS", "STRATEGY") + ) + for item in ingress_routes_list.items: + print( + "%s\t%s\t\t%s\t%s\t%s" + % ( + item.metadata.name, + item.metadata.namespace, + item.spec.virtualhost.fqdn, + item.spec.virtualhost.tls, + item.spec.strategy, + ) + ) + + # Patching the ingressroutes custom resources + + ingressroute_manifest_first["spec"]["strategy"] = "Random" + ingressroute_manifest_second["spec"]["strategy"] = "WeightedLeastRequest" + + patch_ingressroute_first = ingressroute_api.patch( + body=ingressroute_manifest_first, content_type="application/merge-patch+json" + ) + patch_ingressroute_second = ingressroute_api.patch( + body=ingressroute_manifest_second, content_type="application/merge-patch+json" + ) + + print( + "\n[INFO] custom resources `ingress-route-*` patched to update the strategy\n" + ) + ingress_routes_list = ingressroute_api.get() + print( + "%s\t\t\t%s\t%s\t\t%s\t\t\t\t%s" + % ("NAME", "NAMESPACE", "FQDN", "TLS", "STRATEGY") + ) + for item in ingress_routes_list.items: + print( + "%s\t%s\t\t%s\t%s\t%s" + % ( + item.metadata.name, + item.metadata.namespace, + item.spec.virtualhost.fqdn, + item.spec.virtualhost.tls, + item.spec.strategy, + ) + ) + + # Deleting the ingressroutes custom resources + + delete_ingressroute_first = ingressroute_api.delete( + name="ingress-route-first", namespace="default" + ) + delete_ingressroute_second = ingressroute_api.delete( + name="ingress-route-second", namespace="default" + ) + + print("\n[INFO] custom resources `ingress-route-*` deleted") + + # Deleting the ingressroutes.apps.example.com custom resource definition + + crd_api.delete(name=name) + print( + "\n[INFO] custom resource definition `ingressroutes.apps.example.com` deleted" + ) + + +if __name__ == "__main__": + main() diff --git a/examples/dynamic-client/node.py b/examples/dynamic-client/node.py new file mode 100644 index 0000000000..6dff9f5eac --- /dev/null +++ b/examples/dynamic-client/node.py @@ -0,0 +1,49 @@ +# Copyright 2021 The Kubernetes Authors. +# +# 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. + +""" +This example demonstrates how to list cluster nodes using dynamic client. + +""" + +from kubernetes import config, dynamic +from kubernetes.client import api_client + + +def main(): + # Creating a dynamic client + client = dynamic.DynamicClient( + api_client.ApiClient(configuration=config.load_kube_config()) + ) + + # fetching the node api + api = client.resources.get(api_version="v1", kind="Node") + + # Listing cluster nodes + + print("%s\t\t%s\t\t%s" % ("NAME", "STATUS", "VERSION")) + for item in api.get().items: + node = api.get(name=item.metadata.name) + print( + "%s\t%s\t\t%s\n" + % ( + node.metadata.name, + node.status.conditions[3]["type"], + node.status.nodeInfo.kubeProxyVersion, + ) + ) + + +if __name__ == "__main__": + main() diff --git a/examples/dynamic-client/replication_controller.py b/examples/dynamic-client/replication_controller.py new file mode 100644 index 0000000000..8c4bd6c21c --- /dev/null +++ b/examples/dynamic-client/replication_controller.py @@ -0,0 +1,84 @@ +# Copyright 2021 The Kubernetes Authors. +# +# 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. + +""" +This example demonstrates the creation, listing & deletion of a namespaced replication controller using dynamic-client. +""" + +from kubernetes import config, dynamic +from kubernetes.client import api_client + + +def main(): + # Creating a dynamic client + client = dynamic.DynamicClient( + api_client.ApiClient(configuration=config.load_kube_config()) + ) + + # fetching the replication controller api + api = client.resources.get(api_version="v1", kind="ReplicationController") + + name = "frontend-replication-controller" + + replication_controller_manifest = { + "apiVersion": "v1", + "kind": "ReplicationController", + "metadata": {"labels": {"name": name}, "name": name}, + "spec": { + "replicas": 2, + "selector": {"name": name}, + "template": { + "metadata": {"labels": {"name": name}}, + "spec": { + "containers": [ + { + "image": "nginx", + "name": "nginx", + "ports": [{"containerPort": 80, "protocol": "TCP"}], + } + ] + }, + }, + }, + } + + # Creating replication-controller `frontend-replication-controller` in the `default` namespace + replication_controller = api.create( + body=replication_controller_manifest, namespace="default" + ) + + print("\n[INFO] replication-controller `frontend-replication-controller` created\n") + + # Listing replication-controllers in the `default` namespace + replication_controller_created = api.get(name=name, namespace="default") + + print("%s\t%s\t\t\t\t\t%s" % ("NAMESPACE", "NAME", "REPLICAS")) + print( + "%s\t\t%s\t\t%s\n" + % ( + replication_controller_created.metadata.namespace, + replication_controller_created.metadata.name, + replication_controller_created.spec.replicas, + ) + ) + + # Deleting replication-controller `frontend-service` from the `default` namespace + + replication_controller_deleted = api.delete(name=name, body={}, namespace="default") + + print("[INFO] replication-controller `frontend-replication-controller` deleted\n") + + +if __name__ == "__main__": + main() diff --git a/examples/dynamic-client/service.py b/examples/dynamic-client/service.py new file mode 100644 index 0000000000..63206fd001 --- /dev/null +++ b/examples/dynamic-client/service.py @@ -0,0 +1,89 @@ +# Copyright 2021 The Kubernetes Authors. +# +# 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. + +""" +This example demonstrates the following: + - Creation of a k8s service using dynamic-client + - List, patch(update), delete the service +""" + +from kubernetes import config, dynamic +from kubernetes.client import api_client + + +def main(): + # Creating a dynamic client + client = dynamic.DynamicClient( + api_client.ApiClient(configuration=config.load_kube_config()) + ) + + # fetching the service api + api = client.resources.get(api_version="v1", kind="Service") + + name = "frontend-service" + + service_manifest = { + "apiVersion": "v1", + "kind": "Service", + "metadata": {"labels": {"name": name}, "name": name, "resourceversion": "v1"}, + "spec": { + "ports": [ + {"name": "port", "port": 80, "protocol": "TCP", "targetPort": 80} + ], + "selector": {"name": name}, + }, + } + + # Creating service `frontend-service` in the `default` namespace + + service = api.create(body=service_manifest, namespace="default") + + print("\n[INFO] service `frontend-service` created\n") + + # Listing service `frontend-service` in the `default` namespace + service_created = api.get(name=name, namespace="default") + + print("%s\t%s" % ("NAMESPACE", "NAME")) + print( + "%s\t\t%s\n" + % (service_created.metadata.namespace, service_created.metadata.name) + ) + + # Patching the `spec` section of the `frontend-service` + + service_manifest["spec"]["ports"] = [ + {"name": "new", "port": 8080, "protocol": "TCP", "targetPort": 8080} + ] + + service_patched = api.patch(body=service_manifest, name=name, namespace="default") + + print("\n[INFO] service `frontend-service` patched\n") + print("%s\t%s\t\t\t%s" % ("NAMESPACE", "NAME", "PORTS")) + print( + "%s\t\t%s\t%s\n" + % ( + service_patched.metadata.namespace, + service_patched.metadata.name, + service_patched.spec.ports, + ) + ) + + # Deleting service `frontend-service` from the `default` namespace + service_deleted = api.delete(name=name, body={}, namespace="default") + + print("\n[INFO] service `frontend-service` deleted\n") + + +if __name__ == "__main__": + main() diff --git a/examples/remote_cluster.py b/examples/remote_cluster.py index a09e7ed9bb..84ebeb4f64 100644 --- a/examples/remote_cluster.py +++ b/examples/remote_cluster.py @@ -12,9 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This example demonstrate communication with a remote Kube cluster from a -# server outside of the cluster without kube client installed on it. -# The communication is secured with the use of Bearer token. +""" +This example demonstrates the communication between a remote cluster and a +server outside the cluster without kube client installed on it. +The communication is secured with the use of Bearer token. +""" from kubernetes import client, config