Skip to content

Commit 32db472

Browse files
authored
Merge pull request #2547 from yliaog/master
added basic asyncio support
2 parents 7c0ce3b + 3b24e02 commit 32db472

1,730 files changed

Lines changed: 533455 additions & 2 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/e2e-master.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ jobs:
3838
python -m pip install --upgrade pip
3939
python -m pip install -r requirements.txt
4040
python -m pip install -r test-requirements.txt
41+
python -m pip install -r requirements-asyncio.txt
42+
python -m pip install -r test-requirements-asyncio.txt
4143
- name: Install package
4244
run: python -m pip install -e .
4345
- name: Run End to End tests
44-
run: pytest -vvv -s kubernetes/e2e_test
46+
run: pytest -vvv -s kubernetes/e2e_test -s kubernetes_asyncio/e2e_test

.github/workflows/test.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jobs:
2424
run: |
2525
python -m pip install --upgrade pip
2626
pip install -r requirements.txt
27+
pip install -r requirements-asyncio.txt
2728
- name: Lint with flake8
2829
run: |
2930
pip install flake8
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Copyright 2017 The Kubernetes Authors.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# Simple example to show loading config from the cluster
16+
17+
#
18+
# If you get 403 errors from API server you will have to configure
19+
# RBAC to add necessay permissions.
20+
#
21+
# ---
22+
# kind: ClusterRole
23+
# apiVersion: rbac.authorization.k8s.io/v1
24+
# metadata:
25+
# name: pods-list
26+
# rules:
27+
# - apiGroups: [""]
28+
# resources: ["pods"]
29+
# verbs: ["list"]
30+
# ---
31+
# kind: ClusterRoleBinding
32+
# apiVersion: rbac.authorization.k8s.io/v1
33+
# metadata:
34+
# name: pods-list
35+
# subjects:
36+
# - kind: ServiceAccount
37+
# name: default
38+
# namespace: default
39+
# roleRef:
40+
# kind: ClusterRole
41+
# name: pods-list
42+
# apiGroup: rbac.authorization.k8s.io
43+
# ---
44+
#
45+
# Doc: https://kubernetes.io/docs/reference/access-authn-authz/rbac/
46+
#
47+
# This example can be run from the image: https://hub.docker.com/r/tpimages/kubernetes_asyncio_examples/
48+
#
49+
# $ kubectl run kubernetes-asyncio-examples --image tpimages/kubernetes_asyncio_examples
50+
#
51+
52+
import asyncio
53+
import sys
54+
import traceback
55+
56+
from kubernetes_asyncio import client, config
57+
58+
59+
async def main():
60+
61+
while True:
62+
63+
try:
64+
65+
# it works only if this script is run by K8s as a POD
66+
config.load_incluster_config()
67+
68+
v1 = client.CoreV1Api()
69+
print("Listing pods with their IPs:")
70+
ret = await v1.list_pod_for_all_namespaces()
71+
72+
for i in ret.items:
73+
print(i.status.pod_ip, i.metadata.namespace, i.metadata.name)
74+
75+
except Exception:
76+
traceback.print_exc(file=sys.stdout)
77+
78+
finally:
79+
print("sleep 10s")
80+
await asyncio.sleep(10)
81+
82+
83+
if __name__ == "__main__":
84+
loop = asyncio.get_event_loop()
85+
loop.run_until_complete(main())
86+
loop.close()

examples_asyncio/list_pods.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import asyncio
2+
3+
from kubernetes_asyncio import client, config
4+
from kubernetes_asyncio.client.api_client import ApiClient
5+
6+
7+
async def main():
8+
# Configs can be set in Configuration class directly or using helper
9+
# utility. If no argument provided, the config will be loaded from
10+
# default location.
11+
await config.load_kube_config()
12+
13+
# use the context manager to close http sessions automatically
14+
async with ApiClient() as api:
15+
16+
v1 = client.CoreV1Api(api)
17+
print("Listing pods with their IPs:")
18+
ret = await v1.list_pod_for_all_namespaces()
19+
20+
for i in ret.items:
21+
print(i.status.pod_ip, i.metadata.namespace, i.metadata.name)
22+
23+
24+
if __name__ == "__main__":
25+
loop = asyncio.get_event_loop()
26+
loop.run_until_complete(main())
27+
loop.close()

