salt/tests/unit/modules/test_k8s.py

405 lines
15 KiB
Python
Raw Normal View History

2016-03-28 17:37:57 +00:00
# -*- coding: utf-8 -*-
'''
Unit Tests for the k8s execution module.
'''
2016-03-22 06:21:11 +00:00
2016-03-28 17:37:57 +00:00
# Import Python libs
from __future__ import absolute_import
2016-03-22 06:21:11 +00:00
import json
import hashlib
import base64
import time
from subprocess import Popen, PIPE
2016-03-28 17:37:57 +00:00
# Import Salt Testing libs
from tests.support.unit import TestCase
from tests.support.helpers import skip_if_binaries_missing
2016-03-28 17:37:57 +00:00
# Import Salt libs
2017-04-04 12:11:54 +00:00
import salt.utils
2016-03-28 17:37:57 +00:00
import salt.modules.k8s as k8s
Remove repr formatting flag in places where it is used solely for quoting (#34183) * salt/cloud/__init__.py: remove repr formatting * salt/cloud/clouds/azurearm.py: remove repr formatting * salt/cloud/clouds/ec2.py: remove repr formatting * salt/cloud/clouds/profitbricks.py: remove repr formatting * salt/loader.py: remove repr formatting * salt/modules/win_file.py: remove repr formatting * salt/modules/zypper.py: remove repr formatting * salt/pillar/consul_pillar.py: remove repr formatting * salt/renderers/pyobjects.py: remove repr formatting * salt/returners/sentry_return.py: remove repr formatting * salt/states/bower.py: remove repr formatting * salt/states/cabal.py: remove repr formatting * salt/states/cmd.py: remove repr formatting * salt/states/composer.py: remove repr formatting * salt/states/win_network.py: remove repr formatting * salt/states/eselect.py: remove repr formatting * salt/states/file.py: remove repr formatting * salt/states/htpasswd.py: remove repr formatting * salt/states/memcached.py: remove repr formatting * salt/states/npm.py: remove repr formatting * salt/states/pip_state.py: remove repr formatting * salt/states/pkg.py: remove repr formatting * salt/states/pkgrepo.py: remove repr formatting * salt/states/supervisord.py: remove repr formatting * salt/states/timezone.py: remove repr formatting * salt/states/virtualenv_mod.py: remove repr formatting * salt/states/dockerio.py: remove repr formatting * salt/states/win_system.py: remove repr formatting * salt/utils/nb_popen.py: remove repr formatting * salt/utils/cloud.py: remove repr formatting * Add pylint disable due to legit usage of repr flag See https://github.com/saltstack/salt-pylint/pull/6 * Fix composer tests These tests needed to be updated because quoting was changed in the state module in 9dc9146. There was an unnecessary !r used for the exception class there, which means that instead of the exception class being passed through the formatter and coming out with the equivalent value of err.__str__(), we get a repr'ed instance of the exception class (i.e. SaltException('',)) in the state output. The unit test was asserting that we have that repr'ed instance of SaltException in the output, a case of writing the test to confirm the badly-conceived output in the state. This has also been corrected. * salt/cloud/clouds/azurearm.py: lint fixes * salt/modules/boto_s3_bucket.py: lint fixes * salt/modules/minion.py: lint fixes * salt/modules/reg.py: lint fixes * salt/modules/testinframod.py: lint fixes * salt/modules/win_iis.py: lint fixes * salt/pillar/csvpillar.py: lint fixes * salt/utils/win_functions.py: lint fixes * salt/states/nxos.py: lint fixes * salt/returners/mongo_future_return.py: lint fixes * tests/integration/__init__.py: lint fixes * tests/unit/context_test.py: lint fixes * tests/integration/states/file.py: lint fixes * tests/integration/utils/test_reactor.py: lint fixes * tests/integration/utils/testprogram.py: lint fixes * tests/unit/__init__.py: lint fixes * tests/integration/shell/minion.py: lint fixes * tests/unit/modules/boto_apigateway_test.py: lint fixes * tests/unit/modules/boto_cognitoidentity_test.py: lint fixes * tests/unit/modules/boto_elasticsearch_domain_test.py: lint fixes * tests/unit/modules/k8s_test.py: lint fixes * tests/unit/modules/reg_win_test.py: lint fixes * tests/unit/states/boto_apigateway_test.py: lint fixes * tests/unit/states/boto_cognitoidentity_test.py: lint fixes * tests/unit/states/boto_elasticsearch_domain_test.py: lint fixes
2016-06-29 20:30:18 +00:00
# Import 3rd-party libs
from salt.ext.six.moves import range # pylint: disable=import-error
2016-03-28 17:37:57 +00:00
2016-03-22 06:21:11 +00:00
@skip_if_binaries_missing(['kubectl'])
class TestK8SNamespace(TestCase):
maxDiff = None
2016-03-22 06:21:11 +00:00
def test_get_namespaces(self):
res = k8s.get_namespaces(apiserver_url="http://127.0.0.1:8080")
a = len(res.get("items"))
proc = Popen(["kubectl", "get", "namespaces", "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
b = len(kubectl_out.get("items"))
self.assertEqual(a, b)
def test_get_one_namespace(self):
res = k8s.get_namespaces("default", apiserver_url="http://127.0.0.1:8080")
a = res.get("metadata", {}).get("name", "a")
proc = Popen(["kubectl", "get", "namespaces", "default", "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
b = kubectl_out.get("metadata", {}).get("name", "b")
self.assertEqual(a, b)
def test_create_namespace(self):
hash = hashlib.sha1()
hash.update(str(time.time()))
nsname = hash.hexdigest()[:16]
res = k8s.create_namespace(nsname, apiserver_url="http://127.0.0.1:8080")
proc = Popen(["kubectl", "get", "namespaces", nsname, "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
# if creation is failed, kubernetes return non json error message
self.assertTrue(isinstance(kubectl_out, dict))
@skip_if_binaries_missing(['kubectl'])
class TestK8SSecrets(TestCase):
maxDiff = None
2016-03-22 06:21:11 +00:00
def setUp(self):
hash = hashlib.sha1()
hash.update(str(time.time()))
self.name = hash.hexdigest()[:16]
data = {"testsecret": base64.encodestring("teststring")}
self.request = {
"apiVersion": "v1",
"kind": "Secret",
"metadata": {
"name": self.name,
"namespace": "default",
},
"data": data,
}
def test_get_secrets(self):
res = k8s.get_secrets("default", apiserver_url="http://127.0.0.1:8080")
a = len(res.get("items", []))
proc = Popen(["kubectl", "--namespace=default", "get", "secrets", "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
b = len(kubectl_out.get("items", []))
self.assertEqual(a, b)
def test_get_one_secret(self):
name = self.name
filename = "/tmp/{0}.json".format(name)
2017-04-04 12:11:54 +00:00
with salt.utils.fopen(filename, 'w') as f:
2016-03-22 06:21:11 +00:00
json.dump(self.request, f)
create = Popen(["kubectl", "--namespace=default", "create", "-f", filename], stdout=PIPE)
# wee need to give kubernetes time save data in etcd
time.sleep(0.1)
res = k8s.get_secrets("default", name, apiserver_url="http://127.0.0.1:8080")
a = res.get("metadata", {}).get("name", "a")
proc = Popen(["kubectl", "--namespace=default", "get", "secrets", name, "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
b = kubectl_out.get("metadata", {}).get("name", "b")
self.assertEqual(a, b)
def test_get_decoded_secret(self):
name = self.name
filename = "/tmp/{0}.json".format(name)
2017-04-04 12:11:54 +00:00
with salt.utils.fopen(filename, 'w') as f:
2016-03-22 06:21:11 +00:00
json.dump(self.request, f)
create = Popen(["kubectl", "--namespace=default", "create", "-f", filename], stdout=PIPE)
# wee need to give etcd to populate data on all nodes
time.sleep(0.1)
res = k8s.get_secrets("default", name, apiserver_url="http://127.0.0.1:8080", decode=True)
a = res.get("data", {}).get("testsecret", )
self.assertEqual(a, "teststring")
def test_create_secret(self):
name = self.name
names = []
expected_data = {}
for i in range(2):
names.append("/tmp/{0}-{1}".format(name, i))
2017-04-04 12:11:54 +00:00
with salt.utils.fopen("/tmp/{0}-{1}".format(name, i), 'w') as f:
2016-03-22 06:21:11 +00:00
expected_data["{0}-{1}".format(name, i)] = base64.b64encode("{0}{1}".format(name, i))
f.write("{0}{1}".format(name, i))
res = k8s.create_secret("default", name, names, apiserver_url="http://127.0.0.1:8080")
proc = Popen(["kubectl", "--namespace=default", "get", "secrets", name, "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
# if creation is failed, kubernetes return non json error message
b = kubectl_out.get("data", {})
self.assertTrue(isinstance(kubectl_out, dict))
self.assertEqual(expected_data, b)
def test_update_secret(self):
name = self.name
filename = "/tmp/{0}.json".format(name)
2017-04-04 12:11:54 +00:00
with salt.utils.fopen(filename, 'w') as f:
2016-03-22 06:21:11 +00:00
json.dump(self.request, f)
create = Popen(["kubectl", "--namespace=default", "create", "-f", filename], stdout=PIPE)
# wee need to give kubernetes time save data in etcd
time.sleep(0.1)
expected_data = {}
names = []
for i in range(3):
names.append("/tmp/{0}-{1}-updated".format(name, i))
2017-04-04 12:11:54 +00:00
with salt.utils.fopen("/tmp/{0}-{1}-updated".format(name, i), 'w') as f:
2016-03-22 06:21:11 +00:00
expected_data["{0}-{1}-updated".format(name, i)] = base64.b64encode("{0}{1}-updated".format(name, i))
f.write("{0}{1}-updated".format(name, i))
res = k8s.update_secret("default", name, names, apiserver_url="http://127.0.0.1:8080")
# if creation is failed, kubernetes return non json error message
proc = Popen(["kubectl", "--namespace=default", "get", "secrets", name, "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
# if creation is failed, kubernetes return non json error message
b = kubectl_out.get("data", {})
self.assertTrue(isinstance(kubectl_out, dict))
self.assertEqual(expected_data, b)
def test_delete_secret(self):
name = self.name
filename = "/tmp/{0}.json".format(name)
2017-04-04 12:11:54 +00:00
with salt.utils.fopen(filename, 'w') as f:
2016-03-22 06:21:11 +00:00
json.dump(self.request, f)
create = Popen(["kubectl", "--namespace=default", "create", "-f", filename], stdout=PIPE)
# wee need to give kubernetes time save data in etcd
time.sleep(0.1)
res = k8s.delete_secret("default", name, apiserver_url="http://127.0.0.1:8080")
time.sleep(0.1)
proc = Popen(["kubectl", "--namespace=default", "get", "secrets", name, "-o", "json"], stdout=PIPE, stderr=PIPE)
kubectl_out, err = proc.communicate()
# stdout is empty, stderr is showing something like "not found"
self.assertEqual('', kubectl_out)
self.assertEqual('Error from server: secrets "{0}" not found\n'.format(name), err)
@skip_if_binaries_missing(['kubectl'])
class TestK8SResourceQuotas(TestCase):
maxDiff = None
2016-03-22 06:21:11 +00:00
def setUp(self):
hash = hashlib.sha1()
hash.update(str(time.time()))
self.name = hash.hexdigest()[:16]
def test_get_resource_quotas(self):
name = self.name
namespace = self.name
create_namespace = Popen(["kubectl", "create", "namespace", namespace], stdout=PIPE)
create_namespace = Popen(["kubectl", "create", "namespace", namespace], stdout=PIPE)
request = """
apiVersion: v1
kind: ResourceQuota
metadata:
name: {0}
spec:
hard:
cpu: "20"
memory: 1Gi
persistentvolumeclaims: "10"
pods: "10"
replicationcontrollers: "20"
resourcequotas: "1"
secrets: "10"
services: "5"
""".format(name)
filename = "/tmp/{0}.yaml".format(name)
2017-04-04 12:11:54 +00:00
with salt.utils.fopen(filename, 'w') as f:
2016-03-22 06:21:11 +00:00
f.write(request)
create = Popen(["kubectl", "--namespace={0}".format(namespace), "create", "-f", filename], stdout=PIPE)
# wee need to give kubernetes time save data in etcd
time.sleep(0.2)
res = k8s.get_resource_quotas(namespace, apiserver_url="http://127.0.0.1:8080")
a = len(res.get("items", []))
proc = Popen(["kubectl", "--namespace={0}".format(namespace), "get", "quota", "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
b = len(kubectl_out.get("items", []))
self.assertEqual(a, b)
def test_get_one_resource_quota(self):
name = self.name
namespace = self.name
create_namespace = Popen(["kubectl", "create", "namespace", namespace], stdout=PIPE)
request = """
apiVersion: v1
kind: ResourceQuota
metadata:
name: {0}
spec:
hard:
cpu: "20"
memory: 1Gi
persistentvolumeclaims: "10"
pods: "10"
replicationcontrollers: "20"
resourcequotas: "1"
secrets: "10"
services: "5"
""".format(name)
filename = "/tmp/{0}.yaml".format(name)
2017-04-04 12:11:54 +00:00
with salt.utils.fopen(filename, 'w') as f:
2016-03-22 06:21:11 +00:00
f.write(request)
create = Popen(["kubectl", "--namespace={0}".format(namespace), "create", "-f", filename], stdout=PIPE)
# wee need to give kubernetes time save data in etcd
time.sleep(0.2)
res = k8s.get_resource_quotas(namespace, name, apiserver_url="http://127.0.0.1:8080")
a = res.get("metadata", {}).get("name", "a")
proc = Popen(["kubectl", "--namespace={0}".format(namespace), "get", "quota", name, "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
b = kubectl_out.get("metadata", {}).get("name", "b")
self.assertEqual(a, b)
def test_create_resource_quota(self):
name = self.name
namespace = self.name
create_namespace = Popen(["kubectl", "create", "namespace", namespace], stdout=PIPE)
quota = {
"cpu": "20",
"memory": "1Gi"
}
res = k8s.create_resource_quota(namespace, quota, name=name, apiserver_url="http://127.0.0.1:8080")
proc = Popen(["kubectl", "--namespace={0}".format(namespace), "get", "quota", name, "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
self.assertTrue(isinstance(kubectl_out, dict))
def test_update_resource_quota(self):
name = self.name
namespace = self.name
create_namespace = Popen(["kubectl", "create", "namespace", namespace], stdout=PIPE)
request = """
apiVersion: v1
kind: ResourceQuota
metadata:
name: {0}
spec:
hard:
cpu: "20"
memory: 1Gi
persistentvolumeclaims: "10"
pods: "10"
replicationcontrollers: "20"
resourcequotas: "1"
secrets: "10"
services: "5"
""".format(name)
filename = "/tmp/{0}.yaml".format(name)
2017-04-04 12:11:54 +00:00
with salt.utils.fopen(filename, 'w') as f:
2016-03-22 06:21:11 +00:00
f.write(request)
create = Popen(["kubectl", "--namespace={0}".format(namespace), "create", "-f", filename], stdout=PIPE)
# wee need to give kubernetes time save data in etcd
time.sleep(0.2)
quota = {
"cpu": "10",
"memory": "2Gi"
}
res = k8s.create_resource_quota(namespace, quota, name=name, apiserver_url="http://127.0.0.1:8080", update=True)
proc = Popen(["kubectl", "--namespace={0}".format(namespace), "get", "quota", name, "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
limit = kubectl_out.get("spec").get("hard").get("memory")
self.assertEqual("2Gi", limit)
@skip_if_binaries_missing(['kubectl'])
2016-03-28 17:37:57 +00:00
class TestK8SLimitRange(TestCase):
2016-03-22 06:21:11 +00:00
maxDiff = None
2016-03-22 06:21:11 +00:00
def setUp(self):
hash = hashlib.sha1()
hash.update(str(time.time()))
self.name = hash.hexdigest()[:16]
def test_create_limit_range(self):
name = self.name
limits = {
"Container": {
"defaultRequest": {
"cpu": "100m"
}
}
}
res = k8s.create_limit_range("default", limits, name=name, apiserver_url="http://127.0.0.1:8080")
proc = Popen(["kubectl", "--namespace=default", "get", "limits", name, "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
self.assertTrue(isinstance(kubectl_out, dict))
def test_update_limit_range(self):
name = self.name
request = """
apiVersion: v1
kind: LimitRange
metadata:
name: {0}
spec:
limits:
- default:
cpu: 200m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 256Mi
type: Container
""".format(name)
limits = {
"Container": {
"defaultRequest": {
"cpu": "100m"
}
}
}
filename = "/tmp/{0}.yaml".format(name)
2017-04-04 12:11:54 +00:00
with salt.utils.fopen(filename, 'w') as f:
2016-03-22 06:21:11 +00:00
f.write(request)
create = Popen(["kubectl", "--namespace=default", "create", "-f", filename], stdout=PIPE)
# wee need to give kubernetes time save data in etcd
time.sleep(0.1)
res = k8s.create_limit_range("default", limits, name=name, apiserver_url="http://127.0.0.1:8080", update=True)
proc = Popen(["kubectl", "--namespace=default", "get", "limits", name, "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
limit = kubectl_out.get("spec").get("limits")[0].get("defaultRequest").get("cpu")
self.assertEqual("100m", limit)
def test_get_limit_ranges(self):
res = k8s.get_limit_ranges("default", apiserver_url="http://127.0.0.1:8080")
a = len(res.get("items", []))
proc = Popen(["kubectl", "--namespace=default", "get", "limits", "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
b = len(kubectl_out.get("items", []))
self.assertEqual(a, b)
def test_get_one_limit_range(self):
name = self.name
request = """
apiVersion: v1
kind: LimitRange
metadata:
name: {0}
spec:
limits:
- default:
cpu: 200m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 256Mi
type: Container
""".format(name)
filename = "/tmp/{0}.yaml".format(name)
2017-04-04 12:11:54 +00:00
with salt.utils.fopen(filename, 'w') as f:
2016-03-22 06:21:11 +00:00
f.write(request)
create = Popen(["kubectl", "--namespace=default", "create", "-f", filename], stdout=PIPE)
# wee need to give kubernetes time save data in etcd
time.sleep(0.1)
res = k8s.get_limit_ranges("default", name, apiserver_url="http://127.0.0.1:8080")
a = res.get("metadata", {}).get("name", "a")
proc = Popen(["kubectl", "--namespace=default", "get", "limits", name, "-o", "json"], stdout=PIPE)
kubectl_out = json.loads(proc.communicate()[0])
b = kubectl_out.get("metadata", {}).get("name", "b")
self.assertEqual(a, b)