Merge branch 'master' of github.com:kubernetes-client/python into release-8.0

This commit is contained in:
Haowei Cai 2018-11-01 16:49:50 -07:00
commit b538f20d0a
23 changed files with 462 additions and 52 deletions

View File

@ -1,6 +1,6 @@
# ref: https://docs.travis-ci.com/user/languages/python
language: python
dist: trusty
dist: xenial
sudo: true
services:
- docker
@ -12,7 +12,7 @@ matrix:
- python: 2.7
env: TOXENV=py27-functional
- python: 2.7
env: TOXENV=update-pep8
env: TOXENV=update-pycodestyle
- python: 2.7
env: TOXENV=docs
- python: 2.7

View File

@ -1,3 +1,7 @@
# v8.0.0
**New Feature:**
- Add utility to create API resource from yaml file [kubernetes-client/python#655](https://github.com/kubernetes-client/python/pull/655)
# v8.0.0b1
**Bug Fix:**
- Update ExecProvider to use safe\_get() to tolerate kube-config file that sets

View File

@ -118,12 +118,13 @@ between client-python versions.
| 4.0 Alpha/Beta | Kubernetes main repo, 1.8 branch | ✗ |
| 4.0 | Kubernetes main repo, 1.8 branch | ✗ |
| 5.0 Alpha/Beta | Kubernetes main repo, 1.9 branch | ✗ |
| 5.0 | Kubernetes main repo, 1.9 branch | |
| 5.0 | Kubernetes main repo, 1.9 branch | |
| 6.0 Alpha/Beta | Kubernetes main repo, 1.10 branch | ✗ |
| 6.0 | Kubernetes main repo, 1.10 branch | ✓ |
| 7.0 Alpha/Beta | Kubernetes main repo, 1.11 branch | ✗ |
| 7.0 | Kubernetes main repo, 1.11 branch | ✓ |
| 8.0 Alpha/Beta | Kubernetes main repo, 1.12 branch | ✓ |
| 8.0 Alpha/Beta | Kubernetes main repo, 1.12 branch | ✗ |
| 8.0 | Kubernetes main repo, 1.12 branch | ✓ |
Key:

View File

@ -0,0 +1,32 @@
# Copyright 2018 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.
from os import path
from kubernetes import client, config, utils
def main():
# Configs can be set in Configuration class directly or using helper
# utility. If no argument provided, the config will be loaded from
# default location.
config.load_kube_config()
k8s_client = client.ApiClient()
k8s_api = utils.create_from_yaml(k8s_client, "nginx-deployment.yaml")
deps = k8s_api.read_namespaced_deployment("nginx-deployment", "default")
print("Deployment {0} created".format(deps.metadata.name))
if __name__ == '__main__':
main()

View File

@ -0,0 +1,58 @@
# Copyright 2018 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 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.
from kubernetes import client, config
def main():
# Define the barer 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 = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
# Create a configuration object
aConfiguration = client.Configuration()
# Specify the endpoint of your Kube cluster
aConfiguration.host = "https://XXX.XXX.XXX.XXX:443"
# Security part.
# In this simple example we are not going to verify the SSL certificate of
# the remote cluster (for simplicity reason)
aConfiguration.verify_ssl = False
# Nevertheless if you want to do it you can with these 2 parameters
# configuration.verify_ssl=True
# ssl_ca_cert is the filepath to the file that contains the certificate.
# configuration.ssl_ca_cert="certificate"
aConfiguration.api_key = {"authorization": "Bearer " + aToken}
# Create a ApiClient with our config
aApiClient = client.ApiClient(aConfiguration)
# Do calls
v1 = client.CoreV1Api(aApiClient)
print("Listing pods with their IPs:")
ret = v1.list_pod_for_all_namespaces(watch=False)
for i in ret.items:
print("%s\t%s\t%s" %
(i.status.pod_ip, i.metadata.namespace, i.metadata.name))
if __name__ == '__main__':
main()

View File

@ -20,3 +20,4 @@ import kubernetes.client
import kubernetes.config
import kubernetes.watch
import kubernetes.stream
import kubernetes.utils

@ -1 +1 @@
Subproject commit 8d7b6f7dc3158ff5c45fd828e965606d1c0ecfeb
Subproject commit 83ebb9d5fdc0d46bbb2e30afcd8eec42c5da4ad1

View File

@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
# 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.
import unittest
from kubernetes import utils, client
from kubernetes.e2e_test import base
class TestUtils(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.config = base.get_e2e_configuration()
def test_app_yaml(self):
k8s_client = client.api_client.ApiClient(configuration=self.config)
k8s_api = utils.create_from_yaml(k8s_client,
"kubernetes/e2e_test/test_yaml/apps-deployment.yaml")
self.assertEqual("apps/v1beta1",
k8s_api.get_api_resources().group_version)
dep = k8s_api.read_namespaced_deployment(name="nginx-app",
namespace="default")
self.assertIsNotNone(dep)
resp = k8s_api.delete_namespaced_deployment(
name="nginx-app", namespace="default",
body={})
def test_extension_yaml(self):
k8s_client = client.api_client.ApiClient(configuration=self.config)
k8s_api = utils.create_from_yaml(k8s_client,
"kubernetes/e2e_test/test_yaml/extensions-deployment.yaml")
self.assertEqual("extensions/v1beta1",
k8s_api.get_api_resources().group_version)
dep = k8s_api.read_namespaced_deployment(name="nginx-deployment",
namespace="default")
self.assertIsNotNone(dep)
resp = k8s_api.delete_namespaced_deployment(
name="nginx-deployment", namespace="default",
body={})
def test_core_pod_yaml(self):
k8s_client = client.api_client.ApiClient(configuration=self.config)
k8s_api = utils.create_from_yaml(k8s_client,
"kubernetes/e2e_test/test_yaml/core-pod.yaml")
self.assertEqual("v1",
k8s_api.get_api_resources().group_version)
pod = k8s_api.read_namespaced_pod(name="myapp-pod",
namespace="default")
self.assertIsNotNone(pod)
resp = k8s_api.delete_namespaced_pod(
name="myapp-pod", namespace="default",
body={})
def test_core_service_yaml(self):
k8s_client = client.api_client.ApiClient(configuration=self.config)
k8s_api = utils.create_from_yaml(k8s_client,
"kubernetes/e2e_test/test_yaml/core-service.yaml")
self.assertEqual("v1",
k8s_api.get_api_resources().group_version)
svc = k8s_api.read_namespaced_service(name="my-service",
namespace="default")
self.assertIsNotNone(svc)
resp = k8s_api.delete_namespaced_service(
name="my-service", namespace="default",
body={})
def test_core_namespace_yaml(self):
k8s_client = client.api_client.ApiClient(configuration=self.config)
k8s_api = utils.create_from_yaml(k8s_client,
"kubernetes/e2e_test/test_yaml/core-namespace.yaml")
self.assertEqual("v1",
k8s_api.get_api_resources().group_version)
nmsp = k8s_api.read_namespace(name="development")
self.assertIsNotNone(nmsp)
resp = k8s_api.delete_namespace(name="development", body={})
def test_deployment_in_namespace(self):
k8s_client = client.ApiClient(configuration=self.config)
core_api = utils.create_from_yaml(k8s_client,
"kubernetes/e2e_test/test_yaml/core-namespace-dep.yaml")
self.assertEqual("v1",
core_api.get_api_resources().group_version)
nmsp = core_api.read_namespace(name="dep")
self.assertIsNotNone(nmsp)
dep_api = utils.create_from_yaml(k8s_client,
"kubernetes/e2e_test/test_yaml/extensions-deployment-dep.yaml")
dep = dep_api.read_namespaced_deployment(name="nginx-deployment",
namespace="dep")
self.assertIsNotNone(dep)
resp = dep_api.delete_namespaced_deployment(
name="nginx-deployment", namespace="dep",
body={})
resp = core_api.delete_namespace(name="dep", body={})
def test_api_service(self):
k8s_client = client.api_client.ApiClient(configuration=self.config)
k8s_api = utils.create_from_yaml(k8s_client,
"kubernetes/e2e_test/test_yaml/api-service.yaml")
self.assertEqual("apiregistration.k8s.io/v1beta1",
k8s_api.get_api_resources().group_version)
svc = k8s_api.read_api_service(
name="v1alpha1.wardle.k8s.io")
self.assertIsNotNone(svc)
resp = k8s_api.delete_api_service(
name="v1alpha1.wardle.k8s.io", body={})

View File

@ -0,0 +1,13 @@
apiVersion: apiregistration.k8s.io/v1beta1
kind: APIService
metadata:
name: v1alpha1.wardle.k8s.io
spec:
insecureSkipTLSVerify: true
group: wardle.k8s.io
groupPriorityMinimum: 1000
versionPriority: 15
service:
name: api
namespace: wardle
version: v1alpha1

View File

@ -0,0 +1,21 @@
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: nginx-app
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.15.4
ports:
- containerPort: 80

View File

@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: dep
labels:
name: dep

View File

@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: development
labels:
name: development

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']

View File

@ -0,0 +1,11 @@
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376

View File

@ -0,0 +1,18 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
namespace: dep
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80

View File

@ -0,0 +1,17 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80

View File

@ -0,0 +1,15 @@
# Copyright 2018 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.
from .create_from_yaml import create_from_yaml

View File

@ -0,0 +1,74 @@
# Copyright 2018 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.
from os import path
import re
import sys
from six import iteritems
import yaml
from kubernetes import client
def create_from_yaml(k8s_client, yaml_file, verbose=False, **kwargs):
"""
Perform an action from a yaml file. Pass True for verbose to
print confirmation information.
Input:
yaml_file: string. Contains the path to yaml file.
k8s_cline: an ApiClient object, initialized with the client args.
Available parameters for performing the subsequent action:
:param async_req bool
:param bool include_uninitialized: If true, partially initialized resources are included in the response.
:param str pretty: If 'true', then the output is pretty printed.
:param str dry_run: When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed
"""
with open(path.abspath(yaml_file)) as f:
yml_object = yaml.load(f)
#TODO: case of yaml file containing multiple objects
group, _, version = yml_object["apiVersion"].partition("/")
if version == "":
version = group
group = "core"
# Take care for the case e.g. api_type is "apiextensions.k8s.io"
# Only replace the last instance
group = "".join(group.rsplit(".k8s.io", 1))
fcn_to_call = "{0}{1}Api".format(group.capitalize(),
version.capitalize())
k8s_api = getattr(client, fcn_to_call)(k8s_client)
# Replace CamelCased action_type into snake_case
kind = yml_object["kind"]
kind = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', kind)
kind = re.sub('([a-z0-9])([A-Z])', r'\1_\2', kind).lower()
# Decide which namespace we are going to put the object in,
# if any
if "namespace" in yml_object["metadata"]:
namespace = yml_object["metadata"]["namespace"]
else:
namespace = "default"
# Expect the user to create namespaced objects more often
if hasattr(k8s_api, "create_namespaced_{0}".format(kind)):
resp = getattr(k8s_api, "create_namespaced_{0}".format(kind))(
body=yml_object, namespace=namespace, **kwargs)
else:
resp = getattr(k8s_api, "create_{0}".format(kind))(
body=yml_object, **kwargs)
if verbose:
print("{0} created. status='{1}'".format(kind, str(resp.status)))
return k8s_api

View File

@ -30,6 +30,11 @@ trap "clean_exit" EXIT
# Switch off SE-Linux
setenforce 0
# Mount root to fix dns issues
# Define $HOME since somehow this is not defined
HOME=/home/travis
sudo mount --make-rshared /
# Install docker if needed
path_to_executable=$(which docker)
if [ -x "$path_to_executable" ] ; then
@ -40,7 +45,7 @@ fi
docker --version
# Get the latest stable version of kubernetes
export K8S_VERSION=$(curl -sS https://storage.googleapis.com/kubernetes-release/release/stable.txt)
K8S_VERSION=$(curl -sS https://storage.googleapis.com/kubernetes-release/release/stable.txt)
echo "K8S_VERSION : ${K8S_VERSION}"
echo "Starting docker service"
@ -54,48 +59,48 @@ wget -O kubectl "http://storage.googleapis.com/kubernetes-release/release/${K8S_
sudo chmod +x kubectl
sudo mv kubectl /usr/local/bin/
echo "Download localkube from minikube project"
wget -O localkube "https://storage.googleapis.com/minikube/k8sReleases/v1.7.0/localkube-linux-amd64"
sudo chmod +x localkube
sudo mv localkube /usr/local/bin/
echo "Download minikube from minikube project"
wget -O minikube "https://storage.googleapis.com/minikube/releases/v0.30.0/minikube-linux-amd64"
sudo chmod +x minikube
sudo mv minikube /usr/local/bin/
echo "Starting localkube"
sudo nohup localkube --logtostderr=true --enable-dns=false > localkube.log 2>&1 &
# L68-100: Set up minikube within Travis CI
# See https://github.com/kubernetes/minikube/blob/master/README.md#linux-continuous-integration-without-vm-support
echo "Set up minikube"
export MINIKUBE_WANTUPDATENOTIFICATION=false
export MINIKUBE_WANTREPORTERRORPROMPT=false
export CHANGE_MINIKUBE_NONE_USER=true
sudo mkdir -p $HOME/.kube
sudo mkdir -p $HOME/.minikube
sudo touch $HOME/.kube/config
export KUBECONFIG=$HOME/.kube/config
export MINIKUBE_HOME=$HOME
export MINIKUBE_DRIVER=${MINIKUBE_DRIVER:-none}
echo "Waiting for localkube to start..."
if ! timeout 120 sh -c "while ! curl -ks http://127.0.0.1:8080/ >/dev/null; do sleep 1; done"; then
sudo cat localkube.log
die $LINENO "localkube did not start"
# Used bootstrapper to be kubeadm for the most recent k8s version
# since localkube is depreciated and only supported up to version 1.10.0
echo "Starting minikube"
sudo minikube start --vm-driver=$MINIKUBE_DRIVER --bootstrapper=kubeadm --kubernetes-version=$K8S_VERSION --logtostderr
MINIKUBE_OK="false"
echo "Waiting for minikube to start..."
# this for loop waits until kubectl can access the api server that Minikube has created
for i in {1..90}; do # timeout for 3 minutes
kubectl get po &> /dev/null
if [ $? -ne 1 ]; then
MINIKUBE_OK="true"
break
fi
sleep 2
done
# Shut down CI if minikube did not start and show logs
if [ $MINIKUBE_OK == "false" ]; then
sudo minikube logs
die $LINENO "minikube did not start"
fi
echo "Check certificate permissions"
sudo chmod 644 /var/lib/localkube/certs/*
sudo ls -altr /var/lib/localkube/certs/
echo "Set up .kube/config"
mkdir ~/.kube
cat <<EOF > ~/.kube/config
apiVersion: v1
clusters:
- cluster:
insecure-skip-tls-verify: true
server: https://localhost:8443
name: local
contexts:
- context:
cluster: local
user: myself
name: local
current-context: local
kind: Config
preferences: {}
users:
- name: myself
user:
client-certificate: /var/lib/localkube/certs/apiserver.crt
client-key: /var/lib/localkube/certs/apiserver.key
EOF
echo "Dump Kubernetes Objects..."
kubectl get componentstatuses
kubectl get configmaps
@ -124,4 +129,4 @@ kubectl get services
echo "Running tests..."
set -x -e
# Yield execution to venv command
$*
$*

View File

@ -49,7 +49,7 @@ if [[ -z ${ENV} ]]; then
trap "deactivate" EXIT SIGINT
echo "--- Updating tools"
pip install --upgrade pep8
pip install --upgrade pycodestyle
pip install --upgrade autopep8
pip install --upgrade isort
fi
@ -70,10 +70,10 @@ for SOURCE in $SOURCES; do
isort -y $SOURCE
done
echo "--- check pep8 (all need to be fixed manually)"
echo "--- check pycodestyle (all need to be fixed manually)"
set +o errexit
for SOURCE in $SOURCES; do
pep8 $SOURCE
pycodestyle $SOURCE
done
if [[ ! -z ${ENV} ]]; then

View File

@ -57,7 +57,8 @@ setup(
extras_require=EXTRAS,
packages=['kubernetes', 'kubernetes.client', 'kubernetes.config',
'kubernetes.watch', 'kubernetes.client.apis',
'kubernetes.stream', 'kubernetes.client.models'],
'kubernetes.stream', 'kubernetes.client.models',
'kubernetes.utils'],
include_package_data=True,
long_description="""\
Python client for kubernetes http://kubernetes.io/

View File

@ -8,6 +8,6 @@ mock>=2.0.0
sphinx>=1.2.1,!=1.3b1,<1.4 # BSD
recommonmark
codecov>=1.4.0
pep8
pycodestyle
autopep8
isort

View File

@ -15,9 +15,9 @@ commands =
commands =
python setup.py build_sphinx
[testenv:update-pep8]
[testenv:update-pycodestyle]
commands =
{toxinidir}/scripts/update-pep8.sh
{toxinidir}/scripts/update-pycodestyle.sh
[testenv:py27-functional]
commands =