From eecc7576a7cf937c93eba2c11e84883c3e43b4e5 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Thu, 22 Jun 2017 11:23:20 -0400 Subject: [PATCH 01/19] Adding initial changes to the api --- Makefile | 2 +- rootfs/api/migrations/0001_initial.py | 2 ++ rootfs/api/models/app.py | 2 ++ rootfs/api/models/config.py | 4 +++- rootfs/api/models/release.py | 34 +++++++++++++++++++++++++++ rootfs/api/serializers.py | 2 ++ 6 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ed689ab33..822d5865b 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ docker-build: check-docker docker-build-test: check-docker docker build ${DOCKER_BUILD_FLAGS} -t ${IMAGE}.test -f rootfs/Dockerfile.test rootfs -deploy: check-kubectl docker-build docker-push +deploy: docker-build docker-push kubectl --namespace=deis patch deployment deis-$(COMPONENT) --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"$(IMAGE)"}]' clean: check-docker diff --git a/rootfs/api/migrations/0001_initial.py b/rootfs/api/migrations/0001_initial.py index 1ae2dd8fd..a969a7350 100644 --- a/rootfs/api/migrations/0001_initial.py +++ b/rootfs/api/migrations/0001_initial.py @@ -73,6 +73,8 @@ class Migration(migrations.Migration): ('updated', models.DateTimeField(auto_now=True)), ('values', jsonfield.fields.JSONField(default={}, blank=True)), ('memory', jsonfield.fields.JSONField(default={}, blank=True)), + ('lifecycle_post_start', jsonfield.fields.JSONField(default={}, blank=True)), + ('lifecycle_pre_stop', jsonfield.fields.JSONField(default={}, blank=True)), ('cpu', jsonfield.fields.JSONField(default={}, blank=True)), ('tags', jsonfield.fields.JSONField(default={}, blank=True)), ('app', models.ForeignKey(to='api.App')), diff --git a/rootfs/api/models/app.py b/rootfs/api/models/app.py index 9953f723d..e8f2bffba 100644 --- a/rootfs/api/models/app.py +++ b/rootfs/api/models/app.py @@ -1082,6 +1082,8 @@ def _gather_app_settings(self, release, app_settings, process_type, replicas): 'app_type': process_type, 'build_type': release.build.type, 'healthcheck': healthcheck, + 'lifecycle_post_start': config.lifecycle_post_start, + 'lifecycle_pre_stop': config.lifecycle_pre_stop, 'routable': routable, 'deploy_batches': batches, 'deploy_timeout': deploy_timeout, diff --git a/rootfs/api/models/config.py b/rootfs/api/models/config.py index 2e69006d5..49ed4c1bd 100644 --- a/rootfs/api/models/config.py +++ b/rootfs/api/models/config.py @@ -18,6 +18,8 @@ class Config(UuidAuditedModel): app = models.ForeignKey('App', on_delete=models.CASCADE) values = JSONField(default={}, blank=True) memory = JSONField(default={}, blank=True) + lifecycle_post_start = JSONField(default={}, blank=True) + lifecycle_pre_stop = JSONField(default={}, blank=True) cpu = JSONField(default={}, blank=True) tags = JSONField(default={}, blank=True) registry = JSONField(default={}, blank=True) @@ -162,7 +164,7 @@ def save(self, **kwargs): # usually means a totally new app previous_config = self.app.config_set.latest() - for attr in ['cpu', 'memory', 'tags', 'registry', 'values']: + for attr in ['cpu', 'memory', 'tags', 'registry', 'values', 'lifecycle_post_start', 'lifecycle_pre_stop']: data = getattr(previous_config, attr, {}).copy() new_data = getattr(self, attr, {}).copy() diff --git a/rootfs/api/models/release.py b/rootfs/api/models/release.py index 1ccbbd436..35f355060 100644 --- a/rootfs/api/models/release.py +++ b/rootfs/api/models/release.py @@ -424,6 +424,40 @@ def save(self, *args, **kwargs): # noqa changes = 'changed limits for '+', '.join(changes) self.summary += "{} {}".format(self.config.owner, changes) + # if the lifecycle_post_start hooks changed, log the dict diff + changes = [] + old_lifecycle_post_start = old_config.lifecycle_post_start if old_config else {} + diff = dict_diff(self.config.lifecycle_post_start, old_lifecycle_post_start) + # try to be as succinct as possible + added = ', '.join(k for k in diff.get('added', {})) + added = 'added lifecycle_post_start ' + added if added else '' + changed = ', '.join(k for k in diff.get('changed', {})) + changed = 'changed lifecycle_post_start ' + changed if changed else '' + deleted = ', '.join(k for k in diff.get('deleted', {})) + deleted = 'deleted lifecycle_post_start ' + deleted if deleted else '' + changes = ', '.join(i for i in (added, changed, deleted) if i) + if changes: + if self.summary: + self.summary += ' and ' + self.summary += "{} {}".format(self.config.owner, changes) + + # if the lifecycle_post_start hooks changed, log the dict diff + changes = [] + old_lifecycle_post_start = old_config.lifecycle_post_start if old_config else {} + diff = dict_diff(self.config.lifecycle_post_start, old_lifecycle_post_start) + # try to be as succinct as possible + added = ', '.join(k for k in diff.get('added', {})) + added = 'added lifecycle_post_start ' + added if added else '' + changed = ', '.join(k for k in diff.get('changed', {})) + changed = 'changed lifecycle_post_start ' + changed if changed else '' + deleted = ', '.join(k for k in diff.get('deleted', {})) + deleted = 'deleted lifecycle_post_start ' + deleted if deleted else '' + changes = ', '.join(i for i in (added, changed, deleted) if i) + if changes: + if self.summary: + self.summary += ' and ' + self.summary += "{} {}".format(self.config.owner, changes) + # if the tags changed, log the dict diff changes = [] old_tags = old_config.tags if old_config else {} diff --git a/rootfs/api/serializers.py b/rootfs/api/serializers.py index 46a46fb77..3c5bbbe74 100644 --- a/rootfs/api/serializers.py +++ b/rootfs/api/serializers.py @@ -210,6 +210,8 @@ class ConfigSerializer(serializers.ModelSerializer): owner = serializers.ReadOnlyField(source='owner.username') values = JSONFieldSerializer(required=False, binary=True) memory = JSONFieldSerializer(required=False, binary=True) + lifecycle_post_start = JSONFieldSerializer(required=False, binary=True) + lifecycle_pre_stop = JSONFieldSerializer(required=False, binary=True) cpu = JSONFieldSerializer(required=False, binary=True) tags = JSONFieldSerializer(required=False, binary=True) registry = JSONFieldSerializer(required=False, binary=True) From ad405a1a84372641dba5c71f2f52dbc3138a45f3 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Thu, 22 Jun 2017 14:45:44 -0400 Subject: [PATCH 02/19] Adding the django migration for lifecycle hooks --- rootfs/api/migrations/0001_initial.py | 2 -- .../migrations/0024_config_lifecycle_hooks.py | 26 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 rootfs/api/migrations/0024_config_lifecycle_hooks.py diff --git a/rootfs/api/migrations/0001_initial.py b/rootfs/api/migrations/0001_initial.py index a969a7350..1ae2dd8fd 100644 --- a/rootfs/api/migrations/0001_initial.py +++ b/rootfs/api/migrations/0001_initial.py @@ -73,8 +73,6 @@ class Migration(migrations.Migration): ('updated', models.DateTimeField(auto_now=True)), ('values', jsonfield.fields.JSONField(default={}, blank=True)), ('memory', jsonfield.fields.JSONField(default={}, blank=True)), - ('lifecycle_post_start', jsonfield.fields.JSONField(default={}, blank=True)), - ('lifecycle_pre_stop', jsonfield.fields.JSONField(default={}, blank=True)), ('cpu', jsonfield.fields.JSONField(default={}, blank=True)), ('tags', jsonfield.fields.JSONField(default={}, blank=True)), ('app', models.ForeignKey(to='api.App')), diff --git a/rootfs/api/migrations/0024_config_lifecycle_hooks.py b/rootfs/api/migrations/0024_config_lifecycle_hooks.py new file mode 100644 index 000000000..c23d80f9c --- /dev/null +++ b/rootfs/api/migrations/0024_config_lifecycle_hooks.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.2 on 2017-06-22 18:42 +from __future__ import unicode_literals + +from django.db import migrations +import jsonfield.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0023_app_k8s_name_length'), + ] + + operations = [ + migrations.AddField( + model_name='config', + name='lifecycle_post_start', + field=jsonfield.fields.JSONField(blank=True, default={}), + ), + migrations.AddField( + model_name='config', + name='lifecycle_pre_stop', + field=jsonfield.fields.JSONField(blank=True, default={}), + ), + ] From 5c1b73688b9435fcdb3af54f034456320bd53951 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Thu, 29 Jun 2017 16:59:56 -0400 Subject: [PATCH 03/19] Final logic for the lifecycle hooks --- Makefile | 2 +- rootfs/api/models/release.py | 12 ++++----- rootfs/scheduler/resources/pod.py | 43 +++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 822d5865b..ed689ab33 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ docker-build: check-docker docker-build-test: check-docker docker build ${DOCKER_BUILD_FLAGS} -t ${IMAGE}.test -f rootfs/Dockerfile.test rootfs -deploy: docker-build docker-push +deploy: check-kubectl docker-build docker-push kubectl --namespace=deis patch deployment deis-$(COMPONENT) --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"$(IMAGE)"}]' clean: check-docker diff --git a/rootfs/api/models/release.py b/rootfs/api/models/release.py index 35f355060..330540b1e 100644 --- a/rootfs/api/models/release.py +++ b/rootfs/api/models/release.py @@ -441,17 +441,17 @@ def save(self, *args, **kwargs): # noqa self.summary += ' and ' self.summary += "{} {}".format(self.config.owner, changes) - # if the lifecycle_post_start hooks changed, log the dict diff + # if the lifecycle_pre_stop hooks changed, log the dict diff changes = [] - old_lifecycle_post_start = old_config.lifecycle_post_start if old_config else {} - diff = dict_diff(self.config.lifecycle_post_start, old_lifecycle_post_start) + old_lifecycle_pre_stop = old_config.lifecycle_pre_stop if old_config else {} + diff = dict_diff(self.config.lifecycle_pre_stop, old_lifecycle_pre_stop) # try to be as succinct as possible added = ', '.join(k for k in diff.get('added', {})) - added = 'added lifecycle_post_start ' + added if added else '' + added = 'added lifecycle_pre_stop ' + added if added else '' changed = ', '.join(k for k in diff.get('changed', {})) - changed = 'changed lifecycle_post_start ' + changed if changed else '' + changed = 'changed lifecycle_pre_stop ' + changed if changed else '' deleted = ', '.join(k for k in diff.get('deleted', {})) - deleted = 'deleted lifecycle_post_start ' + deleted if deleted else '' + deleted = 'deleted lifecycle_pre_stop ' + deleted if deleted else '' changes = ', '.join(i for i in (added, changed, deleted) if i) if changes: if self.summary: diff --git a/rootfs/scheduler/resources/pod.py b/rootfs/scheduler/resources/pod.py index b8ad48c65..5e52163c3 100644 --- a/rootfs/scheduler/resources/pod.py +++ b/rootfs/scheduler/resources/pod.py @@ -224,6 +224,8 @@ def _set_container(self, namespace, container_name, data, **kwargs): self._set_health_checks(data, env, **kwargs) + self._set_lifecycle_hooks(data, env, **kwargs) + def _set_resources(self, container, kwargs): """ Set CPU/memory resource management manifest """ app_type = kwargs.get("app_type") @@ -278,6 +280,38 @@ def _set_health_checks(self, container, env, **kwargs): elif kwargs.get('routable', False): self._default_readiness_probe(container, kwargs.get('build_type'), env.get('PORT', None)) # noqa + def _set_lifecycle_hooks(self, container, env, **kwargs): + app_type = kwargs.get("app_type") + lifecycle_post_start = kwargs.get('lifecycle_post_start', {}) + lifecycle_post_start = lifecycle_post_start.get(app_type) + lifecycle_pre_stop = kwargs.get('lifecycle_pre_stop', {}) + lifecycle_pre_stop = lifecycle_pre_stop.get(app_type) + lifecycle = defaultdict(dict) + if lifecycle_post_start or lifecycle_pre_stop: + lifecycle = defaultdict(dict) + + if lifecycle_post_start: + lifecycle["postStart"] = { + 'exec': { + "command": [ + "/bin/bash", + "-c", + "{0}".format(lifecycle_post_start) + ] + } + } + if lifecycle_pre_stop: + lifecycle["preStop"] = { + 'exec': { + "command": [ + "/bin/bash", + "-c", + "{0}".format(lifecycle_pre_stop) + ] + } + } + container["lifecycle"] = dict(lifecycle) + def _default_readiness_probe(self, container, build_type, port=None): # Update only the application container with the health check if build_type == "buildpack": @@ -345,6 +379,15 @@ def _default_dockerapp_readiness_probe(self, port, delay=5, timeout=5, period_se } return readinessprobe + def _set_custom_termination_period(self, container, period_seconds=900): + """ + Applies a custom terminationGracePeriod only if provided as env variable. + """ + terminationperiod = { + 'terminationGracePeriodSeconds': int(period_seconds) + } + container.update(terminationperiod) + def delete(self, namespace, name): # get timeout info from pod pod = self.pod.get(namespace, name).json() From df2cd6bcd326b9525498673dfca2d711e3d7166c Mon Sep 17 00:00:00 2001 From: Madison Steiner Date: Tue, 25 Jul 2017 09:02:15 -0700 Subject: [PATCH 04/19] Fix spacing --- rootfs/api/models/config.py | 3 ++- rootfs/scheduler/resources/pod.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rootfs/api/models/config.py b/rootfs/api/models/config.py index 49ed4c1bd..4ab1145e6 100644 --- a/rootfs/api/models/config.py +++ b/rootfs/api/models/config.py @@ -164,7 +164,8 @@ def save(self, **kwargs): # usually means a totally new app previous_config = self.app.config_set.latest() - for attr in ['cpu', 'memory', 'tags', 'registry', 'values', 'lifecycle_post_start', 'lifecycle_pre_stop']: + for attr in ['cpu', 'memory', 'tags', 'registry', 'values', + 'lifecycle_post_start', 'lifecycle_pre_stop']: data = getattr(previous_config, attr, {}).copy() new_data = getattr(self, attr, {}).copy() diff --git a/rootfs/scheduler/resources/pod.py b/rootfs/scheduler/resources/pod.py index 5e52163c3..f1c0e62b8 100644 --- a/rootfs/scheduler/resources/pod.py +++ b/rootfs/scheduler/resources/pod.py @@ -291,7 +291,7 @@ def _set_lifecycle_hooks(self, container, env, **kwargs): lifecycle = defaultdict(dict) if lifecycle_post_start: - lifecycle["postStart"] = { + lifecycle["postStart"] = { 'exec': { "command": [ "/bin/bash", @@ -301,7 +301,7 @@ def _set_lifecycle_hooks(self, container, env, **kwargs): } } if lifecycle_pre_stop: - lifecycle["preStop"] = { + lifecycle["preStop"] = { 'exec': { "command": [ "/bin/bash", From 94d6c66f30eb0b34ca40de69a405758fa17894b4 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Tue, 25 Jul 2017 13:09:14 -0400 Subject: [PATCH 05/19] Fixing the broken config api tests --- rootfs/api/tests/test_config.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rootfs/api/tests/test_config.py b/rootfs/api/tests/test_config.py index c65721af3..08f2a0834 100644 --- a/rootfs/api/tests/test_config.py +++ b/rootfs/api/tests/test_config.py @@ -165,7 +165,8 @@ def test_response_data(self, mock_requests): response = self.client.post(url, body) for key in response.data: self.assertIn(key, ['uuid', 'owner', 'created', 'updated', 'app', 'values', 'memory', - 'cpu', 'tags', 'registry', 'healthcheck']) + 'cpu', 'tags', 'registry', 'healthcheck', 'lifecycle_post_start', + 'lifecycle_pre_stop']) expected = { 'owner': self.user.username, 'app': app_id, @@ -188,7 +189,8 @@ def test_response_data_types_converted(self, mock_requests): self.assertEqual(response.status_code, 201, response.data) for key in response.data: self.assertIn(key, ['uuid', 'owner', 'created', 'updated', 'app', 'values', 'memory', - 'cpu', 'tags', 'registry', 'healthcheck']) + 'cpu', 'tags', 'registry', 'healthcheck', 'lifecycle_post_start', + 'lifecycle_pre_stop']) expected = { 'owner': self.user.username, 'app': app_id, From 68ee0afd620659c7c6748c9d95d30eb6a3e5b3d8 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Wed, 16 Aug 2017 14:18:27 -0400 Subject: [PATCH 06/19] Adding procfile_structure to app api --- .../migrations/0025_app_procfile_structure.py | 22 +++++++++++++++++++ rootfs/api/models/app.py | 13 +++++++++++ rootfs/api/serializers.py | 3 ++- 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 rootfs/api/migrations/0025_app_procfile_structure.py diff --git a/rootfs/api/migrations/0025_app_procfile_structure.py b/rootfs/api/migrations/0025_app_procfile_structure.py new file mode 100644 index 000000000..efee506e8 --- /dev/null +++ b/rootfs/api/migrations/0025_app_procfile_structure.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.2 on 2017-08-14 20:45 +from __future__ import unicode_literals + +import api.models.app +from django.db import migrations +import jsonfield.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0024_config_lifecycle_hooks'), + ] + + operations = [ + migrations.AddField( + model_name='app', + name='procfile_structure', + field=jsonfield.fields.JSONField(blank=True, default={}, validators=[api.models.app.validate_app_structure]), + ), + ] diff --git a/rootfs/api/models/app.py b/rootfs/api/models/app.py index 1e0c2eca5..cec6d9a3b 100644 --- a/rootfs/api/models/app.py +++ b/rootfs/api/models/app.py @@ -71,6 +71,7 @@ class App(UuidAuditedModel): validators=[validate_app_id, validate_reserved_names]) structure = JSONField(default={}, blank=True, validators=[validate_app_structure]) + procfile_structure = JSONField(default={}, blank=True, validators=[validate_app_structure]) class Meta: verbose_name = 'Application' @@ -408,6 +409,7 @@ def scale(self, user, structure): # noqa if new_structure != self.structure: # save new structure to the database self.structure = new_structure + self.procfile_structure = release.build.procfile self.save() try: @@ -474,6 +476,7 @@ def deploy(self, release, force_deploy=False, rollback_on_failure=True): # noqa # set processes structure to default if app is new. if self.structure == {}: self.structure = self._default_structure(release) + self.procfile_structure = self._default_structure(release) self.save() # reset canonical process types if build type has changed. else: @@ -489,8 +492,18 @@ def deploy(self, release, force_deploy=False, rollback_on_failure=True): # noqa # update with the default process type. structure.update(self._default_structure(release)) self.structure = structure + # if procfile structure exists then we use it + if release.build.procfile and \ + release.build.sha and not \ + release.build.dockerfile: + self.procfile_structure = release.build.procfile self.save() + # always set the procfile structure for any new release + if release.build.procfile: + self.procfile_structure = release.build.procfile + self.save() + # deploy application to k8s. Also handles initial scaling app_settings = self.appsettings_set.latest() deploys = {} diff --git a/rootfs/api/serializers.py b/rootfs/api/serializers.py index 3c5bbbe74..b91cc8681 100644 --- a/rootfs/api/serializers.py +++ b/rootfs/api/serializers.py @@ -172,11 +172,12 @@ class AppSerializer(serializers.ModelSerializer): owner = serializers.ReadOnlyField(source='owner.username') structure = serializers.JSONField(required=False) + procfile_structure = serializers.JSONField(required=False) class Meta: """Metadata options for a :class:`AppSerializer`.""" model = models.App - fields = ['uuid', 'id', 'owner', 'structure', 'created', 'updated'] + fields = ['uuid', 'id', 'owner', 'structure', 'procfile_structure', 'created', 'updated'] class BuildSerializer(serializers.ModelSerializer): From d93fb516ba1a4f0a5af1a2b5f44e2a6b055a29f2 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Thu, 17 Aug 2017 14:44:28 -0400 Subject: [PATCH 07/19] Fixing the test_app.py failure --- rootfs/api/tests/test_app.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rootfs/api/tests/test_app.py b/rootfs/api/tests/test_app.py index 40dcb4197..5b4b3bf0f 100644 --- a/rootfs/api/tests/test_app.py +++ b/rootfs/api/tests/test_app.py @@ -90,7 +90,8 @@ def test_response_data(self, mock_requests): body = {'id': 'app-{}'.format(random.randrange(1000, 10000))} response = self.client.post('/v2/apps', body) for key in response.data: - self.assertIn(key, ['uuid', 'created', 'updated', 'id', 'owner', 'structure']) + self.assertIn(key, ['uuid', 'created', 'updated', 'id', 'owner', 'structure', + 'procfile_structure']) expected = { 'id': body['id'], 'owner': self.user.username, From c449566db21875e7fe25daae762d8ba9ccf4c8e2 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Mon, 28 Aug 2017 15:05:34 -0400 Subject: [PATCH 08/19] Adding exception msg to the release api with tests --- .../api/migrations/0026_release_exception.py | 20 +++++++++++++++++++ rootfs/api/models/build.py | 2 ++ rootfs/api/models/release.py | 3 +++ rootfs/api/tests/test_release.py | 2 +- rootfs/api/views.py | 2 ++ 5 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 rootfs/api/migrations/0026_release_exception.py diff --git a/rootfs/api/migrations/0026_release_exception.py b/rootfs/api/migrations/0026_release_exception.py new file mode 100644 index 000000000..3f681cc7d --- /dev/null +++ b/rootfs/api/migrations/0026_release_exception.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.2 on 2017-08-28 14:59 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0025_app_procfile_structure'), + ] + + operations = [ + migrations.AddField( + model_name='release', + name='exception', + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/rootfs/api/models/build.py b/rootfs/api/models/build.py index 34e58d426..924b634b0 100644 --- a/rootfs/api/models/build.py +++ b/rootfs/api/models/build.py @@ -72,6 +72,8 @@ def create(self, user, *args, **kwargs): if 'new_release' in locals(): new_release.failed = True new_release.summary = "{} deployed {} which failed".format(self.owner, str(self.uuid)[:7]) # noqa + # Get the exception that has occured + new_release.exception = "error: {}".format(str(e)) new_release.save() else: self.delete() diff --git a/rootfs/api/models/release.py b/rootfs/api/models/release.py index 330540b1e..8f98f86f5 100644 --- a/rootfs/api/models/release.py +++ b/rootfs/api/models/release.py @@ -24,6 +24,7 @@ class Release(UuidAuditedModel): version = models.PositiveIntegerField() summary = models.TextField(blank=True, null=True) failed = models.BooleanField(default=False) + exception = models.TextField(blank=True, null=True) config = models.ForeignKey('Config', on_delete=models.CASCADE) build = models.ForeignKey('Build', null=True, on_delete=models.CASCADE) @@ -243,6 +244,8 @@ def rollback(self, user, version=None): if 'new_release' in locals(): new_release.failed = True new_release.summary = "{} performed roll back to a release that failed".format(self.owner) # noqa + # Get the exception that has occured + new_release.exception = "error: {}".format(str(e)) new_release.save() raise DeisException(str(e)) from e diff --git a/rootfs/api/tests/test_release.py b/rootfs/api/tests/test_release.py index 71e3d231b..cdd5eedb4 100644 --- a/rootfs/api/tests/test_release.py +++ b/rootfs/api/tests/test_release.py @@ -114,7 +114,7 @@ def test_response_data(self, mock_requests): response = self.client.get(url) for key in response.data.keys(): self.assertIn(key, ['uuid', 'owner', 'created', 'updated', 'app', 'build', 'config', - 'summary', 'version', 'failed']) + 'summary', 'version', 'failed', 'exception']) expected = { 'owner': self.user.username, 'app': app_id, diff --git a/rootfs/api/views.py b/rootfs/api/views.py index 86c6624db..6866fca10 100644 --- a/rootfs/api/views.py +++ b/rootfs/api/views.py @@ -289,6 +289,8 @@ def post_save(self, config): if hasattr(self, 'release'): self.release.failed = True self.release.summary = "{} deployed a config that failed".format(self.request.user) # noqa + # Get the exception that has occured + self.release.exception = "error: {}".format(str(e)) self.release.save() else: config.delete() From 13f463ed1b689bbbb696c4063493fdc3cb36e906 Mon Sep 17 00:00:00 2001 From: Madison Steiner Date: Thu, 7 Sep 2017 15:15:42 -0700 Subject: [PATCH 09/19] Remove EOL warnings --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index ea0c0a578..2e6a7e3ce 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,4 @@ -|![](https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Warning.svg/156px-Warning.svg.png) | Deis Workflow will soon no longer be maintained.
Please [read the announcement](https://deis.com/blog/2017/deis-workflow-final-release/) for more detail. | -|---:|---| -| 09/07/2017 | Deis Workflow [v2.18][] final release before entering maintenance mode | -| 03/01/2018 | End of Workflow maintenance: critical patches no longer merged | - # Deis Controller [![Build Status](https://ci.deis.io/job/controller/badge/icon)](https://ci.deis.io/job/controller) From f42af9b3cf27bf232ceac57447c023193a360d7d Mon Sep 17 00:00:00 2001 From: Madison Steiner Date: Thu, 7 Sep 2017 15:28:20 -0700 Subject: [PATCH 10/19] Update URLs --- .github/PULL_REQUEST_TEMPLATE | 4 ++-- Makefile | 2 +- README.md | 10 +++++----- charts/controller/Chart.yaml | 2 +- rootfs/api/serializers.py | 2 +- rootfs/api/tests/test_app_settings.py | 2 +- rootfs/api/tests/test_auth.py | 2 +- rootfs/api/tests/test_config.py | 2 +- rootfs/api/tests/test_domain.py | 4 ++-- rootfs/api/tests/test_limits.py | 6 +++--- rootfs/api/tests/test_pods.py | 4 ++-- rootfs/api/tests/test_tls.py | 2 +- rootfs/dev_requirements.txt | 2 +- rootfs/scheduler/resources/pod.py | 4 ++-- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index a77ccb28e..c2d62322d 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -4,5 +4,5 @@ requires deis/workflow#1234 requires deis/workflow-e2e#5678 -[docs]: https://github.com/deis/workflow -[e2e]: https://github.com/deis/workflow-e2e +[docs]: https://github.com/deisthree/workflow +[e2e]: https://github.com/deisthree/workflow-e2e diff --git a/Makefile b/Makefile index ed689ab33..2e0d65a6e 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ test-functional: @echo "Implement functional tests in _tests directory" test-integration: - @echo "Check https://github.com/deis/workflow-e2e for the complete integration test suite" + @echo "Check https://github.com/deisthree/workflow-e2e for the complete integration test suite" upload-coverage: $(eval CI_ENV := $(shell curl -s https://codecov.io/env | bash)) diff --git a/README.md b/README.md index 2e6a7e3ce..9417cf063 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Deis (pronounced DAY-iss) Workflow is an open source Platform as a Service (PaaS) that adds a developer-friendly layer to any [Kubernetes](http://kubernetes.io) cluster, making it easy to deploy and manage applications on your own servers. -For more information about the Deis Workflow, please visit the main project page at https://github.com/deis/workflow. +For more information about the Deis Workflow, please visit the main project page at https://github.com/deisthree/workflow. We welcome your input! If you have feedback, please [submit an issue][issues]. If you'd like to participate in development, please read the "Development" section below and [submit a pull request][prs]. @@ -77,8 +77,8 @@ kubectl get pod --namespace=deis -w | grep deis-controller ``` [install-k8s]: https://kubernetes.io/docs/setup/pick-right-solution -[issues]: https://github.com/deis/controller/issues -[prs]: https://github.com/deis/controller/pulls -[workflow]: https://github.com/deis/workflow +[issues]: https://github.com/deisthree/controller/issues +[prs]: https://github.com/deisthree/controller/pulls +[workflow]: https://github.com/deisthree/workflow [Docker]: https://www.docker.com/ -[v2.18]: https://github.com/deis/workflow/releases/tag/v2.18.0 +[v2.18]: https://github.com/deisthree/workflow/releases/tag/v2.18.0 diff --git a/charts/controller/Chart.yaml b/charts/controller/Chart.yaml index 7071a1c51..b7928fe8b 100644 --- a/charts/controller/Chart.yaml +++ b/charts/controller/Chart.yaml @@ -1,5 +1,5 @@ name: controller -home: https://github.com/deis/controller +home: https://github.com/deisthree/controller version: description: Deis Workflow Controller (API). maintainers: diff --git a/rootfs/api/serializers.py b/rootfs/api/serializers.py index 46a46fb77..40087f16c 100644 --- a/rootfs/api/serializers.py +++ b/rootfs/api/serializers.py @@ -244,7 +244,7 @@ def validate_values(self, data): if key == 'HEALTHCHECK_URL': # Only Path information is supported, not query / anchor or anything else # Path is the only thing Kubernetes supports right now - # See https://github.com/deis/controller/issues/774 + # See https://github.com/deisthree/controller/issues/774 uri = urlparse(value) if not uri.path: diff --git a/rootfs/api/tests/test_app_settings.py b/rootfs/api/tests/test_app_settings.py index 27ef76d97..b587f5607 100644 --- a/rootfs/api/tests/test_app_settings.py +++ b/rootfs/api/tests/test_app_settings.py @@ -276,7 +276,7 @@ def test_settings_labels(self, mock_requests): base_labels = { 'label': { - 'git_repo': 'https://github.com/deis/controller', + 'git_repo': 'https://github.com/deisthree/controller', 'team': 'frontend', 'empty': '' } diff --git a/rootfs/api/tests/test_auth.py b/rootfs/api/tests/test_auth.py index 41d7efcea..0495e258c 100644 --- a/rootfs/api/tests/test_auth.py +++ b/rootfs/api/tests/test_auth.py @@ -378,5 +378,5 @@ def test_regenerate(self): def test_auth_no_ldap_by_default(self, mock_logger): """Ensure that LDAP authentication is disabled by default.""" self.test_auth() - # NOTE(bacongobbler): Using https://github.com/deis/controller/issues/1189 as a test case + # NOTE(bacongobbler): Using https://github.com/deisthree/controller/issues/1189 as a test case mock_logger.warning.assert_not_called() diff --git a/rootfs/api/tests/test_config.py b/rootfs/api/tests/test_config.py index c65721af3..f14fc3506 100644 --- a/rootfs/api/tests/test_config.py +++ b/rootfs/api/tests/test_config.py @@ -340,7 +340,7 @@ def test_admin_can_create_config_on_other_apps(self, mock_requests): def test_config_owner_is_requesting_user(self, mock_requests): """ Ensure that setting the config value is owned by the requesting user - See https://github.com/deis/deis/issues/2650 + See https://github.com/deisthree/deis/issues/2650 """ response = self.test_admin_can_create_config_on_other_apps() self.assertEqual(response.data['owner'], self.user.username) diff --git a/rootfs/api/tests/test_domain.py b/rootfs/api/tests/test_domain.py index 47d831eb7..9a024ab79 100644 --- a/rootfs/api/tests/test_domain.py +++ b/rootfs/api/tests/test_domain.py @@ -237,7 +237,7 @@ def test_delete_domain_does_not_exist(self): self.assertEqual(response.status_code, 404) def test_delete_domain_does_not_remove_latest(self): - """https://github.com/deis/deis/issues/3239""" + """https://github.com/deisthree/deis/issues/3239""" url = '/v2/apps/{app_id}/domains'.format(app_id=self.app_id) test_domains = [ 'test-domain.example.com', @@ -255,7 +255,7 @@ def test_delete_domain_does_not_remove_latest(self): Domain.objects.get(domain=test_domains[0]) def test_delete_domain_does_not_remove_others(self): - """https://github.com/deis/deis/issues/3475""" + """https://github.com/deisthree/deis/issues/3475""" self.test_delete_domain_does_not_remove_latest() self.assertEqual(Domain.objects.all().count(), 2) diff --git a/rootfs/api/tests/test_limits.py b/rootfs/api/tests/test_limits.py index d7b1f44aa..144c7bef8 100644 --- a/rootfs/api/tests/test_limits.py +++ b/rootfs/api/tests/test_limits.py @@ -64,7 +64,7 @@ def test_request_limit_memory(self, mock_requests): self.assertEqual(response.status_code, 200, response.data) self.assertIn('memory', response.data) self.assertEqual(response.data['memory'], {}) - # regression test for https://github.com/deis/deis/issues/1563 + # regression test for https://github.com/deisthree/deis/issues/1563 self.assertNotIn('"', response.data['memory']) # set an initial limit @@ -105,7 +105,7 @@ def test_request_limit_memory(self, mock_requests): self.assertIn('web', memory) self.assertEqual(memory['web'], '1G') - # regression test for https://github.com/deis/deis/issues/1613 + # regression test for https://github.com/deisthree/deis/issues/1613 # ensure that config:set doesn't wipe out previous limits body = {'values': json.dumps({'NEW_URL2': 'http://localhost:8080/'})} response = self.client.post(url, body) @@ -193,7 +193,7 @@ def test_request_limit_cpu(self, mock_requests): self.assertEqual(response.status_code, 200, response.data) self.assertIn('cpu', response.data) self.assertEqual(response.data['cpu'], {}) - # regression test for https://github.com/deis/deis/issues/1563 + # regression test for https://github.com/deisthree/deis/issues/1563 self.assertNotIn('"', response.data['cpu']) # set an initial limit diff --git a/rootfs/api/tests/test_pods.py b/rootfs/api/tests/test_pods.py index 978c97240..ecc48ca93 100644 --- a/rootfs/api/tests/test_pods.py +++ b/rootfs/api/tests/test_pods.py @@ -325,7 +325,7 @@ def test_container_str(self, mock_requests): self.assertRegex(pod['name'], app_id + '-(worker|web)-[0-9]{8,10}-[a-z0-9]{5}') def test_pod_command_format(self, mock_requests): - # regression test for https://github.com/deis/deis/pull/1285 + # regression test for https://github.com/deisthree/deis/pull/1285 app_id = self.create_app() # post a new build @@ -580,7 +580,7 @@ def test_run_command_good(self, mock_requests): def test_run_not_fail_on_debug(self, mock_requests): """ - do a run with DEIS_DEBUG on - https://github.com/deis/controller/issues/583 + do a run with DEIS_DEBUG on - https://github.com/deisthree/controller/issues/583 """ env = EnvironmentVarGuard() env['DEIS_DEBUG'] = 'true' diff --git a/rootfs/api/tests/test_tls.py b/rootfs/api/tests/test_tls.py index aba25aca0..fb09d95a0 100644 --- a/rootfs/api/tests/test_tls.py +++ b/rootfs/api/tests/test_tls.py @@ -66,7 +66,7 @@ def test_tls_created_on_app_create(self, mock_requests): """ Ensure that a TLS object is created for an App with default values. - See https://github.com/deis/controller/issues/1042 + See https://github.com/deisthree/controller/issues/1042 """ app_id = self.create_app() response = self.client.get('/v2/apps/{}/tls'.format(app_id)) diff --git a/rootfs/dev_requirements.txt b/rootfs/dev_requirements.txt index 4d4b2df0a..0281c4cf9 100644 --- a/rootfs/dev_requirements.txt +++ b/rootfs/dev_requirements.txt @@ -9,7 +9,7 @@ codecov==2.0.9 # mock out python-requests, mostly k8s # requests-mock==1.3.0 -git+https://github.com/deis/requests-mock.git@class_adapter#egg=request_mock +git+https://github.com/deisthree/requests-mock.git@class_adapter#egg=request_mock # tail a log and pipe into tbgrep to find all tracebacks tbgrep==0.3.0 diff --git a/rootfs/scheduler/resources/pod.py b/rootfs/scheduler/resources/pod.py index b8ad48c65..1443ce4a9 100644 --- a/rootfs/scheduler/resources/pod.py +++ b/rootfs/scheduler/resources/pod.py @@ -290,11 +290,11 @@ def _default_readiness_probe(self, container, build_type, port=None): http://kubernetes.io/docs/user-guide/pod-states/#container-probes /runner/init is the entry point of the slugrunner. - https://github.com/deis/slugrunner/blob/01eac53f1c5f1d1dfa7570bbd6b9e45c00441fea/rootfs/Dockerfile#L20 + https://github.com/deisthree/slugrunner/blob/01eac53f1c5f1d1dfa7570bbd6b9e45c00441fea/rootfs/Dockerfile#L20 Once it downloads the slug it starts running using `exec` which means the pid 1 will point to the slug/application command instead of entry point once the application has started. - https://github.com/deis/slugrunner/blob/01eac53f1c5f1d1dfa7570bbd6b9e45c00441fea/rootfs/runner/init#L90 + https://github.com/deisthree/slugrunner/blob/01eac53f1c5f1d1dfa7570bbd6b9e45c00441fea/rootfs/runner/init#L90 This should be added only for the build pack apps when a custom liveness probe is not set to make sure that the pod is ready only when the slug is downloaded and started running. From c60680f267ff1449281d227e9cfcb6295034d064 Mon Sep 17 00:00:00 2001 From: Duncan McNaught Date: Mon, 30 Oct 2017 13:49:23 -0600 Subject: [PATCH 11/19] Fixes #1326 deis run need pods-create perms rbac --- charts/controller/templates/controller-clusterrole.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/controller/templates/controller-clusterrole.yaml b/charts/controller/templates/controller-clusterrole.yaml index d0a08470a..53c934d72 100644 --- a/charts/controller/templates/controller-clusterrole.yaml +++ b/charts/controller/templates/controller-clusterrole.yaml @@ -34,7 +34,7 @@ rules: verbs: ["get"] - apiGroups: [""] resources: ["pods"] - verbs: ["get", "list", "delete"] + verbs: ["get", "list", "create", "delete"] - apiGroups: [""] resources: ["resourcequotas"] verbs: ["get", "create"] From bf1618cc0fb2949ffc7f4c166f6d9535c7a5e481 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Sun, 12 Nov 2017 21:21:43 -0500 Subject: [PATCH 12/19] Adding a travis file for testing --- .travis | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .travis diff --git a/.travis b/.travis new file mode 100644 index 000000000..0a8e4c46e --- /dev/null +++ b/.travis @@ -0,0 +1,7 @@ +sudo: required + +services: + - docker + +script: + make test \ No newline at end of file From 7010764e2b6001940d95659fe99b7b1129992719 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Sun, 12 Nov 2017 21:25:06 -0500 Subject: [PATCH 13/19] Rename file to .travis.yml --- .travis => .travis.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .travis => .travis.yml (100%) diff --git a/.travis b/.travis.yml similarity index 100% rename from .travis rename to .travis.yml From 8a762729c67dead9c7aef55896843f9d42e56042 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Sun, 12 Nov 2017 21:38:56 -0500 Subject: [PATCH 14/19] Adding language as go to travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0a8e4c46e..0f3fd606c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ sudo: required +language: go services: - docker From 8fe90cfe744580eaca26a841cd99aed612c6a922 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Mon, 13 Nov 2017 12:41:10 -0500 Subject: [PATCH 15/19] Fixing an api test failure --- rootfs/api/tests/test_auth.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rootfs/api/tests/test_auth.py b/rootfs/api/tests/test_auth.py index 0495e258c..9a826c0a5 100644 --- a/rootfs/api/tests/test_auth.py +++ b/rootfs/api/tests/test_auth.py @@ -378,5 +378,6 @@ def test_regenerate(self): def test_auth_no_ldap_by_default(self, mock_logger): """Ensure that LDAP authentication is disabled by default.""" self.test_auth() - # NOTE(bacongobbler): Using https://github.com/deisthree/controller/issues/1189 as a test case + # NOTE(bacongobbler): Using https://github.com/deisthree/controller/issues/1189 + # as a test case mock_logger.warning.assert_not_called() From c0d3d35c72ce4d2b7c029385e9931fc416132d33 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Tue, 14 Nov 2017 17:39:54 -0500 Subject: [PATCH 16/19] Trying out the travis notifications to Slack --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0f3fd606c..ce3dde90e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ sudo: required language: go - services: - - docker - -script: - make test \ No newline at end of file +- docker +script: make test +notifications: + slack: + secure: pWDCV3od8gxvzxh9DrOTvBL54XoCfWYhZZlwd2ZbyyOz6SS12Psg/ZuCT2253p4yMfF/LPlsz76mr7NgcCrMI0ReveTa/rnt3XBZtyY+1rlsQsy2oxgdAzbO587ENCQeMw2F/OWHaixMT8NDqxEqQd6xafK9Zmg6BeBjwgs7XfXKcR3WzNIuCO0ZG05+Yd0FIxmd/8Xm5tGiFEYr05+Ix6MLdF9MSCXZUPeu1EsYXhDljokLq49w63W1UMU10tm4t7VCEdaO+X9w6EJ5Ov8HDxb6L6IviUYY6+IGTZ01nwIoM6OrGQqfEAytYqgTKdehgQzQnAbLI6TW2wJ0twqEsLrlbTa4NW4j0KkazQJkN5kqcKYQvaeKJJhvJIG44Gi/u78pW3S6W7NU5DhrlE6bbxdIBHJW1vJBimkqu2oBNrO5ZoBB9MS9zflBsU5g/pQpVeHWMnWE8fcYDGa1PqAcr7q6wtdPsrVZhnHmmARN3PwZzIVVVsXbaIQG8VLC5grLGnwMf1Y1fz2nK3sVpCftvrYZT3G6CNAASo+eLOwYdZdiJ9jIS7WNLN1GtpIEvjeDt3QRqsDyH8YoAKUvY5h/v8IWPP/BaSwQbJwep4+Dj7xkpXX5/4wm4jEnVFV1p4xE0lD1AXvEMAVHtPhhggvscNhF9j6oeoPju6eTPcxG+5o= From ddbd8acef713e10c2918c28f1967ed937e32a817 Mon Sep 17 00:00:00 2001 From: Santiago Del Castillo Date: Fri, 15 Dec 2017 17:05:12 -0300 Subject: [PATCH 17/19] add support for rbac v1 API endpoint kubernetes >=1.8 moved rbac to v1 --- charts/controller/templates/_helpers.tmpl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/charts/controller/templates/_helpers.tmpl b/charts/controller/templates/_helpers.tmpl index 0b9deb080..c7f92fe10 100644 --- a/charts/controller/templates/_helpers.tmpl +++ b/charts/controller/templates/_helpers.tmpl @@ -2,9 +2,11 @@ Set apiVersion based on Kubernetes version */}} {{- define "rbacAPIVersion" -}} -{{- if ge .Capabilities.KubeVersion.Minor "6" -}} +{{- if lt .Capabilities.KubeVersion.Minor "6" -}} +rbac.authorization.k8s.io/v1alpha1 +{{- else if (and (ge .Capabilities.KubeVersion.Minor "6") (le .Capabilities.KubeVersion.Minor "7")) -}} rbac.authorization.k8s.io/v1beta1 {{- else -}} -rbac.authorization.k8s.io/v1alpha1 +rbac.authorization.k8s.io/v1 {{- end -}} {{- end -}} From 7fadd87bce0ca95cd535c867b397f47adc71761b Mon Sep 17 00:00:00 2001 From: Kingdon Barrett Date: Sat, 30 Jun 2018 13:50:32 -0400 Subject: [PATCH 18/19] fix(charts): int cast in version comparison --- charts/controller/templates/_helpers.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/controller/templates/_helpers.tmpl b/charts/controller/templates/_helpers.tmpl index c7f92fe10..f2541e3fb 100644 --- a/charts/controller/templates/_helpers.tmpl +++ b/charts/controller/templates/_helpers.tmpl @@ -2,9 +2,9 @@ Set apiVersion based on Kubernetes version */}} {{- define "rbacAPIVersion" -}} -{{- if lt .Capabilities.KubeVersion.Minor "6" -}} +{{- if (lt (int (.Capabilities.KubeVersion.Minor)) 6) -}} rbac.authorization.k8s.io/v1alpha1 -{{- else if (and (ge .Capabilities.KubeVersion.Minor "6") (le .Capabilities.KubeVersion.Minor "7")) -}} +{{- else if (and (ge (int (.Capabilities.KubeVersion.Minor)) 6) (le (int (.Capabilities.KubeVersion.Minor)) 7)) -}} rbac.authorization.k8s.io/v1beta1 {{- else -}} rbac.authorization.k8s.io/v1 From 877a7d94da5f88f7391e2c3d1b02d594a5035f70 Mon Sep 17 00:00:00 2001 From: Cryptophobia Date: Wed, 8 Aug 2018 12:08:48 -0400 Subject: [PATCH 19/19] fix(charts): set rbac apiVersion without casting --- charts/controller/templates/_helpers.tmpl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/controller/templates/_helpers.tmpl b/charts/controller/templates/_helpers.tmpl index f2541e3fb..422a5ae3f 100644 --- a/charts/controller/templates/_helpers.tmpl +++ b/charts/controller/templates/_helpers.tmpl @@ -1,11 +1,11 @@ {{/* -Set apiVersion based on Kubernetes version +Set apiVersion based on .Capabilities.APIVersions */}} {{- define "rbacAPIVersion" -}} -{{- if (lt (int (.Capabilities.KubeVersion.Minor)) 6) -}} -rbac.authorization.k8s.io/v1alpha1 -{{- else if (and (ge (int (.Capabilities.KubeVersion.Minor)) 6) (le (int (.Capabilities.KubeVersion.Minor)) 7)) -}} +{{- if .Capabilities.APIVersions.Has "rbac.authorization.k8s.io/v1beta1" -}} rbac.authorization.k8s.io/v1beta1 +{{- else if .Capabilities.APIVersions.Has "rbac.authorization.k8s.io/v1alpha1" -}} +rbac.authorization.k8s.io/v1alpha1 {{- else -}} rbac.authorization.k8s.io/v1 {{- end -}}