Merge branch 'master' of github.com:kubernetes-client/python into release-18b1
This commit is contained in:
commit
d8fd974e63
72
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
72
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
<!-- Thanks for sending a pull request! Here are some tips for you:
|
||||
|
||||
1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide/first-contribution.md#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
|
||||
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. For reference on required PR/issue labels, read here:
|
||||
https://git.k8s.io/community/contributors/devel/sig-release/release.md#issuepr-kind-label
|
||||
3. Ensure you have added or ran the appropriate tests for your PR: https://git.k8s.io/community/contributors/devel/sig-testing/testing.md
|
||||
4. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
|
||||
5. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
|
||||
-->
|
||||
|
||||
#### What type of PR is this?
|
||||
|
||||
<!--
|
||||
Add one of the following kinds:
|
||||
/kind bug
|
||||
/kind cleanup
|
||||
/kind documentation
|
||||
/kind feature
|
||||
/kind design
|
||||
|
||||
Optionally add one or more of the following kinds if applicable:
|
||||
/kind api-change
|
||||
/kind deprecation
|
||||
/kind failing-test
|
||||
/kind flake
|
||||
/kind regression
|
||||
-->
|
||||
|
||||
#### What this PR does / why we need it:
|
||||
|
||||
#### Which issue(s) this PR fixes:
|
||||
<!--
|
||||
*Automatically closes linked issue when PR is merged.
|
||||
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
|
||||
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
|
||||
-->
|
||||
Fixes #
|
||||
|
||||
#### Special notes for your reviewer:
|
||||
|
||||
#### Does this PR introduce a user-facing change?
|
||||
<!--
|
||||
If no, just write "NONE" in the release-note block below.
|
||||
If yes, a release note is required:
|
||||
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
|
||||
|
||||
For more information on release notes see: https://git.k8s.io/community/contributors/guide/release-notes.md
|
||||
-->
|
||||
```release-note
|
||||
|
||||
```
|
||||
|
||||
#### Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.:
|
||||
|
||||
<!--
|
||||
This section can be blank if this pull request does not require a release note.
|
||||
|
||||
When adding links which point to resources within git repositories, like
|
||||
KEPs or supporting documentation, please reference a specific commit and avoid
|
||||
linking directly to the master branch. This ensures that links reference a
|
||||
specific point in time, rather than a document that may change over time.
|
||||
|
||||
See here for guidance on getting permanent links to files: https://help.github.com/en/articles/getting-permanent-links-to-files
|
||||
|
||||
Please use the following format for linking documentation:
|
||||
- [KEP]: <link>
|
||||
- [Usage]: <link>
|
||||
- [Other doc]: <link>
|
||||
-->
|
||||
```docs
|
||||
|
||||
```
|
||||
44
.github/workflows/e2e-master.yaml
vendored
Normal file
44
.github/workflows/e2e-master.yaml
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
name: End to End Tests - master
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.6, 3.7, 3.8, 3.9]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Create Kind Cluster
|
||||
uses: helm/kind-action@v1.1.0
|
||||
with:
|
||||
cluster_name: kubernetes-python-e2e-master-${{ matrix.python-version }}
|
||||
# The kind version to be used to spin the cluster up
|
||||
# this needs to be updated whenever a new Kind version is released
|
||||
version: v0.11.1
|
||||
# Update the config here whenever a new client snapshot is performed
|
||||
# This would eventually point to cluster with the latest Kubernetes version
|
||||
# as we sync with Kubernetes upstream
|
||||
config: .github/workflows/kind-configs/cluster-1.18.yaml
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2.2.2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements.txt
|
||||
python -m pip install -r test-requirements.txt
|
||||
- name: Install package
|
||||
run: python -m pip install -e .
|
||||
- name: Run End to End tests
|
||||
run: pytest -vvv -s kubernetes/e2e_test
|
||||
44
.github/workflows/e2e-release-11.0.yaml
vendored
Normal file
44
.github/workflows/e2e-release-11.0.yaml
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
name: End to End Tests - release-11.0
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- release-11.0
|
||||
pull_request:
|
||||
branches:
|
||||
- release-11.0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Create Kind Cluster
|
||||
uses: helm/kind-action@v1.1.0
|
||||
with:
|
||||
cluster_name: kubernetes-python-e2e-release-11.0-${{ matrix.python-version }}
|
||||
# The kind version to be used to spin the cluster up
|
||||
# this needs to be updated whenever a new Kind version is released
|
||||
version: v0.11.1
|
||||
# Update the config here whenever a new client snapshot is performed
|
||||
# This would eventually point to cluster with the latest Kubernetes version
|
||||
# as we sync with Kubernetes upstream
|
||||
config: .github/workflows/kind-configs/cluster-1.15.yaml
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2.2.2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements.txt
|
||||
python -m pip install -r test-requirements.txt
|
||||
- name: Install package
|
||||
run: python -m pip install -e .
|
||||
- name: Run End to End tests
|
||||
run: pytest -vvv -s kubernetes/e2e_test
|
||||
44
.github/workflows/e2e-release-12.0.yaml
vendored
Normal file
44
.github/workflows/e2e-release-12.0.yaml
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
name: End to End Tests - release-12.0
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- release-12.0
|
||||
pull_request:
|
||||
branches:
|
||||
- release-12.0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Create Kind Cluster
|
||||
uses: helm/kind-action@v1.1.0
|
||||
with:
|
||||
cluster_name: kubernetes-python-e2e-release-12.0-${{ matrix.python-version }}
|
||||
# The kind version to be used to spin the cluster up
|
||||
# this needs to be updated whenever a new Kind version is released
|
||||
version: v0.11.1
|
||||
# Update the config here whenever a new client snapshot is performed
|
||||
# This would eventually point to cluster with the latest Kubernetes version
|
||||
# as we sync with Kubernetes upstream
|
||||
config: .github/workflows/kind-configs/cluster-1.16.yaml
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2.2.2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements.txt
|
||||
python -m pip install -r test-requirements.txt
|
||||
- name: Install package
|
||||
run: python -m pip install -e .
|
||||
- name: Run End to End tests
|
||||
run: pytest -vvv -s kubernetes/e2e_test
|
||||
44
.github/workflows/e2e-release-17.0.yaml
vendored
Normal file
44
.github/workflows/e2e-release-17.0.yaml
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
name: End to End Tests - release-17.0
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- release-17.0
|
||||
pull_request:
|
||||
branches:
|
||||
- release-17.0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Create Kind Cluster
|
||||
uses: helm/kind-action@v1.1.0
|
||||
with:
|
||||
cluster_name: kubernetes-python-e2e-release-17.0-${{ matrix.python-version }}
|
||||
# The kind version to be used to spin the cluster up
|
||||
# this needs to be updated whenever a new Kind version is released
|
||||
version: v0.11.1
|
||||
# Update the config here whenever a new client snapshot is performed
|
||||
# This would eventually point to cluster with the latest Kubernetes version
|
||||
# as we sync with Kubernetes upstream
|
||||
config: .github/workflows/kind-configs/cluster-1.17.yaml
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2.2.2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements.txt
|
||||
python -m pip install -r test-requirements.txt
|
||||
- name: Install package
|
||||
run: python -m pip install -e .
|
||||
- name: Run End to End tests
|
||||
run: pytest -vvv -s kubernetes/e2e_test
|
||||
44
.github/workflows/e2e-release-18.0.yaml
vendored
Normal file
44
.github/workflows/e2e-release-18.0.yaml
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
name: End to End Tests - release-18.0
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- release-18.0
|
||||
pull_request:
|
||||
branches:
|
||||
- release-18.0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.6, 3.7, 3.8, 3.9]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Create Kind Cluster
|
||||
uses: helm/kind-action@v1.1.0
|
||||
with:
|
||||
cluster_name: kubernetes-python-e2e-release-18.0-${{ matrix.python-version }}
|
||||
# The kind version to be used to spin the cluster up
|
||||
# this needs to be updated whenever a new Kind version is released
|
||||
version: v0.11.1
|
||||
# Update the config here whenever a new client snapshot is performed
|
||||
# This would eventually point to cluster with the latest Kubernetes version
|
||||
# as we sync with Kubernetes upstream
|
||||
config: .github/workflows/kind-configs/cluster-1.18.yaml
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2.2.2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements.txt
|
||||
python -m pip install -r test-requirements.txt
|
||||
- name: Install package
|
||||
run: python -m pip install -e .
|
||||
- name: Run End to End tests
|
||||
run: pytest -vvv -s kubernetes/e2e_test
|
||||
7
.github/workflows/kind-configs/cluster-1.15.yaml
vendored
Normal file
7
.github/workflows/kind-configs/cluster-1.15.yaml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
kind: Cluster
|
||||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
nodes:
|
||||
- role: control-plane
|
||||
image: kindest/node:v1.15.12@sha256:b920920e1eda689d9936dfcf7332701e80be12566999152626b2c9d730397a95
|
||||
- role: worker
|
||||
image: kindest/node:v1.15.12@sha256:b920920e1eda689d9936dfcf7332701e80be12566999152626b2c9d730397a95
|
||||
7
.github/workflows/kind-configs/cluster-1.16.yaml
vendored
Normal file
7
.github/workflows/kind-configs/cluster-1.16.yaml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
kind: Cluster
|
||||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
nodes:
|
||||
- role: control-plane
|
||||
image: kindest/node:v1.16.15@sha256:83067ed51bf2a3395b24687094e283a7c7c865ccc12a8b1d7aa673ba0c5e8861
|
||||
- role: worker
|
||||
image: kindest/node:v1.16.15@sha256:83067ed51bf2a3395b24687094e283a7c7c865ccc12a8b1d7aa673ba0c5e8861
|
||||
7
.github/workflows/kind-configs/cluster-1.17.yaml
vendored
Normal file
7
.github/workflows/kind-configs/cluster-1.17.yaml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
kind: Cluster
|
||||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
nodes:
|
||||
- role: control-plane
|
||||
image: kindest/node:v1.17.17@sha256:66f1d0d91a88b8a001811e2f1054af60eef3b669a9a74f9b6db871f2f1eeed00
|
||||
- role: worker
|
||||
image: kindest/node:v1.17.17@sha256:66f1d0d91a88b8a001811e2f1054af60eef3b669a9a74f9b6db871f2f1eeed00
|
||||
7
.github/workflows/kind-configs/cluster-1.18.yaml
vendored
Normal file
7
.github/workflows/kind-configs/cluster-1.18.yaml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
kind: Cluster
|
||||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
nodes:
|
||||
- role: control-plane
|
||||
image: kindest/node:v1.18.19@sha256:7af1492e19b3192a79f606e43c35fb741e520d195f96399284515f077b3b622c
|
||||
- role: worker
|
||||
image: kindest/node:v1.18.19@sha256:7af1492e19b3192a79f606e43c35fb741e520d195f96399284515f077b3b622c
|
||||
4
.github/workflows/test.yaml
vendored
4
.github/workflows/test.yaml
vendored
@ -8,14 +8,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
|
||||
python-version: [3.6, 3.7, 3.8, 3.9]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2.1.4
|
||||
uses: actions/setup-python@v2.2.2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
|
||||
54
.travis.yml
54
.travis.yml
@ -24,32 +24,20 @@ jobs:
|
||||
[[ "${TRAVIS_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(([ab]|dev|rc)[0-9]+)?$ ]]
|
||||
|
||||
- stage: test
|
||||
python: 2.7
|
||||
python: 3.9
|
||||
env: TOXENV=update-pycodestyle
|
||||
- python: 3.9
|
||||
env: TOXENV=coverage,codecov
|
||||
- python: 3.7
|
||||
env: TOXENV=docs
|
||||
- python: 2.7
|
||||
env: TOXENV=coverage,codecov
|
||||
- python: 2.7
|
||||
env: TOXENV=py27
|
||||
- python: 2.7
|
||||
env: TOXENV=py27-functional
|
||||
- python: 3.5
|
||||
env: TOXENV=py35
|
||||
- python: 3.5
|
||||
env: TOXENV=py35-functional
|
||||
- python: 3.6
|
||||
env: TOXENV=py36
|
||||
- python: 3.6
|
||||
env: TOXENV=py36-functional
|
||||
- python: 3.7
|
||||
env: TOXENV=py37
|
||||
- python: 3.7
|
||||
env: TOXENV=py37-functional
|
||||
- python: 3.8
|
||||
env: TOXENV=py38
|
||||
- python: 3.8
|
||||
env: TOXENV=py38-functional
|
||||
- python: 3.9
|
||||
env: TOXENV=py39
|
||||
- stage: deploy
|
||||
script: skip
|
||||
deploy:
|
||||
@ -63,6 +51,38 @@ jobs:
|
||||
repo: kubernetes-client/python
|
||||
distributions: sdist bdist_wheel
|
||||
|
||||
- stage: test
|
||||
python: 3.9
|
||||
env: TOXENV=update-pycodestyle
|
||||
arch: ppc64le
|
||||
- python: 3.7
|
||||
env: TOXENV=docs
|
||||
arch: ppc64le
|
||||
- python: 3.6
|
||||
env: TOXENV=py36
|
||||
arch: ppc64le
|
||||
- python: 3.7
|
||||
env: TOXENV=py37
|
||||
arch: ppc64le
|
||||
- python: 3.8
|
||||
env: TOXENV=py38
|
||||
- python: 3.9
|
||||
env: TOXENV=py39
|
||||
arch: ppc64le
|
||||
- stage: deploy
|
||||
script: skip
|
||||
arch: ppc64le
|
||||
deploy:
|
||||
provider: pypi
|
||||
user: __token__
|
||||
password:
|
||||
secure: gY5Rixj7mWHC9XP5qV5DfWGdX4ZVwCEUElnQA2OeIg235I3eMBqRFM4Q/SKwAG2DzgIWNKsXXVQsZHp7BAjWFMFVQloiU7zohuBRToJUim9U1RaqAjUIr4OU7JPtXenAl5zyyBdywvJiG8UZ4wmt1DBYtdpozQvOwDXvOxNTmElKh5mfDhiSsipmFr2198NtIhiRVC+CZliZsi6osUkt+G6yl9CW+SJU3otgzdaS+VBP26HO0kWHMJiDKvQoIl/Q50IqJUWieFhCLh7lSV71VNVEmM4bMcYK8cAv3zMZHo6REKHF7xrF5tzYMXqpmEGt6L798d2H4BISr6BIlYgiYCatjyE9hxih9iBzGs0XaGUUFD8u1iuzOQI76a5dapG/DixQrGD2o9Gn/Qw6Zp9USIuKZSWUn5hSobwxJUKVNy+afpaJNQUb2W9Hj+jMXAnBDodCzo3nu+QF8GN72cmk3uqVyKUVABtI4kNe3qcEx3DyKfoh7aqJrgydeaRwESKuZ41l5CA+vqXSbbNW8z1MYDYgVdwEyRFsLg6aQk5pPsxuiILaaGy13TUndhuC+GuKcW6wCDf6WpUAwwGAF8+sz4hZ1pfSUdE3F8nfDBW3Bv+G9cB/cKkWJ2vOd9httRrvir8qUc/xPP5aW4pacnfNCQ04Iep/k4PCAdYJDtVGhCY=
|
||||
skip_existing: true
|
||||
on:
|
||||
tags: true
|
||||
repo: kubernetes-client/python
|
||||
distributions: sdist bdist_wheel
|
||||
|
||||
- stage: test
|
||||
python: 2.7
|
||||
env: TOXENV=update-pycodestyle
|
||||
|
||||
31
CHANGELOG.md
31
CHANGELOG.md
@ -47,6 +47,37 @@ Kubernetes API Version: 1.18.17
|
||||
|
||||
To read the full CHANGELOG visit [here](https://raw.githubusercontent.com/kubernetes/kubernetes/master/CHANGELOG/CHANGELOG-1.18.md).
|
||||
|
||||
# v17.17.0
|
||||
|
||||
Kubernetes API Version: 1.17.17
|
||||
|
||||
Changelog since v17.17.0b1:
|
||||
|
||||
### Bug or Regression
|
||||
- Fix watch stream non-chunked response handling ([kubernetes-client/python-base#231](https://github.com/kubernetes-client/python-base/pull/231), [@dhague](https://github.com/dhague))
|
||||
- Fixed a decoding error for BOOTMARK watch events ([kubernetes-client/python-base#234](https://github.com/kubernetes-client/python-base/pull/234), [@yliaog](https://github.com/yliaog))
|
||||
|
||||
### Feature
|
||||
- Load_kube_config_from_dict() support define custom temp files path ([kubernetes-client/python-base#233](https://github.com/kubernetes-client/python-base/pull/233), [@onecer](https://github.com/onecer))
|
||||
- The dynamic client now supports customizing http "Accept" header through the `header_params` parameter, which can be used to customizing API server response, e.g. retrieving object metadata only. ([kubernetes-client/python-base#236](https://github.com/kubernetes-client/python-base/pull/236), [@Yashks1994](https://github.com/Yashks1994))
|
||||
|
||||
# v17.17.0b1
|
||||
|
||||
Kubernetes API Version: 1.17.17
|
||||
|
||||
Changelog since v17.14.0a1:
|
||||
|
||||
**New Feature:**
|
||||
- Add Python 3.9 to build [kubernetes-client/python#1311](https://github.com/kubernetes-client/python/pull/1311)
|
||||
- Enable leaderelection [kubernetes-client/python#1363](https://github.com/kubernetes-client/python/pull/1363)
|
||||
|
||||
**API Change:**
|
||||
- Add allowWatchBookmarks, resoureVersionMatch parameters to custom objects. [kubernetes-client/gen#180](https://github.com/kubernetes-client/gen/pull/180)
|
||||
|
||||
**Bug Fix:**
|
||||
- fix: load cache error when CacheDecoder object is not callable [kubernetes-client/python-base#226](https://github.com/kubernetes-client/python-base/pull/226)
|
||||
- raise exception when an empty config file is passed to load_kube_config [kubernetes-client/python-base#223](https://github.com/kubernetes-client/python-base/pull/223)
|
||||
- Fix bug with Watch and 410 retries [kubernetes-client/python-base#227](https://github.com/kubernetes-client/python-base/pull/227)
|
||||
|
||||
# v17.14.0a1
|
||||
|
||||
|
||||
@ -140,7 +140,7 @@ this step and go back to the master branch if there are any API changes.
|
||||
## Make distribution packages
|
||||
|
||||
First make sure you are using a clean version of python. Use virtualenv and
|
||||
pyenv packages. Make sure you are using python 2.7.12. I would normally do this
|
||||
pyenv packages. Make sure you are using python 3.9.1. I would normally do this
|
||||
on a clean machine:
|
||||
|
||||
(install [pyenv](https://github.com/yyuu/pyenv#installation))
|
||||
@ -149,11 +149,11 @@ on a clean machine:
|
||||
|
||||
```bash
|
||||
git clean -xdf
|
||||
pyenv install -s 2.7.12
|
||||
pyenv global 2.7.12
|
||||
pyenv install -s 3.9.1
|
||||
pyenv global 3.9.1
|
||||
virtualenv .release
|
||||
source .release/bin/activate
|
||||
python --version # Make sure you get Python 2.7.12
|
||||
python --version # Make sure you get Python 3.9.1
|
||||
pip install twine
|
||||
```
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ git submodule update --init
|
||||
If you changed [kubernetes-client/python-base](https://github.com/kubernetes-client/python-base) and want to pull your changes into this repo run this command:
|
||||
|
||||
```bash
|
||||
git submodule update --remote
|
||||
scripts/update-submodule.sh
|
||||
```
|
||||
|
||||
Once updated, you should create a new PR to commit changes to the repository.
|
||||
After the script finishes, please create a commit "generated python-base update" and send a PR to this repository.
|
||||
|
||||
150
examples/cluster_scoped_custom_object.py
Normal file
150
examples/cluster_scoped_custom_object.py
Normal file
@ -0,0 +1,150 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Uses a Custom Resource Definition (CRD) to create a Custom Resource (CR), in this case
|
||||
a CronTab. This example use an example CRD from this tutorial:
|
||||
https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/
|
||||
|
||||
Apply the following yaml manifest to create a cluster-scoped CustomResourceDefinition (CRD)
|
||||
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: crontabs.stable.example.com
|
||||
spec:
|
||||
group: stable.example.com
|
||||
versions:
|
||||
- name: v1
|
||||
served: true
|
||||
storage: true
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
properties:
|
||||
cronSpec:
|
||||
type: string
|
||||
image:
|
||||
type: string
|
||||
replicas:
|
||||
type: integer
|
||||
scope: Cluster
|
||||
names:
|
||||
plural: crontabs
|
||||
singular: crontab
|
||||
kind: CronTab
|
||||
shortNames:
|
||||
- ct
|
||||
"""
|
||||
|
||||
from pprint import pprint
|
||||
|
||||
from kubernetes import client, config
|
||||
|
||||
|
||||
def main():
|
||||
config.load_kube_config()
|
||||
|
||||
api = client.CustomObjectsApi()
|
||||
|
||||
# definition of custom resource
|
||||
test_resource = {
|
||||
"apiVersion": "stable.example.com/v1",
|
||||
"kind": "CronTab",
|
||||
"metadata": {"name": "test-crontab"},
|
||||
"spec": {"cronSpec": "* * * * */5", "image": "my-awesome-cron-image"},
|
||||
}
|
||||
|
||||
# patch to update the `spec.cronSpec` field
|
||||
cronspec_patch = {
|
||||
"spec": {"cronSpec": "* * * * */15", "image": "my-awesome-cron-image"}
|
||||
}
|
||||
|
||||
# patch to add the `metadata.labels` field
|
||||
metadata_label_patch = {
|
||||
"metadata": {
|
||||
"labels": {
|
||||
"foo": "bar",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# create a cluster scoped resource
|
||||
created_resource = api.create_cluster_custom_object(
|
||||
group="stable.example.com",
|
||||
version="v1",
|
||||
plural="crontabs",
|
||||
body=test_resource,
|
||||
)
|
||||
print("[INFO] Custom resource `test-crontab` created!\n")
|
||||
|
||||
# get the cluster scoped resource
|
||||
resource = api.get_cluster_custom_object(
|
||||
group="stable.example.com",
|
||||
version="v1",
|
||||
name="test-crontab",
|
||||
plural="crontabs",
|
||||
)
|
||||
print("%s\t\t%s" % ("NAME", "CRON-SPEC"))
|
||||
print(
|
||||
"%s\t%s\n" %
|
||||
(resource["metadata"]["name"],
|
||||
resource["spec"]["cronSpec"]))
|
||||
|
||||
# patch the `spec.cronSpec` field of the custom resource
|
||||
patched_resource = api.patch_cluster_custom_object(
|
||||
group="stable.example.com",
|
||||
version="v1",
|
||||
plural="crontabs",
|
||||
name="test-crontab",
|
||||
body=cronspec_patch,
|
||||
)
|
||||
print("[INFO] Custom resource `test-crontab` patched to update the cronSpec schedule!\n")
|
||||
print("%s\t\t%s" % ("NAME", "PATCHED-CRON-SPEC"))
|
||||
print(
|
||||
"%s\t%s\n" %
|
||||
(patched_resource["metadata"]["name"],
|
||||
patched_resource["spec"]["cronSpec"]))
|
||||
|
||||
# patch the `metadata.labels` field of the custom resource
|
||||
patched_resource = api.patch_cluster_custom_object(
|
||||
group="stable.example.com",
|
||||
version="v1",
|
||||
plural="crontabs",
|
||||
name="test-crontab",
|
||||
body=metadata_label_patch,
|
||||
)
|
||||
print("[INFO] Custom resource `test-crontab` patched to apply new metadata labels!\n")
|
||||
print("%s\t\t%s" % ("NAME", "PATCHED_LABELS"))
|
||||
print(
|
||||
"%s\t%s\n" %
|
||||
(patched_resource["metadata"]["name"],
|
||||
patched_resource["metadata"]["labels"]))
|
||||
|
||||
# delete the custom resource "test-crontab"
|
||||
api.delete_cluster_custom_object(
|
||||
group="stable.example.com",
|
||||
version="v1",
|
||||
name="test-crontab",
|
||||
plural="crontabs",
|
||||
body=client.V1DeleteOptions(),
|
||||
)
|
||||
print("[INFO] Custom resource `test-crontab` deleted!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -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
|
||||
|
||||
@ -13,9 +13,16 @@
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
Creates, updates, and deletes a deployment using AppsV1Api.
|
||||
The example covers the following:
|
||||
- Creation of a deployment using AppsV1Api
|
||||
- update/patch to perform rolling restart on the deployment
|
||||
- deletetion of the deployment
|
||||
"""
|
||||
|
||||
import datetime
|
||||
|
||||
import pytz
|
||||
|
||||
from kubernetes import client, config
|
||||
|
||||
DEPLOYMENT_NAME = "nginx-deployment"
|
||||
@ -29,56 +36,110 @@ def create_deployment_object():
|
||||
ports=[client.V1ContainerPort(container_port=80)],
|
||||
resources=client.V1ResourceRequirements(
|
||||
requests={"cpu": "100m", "memory": "200Mi"},
|
||||
limits={"cpu": "500m", "memory": "500Mi"}
|
||||
)
|
||||
limits={"cpu": "500m", "memory": "500Mi"},
|
||||
),
|
||||
)
|
||||
|
||||
# Create and configurate a spec section
|
||||
template = client.V1PodTemplateSpec(
|
||||
metadata=client.V1ObjectMeta(labels={"app": "nginx"}),
|
||||
spec=client.V1PodSpec(containers=[container]))
|
||||
spec=client.V1PodSpec(containers=[container]),
|
||||
)
|
||||
|
||||
# Create the specification of deployment
|
||||
spec = client.V1DeploymentSpec(
|
||||
replicas=3,
|
||||
template=template,
|
||||
selector={'matchLabels': {'app': 'nginx'}})
|
||||
replicas=3, template=template, selector={
|
||||
"matchLabels":
|
||||
{"app": "nginx"}})
|
||||
|
||||
# Instantiate the deployment object
|
||||
deployment = client.V1Deployment(
|
||||
api_version="apps/v1",
|
||||
kind="Deployment",
|
||||
metadata=client.V1ObjectMeta(name=DEPLOYMENT_NAME),
|
||||
spec=spec)
|
||||
spec=spec,
|
||||
)
|
||||
|
||||
return deployment
|
||||
|
||||
|
||||
def create_deployment(api_instance, deployment):
|
||||
def create_deployment(api, deployment):
|
||||
# Create deployement
|
||||
api_response = api_instance.create_namespaced_deployment(
|
||||
body=deployment,
|
||||
namespace="default")
|
||||
print("Deployment created. status='%s'" % str(api_response.status))
|
||||
resp = api.create_namespaced_deployment(
|
||||
body=deployment, namespace="default"
|
||||
)
|
||||
|
||||
print("\n[INFO] deployment `nginx-deployment` created.\n")
|
||||
print("%s\t%s\t\t\t%s\t%s" % ("NAMESPACE", "NAME", "REVISION", "IMAGE"))
|
||||
print(
|
||||
"%s\t\t%s\t%s\t\t%s\n"
|
||||
% (
|
||||
resp.metadata.namespace,
|
||||
resp.metadata.name,
|
||||
resp.metadata.generation,
|
||||
resp.spec.template.spec.containers[0].image,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def update_deployment(api_instance, deployment):
|
||||
def update_deployment(api, deployment):
|
||||
# Update container image
|
||||
deployment.spec.template.spec.containers[0].image = "nginx:1.16.0"
|
||||
# Update the deployment
|
||||
api_response = api_instance.patch_namespaced_deployment(
|
||||
name=DEPLOYMENT_NAME,
|
||||
namespace="default",
|
||||
body=deployment)
|
||||
print("Deployment updated. status='%s'" % str(api_response.status))
|
||||
|
||||
# patch the deployment
|
||||
resp = api.patch_namespaced_deployment(
|
||||
name=DEPLOYMENT_NAME, namespace="default", body=deployment
|
||||
)
|
||||
|
||||
print("\n[INFO] deployment's container image updated.\n")
|
||||
print("%s\t%s\t\t\t%s\t%s" % ("NAMESPACE", "NAME", "REVISION", "IMAGE"))
|
||||
print(
|
||||
"%s\t\t%s\t%s\t\t%s\n"
|
||||
% (
|
||||
resp.metadata.namespace,
|
||||
resp.metadata.name,
|
||||
resp.metadata.generation,
|
||||
resp.spec.template.spec.containers[0].image,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def delete_deployment(api_instance):
|
||||
def restart_deployment(api, deployment):
|
||||
# update `spec.template.metadata` section
|
||||
# to add `kubectl.kubernetes.io/restartedAt` annotation
|
||||
deployment.spec.template.metadata.annotations = {
|
||||
"kubectl.kubernetes.io/restartedAt": datetime.datetime.utcnow()
|
||||
.replace(tzinfo=pytz.UTC)
|
||||
.isoformat()
|
||||
}
|
||||
|
||||
# patch the deployment
|
||||
resp = api.patch_namespaced_deployment(
|
||||
name=DEPLOYMENT_NAME, namespace="default", body=deployment
|
||||
)
|
||||
|
||||
print("\n[INFO] deployment `nginx-deployment` restarted.\n")
|
||||
print("%s\t\t\t%s\t%s" % ("NAME", "REVISION", "RESTARTED-AT"))
|
||||
print(
|
||||
"%s\t%s\t\t%s\n"
|
||||
% (
|
||||
resp.metadata.name,
|
||||
resp.metadata.generation,
|
||||
resp.spec.template.metadata.annotations,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def delete_deployment(api):
|
||||
# Delete deployment
|
||||
api_response = api_instance.delete_namespaced_deployment(
|
||||
resp = api.delete_namespaced_deployment(
|
||||
name=DEPLOYMENT_NAME,
|
||||
namespace="default",
|
||||
body=client.V1DeleteOptions(
|
||||
propagation_policy='Foreground',
|
||||
grace_period_seconds=5))
|
||||
print("Deployment deleted. status='%s'" % str(api_response.status))
|
||||
propagation_policy="Foreground", grace_period_seconds=5
|
||||
),
|
||||
)
|
||||
print("\n[INFO] deployment `nginx-deployment` deleted.")
|
||||
|
||||
|
||||
def main():
|
||||
@ -101,8 +162,10 @@ def main():
|
||||
|
||||
update_deployment(apps_v1, deployment)
|
||||
|
||||
restart_deployment(apps_v1, deployment)
|
||||
|
||||
delete_deployment(apps_v1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
43
examples/dynamic-client/accept_header.py
Normal file
43
examples/dynamic-client/accept_header.py
Normal file
@ -0,0 +1,43 @@
|
||||
# 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 pass the custom header in the cluster.
|
||||
|
||||
"""
|
||||
|
||||
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")
|
||||
|
||||
# Creating a custom header
|
||||
params = {'header_params': {'Accept': 'application/json;as=PartialObjectMetadataList;v=v1;g=meta.k8s.io'}}
|
||||
|
||||
resp = api.get(**params)
|
||||
|
||||
# Printing the kind and apiVersion after passing new header params.
|
||||
print("%s\t\t\t%s" %("VERSION", "KIND"))
|
||||
print("%s\t\t%s" %(resp.apiVersion, resp.kind))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
213
examples/dynamic-client/cluster_scoped_custom_resource.py
Normal file
213
examples/dynamic-client/cluster_scoped_custom_resource.py
Normal file
@ -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()
|
||||
85
examples/dynamic-client/configmap.py
Normal file
85
examples/dynamic-client/configmap.py
Normal file
@ -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()
|
||||
120
examples/dynamic-client/deployment_rolling_restart.py
Normal file
120
examples/dynamic-client/deployment_rolling_restart.py
Normal file
@ -0,0 +1,120 @@
|
||||
# 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 deployment using dynamic-client
|
||||
- Rolling restart of the deployment (demonstrate patch/update action)
|
||||
- Listing & deletion of the deployment
|
||||
"""
|
||||
|
||||
|
||||
from kubernetes import config, dynamic
|
||||
from kubernetes.client import api_client
|
||||
import datetime
|
||||
import pytz
|
||||
|
||||
def main():
|
||||
# Creating a dynamic client
|
||||
client = dynamic.DynamicClient(
|
||||
api_client.ApiClient(configuration=config.load_kube_config())
|
||||
)
|
||||
|
||||
# fetching the deployment api
|
||||
api = client.resources.get(api_version="apps/v1", kind="Deployment")
|
||||
|
||||
name = "nginx-deployment"
|
||||
|
||||
deployment_manifest = {
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": {"labels": {"app": "nginx"}, "name": name},
|
||||
"spec": {
|
||||
"replicas": 3,
|
||||
"selector": {"matchLabels": {"app": "nginx"}},
|
||||
"template": {
|
||||
"metadata": {"labels": {"app": "nginx"}},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "nginx",
|
||||
"image": "nginx:1.14.2",
|
||||
"ports": [{"containerPort": 80}],
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Creating deployment `nginx-deployment` in the `default` namespace
|
||||
|
||||
deployment = api.create(body=deployment_manifest, namespace="default")
|
||||
|
||||
print("\n[INFO] deployment `nginx-deployment` created\n")
|
||||
|
||||
# Listing deployment `nginx-deployment` in the `default` namespace
|
||||
|
||||
deployment_created = api.get(name=name, namespace="default")
|
||||
|
||||
print("%s\t%s\t\t\t%s\t%s" % ("NAMESPACE", "NAME", "REVISION", "RESTARTED-AT"))
|
||||
print(
|
||||
"%s\t\t%s\t%s\t\t%s\n"
|
||||
% (
|
||||
deployment_created.metadata.namespace,
|
||||
deployment_created.metadata.name,
|
||||
deployment_created.metadata.annotations,
|
||||
deployment_created.spec.template.metadata.annotations,
|
||||
)
|
||||
)
|
||||
|
||||
# Patching the `spec.template.metadata` section to add `kubectl.kubernetes.io/restartedAt` annotation
|
||||
# In order to perform a rolling restart on the deployment `nginx-deployment`
|
||||
|
||||
deployment_manifest["spec"]["template"]["metadata"] = {
|
||||
"annotations": {
|
||||
"kubectl.kubernetes.io/restartedAt": datetime.datetime.utcnow()
|
||||
.replace(tzinfo=pytz.UTC)
|
||||
.isoformat()
|
||||
}
|
||||
}
|
||||
|
||||
deployment_patched = api.patch(
|
||||
body=deployment_manifest, name=name, namespace="default"
|
||||
)
|
||||
|
||||
print("\n[INFO] deployment `nginx-deployment` restarted\n")
|
||||
print(
|
||||
"%s\t%s\t\t\t%s\t\t\t\t\t\t%s"
|
||||
% ("NAMESPACE", "NAME", "REVISION", "RESTARTED-AT")
|
||||
)
|
||||
print(
|
||||
"%s\t\t%s\t%s\t\t%s\n"
|
||||
% (
|
||||
deployment_patched.metadata.namespace,
|
||||
deployment_patched.metadata.name,
|
||||
deployment_patched.metadata.annotations,
|
||||
deployment_patched.spec.template.metadata.annotations,
|
||||
)
|
||||
)
|
||||
|
||||
# Deleting deployment `nginx-deployment` from the `default` namespace
|
||||
|
||||
deployment_deleted = api.delete(name=name, body={}, namespace="default")
|
||||
|
||||
print("\n[INFO] deployment `nginx-deployment` deleted\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
250
examples/dynamic-client/namespaced_custom_resource.py
Normal file
250
examples/dynamic-client/namespaced_custom_resource.py
Normal file
@ -0,0 +1,250 @@
|
||||
# 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 import client as k8s_client
|
||||
from kubernetes.dynamic.exceptions import ResourceNotFoundError
|
||||
from kubernetes.client import api_client
|
||||
import time
|
||||
|
||||
def list_ingressroute_for_all_namespaces(group, version, plural):
|
||||
custom_object_api = k8s_client.CustomObjectsApi()
|
||||
|
||||
list_of_ingress_routes = custom_object_api.list_cluster_custom_object(
|
||||
group, version, plural
|
||||
)
|
||||
print(
|
||||
"%s\t\t\t%s\t\t\t%s\t\t%s\t\t\t\t%s"
|
||||
% ("NAME", "NAMESPACE", "FQDN", "TLS", "STRATEGY")
|
||||
)
|
||||
for item in list_of_ingress_routes["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"]
|
||||
)
|
||||
)
|
||||
|
||||
def create_namespace(namespace_api, name):
|
||||
namespace_manifest = {
|
||||
"apiVersion": "v1",
|
||||
"kind": "Namespace",
|
||||
"metadata": {"name": name, "resourceversion": "v1"},
|
||||
}
|
||||
namespace_api.create(body=namespace_manifest)
|
||||
|
||||
|
||||
def delete_namespace(namespace_api, name):
|
||||
namespace_api.delete(name=name)
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
namespace_api = client.resources.get(api_version="v1", kind="Namespace")
|
||||
|
||||
# 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`
|
||||
|
||||
namespace_first = "test-namespace-first"
|
||||
namespace_second = "test-namespace-second"
|
||||
|
||||
create_namespace(namespace_api, namespace_first)
|
||||
create_namespace(namespace_api, namespace_second)
|
||||
|
||||
ingressroute_manifest_first = {
|
||||
"apiVersion": "apps.example.com/v1",
|
||||
"kind": "IngressRoute",
|
||||
"metadata": {
|
||||
"name": "ingress-route-first",
|
||||
"namespace": namespace_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",
|
||||
"namespace": namespace_second,
|
||||
},
|
||||
"spec": {
|
||||
"virtualhost": {
|
||||
"fqdn": "www.yahoo.com",
|
||||
"tls": {"secretName": "yahoo-tls"},
|
||||
},
|
||||
"strategy": "RoundRobin",
|
||||
},
|
||||
}
|
||||
|
||||
ingressroute_api.create(body=ingressroute_manifest_first, namespace=namespace_first)
|
||||
ingressroute_api.create(body=ingressroute_manifest_second, namespace=namespace_second)
|
||||
print("\n[INFO] custom resources `ingress-route-*` created\n")
|
||||
|
||||
# Listing the `ingress-route-*` custom resources
|
||||
|
||||
list_ingressroute_for_all_namespaces(
|
||||
group="apps.example.com", version="v1", plural="ingressroutes"
|
||||
)
|
||||
|
||||
# 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"
|
||||
)
|
||||
list_ingressroute_for_all_namespaces(
|
||||
group="apps.example.com", version="v1", plural="ingressroutes"
|
||||
)
|
||||
|
||||
# Deleting the ingressroutes custom resources
|
||||
|
||||
delete_ingressroute_first = ingressroute_api.delete(
|
||||
name="ingress-route-first", namespace=namespace_first
|
||||
)
|
||||
delete_ingressroute_second = ingressroute_api.delete(
|
||||
name="ingress-route-second", namespace=namespace_second
|
||||
)
|
||||
|
||||
print("\n[INFO] custom resources `ingress-route-*` deleted")
|
||||
|
||||
# Deleting the namespaces
|
||||
|
||||
delete_namespace(namespace_api, namespace_first)
|
||||
time.sleep(4)
|
||||
delete_namespace(namespace_api, namespace_second)
|
||||
time.sleep(4)
|
||||
|
||||
print("\n[INFO] test namespaces 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()
|
||||
49
examples/dynamic-client/node.py
Normal file
49
examples/dynamic-client/node.py
Normal file
@ -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()
|
||||
84
examples/dynamic-client/replication_controller.py
Normal file
84
examples/dynamic-client/replication_controller.py
Normal file
@ -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()
|
||||
89
examples/dynamic-client/service.py
Normal file
89
examples/dynamic-client/service.py
Normal file
@ -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()
|
||||
@ -17,6 +17,7 @@ Creates, updates, and deletes a job object.
|
||||
"""
|
||||
|
||||
from os import path
|
||||
from time import sleep
|
||||
|
||||
import yaml
|
||||
|
||||
@ -54,6 +55,20 @@ def create_job(api_instance, job):
|
||||
body=job,
|
||||
namespace="default")
|
||||
print("Job created. status='%s'" % str(api_response.status))
|
||||
get_job_status(api_instance)
|
||||
|
||||
|
||||
def get_job_status(api_instance):
|
||||
job_completed = False
|
||||
while not job_completed:
|
||||
api_response = api_instance.read_namespaced_job_status(
|
||||
name=JOB_NAME,
|
||||
namespace="default")
|
||||
if api_response.status.succeeded is not None or \
|
||||
api_response.status.failed is not None:
|
||||
job_completed = True
|
||||
sleep(1)
|
||||
print("Job status='%s'" % str(api_response.status))
|
||||
|
||||
|
||||
def update_job(api_instance, job):
|
||||
|
||||
@ -18,9 +18,10 @@ Allows you to pick a context and then lists all pods in the chosen context.
|
||||
Please install the pick library before running this example.
|
||||
"""
|
||||
|
||||
from pick import pick # install pick using `pip install pick`
|
||||
|
||||
from kubernetes import client, config
|
||||
from kubernetes.client import configuration
|
||||
from pick import pick # install pick using `pip install pick`
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@ -17,7 +17,7 @@ Uses a Custom Resource Definition (CRD) to create a custom object, in this case
|
||||
a CronTab. This example use an example CRD from this tutorial:
|
||||
https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/
|
||||
|
||||
The following yaml manifest has to be applied first:
|
||||
The following yaml manifest has to be applied first for namespaced scoped CRD:
|
||||
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
@ -29,6 +29,19 @@ spec:
|
||||
- name: v1
|
||||
served: true
|
||||
storage: true
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
properties:
|
||||
cronSpec:
|
||||
type: string
|
||||
image:
|
||||
type: string
|
||||
replicas:
|
||||
type: integer
|
||||
scope: Namespaced
|
||||
names:
|
||||
plural: crontabs
|
||||
@ -59,6 +72,11 @@ def main():
|
||||
}
|
||||
}
|
||||
|
||||
# patch to update the `spec.cronSpec` field
|
||||
patch_body = {
|
||||
"spec": {"cronSpec": "* * * * */10", "image": "my-awesome-cron-image"}
|
||||
}
|
||||
|
||||
# create the resource
|
||||
api.create_namespaced_custom_object(
|
||||
group="stable.example.com",
|
||||
@ -80,6 +98,18 @@ def main():
|
||||
print("Resource details:")
|
||||
pprint(resource)
|
||||
|
||||
# patch the namespaced custom object to update the `spec.cronSpec` field
|
||||
patch_resource = api.patch_namespaced_custom_object(
|
||||
group="stable.example.com",
|
||||
version="v1",
|
||||
name="my-new-cron-object",
|
||||
namespace="default",
|
||||
plural="crontabs",
|
||||
body=patch_body,
|
||||
)
|
||||
print("Resource details:")
|
||||
pprint(patch_resource)
|
||||
|
||||
# delete it
|
||||
api.delete_namespaced_custom_object(
|
||||
group="stable.example.com",
|
||||
@ -13,13 +13,14 @@
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
Changes the labels of the "minikube" node. Adds the label "foo" with value
|
||||
"bar" and will overwrite the "foo" label if it already exists. Removes the
|
||||
label "baz".
|
||||
This example demonstrates the following:
|
||||
- Get a list of all the cluster nodes
|
||||
- Iterate through each node list item
|
||||
- Add or overwirite label "foo" with the value "bar"
|
||||
- Remove the label "baz"
|
||||
- Return the list of node with updated labels
|
||||
"""
|
||||
|
||||
from pprint import pprint
|
||||
|
||||
from kubernetes import client, config
|
||||
|
||||
|
||||
@ -36,9 +37,14 @@ def main():
|
||||
}
|
||||
}
|
||||
|
||||
api_response = api_instance.patch_node("minikube", body)
|
||||
# Listing the cluster nodes
|
||||
node_list = api_instance.list_node()
|
||||
|
||||
pprint(api_response)
|
||||
print("%s\t\t%s" % ("NAME", "LABELS"))
|
||||
# Patching the node labels
|
||||
for node in node_list.items:
|
||||
api_response = api_instance.patch_node(node.metadata.name, body)
|
||||
print("%s\t%s" % (node.metadata.name, node.metadata.labels))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@ -18,9 +18,10 @@ Allows you to pick a context and then lists all pods in the chosen context.
|
||||
Please install the pick library before running this example.
|
||||
"""
|
||||
|
||||
from pick import pick # install pick using `pip install pick`
|
||||
|
||||
from kubernetes import client, config
|
||||
from kubernetes.client import configuration
|
||||
from pick import pick # install pick using `pip install pick`
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@ -19,9 +19,10 @@ context includes a cluster, a user, and a namespace.
|
||||
Please install the pick library before running this example.
|
||||
"""
|
||||
|
||||
from pick import pick # install pick using `pip install pick`
|
||||
|
||||
from kubernetes import client, config
|
||||
from kubernetes.client import configuration
|
||||
from pick import pick # install pick using `pip install pick`
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@ -12,15 +12,17 @@
|
||||
# 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
|
||||
|
||||
|
||||
def main():
|
||||
# Define the barer token we are going to use to authenticate.
|
||||
# Define the bearer token we are going to use to authenticate.
|
||||
# See here to create the token:
|
||||
# https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/
|
||||
aToken = "<token>"
|
||||
|
||||
@ -4,7 +4,7 @@ No description provided (generated by Openapi Generator https://github.com/opena
|
||||
This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
|
||||
|
||||
- API version: release-1.18
|
||||
- Package version: 18.17.0a1
|
||||
- Package version: 18.0.0-snapshot
|
||||
- Build package: org.openapitools.codegen.languages.PythonClientCodegen
|
||||
|
||||
## Requirements.
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
__project__ = 'kubernetes'
|
||||
# The version is auto-updated. Please do not edit.
|
||||
__version__ = "18.17.0a1"
|
||||
__version__ = "18.0.0-snapshot"
|
||||
|
||||
import kubernetes.client
|
||||
import kubernetes.config
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
__version__ = "18.17.0a1"
|
||||
__version__ = "18.0.0-snapshot"
|
||||
|
||||
# import apis into sdk package
|
||||
from kubernetes.client.api.admissionregistration_api import AdmissionregistrationApi
|
||||
|
||||
@ -78,7 +78,7 @@ class ApiClient(object):
|
||||
self.default_headers[header_name] = header_value
|
||||
self.cookie = cookie
|
||||
# Set default User-Agent.
|
||||
self.user_agent = 'OpenAPI-Generator/18.17.0a1/python'
|
||||
self.user_agent = 'OpenAPI-Generator/18.0.0-snapshot/python'
|
||||
self.client_side_validation = configuration.client_side_validation
|
||||
|
||||
def __enter__(self):
|
||||
|
||||
@ -347,7 +347,7 @@ class Configuration(object):
|
||||
"OS: {env}\n"\
|
||||
"Python Version: {pyversion}\n"\
|
||||
"Version of the API: release-1.18\n"\
|
||||
"SDK Package Version: 18.17.0a1".\
|
||||
"SDK Package Version: 18.0.0-snapshot".\
|
||||
format(env=sys.platform, pyversion=sys.version)
|
||||
|
||||
def get_host_settings(self):
|
||||
|
||||
@ -19,15 +19,22 @@ import socket
|
||||
import time
|
||||
import unittest
|
||||
import uuid
|
||||
import six
|
||||
|
||||
from kubernetes.client import api_client
|
||||
from kubernetes.client.api import core_v1_api
|
||||
from kubernetes.e2e_test import base
|
||||
from kubernetes.stream import stream, portforward
|
||||
from kubernetes.stream.ws_client import ERROR_CHANNEL
|
||||
from kubernetes.client.rest import ApiException
|
||||
|
||||
import six.moves.urllib.request as urllib_request
|
||||
|
||||
if six.PY3:
|
||||
from http import HTTPStatus
|
||||
else:
|
||||
import httplib
|
||||
|
||||
def short_uuid():
|
||||
id = str(uuid.uuid4())
|
||||
return id[-12:]
|
||||
@ -65,6 +72,27 @@ class TestClient(unittest.TestCase):
|
||||
|
||||
name = 'busybox-test-' + short_uuid()
|
||||
pod_manifest = manifest_with_command(name, "while true;do date;sleep 5; done")
|
||||
|
||||
# wait for the default service account to be created
|
||||
timeout = time.time() + 30
|
||||
while True:
|
||||
if time.time() > timeout:
|
||||
print('timeout waiting for default service account creation')
|
||||
break
|
||||
try:
|
||||
resp = api.read_namespaced_service_account(name='default',
|
||||
namespace='default')
|
||||
except ApiException as e:
|
||||
if (six.PY3 and e.status != HTTPStatus.NOT_FOUND) or (
|
||||
six.PY3 is False and e.status != httplib.NOT_FOUND):
|
||||
print('error: %s' % e)
|
||||
self.fail(msg="unexpected error getting default service account")
|
||||
print('default service not found yet: %s' % e)
|
||||
time.sleep(1)
|
||||
continue
|
||||
self.assertEqual('default', resp.metadata.name)
|
||||
break
|
||||
|
||||
resp = api.create_namespaced_pod(body=pod_manifest,
|
||||
namespace='default')
|
||||
self.assertEqual(name, resp.metadata.name)
|
||||
@ -130,6 +158,28 @@ class TestClient(unittest.TestCase):
|
||||
|
||||
name = 'busybox-test-' + short_uuid()
|
||||
pod_manifest = manifest_with_command(name, "while true;do date;sleep 5; done")
|
||||
|
||||
# wait for the default service account to be created
|
||||
timeout = time.time() + 30
|
||||
while True:
|
||||
if time.time() > timeout:
|
||||
print('timeout waiting for default service account creation')
|
||||
break
|
||||
|
||||
try:
|
||||
resp = api.read_namespaced_service_account(name='default',
|
||||
namespace='default')
|
||||
except ApiException as e:
|
||||
if (six.PY3 and e.status != HTTPStatus.NOT_FOUND) or (
|
||||
six.PY3 is False and e.status != httplib.NOT_FOUND):
|
||||
print('error: %s' % e)
|
||||
self.fail(msg="unexpected error getting default service account")
|
||||
print('default service not found yet: %s' % e)
|
||||
time.sleep(1)
|
||||
continue
|
||||
self.assertEqual('default', resp.metadata.name)
|
||||
break
|
||||
|
||||
resp = api.create_namespaced_pod(body=pod_manifest,
|
||||
namespace='default')
|
||||
self.assertEqual(name, resp.metadata.name)
|
||||
@ -164,6 +214,10 @@ class TestClient(unittest.TestCase):
|
||||
resp = api.delete_namespaced_pod(name=name, body={},
|
||||
namespace='default')
|
||||
|
||||
# Skipping this test as this flakes a lot
|
||||
# See: https://github.com/kubernetes-client/python/issues/1300
|
||||
# Re-enable the test once the flakiness is investigated
|
||||
@unittest.skip("skipping due to extreme flakiness")
|
||||
def test_portforward_raw(self):
|
||||
client = api_client.ApiClient(configuration=self.config)
|
||||
api = core_v1_api.CoreV1Api(client)
|
||||
|
||||
@ -2,7 +2,7 @@ certifi>=14.05.14 # MPL
|
||||
six>=1.9.0 # MIT
|
||||
python-dateutil>=2.5.3 # BSD
|
||||
setuptools>=21.0.0 # PSF/ZPL
|
||||
pyyaml>=3.12 # MIT
|
||||
pyyaml>=5.4.1 # MIT
|
||||
google-auth>=1.0.1 # Apache-2.0
|
||||
ipaddress>=1.0.17;python_version=="2.7" # PSF
|
||||
websocket-client>=0.32.0,!=0.40.0,!=0.41.*,!=0.42.* # LGPLv2+
|
||||
|
||||
@ -38,7 +38,7 @@ fi
|
||||
# UPDATE: The commit being cherry-picked is updated since the the client generated in 1adaaecd0879d7315f48259ad8d6cbd66b835385
|
||||
# differs from the initial hotfix
|
||||
# Ref: https://github.com/kubernetes-client/python/pull/995/commits/9959273625b999ae9a8f0679c4def2ee7d699ede
|
||||
git cherry-pick -n a138dcbb7a9da972402a847ce982b027e0224e60
|
||||
git cherry-pick -n 9959273625b999ae9a8f0679c4def2ee7d699ede
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
echo Succesfully patched changes for custom client behavior
|
||||
@ -51,7 +51,7 @@ fi
|
||||
# Patching commits for enabling from kubernetes import apis
|
||||
# UPDATE: The commit being cherry-picked is updated to include both the commits as one
|
||||
# Ref: https://github.com/kubernetes-client/python/blob/0976d59d6ff206f2f428cabc7a6b7b1144843b2a/kubernetes/client/apis/__init__.py
|
||||
git cherry-pick -n 228a29a982aee922831c3af4fef66a7846ce4bb8
|
||||
git cherry-pick -n 56ab983036bcb5c78eee91483c1e610da69216d1
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
echo Succesfully patched changes for enabling from kubernetes import apis
|
||||
|
||||
@ -18,7 +18,7 @@ import sys
|
||||
KUBERNETES_BRANCH = "release-1.18"
|
||||
|
||||
# client version for packaging and releasing.
|
||||
CLIENT_VERSION = "18.17.0a1"
|
||||
CLIENT_VERSION = "18.0.0-snapshot"
|
||||
|
||||
# Name of the release package
|
||||
PACKAGE_NAME = "kubernetes"
|
||||
|
||||
@ -21,6 +21,9 @@ set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
# The openapi-generator version used by this client
|
||||
export OPENAPI_GENERATOR_COMMIT="v4.3.0"
|
||||
|
||||
SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")
|
||||
CLIENT_ROOT="${SCRIPT_ROOT}/../kubernetes"
|
||||
CLIENT_VERSION=$(python "${SCRIPT_ROOT}/constants.py" CLIENT_VERSION)
|
||||
@ -31,11 +34,14 @@ pushd "${SCRIPT_ROOT}" > /dev/null
|
||||
SCRIPT_ROOT=`pwd`
|
||||
popd > /dev/null
|
||||
|
||||
source ${SCRIPT_ROOT}/util/common.sh
|
||||
util::common::check_sed
|
||||
|
||||
pushd "${CLIENT_ROOT}" > /dev/null
|
||||
CLIENT_ROOT=`pwd`
|
||||
popd > /dev/null
|
||||
|
||||
TEMP_FOLDER=$(mktemp -d)
|
||||
TEMP_FOLDER=$(mktemp -d)
|
||||
trap "rm -rf ${TEMP_FOLDER}" EXIT SIGINT
|
||||
|
||||
SETTING_FILE="${TEMP_FOLDER}/settings"
|
||||
|
||||
@ -67,7 +67,7 @@ done
|
||||
|
||||
echo "--- applying isort"
|
||||
for SOURCE in $SOURCES; do
|
||||
isort -y $SOURCE
|
||||
isort $SOURCE
|
||||
done
|
||||
|
||||
echo "--- check pycodestyle (all need to be fixed manually)"
|
||||
|
||||
69
scripts/update-submodule.sh
Executable file
69
scripts/update-submodule.sh
Executable file
@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
|
||||
# Update python-base submodule and collect release notes.
|
||||
# Usage:
|
||||
#
|
||||
# $ scripts/update-submodule.sh
|
||||
#
|
||||
# # To update the release notes for a specific release (e.g. v18.17.0a1):
|
||||
# $ TARGET_RELEASE="v18.17.0a1" scripts/update-submodule.sh
|
||||
#
|
||||
# After the script finishes, please create a commit "generated python-base update"
|
||||
# and send a PR to this repository.
|
||||
# TODO(roycaihw): make the script send a PR
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
|
||||
repo_root="$(git rev-parse --show-toplevel)"
|
||||
declare -r repo_root
|
||||
cd "${repo_root}"
|
||||
|
||||
source scripts/util/changelog.sh
|
||||
source scripts/util/common.sh
|
||||
|
||||
util::common::check_sed
|
||||
go get k8s.io/release/cmd/release-notes
|
||||
|
||||
TARGET_RELEASE=${TARGET_RELEASE:-"v$(grep "^CLIENT_VERSION = \"" scripts/constants.py | sed "s/CLIENT_VERSION = \"//g" | sed "s/\"//g")"}
|
||||
|
||||
# update submodule
|
||||
git submodule update --remote
|
||||
|
||||
# download release notes
|
||||
start_sha=$(git diff | grep "^-Subproject commit " | sed 's/-Subproject commit //g')
|
||||
end_sha=$(git diff | grep "^+Subproject commit " | sed 's/+Subproject commit //g')
|
||||
output="/tmp/python-base-relnote.md"
|
||||
release-notes --dependencies=false --org kubernetes-client --repo python-base --start-sha $start_sha --end-sha $end_sha --output $output
|
||||
sed -i 's/(\[\#/(\[kubernetes-client\/python-base\#/g' $output
|
||||
|
||||
# update changelog
|
||||
IFS_backup=$IFS
|
||||
IFS=$'\n'
|
||||
sections=($(grep "^### " $output))
|
||||
IFS=$IFS_backup
|
||||
for section in "${sections[@]}"; do
|
||||
# ignore section titles and empty lines; replace newline with liternal "\n"
|
||||
release_notes=$(sed -n "/$section/,/###/{/###/!p}" $output | sed -n "{/^$/!p}" | sed ':a;N;$!ba;s/\n/\\n/g')
|
||||
util::changelog::write_changelog "$TARGET_RELEASE" "$section" "$release_notes"
|
||||
done
|
||||
|
||||
rm -f $output
|
||||
echo "Successfully updated CHANGELOG for submodule."
|
||||
109
scripts/util/changelog.sh
Executable file
109
scripts/util/changelog.sh
Executable file
@ -0,0 +1,109 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
changelog="$(git rev-parse --show-toplevel)/CHANGELOG.md"
|
||||
|
||||
function util::changelog::has_release {
|
||||
local release=$1
|
||||
return $(grep -q "^# $release$" $changelog)
|
||||
}
|
||||
|
||||
# find_release_start returns the number of the first line of the given release
|
||||
function util::changelog::find_release_start {
|
||||
local release=$1
|
||||
echo $(grep -n "^# $release$" $changelog | head -1 | cut -d: -f1)
|
||||
}
|
||||
|
||||
# find_release_end returns the number of the last line of the given release
|
||||
function util::changelog::find_release_end {
|
||||
local release=$1
|
||||
|
||||
local release_start=$(util::changelog::find_release_start $release)
|
||||
local next_release_index=0
|
||||
local releases=($(grep -n "^# " $changelog | cut -d: -f1))
|
||||
for i in "${!releases[@]}"; do
|
||||
if [[ "${releases[$i]}" = "$release_start" ]]; then
|
||||
next_release_index=$((i+1))
|
||||
break
|
||||
fi
|
||||
done
|
||||
# return the line before the next release
|
||||
echo $((${releases[${next_release_index}]}-1))
|
||||
}
|
||||
|
||||
# has_section returns if the given section exists between start and end
|
||||
function util::changelog::has_section_in_range {
|
||||
local section="$1"
|
||||
local start=$2
|
||||
local end=$3
|
||||
|
||||
local lines=($(grep -n "$section" "$changelog" | cut -d: -f1))
|
||||
for i in "${!lines[@]}"; do
|
||||
if [[ ${lines[$i]} -ge $start && ${lines[$i]} -le $end ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# find_section returns the number of the first line of the given section
|
||||
function util::changelog::find_section_in_range {
|
||||
local section="$1"
|
||||
local start=$2
|
||||
local end=$3
|
||||
|
||||
local line="0"
|
||||
local lines=($(grep -n "$section" "$changelog" | cut -d: -f1))
|
||||
for i in "${!lines[@]}"; do
|
||||
if [[ ${lines[$i]} -ge $start && ${lines[$i]} -le $end ]]; then
|
||||
line=${lines[$i]}
|
||||
break
|
||||
fi
|
||||
done
|
||||
echo $line
|
||||
}
|
||||
|
||||
# write_changelog writes release_notes to section in target_release
|
||||
function util::changelog::write_changelog {
|
||||
local target_release="$1"
|
||||
local section="$2"
|
||||
local release_notes="$3"
|
||||
|
||||
# find the place in the changelog that we want to edit
|
||||
local line_to_edit="1"
|
||||
if util::changelog::has_release $target_release; then
|
||||
# the target release exists
|
||||
release_first_line=$(util::changelog::find_release_start $target_release)
|
||||
release_last_line=$(util::changelog::find_release_end $target_release)
|
||||
if util::changelog::has_section_in_range "$section" "$release_first_line" "$release_last_line"; then
|
||||
# prepend to existing section
|
||||
line_to_edit=$(($(util::changelog::find_section_in_range "$section" "$release_first_line" "$release_last_line")+1))
|
||||
else
|
||||
# add a new section; plus 4 so that the section is placed below "Kubernetes API Version"
|
||||
line_to_edit=$(($(util::changelog::find_release_start $target_release)+4))
|
||||
release_notes="$section\n$release_notes\n"
|
||||
fi
|
||||
else
|
||||
# add a new release
|
||||
release_notes="# $target_release\n\nKubernetes API Version: To Be Updated\n\n$section\n$release_notes\n"
|
||||
fi
|
||||
|
||||
echo "Writing the following release notes to CHANGELOG line $line_to_edit:"
|
||||
echo -e $release_notes
|
||||
|
||||
# update changelog
|
||||
sed -i "${line_to_edit}i${release_notes}" $changelog
|
||||
}
|
||||
35
scripts/util/common.sh
Normal file
35
scripts/util/common.sh
Normal file
@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
# check_sed returns an error and suggests installing GNU sed, if OS X sed is
|
||||
# detected.
|
||||
function util::common::check_sed {
|
||||
# OS X sed doesn't support "--version". This way we can tell if OS X sed is
|
||||
# used.
|
||||
if ! sed --version &>/dev/null; then
|
||||
# OS X sed and GNU sed aren't compatible with backup flag "-i". Namely
|
||||
# sed -i ... - does not work on OS X
|
||||
# sed -i'' ... - does not work on certain OS X versions
|
||||
# sed -i '' ... - does not work on GNU
|
||||
echo ">>> OS X sed detected, which may be incompatible with this script. Please install and use GNU sed instead:
|
||||
$ brew install gnu-sed
|
||||
$ brew info gnu-sed
|
||||
# Find the path to the installed gnu-sed and add it to your PATH. The default
|
||||
# is:
|
||||
# PATH=\"/Users/\$USER/homebrew/opt/gnu-sed/libexec/gnubin:\$PATH\""
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
6
setup.py
6
setup.py
@ -16,7 +16,7 @@ from setuptools import setup
|
||||
|
||||
# Do not edit these constants. They will be updated automatically
|
||||
# by scripts/update-client.sh.
|
||||
CLIENT_VERSION = "18.17.0a1"
|
||||
CLIENT_VERSION = "18.0.0-snapshot"
|
||||
PACKAGE_NAME = "kubernetes"
|
||||
DEVELOPMENT_STATUS = "3 - Alpha"
|
||||
|
||||
@ -72,12 +72,10 @@ setup(
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 2",
|
||||
"Programming Language :: Python :: 2.7",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
],
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user