mirror of
https://github.com/ansible/awx.git
synced 2026-03-09 05:29:26 -02:30
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -109,7 +109,7 @@ class VarsDictProperty(object):
|
|||||||
pass
|
pass
|
||||||
if d is None and self.key_value:
|
if d is None and self.key_value:
|
||||||
d = {}
|
d = {}
|
||||||
for kv in [x.decode('utf-8') for x in shlex.split(extra_vars, posix=True)]:
|
for kv in [x.decode('utf-8') for x in shlex.split(v, posix=True)]:
|
||||||
if '=' in kv:
|
if '=' in kv:
|
||||||
k, v = kv.split('=', 1)
|
k, v = kv.split('=', 1)
|
||||||
d[k] = v
|
d[k] = v
|
||||||
|
|||||||
@@ -523,9 +523,9 @@ class HostSerializer(BaseSerializerWithVariables):
|
|||||||
d['groups'] = [{'id': g.id, 'name': g.name} for g in obj.groups.all()]
|
d['groups'] = [{'id': g.id, 'name': g.name} for g in obj.groups.all()]
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def _validate_name(self, attrs, source):
|
def _get_host_port_from_name(self, name):
|
||||||
name = unicode(attrs.get(source, ''))
|
|
||||||
# Allow hostname (except IPv6 for now) to specify the port # inline.
|
# Allow hostname (except IPv6 for now) to specify the port # inline.
|
||||||
|
port = None
|
||||||
if name.count(':') == 1:
|
if name.count(':') == 1:
|
||||||
name, port = name.split(':')
|
name, port = name.split(':')
|
||||||
try:
|
try:
|
||||||
@@ -533,20 +533,52 @@ class HostSerializer(BaseSerializerWithVariables):
|
|||||||
if port < 1 or port > 65535:
|
if port < 1 or port > 65535:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise serializers.ValidationError('Invalid port specification')
|
raise serializers.ValidationError('Invalid port specification: %s' % str(port))
|
||||||
for family in (socket.AF_INET, socket.AF_INET6):
|
return name, port
|
||||||
try:
|
|
||||||
socket.inet_pton(family, name)
|
def validate_name(self, attrs, source):
|
||||||
return attrs
|
name = unicode(attrs.get(source, ''))
|
||||||
except socket.error:
|
# Validate here only, update in main validate method.
|
||||||
pass
|
host, port = self._get_host_port_from_name(name)
|
||||||
|
#for family in (socket.AF_INET, socket.AF_INET6):
|
||||||
|
# try:
|
||||||
|
# socket.inet_pton(family, name)
|
||||||
|
# return attrs
|
||||||
|
# except socket.error:
|
||||||
|
# pass
|
||||||
# Hostname should match the following regular expression and have at
|
# Hostname should match the following regular expression and have at
|
||||||
# last one letter in the name (to catch invalid IPv4 addresses from
|
# last one letter in the name (to catch invalid IPv4 addresses from
|
||||||
# above).
|
# above).
|
||||||
valid_host_re = r'^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$'
|
#valid_host_re = r'^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$'
|
||||||
if re.match(valid_host_re, name) and re.match(r'^.*?[a-zA-Z].*?$', name):
|
#if re.match(valid_host_re, name) and re.match(r'^.*?[a-zA-Z].*?$', name):
|
||||||
return attrs
|
# return attrs
|
||||||
raise serializers.ValidationError('Invalid host name or IP')
|
#raise serializers.ValidationError('Invalid host name or IP')
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
name = unicode(attrs.get('name', ''))
|
||||||
|
host, port = self._get_host_port_from_name(name)
|
||||||
|
|
||||||
|
if port:
|
||||||
|
attrs['name'] = host
|
||||||
|
if self.object:
|
||||||
|
variables = unicode(attrs.get('variables', self.object.variables) or '')
|
||||||
|
else:
|
||||||
|
variables = unicode(attrs.get('variables', ''))
|
||||||
|
try:
|
||||||
|
vars_dict = json.loads(variables.strip() or '{}')
|
||||||
|
vars_dict['ansible_ssh_port'] = port
|
||||||
|
attrs['variables'] = json.dumps(vars_dict)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
try:
|
||||||
|
vars_dict = yaml.safe_load(variables)
|
||||||
|
vars_dict['ansible_ssh_port'] = port
|
||||||
|
attrs['variables'] = yaml.dump(vars_dict)
|
||||||
|
except (yaml.YAMLError, TypeError):
|
||||||
|
raise serializers.ValidationError('Must be valid JSON or YAML')
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class GroupSerializer(BaseSerializerWithVariables):
|
class GroupSerializer(BaseSerializerWithVariables):
|
||||||
|
|
||||||
@@ -588,7 +620,8 @@ class GroupTreeSerializer(GroupSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Group
|
model = Group
|
||||||
fields = BASE_FIELDS + ('inventory', 'variables', 'has_active_failures',
|
fields = BASE_FIELDS + ('inventory', 'variables', 'has_active_failures',
|
||||||
'hosts_with_active_failures',
|
'total_hosts', 'hosts_with_active_failures',
|
||||||
|
'total_groups', 'groups_with_active_failures',
|
||||||
'has_inventory_sources', 'children')
|
'has_inventory_sources', 'children')
|
||||||
|
|
||||||
def get_children(self, obj):
|
def get_children(self, obj):
|
||||||
@@ -642,6 +675,7 @@ class InventorySourceSerializer(BaseSerializer):
|
|||||||
'source_regions', 'source_tags', 'overwrite',
|
'source_regions', 'source_tags', 'overwrite',
|
||||||
'overwrite_vars', 'update_on_launch', 'update_interval',
|
'overwrite_vars', 'update_on_launch', 'update_interval',
|
||||||
'last_update_failed', 'status', 'last_updated')
|
'last_update_failed', 'status', 'last_updated')
|
||||||
|
read_only_fields = ('inventory', 'group')
|
||||||
|
|
||||||
def to_native(self, obj):
|
def to_native(self, obj):
|
||||||
ret = super(InventorySourceSerializer, self).to_native(obj)
|
ret = super(InventorySourceSerializer, self).to_native(obj)
|
||||||
|
|||||||
@@ -260,11 +260,17 @@ class InventoryTest(BaseTest):
|
|||||||
invalid = dict(name='asdf0.example.com')
|
invalid = dict(name='asdf0.example.com')
|
||||||
new_host_a = dict(name='asdf0.example.com:1022', inventory=inv.pk)
|
new_host_a = dict(name='asdf0.example.com:1022', inventory=inv.pk)
|
||||||
new_host_b = dict(name='asdf1.example.com', inventory=inv.pk)
|
new_host_b = dict(name='asdf1.example.com', inventory=inv.pk)
|
||||||
new_host_c = dict(name='127.1.2.3:2022', inventory=inv.pk)
|
new_host_c = dict(name='127.1.2.3:2022', inventory=inv.pk,
|
||||||
|
variables=json.dumps({'who': 'what?'}))
|
||||||
new_host_d = dict(name='asdf3.example.com', inventory=inv.pk)
|
new_host_d = dict(name='asdf3.example.com', inventory=inv.pk)
|
||||||
new_host_e = dict(name='asdf4.example.com', inventory=inv.pk)
|
new_host_e = dict(name='asdf4.example.com', inventory=inv.pk)
|
||||||
host_data0 = self.post(hosts, data=invalid, expect=400, auth=self.get_super_credentials())
|
host_data0 = self.post(hosts, data=invalid, expect=400, auth=self.get_super_credentials())
|
||||||
host_data0 = self.post(hosts, data=new_host_a, expect=201, auth=self.get_super_credentials())
|
host_data0 = self.post(hosts, data=new_host_a, expect=201, auth=self.get_super_credentials())
|
||||||
|
|
||||||
|
# Port should be split out into host variables.
|
||||||
|
host_a = Host.objects.get(pk=host_data0['id'])
|
||||||
|
self.assertEqual(host_a.name, 'asdf0.example.com')
|
||||||
|
self.assertEqual(host_a.variables_dict, {'ansible_ssh_port': 1022})
|
||||||
|
|
||||||
# an org admin can add hosts
|
# an org admin can add hosts
|
||||||
host_data1 = self.post(hosts, data=new_host_e, expect=201, auth=self.get_normal_credentials())
|
host_data1 = self.post(hosts, data=new_host_e, expect=201, auth=self.get_normal_credentials())
|
||||||
@@ -280,6 +286,11 @@ class InventoryTest(BaseTest):
|
|||||||
)
|
)
|
||||||
host_data3 = self.post(hosts, data=new_host_c, expect=201, auth=self.get_other_credentials())
|
host_data3 = self.post(hosts, data=new_host_c, expect=201, auth=self.get_other_credentials())
|
||||||
|
|
||||||
|
# Port should be split out into host variables, other variables kept intact.
|
||||||
|
host_c = Host.objects.get(pk=host_data3['id'])
|
||||||
|
self.assertEqual(host_c.name, '127.1.2.3')
|
||||||
|
self.assertEqual(host_c.variables_dict, {'ansible_ssh_port': 2022, 'who': 'what?'})
|
||||||
|
|
||||||
# hostnames must be unique inside an organization
|
# hostnames must be unique inside an organization
|
||||||
host_data4 = self.post(hosts, data=new_host_c, expect=400, auth=self.get_other_credentials())
|
host_data4 = self.post(hosts, data=new_host_c, expect=400, auth=self.get_other_credentials())
|
||||||
|
|
||||||
@@ -680,22 +691,22 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# Try with invalid hostnames and invalid IPs.
|
# Try with invalid hostnames and invalid IPs.
|
||||||
hosts = reverse('main:host_list')
|
hosts = reverse('main:host_list')
|
||||||
invalid_expect = 201 # hostname validation is disabled for now.
|
invalid_expect = 400 # hostname validation is disabled for now.
|
||||||
data = dict(name='', inventory=inv.pk)
|
data = dict(name='', inventory=inv.pk)
|
||||||
with self.current_user(self.super_django_user):
|
with self.current_user(self.super_django_user):
|
||||||
response = self.post(hosts, data=data, expect=400)
|
response = self.post(hosts, data=data, expect=400)
|
||||||
data = dict(name='not a valid host name', inventory=inv.pk)
|
#data = dict(name='not a valid host name', inventory=inv.pk)
|
||||||
with self.current_user(self.super_django_user):
|
#with self.current_user(self.super_django_user):
|
||||||
response = self.post(hosts, data=data, expect=invalid_expect)
|
# response = self.post(hosts, data=data, expect=invalid_expect)
|
||||||
data = dict(name='validhost:99999', inventory=inv.pk)
|
data = dict(name='validhost:99999', inventory=inv.pk)
|
||||||
with self.current_user(self.super_django_user):
|
with self.current_user(self.super_django_user):
|
||||||
response = self.post(hosts, data=data, expect=invalid_expect)
|
response = self.post(hosts, data=data, expect=invalid_expect)
|
||||||
data = dict(name='123.234.345.456', inventory=inv.pk)
|
#data = dict(name='123.234.345.456', inventory=inv.pk)
|
||||||
with self.current_user(self.super_django_user):
|
#with self.current_user(self.super_django_user):
|
||||||
response = self.post(hosts, data=data, expect=invalid_expect)
|
# response = self.post(hosts, data=data, expect=invalid_expect)
|
||||||
data = dict(name='2001::1::3F', inventory=inv.pk)
|
#data = dict(name='2001::1::3F', inventory=inv.pk)
|
||||||
with self.current_user(self.super_django_user):
|
#with self.current_user(self.super_django_user):
|
||||||
response = self.post(hosts, data=data, expect=invalid_expect)
|
# response = self.post(hosts, data=data, expect=invalid_expect)
|
||||||
|
|
||||||
#########################################################
|
#########################################################
|
||||||
# FIXME: TAGS
|
# FIXME: TAGS
|
||||||
|
|||||||
Reference in New Issue
Block a user