mirror of
https://github.com/ansible/awx.git
synced 2026-01-18 21:21:21 -03:30
AC-687 Add ec2/rax region choices to inventory source options response, add validation for source_regions.
This commit is contained in:
parent
7929cfedd8
commit
8bf198f7ed
@ -677,6 +677,13 @@ class InventorySourceSerializer(BaseSerializer):
|
||||
# FIXME
|
||||
return attrs
|
||||
|
||||
def metadata(self):
|
||||
metadata = super(InventorySourceSerializer, self).metadata()
|
||||
field_opts = metadata.get('source_regions', {})
|
||||
field_opts['ec2_region_choices'] = self.opts.model.get_ec2_region_choices()
|
||||
field_opts['rax_region_choices'] = self.opts.model.get_rax_region_choices()
|
||||
return metadata
|
||||
|
||||
|
||||
class InventoryUpdateSerializer(BaseSerializer):
|
||||
|
||||
|
||||
@ -561,6 +561,36 @@ class InventorySource(PrimordialModel):
|
||||
editable=False,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_ec2_region_choices(cls):
|
||||
ec2_region_names = getattr(settings, 'EC2_REGION_NAMES', {})
|
||||
ec2_name_replacements = {
|
||||
'us': 'US',
|
||||
'ap': 'Asia Pacific',
|
||||
'eu': 'Europe',
|
||||
'sa': 'South America',
|
||||
}
|
||||
import boto.ec2
|
||||
regions = [('all', 'All')]
|
||||
for region in boto.ec2.regions():
|
||||
label = ec2_region_names.get(region.name, '')
|
||||
if not label:
|
||||
label_parts = []
|
||||
for part in region.name.split('-'):
|
||||
part = ec2_name_replacements.get(part.lower(), part.title())
|
||||
label_parts.append(part)
|
||||
label = ' '.join(label_parts)
|
||||
regions.append((region.name, label))
|
||||
return regions
|
||||
|
||||
@classmethod
|
||||
def get_rax_region_choices(cls):
|
||||
# Not possible to get rax regions without first authenticating, so use
|
||||
# list from settings.
|
||||
regions = list(getattr(settings, 'RAX_REGION_CHOICES', []))
|
||||
regions.insert(0, ('ALL', 'All'))
|
||||
return regions
|
||||
|
||||
def clean_credential(self):
|
||||
if not self.source:
|
||||
return None
|
||||
@ -576,6 +606,31 @@ class InventorySource(PrimordialModel):
|
||||
raise ValidationError('Credential is required for a cloud source')
|
||||
return cred
|
||||
|
||||
def clean_source_regions(self):
|
||||
regions = self.source_regions
|
||||
if self.source == 'ec2':
|
||||
valid_regions = [x[0] for x in self.get_ec2_region_choices()]
|
||||
region_transform = lambda x: x.strip().lower()
|
||||
elif self.source == 'rax':
|
||||
valid_regions = [x[0] for x in self.get_rax_region_choices()]
|
||||
region_transform = lambda x: x.strip().upper()
|
||||
else:
|
||||
return ''
|
||||
all_region = region_transform('all')
|
||||
valid_regions = [region_transform(x) for x in valid_regions]
|
||||
regions = [region_transform(x) for x in regions.split(',') if x.strip()]
|
||||
if all_region in regions:
|
||||
return all_region
|
||||
invalid_regions = []
|
||||
for r in regions:
|
||||
if r not in valid_regions and r not in invalid_regions:
|
||||
invalid_regions.append(r)
|
||||
if invalid_regions:
|
||||
raise ValidationError('Invalid %s region%s: %s' % (self.source,
|
||||
'' if len(invalid_regions) == 1 else 's',
|
||||
', '.join(invalid_regions)))
|
||||
return ','.join(regions)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
new_instance = not bool(self.pk)
|
||||
# If update_fields has been specified, add our field names to it,
|
||||
|
||||
@ -1030,6 +1030,116 @@ class InventoryUpdatesTest(BaseTransactionTest):
|
||||
self.assertFalse(re.match(r'^i-[0-9a-f]{8}$', group.name, re.I),
|
||||
group.name)
|
||||
|
||||
def test_put_inventory_source_detail_with_regions(self):
|
||||
creds_url = reverse('api:credential_list')
|
||||
inv_src_url1 = reverse('api:inventory_source_detail',
|
||||
args=(self.group.inventory_source.pk,))
|
||||
inv_src_url2 = reverse('api:inventory_source_detail',
|
||||
args=(self.group2.inventory_source.pk,))
|
||||
# Create an AWS credential to use for first inventory source.
|
||||
aws_cred_data = {
|
||||
'name': 'AWS key that does not need to have valid info because '
|
||||
'we do not care if the update actually succeeds',
|
||||
'kind': 'aws',
|
||||
'user': self.super_django_user.pk,
|
||||
'username': 'aws access key id goes here',
|
||||
'password': 'aws secret access key goes here',
|
||||
}
|
||||
with self.current_user(self.super_django_user):
|
||||
aws_cred_response = self.post(creds_url, aws_cred_data, expect=201)
|
||||
aws_cred_id = aws_cred_response['id']
|
||||
# Create a RAX credential to use for second inventory source.
|
||||
rax_cred_data = {
|
||||
'name': 'RAX cred that does not need to have valid info because '
|
||||
'we do not care if the update actually succeeds',
|
||||
'kind': 'rax',
|
||||
'user': self.super_django_user.pk,
|
||||
'username': 'rax username',
|
||||
'password': 'rax api key',
|
||||
}
|
||||
with self.current_user(self.super_django_user):
|
||||
rax_cred_response = self.post(creds_url, rax_cred_data, expect=201)
|
||||
rax_cred_id = rax_cred_response['id']
|
||||
# Verify the options request gives ec2 and rax region choices.
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.options(inv_src_url1, expect=200)
|
||||
self.assertTrue('ec2_region_choices' in response['actions']['GET']['source_regions'])
|
||||
self.assertTrue('rax_region_choices' in response['actions']['GET']['source_regions'])
|
||||
# Updaate the first inventory source to use EC2 with empty regions.
|
||||
inv_src_data = {
|
||||
'source': 'ec2',
|
||||
'credential': aws_cred_id,
|
||||
'source_regions': '',
|
||||
}
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url1, inv_src_data, expect=200)
|
||||
self.assertEqual(response['source_regions'], '')
|
||||
# All region.
|
||||
inv_src_data['source_regions'] = 'ALL'
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url1, inv_src_data, expect=200)
|
||||
self.assertEqual(response['source_regions'], 'all')
|
||||
# Invalid region.
|
||||
inv_src_data['source_regions'] = 'us-north-99'
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url1, inv_src_data, expect=400)
|
||||
# All takes precedence over any other regions.
|
||||
inv_src_data['source_regions'] = 'us-north-99,,all'
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url1, inv_src_data, expect=200)
|
||||
self.assertEqual(response['source_regions'], 'all')
|
||||
# Valid region.
|
||||
inv_src_data['source_regions'] = 'us-west-1'
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url1, inv_src_data, expect=200)
|
||||
self.assertEqual(response['source_regions'], 'us-west-1')
|
||||
# Invalid region (along with valid one).
|
||||
inv_src_data['source_regions'] = 'us-west-1, us-north-99'
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url1, inv_src_data, expect=400)
|
||||
# Valid regions.
|
||||
inv_src_data['source_regions'] = 'us-west-1, us-east-1, '
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url1, inv_src_data, expect=200)
|
||||
self.assertEqual(response['source_regions'], 'us-west-1,us-east-1')
|
||||
# Updaate the second inventory source to use RAX with empty regions.
|
||||
inv_src_data = {
|
||||
'source': 'rax',
|
||||
'credential': rax_cred_id,
|
||||
'source_regions': '',
|
||||
}
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url2, inv_src_data, expect=200)
|
||||
self.assertEqual(response['source_regions'], '')
|
||||
# All region.
|
||||
inv_src_data['source_regions'] = 'all'
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url2, inv_src_data, expect=200)
|
||||
self.assertEqual(response['source_regions'], 'ALL')
|
||||
# Invalid region.
|
||||
inv_src_data['source_regions'] = 'RDU'
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url2, inv_src_data, expect=400)
|
||||
# All takes precedence over any other regions.
|
||||
inv_src_data['source_regions'] = 'RDU,,all'
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url2, inv_src_data, expect=200)
|
||||
self.assertEqual(response['source_regions'], 'ALL')
|
||||
# Valid region.
|
||||
inv_src_data['source_regions'] = 'dfw'
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url2, inv_src_data, expect=200)
|
||||
self.assertEqual(response['source_regions'], 'DFW')
|
||||
# Invalid region (along with valid one).
|
||||
inv_src_data['source_regions'] = 'dfw, rdu'
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url2, inv_src_data, expect=400)
|
||||
# Valid regions.
|
||||
inv_src_data['source_regions'] = 'ORD, iad, '
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.put(inv_src_url2, inv_src_data, expect=200)
|
||||
self.assertEqual(response['source_regions'], 'ORD,IAD')
|
||||
|
||||
def test_post_inventory_source_update(self):
|
||||
creds_url = reverse('api:credential_list')
|
||||
inv_src_url = reverse('api:inventory_source_detail',
|
||||
|
||||
@ -292,6 +292,33 @@ ANSIBLE_PARAMIKO_RECORD_HOST_KEYS = False
|
||||
# the celery task.
|
||||
AWX_TASK_ENV = {}
|
||||
|
||||
# Not possible to get list of regions without authenticating, so use this list
|
||||
# instead (based on docs from:
|
||||
# http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/Service_Access_Endpoints-d1e517.html)
|
||||
RAX_REGION_CHOICES = [
|
||||
('ORD', 'Chicago'),
|
||||
('DFW', 'Dallas/Ft. Worth'),
|
||||
('IAD', 'Northern Virginia'),
|
||||
('LON', 'London'),
|
||||
('SYD', 'Sydney'),
|
||||
('HKG', 'Hong Kong'),
|
||||
]
|
||||
|
||||
# AWS does not appear to provide pretty region names via any API, so store the
|
||||
# list of names here. The available region IDs will be pulled from boto.
|
||||
# http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region
|
||||
EC2_REGION_NAMES = {
|
||||
'us-east-1': 'US East (Northern Virginia)',
|
||||
'us-west-2': 'US West (Oregon)',
|
||||
'us-west-1': 'US West (Northern California)',
|
||||
'eu-west-1': 'EU (Ireland)',
|
||||
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
||||
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
||||
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
||||
'sa-east-1': 'South America (Sao Paulo)',
|
||||
'us-gov-west-1': 'US West (GovCloud)',
|
||||
}
|
||||
|
||||
# Internal API URL for use by inventory scripts and callback plugin.
|
||||
if 'devserver' in INSTALLED_APPS:
|
||||
INTERNAL_API_URL = 'http://127.0.0.1:%s' % DEVSERVER_DEFAULT_PORT
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user