Skip to content

Commit 6a365d4

Browse files
author
v-reyder
committed
Set default resource quota for application namespace if KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC specified
1 parent 7bfd858 commit 6a365d4

5 files changed

Lines changed: 89 additions & 1 deletion

File tree

rootfs/api/models/app.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,16 @@ def create(self, *args, **kwargs): # noqa
211211
except KubeException:
212212
self._scheduler.ns.create(namespace)
213213

214+
if settings.KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC != '':
215+
quota_name = '{}-quota'.format(namespace)
216+
self.log(settings.KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC)
217+
quota_spec = json.loads(settings.KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC)
218+
self.log('creating Quota {} for namespace {}'.format(quota_name, namespace), level=logging.DEBUG)
219+
try:
220+
self._scheduler.quota.get(namespace, quota_name)
221+
except KubeException:
222+
self._scheduler.quota.create(namespace, quota_name, data=quota_spec)
223+
214224
try:
215225
self._scheduler.svc.get(namespace, service)
216226
except KubeException:

rootfs/api/settings/production.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,9 @@
299299
# How long k8s waits for a pod to finish work after a SIGTERM before sending SIGKILL
300300
KUBERNETES_POD_TERMINATION_GRACE_PERIOD_SECONDS = int(os.environ.get('KUBERNETES_POD_TERMINATION_GRACE_PERIOD_SECONDS', 30)) # noqa
301301

302+
# Default quota spec for application namespace
303+
KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC = os.environ.get('KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC', '') # noqa
304+
302305
# registry settings
303306
REGISTRY_HOST = os.environ.get('DEIS_REGISTRY_SERVICE_HOST', '127.0.0.1')
304307
REGISTRY_PORT = os.environ.get('DEIS_REGISTRY_SERVICE_PORT', 5000)

rootfs/scheduler/mock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def _acquire(self):
8080
resources = [
8181
'namespaces', 'nodes', 'pods', 'replicationcontrollers',
8282
'secrets', 'services', 'events', 'deployments', 'replicasets',
83-
'horizontalpodautoscalers', 'scale',
83+
'horizontalpodautoscalers', 'scale', 'resourcequotas'
8484
]
8585

8686

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from scheduler.exceptions import KubeHTTPException
2+
from scheduler.resources import Resource
3+
from scheduler.utils import dict_merge
4+
5+
6+
class Quota(Resource):
7+
short_name = 'quota'
8+
9+
def get(self, namespace_name, name):
10+
"""
11+
Fetch a single quota
12+
"""
13+
url = '/namespaces/{}/resourcequotas/{}'.format(namespace_name, name)
14+
message = 'get quota {} for namespace {}'.format(name, namespace_name)
15+
url = self.api(url)
16+
response = self.http_get(url)
17+
if self.unhealthy(response.status_code):
18+
raise KubeHTTPException(response, message)
19+
20+
return response
21+
22+
def create(self, namespace_name, name, **kwargs):
23+
"""
24+
Create resource quota for namespace
25+
"""
26+
url = self.api("/namespaces/{}/resourcequotas".format(namespace_name))
27+
manifest = {
28+
"kind": "ResourceQuota",
29+
"apiVersion": "v1",
30+
"metadata": {
31+
"namespace": namespace_name,
32+
"name": name,
33+
'labels': {
34+
'app': namespace_name,
35+
'heritage': 'deis'
36+
},
37+
},
38+
'spec': {}
39+
}
40+
41+
data = dict_merge(manifest, kwargs.get('data', {}))
42+
response = self.http_post(url, json=data)
43+
if not response.status_code == 201:
44+
raise KubeHTTPException(response,
45+
"create quota {} for namespace {}".format(
46+
name, namespace_name))
47+
48+
return response
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""
2+
Unit tests for the Deis scheduler module.
3+
4+
Run the tests with './manage.py test scheduler'
5+
"""
6+
from scheduler.tests import TestCase
7+
8+
9+
class QuotaTest(TestCase):
10+
11+
def test_create_quota(self):
12+
namespace_name = self.create_namespace()
13+
quota = {
14+
'spec': {
15+
'hard': {
16+
'cpu': '3',
17+
'pods': '10',
18+
'secrets': '5'
19+
}
20+
}
21+
}
22+
self.scheduler.quota.create(namespace_name, 'test1', data=quota)
23+
24+
response = self.scheduler.quota.get(namespace_name, 'test1')
25+
data = response.json()
26+
self.assertEqual(data.get('spec', {}), quota['spec'])
27+
self.assertEqual(data['metadata']['namespace'], namespace_name)

0 commit comments

Comments
 (0)