examples_asyncio/patch.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import asyncio
2+
3+
from kubernetes_asyncio import client, config
4+
from kubernetes_asyncio.client.api_client import ApiClient
5+
6+
SERVICE_NAME = "example-service"
7+
SERVICE_NS = "default"
8+
SERVICE_SPEC = {
9+
"apiVersion": "v1",
10+
"kind": "Service",
11+
"metadata": {
12+
"labels": {"name": SERVICE_NAME},
13+
"name": SERVICE_NAME,
14+
"resourceversion": "v1",
15+
},
16+
"spec": {
17+
"ports": [{"name": "port-80", "port": 80, "protocol": "TCP", "targetPort": 80}],
18+
"selector": {"name": SERVICE_NAME},
19+
},
20+
}
21+
22+
23+
async def main():
24+
25+
await config.load_kube_config()
26+
27+
async with ApiClient() as api:
28+
29+
v1 = client.CoreV1Api(api)
30+
31+
print(f"Recreate {SERVICE_NAME}...")
32+
try:
33+
await v1.read_namespaced_service(SERVICE_NAME, SERVICE_NS)
34+
await v1.delete_namespaced_service(SERVICE_NAME, SERVICE_NS)
35+
except client.exceptions.ApiException as ex:
36+
if ex.status == 404:
37+
pass
38+
39+
await v1.create_namespaced_service(SERVICE_NS, SERVICE_SPEC)
40+
41+
print("Patch using JSON patch - replace port-80 with port-1000")
42+
patch = [
43+
{
44+
"op": "replace",
45+
"path": "/spec/ports/0",
46+
"value": {
47+
"name": "port-1000",
48+
"protocol": "TCP",
49+
"port": 1000,
50+
"targetPort": 1000,
51+
},
52+
}
53+
]
54+
await v1.patch_namespaced_service(
55+
SERVICE_NAME,
56+
SERVICE_NS,
57+
patch,
58+
# _content_type='application/json-patch+json' # (optional, default if patch is a list)
59+
)
60+
61+
print(
62+
"Patch using strategic merge patch - add port-2000, service will have two ports: port-1000 and port-2000"
63+
)
64+
patch = {
65+
"spec": {
66+
"ports": [
67+
{
68+
"name": "port-2000",
69+
"protocol": "TCP",
70+
"port": 2000,
71+
"targetPort": 2000,
72+
}
73+
]
74+
}
75+
}
76+
await v1.patch_namespaced_service(
77+
SERVICE_NAME,
78+
SERVICE_NS,
79+
patch,
80+
# _content_type='application/strategic-merge-patch+json' # (optional, default if patch is a dict)
81+
)
82+
83+
print(
84+
"Patch using merge patch - recreate list of ports, service will have only one port: port-3000"
85+
)
86+
patch = {
87+
"spec": {
88+
"ports": [
89+
{
90+
"name": "port-3000",
91+
"protocol": "TCP",
92+
"port": 3000,
93+
"targetPort": 3000,
94+
}
95+
]
96+
}
97+
}
98+
await v1.patch_namespaced_service(
99+
SERVICE_NAME,
100+
SERVICE_NS,
101+
patch,
102+
_content_type="application/merge-patch+json", # required to force merge patch
103+
)
104+
105+
106+
if __name__ == "__main__":
107+
loop = asyncio.get_event_loop()
108+
loop.run_until_complete(main())
109+
loop.close()

kubernetes_asyncio/.gitignore

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
env/
12+
build/
13+
develop-eggs/
14+
dist/
15+
downloads/
16+
eggs/
17+
.eggs/
18+
lib/
19+
lib64/
20+
parts/
21+
sdist/
22+
var/
23+
*.egg-info/
24+
.installed.cfg
25+
*.egg
26+
27+
# PyInstaller
28+
# Usually these files are written by a python script from a template
29+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
30+
*.manifest
31+
*.spec
32+
33+
# Installer logs
34+
pip-log.txt
35+
pip-delete-this-directory.txt
36+
37+
# Unit test / coverage reports
38+
htmlcov/
39+
.tox/
40+
.coverage
41+
.coverage.*
42+
.cache
43+
nosetests.xml
44+
coverage.xml
45+
*,cover
46+
.hypothesis/
47+
venv/
48+
.venv/
49+
.python-version
50+
.pytest_cache
51+
52+
# Translations
53+
*.mo
54+
*.pot
55+
56+
# Django stuff:
57+
*.log
58+
59+
# Sphinx documentation
60+
docs/_build/
61+
62+
# PyBuilder
63+
target/
64+
65+
#Ipython Notebook
66+
.ipynb_checkpoints

kubernetes_asyncio/.gitlab-ci.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# ref: https://docs.gitlab.com/ee/ci/README.html
2+
3+
stages:
4+
- test
5+
6+
.nosetest:
7+
stage: test
8+
script:
9+
- pip install -r requirements.txt
10+
- pip install -r test-requirements.txt
11+
- pytest --cov=client
12+
13+
nosetest-2.7:
14+
extends: .nosetest
15+
image: python:2.7-alpine
16+
nosetest-3.3:
17+
extends: .nosetest
18+
image: python:3.3-alpine
19+
nosetest-3.4:
20+
extends: .nosetest
21+
image: python:3.4-alpine
22+
nosetest-3.5:
23+
extends: .nosetest
24+
image: python:3.5-alpine
25+
nosetest-3.6:
26+
extends: .nosetest
27+
image: python:3.6-alpine
28+
nosetest-3.7:
29+
extends: .nosetest
30+
image: python:3.7-alpine
31+
nosetest-3.8:
32+
extends: .nosetest
33+
image: python:3.8-alpine
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# OpenAPI Generator Ignore
2+
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
3+
4+
# Use this file to prevent files from being overwritten by the generator.
5+
# The patterns follow closely to .gitignore or .dockerignore.
6+
7+
# As an example, the C# client generator defines ApiClient.cs.
8+
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
9+
#ApiClient.cs
10+
11+
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
12+
#foo/*/qux
13+
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
14+
15+
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
16+
#foo/**/qux
17+
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
18+
19+
# You can also negate patterns with an exclamation (!).
20+
# For example, you can ignore all files in a docs folder with the file extension .md:
21+
#docs/*.md
22+
# Then explicitly reverse the ignore rule for a single file:
23+
#!docs/README.md
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Requested Commit/Tag : v6.6.0
2+
Actual Commit : 7f8b853f502d9039c9a0aac2614ce92871e895ed

0 commit comments

Comments
 (0)