mirror of
https://github.com/ansible/awx.git
synced 2026-05-17 06:17:36 -02:30
Feature: custom virtual environment directories
Currently, users are allowed to define virtual environments in `settings.BASE_VENV_PATH` only, because that's the only place Tower looks for virtual environments. This feature allows users to custom define the directory paths, using API or UI, to look for virtual environments. Tower aggregates virtual environments from all these paths, except environments with special name `awx`. Signed-off-by: Vismay Golwala <vgolwala@redhat.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
# Python
|
||||
import os
|
||||
import logging
|
||||
import urllib.parse as urlparse
|
||||
from collections import OrderedDict
|
||||
@@ -96,6 +97,26 @@ class StringListBooleanField(ListField):
|
||||
self.fail('type_error', input_type=type(data))
|
||||
|
||||
|
||||
class StringListPathField(StringListField):
|
||||
|
||||
default_error_messages = {
|
||||
'type_error': _('Expected list of strings but got {input_type} instead.'),
|
||||
'path_error': _('{path} is not a valid path choice.'),
|
||||
}
|
||||
|
||||
def to_internal_value(self, paths):
|
||||
if isinstance(paths, (list, tuple)):
|
||||
for p in paths:
|
||||
if not isinstance(p, str):
|
||||
self.fail('type_error', input_type=type(p))
|
||||
if not os.path.exists(p):
|
||||
self.fail('path_error', path=p)
|
||||
|
||||
return super(StringListPathField, self).to_internal_value(sorted({os.path.normpath(path) for path in paths}))
|
||||
else:
|
||||
self.fail('type_error', input_type=type(paths))
|
||||
|
||||
|
||||
class URLField(CharField):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
|
||||
from rest_framework.fields import ValidationError
|
||||
from awx.conf.fields import StringListBooleanField, ListTuplesField
|
||||
from awx.conf.fields import StringListBooleanField, StringListPathField, ListTuplesField
|
||||
|
||||
|
||||
class TestStringListBooleanField():
|
||||
@@ -84,3 +84,49 @@ class TestListTuplesField():
|
||||
assert e.value.detail[0] == "Expected a list of tuples of max length 2 " \
|
||||
"but got {} instead.".format(t)
|
||||
|
||||
|
||||
class TestStringListPathField():
|
||||
|
||||
FIELD_VALUES = [
|
||||
((".", "..", "/"), [".", "..", "/"]),
|
||||
(("/home",), ["/home"]),
|
||||
(("///home///",), ["/home"]),
|
||||
(("/home/././././",), ["/home"]),
|
||||
(("/home", "/home", "/home/"), ["/home"]),
|
||||
(["/home/", "/home/", "/opt/", "/opt/", "/var/"], ["/home", "/opt", "/var"])
|
||||
]
|
||||
|
||||
FIELD_VALUES_INVALID_TYPE = [
|
||||
1.245,
|
||||
{"a": "b"},
|
||||
("/home"),
|
||||
]
|
||||
|
||||
FIELD_VALUES_INVALID_PATH = [
|
||||
"",
|
||||
"~/",
|
||||
"home",
|
||||
"/invalid_path",
|
||||
"/home/invalid_path",
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("value_in, value_known", FIELD_VALUES)
|
||||
def test_to_internal_value_valid(self, value_in, value_known):
|
||||
field = StringListPathField()
|
||||
v = field.to_internal_value(value_in)
|
||||
assert v == value_known
|
||||
|
||||
@pytest.mark.parametrize("value", FIELD_VALUES_INVALID_TYPE)
|
||||
def test_to_internal_value_invalid_type(self, value):
|
||||
field = StringListPathField()
|
||||
with pytest.raises(ValidationError) as e:
|
||||
field.to_internal_value(value)
|
||||
assert e.value.detail[0] == "Expected list of strings but got {} instead.".format(type(value))
|
||||
|
||||
@pytest.mark.parametrize("value", FIELD_VALUES_INVALID_PATH)
|
||||
def test_to_internal_value_invalid_path(self, value):
|
||||
field = StringListPathField()
|
||||
with pytest.raises(ValidationError) as e:
|
||||
field.to_internal_value([value])
|
||||
assert e.value.detail[0] == "{} is not a valid path choice.".format(value)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user