Skip to content

Commit aa7647c

Browse files
committed
Add feature flag management command
1 parent 8683e6c commit aa7647c

File tree

8 files changed

+57
-28
lines changed

8 files changed

+57
-28
lines changed

ansible_base/feature_flags/management/__init__.py

Whitespace-only changes.

ansible_base/feature_flags/management/commands/__init__.py

Whitespace-only changes.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
try:
2+
from tabulate import tabulate
3+
4+
HAS_TABULATE = True
5+
except ImportError:
6+
HAS_TABULATE = False
7+
8+
from django.core.management.base import BaseCommand
9+
from flags.state import flag_state
10+
11+
from ansible_base.feature_flags.models import AAPFlag
12+
13+
14+
class Command(BaseCommand):
15+
help = "AAP Feature Flag management command"
16+
17+
def add_arguments(self, parser):
18+
parser.add_argument("--list", action="store_true", help="List feature flags", required=False)
19+
20+
def handle(self, *args, **options):
21+
if options["list"]:
22+
self.list_feature_flags()
23+
24+
def list_feature_flags(self):
25+
feature_flags = []
26+
headers = ["Name", "UI_Name", "Value", "State", "Support Level", "Visibility", "Toggle Type", "Description", "Support URL"]
27+
28+
for feature_flag in AAPFlag.objects.all().order_by('name'):
29+
feature_flags.append(
30+
[
31+
f'{feature_flag.name}',
32+
f'{feature_flag.ui_name}',
33+
f'{feature_flag.value}',
34+
f'{flag_state(feature_flag.name)}',
35+
f'{feature_flag.support_level}',
36+
f'{feature_flag.visibility}',
37+
f'{feature_flag.toggle_type}',
38+
f'{feature_flag.description}',
39+
f'{feature_flag.support_url}',
40+
]
41+
)
42+
self.stdout.write('')
43+
44+
if HAS_TABULATE:
45+
self.stdout.write(tabulate(feature_flags, headers, tablefmt="github"))
46+
else:
47+
self.stdout.write("\t".join(headers))
48+
for feature_flag in feature_flags:
49+
self.stdout.write("\t".join(feature_flag))
50+
self.stdout.write('')

ansible_base/feature_flags/models/aap_flag.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
from ansible_base.activitystream.models import AuditableModel
66
from ansible_base.lib.abstract_models.common import NamedCommonModel
7-
from ansible_base.resource_registry.fields import AnsibleResourceField
7+
8+
# from ansible_base.resource_registry.fields import AnsibleResourceField
89

910

1011
def validate_feature_flag_name(value: str):
@@ -34,12 +35,7 @@ def __str__(self):
3435
validators=[validate_feature_flag_name],
3536
blank=False,
3637
)
37-
ui_name = models.CharField(
38-
max_length=64,
39-
null=False,
40-
blank=False,
41-
help_text=_("The pretty name to display in the application User Interface")
42-
)
38+
ui_name = models.CharField(max_length=64, null=False, blank=False, help_text=_("The pretty name to display in the application User Interface"))
4339
condition = models.CharField(max_length=64, default="boolean", help_text=_("Used to specify a condition, which if met, will enable the feature flag."))
4440
value = models.CharField(max_length=127, default="True", help_text=_("The value used to evaluate the conditional specified."))
4541
required = models.BooleanField(

ansible_base/feature_flags/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from django.apps import apps
2+
from django.conf import settings
23
from django.core.exceptions import ValidationError
34
from flags.sources import get_flags
45

@@ -51,6 +52,8 @@ def load_feature_flags():
5152
if existing_flag:
5253
update_feature_flag(existing_flag.first(), flag)
5354
else:
55+
if hasattr(settings, flag['name']):
56+
flag['value'] = getattr(settings, flag['name'])
5457
FeatureFlags.objects.create(**flag)
5558
AAPFlag(**flag).full_clean()
5659
except ValidationError as e:

ansible_base/feature_flags/views.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django.shortcuts import get_object_or_404
22
from django.utils.translation import gettext_lazy as _
3-
from flags.state import flag_enabled, flag_state, get_flags
3+
from flags.state import flag_enabled
44
from rest_framework import status
55
from rest_framework.response import Response
66
from rest_framework.viewsets import ModelViewSet
@@ -10,7 +10,6 @@
1010
from ansible_base.lib.utils.views.ansible_base import AnsibleBaseView
1111
from ansible_base.lib.utils.views.django_app_api import AnsibleBaseDjangoAppApiView
1212
from ansible_base.lib.utils.views.permissions import IsSuperuserOrAuditor
13-
from ansible_base.rest_pagination import DefaultPaginator
1413

1514
from .utils import get_django_flags, is_boolean_str
1615

@@ -31,10 +30,6 @@ def update(self, request, **kwargs):
3130
if not value:
3231
return Response(status=status.HTTP_400_BAD_REQUEST, data={"details": "Invalid request object."})
3332

34-
# Disable runtime toggle if the feature flag feature is not enabled
35-
if not flag_enabled('FEATURE_FEATURE_FLAGS_ENABLED'):
36-
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED, data={"details": "Runtime feature flags toggle is not enabled."})
37-
3833
feature_flag = get_object_or_404(AAPFlag, pk=_feature_flag.id)
3934
if feature_flag.toggle_type == 'install-time':
4035
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED, data={"details": "Install-time feature flags cannot be toggled at run-time."})

ansible_base/lib/dynamic_config/feature_flags/platform_flags.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,6 @@ class AAPFlagNameSchema(TypedDict):
1616

1717

1818
AAP_FEATURE_FLAGS: list[AAPFlagNameSchema] = [
19-
AAPFlagNameSchema(
20-
name="FEATURE_FEATURE_FLAGS_ENABLED",
21-
ui_name="Feature Flags",
22-
condition="boolean",
23-
value="True",
24-
support_level='READY_FOR_PRODUCTION',
25-
visibility="public",
26-
toggle_type='install-time',
27-
description='If enabled, feature flags can be toggled on/off at runtime via UI or API. '
28-
'If disabled, feature flags can only be toggled on/off at install-time.',
29-
support_url="",
30-
labels=['platform'],
31-
),
3219
AAPFlagNameSchema(
3320
name="FEATURE_INDIRECT_NODE_COUNTING_ENABLED",
3421
ui_name="Indirect Node Counting",

test_app/tests/feature_flags/test_old_api.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,3 @@ def test_feature_flags_state_api_list(admin_api_client: APIClient):
1414
assert response.data["FEATURE_EDA_ANALYTICS_ENABLED"] is False
1515
assert 'FEATURE_INDIRECT_NODE_COUNTING_ENABLED' in response.data
1616
assert response.data["FEATURE_INDIRECT_NODE_COUNTING_ENABLED"] is False
17-
assert 'FEATURE_FEATURE_FLAGS_ENABLED' in response.data
18-
assert response.data["FEATURE_FEATURE_FLAGS_ENABLED"] is True

0 commit comments

Comments
 (0)