mirror of
https://github.com/ZwareBear/awx.git
synced 2026-05-01 12:21:48 -05:00
Merge branch 'rbac' of github.com:ansible/ansible-tower into rbac
This commit is contained in:
@@ -1054,12 +1054,16 @@ class UnifiedJobTemplateAccess(BaseAccess):
|
||||
'last_job',
|
||||
'current_job',
|
||||
)
|
||||
qs = qs.prefetch_related(
|
||||
#'project',
|
||||
'inventory',
|
||||
'credential',
|
||||
'cloud_credential',
|
||||
)
|
||||
|
||||
# WISH - sure would be nice if the following worked, but it does not.
|
||||
# In the future, as django and polymorphic libs are upgraded, try again.
|
||||
|
||||
#qs = qs.prefetch_related(
|
||||
# 'project',
|
||||
# 'inventory',
|
||||
# 'credential',
|
||||
# 'cloud_credential',
|
||||
#)
|
||||
|
||||
return qs.all()
|
||||
|
||||
@@ -1089,20 +1093,26 @@ class UnifiedJobAccess(BaseAccess):
|
||||
)
|
||||
qs = qs.prefetch_related(
|
||||
'unified_job_template',
|
||||
'project',
|
||||
'inventory',
|
||||
'credential',
|
||||
'job_template',
|
||||
'inventory_source',
|
||||
'cloud_credential',
|
||||
'project___credential',
|
||||
'inventory_source___credential',
|
||||
'inventory_source___inventory',
|
||||
'job_template__inventory',
|
||||
'job_template__project',
|
||||
'job_template__credential',
|
||||
'job_template__cloud_credential',
|
||||
)
|
||||
|
||||
# WISH - sure would be nice if the following worked, but it does not.
|
||||
# In the future, as django and polymorphic libs are upgraded, try again.
|
||||
|
||||
#qs = qs.prefetch_related(
|
||||
# 'project',
|
||||
# 'inventory',
|
||||
# 'credential',
|
||||
# 'job_template',
|
||||
# 'inventory_source',
|
||||
# 'cloud_credential',
|
||||
# 'project___credential',
|
||||
# 'inventory_source___credential',
|
||||
# 'inventory_source___inventory',
|
||||
# 'job_template__inventory',
|
||||
# 'job_template__project',
|
||||
# 'job_template__credential',
|
||||
# 'job_template__cloud_credential',
|
||||
#)
|
||||
return qs.all()
|
||||
|
||||
class ScheduleAccess(BaseAccess):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Copyright (c) 2015 Ansible, Inc.
|
||||
# All Rights Reserved.
|
||||
|
||||
CLOUD_PROVIDERS = ('azure', 'ec2', 'gce', 'rax', 'vmware', 'openstack', 'openstack_v3')
|
||||
CLOUD_PROVIDERS = ('azure', 'ec2', 'gce', 'rax', 'vmware', 'openstack')
|
||||
SCHEDULEABLE_PROVIDERS = CLOUD_PROVIDERS + ('custom',)
|
||||
|
||||
@@ -381,7 +381,7 @@ class Migration(migrations.Migration):
|
||||
name='AdHocCommand',
|
||||
fields=[
|
||||
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJob')),
|
||||
('job_type', models.CharField(default=b'run', max_length=64, choices=[(b'run', 'Run'), (b'check', 'Check'), (b'scan', 'Scan')])),
|
||||
('job_type', models.CharField(default=b'run', max_length=64, choices=[(b'run', 'Run'), (b'check', 'Check')])),
|
||||
('limit', models.CharField(default=b'', max_length=1024, blank=True)),
|
||||
('module_name', models.CharField(default=b'', max_length=1024, blank=True)),
|
||||
('module_args', models.TextField(default=b'', blank=True)),
|
||||
|
||||
@@ -36,7 +36,7 @@ class AdHocCommand(UnifiedJob):
|
||||
|
||||
job_type = models.CharField(
|
||||
max_length=64,
|
||||
choices=JOB_TYPE_CHOICES,
|
||||
choices=AD_HOC_JOB_TYPE_CHOICES,
|
||||
default='run',
|
||||
)
|
||||
inventory = models.ForeignKey(
|
||||
|
||||
@@ -29,7 +29,7 @@ __all__ = ['VarsDictProperty', 'BaseModel', 'CreatedModifiedModel',
|
||||
'PERM_INVENTORY_ADMIN', 'PERM_INVENTORY_READ',
|
||||
'PERM_INVENTORY_WRITE', 'PERM_INVENTORY_DEPLOY', 'PERM_INVENTORY_SCAN',
|
||||
'PERM_INVENTORY_CHECK', 'PERM_JOBTEMPLATE_CREATE', 'JOB_TYPE_CHOICES',
|
||||
'PERMISSION_TYPE_CHOICES', 'CLOUD_INVENTORY_SOURCES',
|
||||
'AD_HOC_JOB_TYPE_CHOICES', 'PERMISSION_TYPE_CHOICES', 'CLOUD_INVENTORY_SOURCES',
|
||||
'VERBOSITY_CHOICES']
|
||||
|
||||
PERM_INVENTORY_ADMIN = 'admin'
|
||||
@@ -46,6 +46,11 @@ JOB_TYPE_CHOICES = [
|
||||
(PERM_INVENTORY_SCAN, _('Scan')),
|
||||
]
|
||||
|
||||
AD_HOC_JOB_TYPE_CHOICES = [
|
||||
(PERM_INVENTORY_DEPLOY, _('Run')),
|
||||
(PERM_INVENTORY_CHECK, _('Check')),
|
||||
]
|
||||
|
||||
PERMISSION_TYPE_CHOICES = [
|
||||
(PERM_INVENTORY_READ, _('Read Inventory')),
|
||||
(PERM_INVENTORY_WRITE, _('Edit Inventory')),
|
||||
@@ -56,7 +61,7 @@ PERMISSION_TYPE_CHOICES = [
|
||||
(PERM_JOBTEMPLATE_CREATE, _('Create a Job Template')),
|
||||
]
|
||||
|
||||
CLOUD_INVENTORY_SOURCES = ['ec2', 'rax', 'vmware', 'gce', 'azure', 'openstack', 'openstack_v3', 'custom']
|
||||
CLOUD_INVENTORY_SOURCES = ['ec2', 'rax', 'vmware', 'gce', 'azure', 'openstack', 'custom']
|
||||
|
||||
VERBOSITY_CHOICES = [
|
||||
(0, '0 (Normal)'),
|
||||
|
||||
@@ -40,7 +40,6 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
|
||||
('gce', _('Google Compute Engine')),
|
||||
('azure', _('Microsoft Azure')),
|
||||
('openstack', _('OpenStack')),
|
||||
('openstack_v3', _('OpenStack V3')),
|
||||
]
|
||||
|
||||
BECOME_METHOD_CHOICES = [
|
||||
@@ -237,18 +236,12 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
|
||||
host = self.host or ''
|
||||
if not host and self.kind == 'vmware':
|
||||
raise ValidationError('Host required for VMware credential.')
|
||||
if not host and self.kind in ('openstack', 'openstack_v3'):
|
||||
if not host and self.kind == 'openstack':
|
||||
raise ValidationError('Host required for OpenStack credential.')
|
||||
return host
|
||||
|
||||
def clean_domain(self):
|
||||
"""For case of Keystone v3 identity service that requires a
|
||||
`domain`, that a domain is provided.
|
||||
"""
|
||||
domain = self.domain or ''
|
||||
if not domain and self.kind == 'openstack_v3':
|
||||
raise ValidationError('Domain required for OpenStack with Keystone v3.')
|
||||
return domain
|
||||
return self.domain or ''
|
||||
|
||||
def clean_username(self):
|
||||
username = self.username or ''
|
||||
@@ -259,7 +252,7 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
|
||||
'credential.')
|
||||
if not username and self.kind == 'vmware':
|
||||
raise ValidationError('Username required for VMware credential.')
|
||||
if not username and self.kind in ('openstack', 'openstack_v3'):
|
||||
if not username and self.kind == 'openstack':
|
||||
raise ValidationError('Username required for OpenStack credential.')
|
||||
return username
|
||||
|
||||
@@ -271,13 +264,13 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
|
||||
raise ValidationError('API key required for Rackspace credential.')
|
||||
if not password and self.kind == 'vmware':
|
||||
raise ValidationError('Password required for VMware credential.')
|
||||
if not password and self.kind in ('openstack', 'openstack_v3'):
|
||||
if not password and self.kind == 'openstack':
|
||||
raise ValidationError('Password or API key required for OpenStack credential.')
|
||||
return password
|
||||
|
||||
def clean_project(self):
|
||||
project = self.project or ''
|
||||
if self.kind in ('openstack', 'openstack_v3') and not project:
|
||||
if self.kind == 'openstack' and not project:
|
||||
raise ValidationError('Project name required for OpenStack credential.')
|
||||
return project
|
||||
|
||||
|
||||
@@ -733,7 +733,6 @@ class InventorySourceOptions(BaseModel):
|
||||
('azure', _('Microsoft Azure')),
|
||||
('vmware', _('VMware vCenter')),
|
||||
('openstack', _('OpenStack')),
|
||||
('openstack_v3', _('OpenStack V3')),
|
||||
('custom', _('Custom Script')),
|
||||
]
|
||||
|
||||
@@ -962,11 +961,6 @@ class InventorySourceOptions(BaseModel):
|
||||
"""I don't think openstack has regions"""
|
||||
return [('all', 'All')]
|
||||
|
||||
@classmethod
|
||||
def get_openstack_v3_region_choices(self):
|
||||
"""Defer to the behavior of openstack"""
|
||||
return self.get_openstack_region_choices()
|
||||
|
||||
def clean_credential(self):
|
||||
if not self.source:
|
||||
return None
|
||||
|
||||
@@ -378,6 +378,10 @@ class BaseTask(Task):
|
||||
if 'OPENSSH PRIVATE KEY' in data and not openssh_keys_supported:
|
||||
raise RuntimeError(OPENSSH_KEY_ERROR)
|
||||
for name, data in private_data.iteritems():
|
||||
# OpenSSH formatted keys must have a trailing newline to be
|
||||
# accepted by ssh-add.
|
||||
if 'OPENSSH PRIVATE KEY' in data and not data.endswith('\n'):
|
||||
data += '\n'
|
||||
# For credentials used with ssh-add, write to a named pipe which
|
||||
# will be read then closed, instead of leaving the SSH key on disk.
|
||||
if name in ('credential', 'scm_credential', 'ad_hoc_credential') and not ssh_too_old:
|
||||
@@ -695,7 +699,7 @@ class RunJob(BaseTask):
|
||||
if credential.ssh_key_data not in (None, ''):
|
||||
private_data[cred_name] = decrypt_field(credential, 'ssh_key_data') or ''
|
||||
|
||||
if job.cloud_credential and job.cloud_credential.kind in ('openstack', 'openstack_v3'):
|
||||
if job.cloud_credential and job.cloud_credential.kind == 'openstack':
|
||||
credential = job.cloud_credential
|
||||
openstack_auth = dict(auth_url=credential.host,
|
||||
username=credential.username,
|
||||
@@ -787,7 +791,7 @@ class RunJob(BaseTask):
|
||||
env['VMWARE_USER'] = cloud_cred.username
|
||||
env['VMWARE_PASSWORD'] = decrypt_field(cloud_cred, 'password')
|
||||
env['VMWARE_HOST'] = cloud_cred.host
|
||||
elif cloud_cred and cloud_cred.kind in ('openstack', 'openstack_v3'):
|
||||
elif cloud_cred and cloud_cred.kind == 'openstack':
|
||||
env['OS_CLIENT_CONFIG_FILE'] = kwargs.get('private_data_files', {}).get('cloud_credential', '')
|
||||
|
||||
# Set environment variables related to scan jobs
|
||||
@@ -1136,7 +1140,7 @@ class RunInventoryUpdate(BaseTask):
|
||||
credential = inventory_update.credential
|
||||
return dict(cloud_credential=decrypt_field(credential, 'ssh_key_data'))
|
||||
|
||||
if inventory_update.source in ('openstack', 'openstack_v3'):
|
||||
if inventory_update.source == 'openstack':
|
||||
credential = inventory_update.credential
|
||||
openstack_auth = dict(auth_url=credential.host,
|
||||
username=credential.username,
|
||||
@@ -1291,7 +1295,7 @@ class RunInventoryUpdate(BaseTask):
|
||||
env['GCE_PROJECT'] = passwords.get('source_project', '')
|
||||
env['GCE_PEM_FILE_PATH'] = cloud_credential
|
||||
env['GCE_ZONE'] = inventory_update.source_regions
|
||||
elif inventory_update.source in ('openstack', 'openstack_v3'):
|
||||
elif inventory_update.source == 'openstack':
|
||||
env['OS_CLIENT_CONFIG_FILE'] = cloud_credential
|
||||
elif inventory_update.source == 'file':
|
||||
# FIXME: Parse source_env to dict, update env.
|
||||
@@ -1334,11 +1338,6 @@ class RunInventoryUpdate(BaseTask):
|
||||
# to a shorter variable. :)
|
||||
src = inventory_update.source
|
||||
|
||||
# OpenStack V3 has everything in common with OpenStack aside
|
||||
# from one extra parameter, so share these resources between them.
|
||||
if src == 'openstack_v3':
|
||||
src = 'openstack'
|
||||
|
||||
# Get the path to the inventory plugin, and append it to our
|
||||
# arguments.
|
||||
plugin_path = self.get_path_to('..', 'plugins', 'inventory',
|
||||
|
||||
@@ -84,8 +84,7 @@ HPUhg3adAmIJ9z9u/VmTErbVklcKWlyZuTUkxeQ/BJmSIRUQAAAIEA3oKAzdDURjy8zxLX
|
||||
gBLCPdi8AxCiqQJBCsGxXCgKtZewset1XJHIN9ryfb4QSZFkSOlm/LgdeGtS8Or0GNPRYd
|
||||
hgnUCF0LkEsDQ7HzPZYujLrAwjumvGQH6ORp5vRh0tQb93o4e1/A2vpdSKeH7gCe/jfUSY
|
||||
h7dFGNoAI4cF7/0AAAAUcm9vdEBwaWxsb3cuaXhtbS5uZXQBAgMEBQYH
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
'''
|
||||
-----END OPENSSH PRIVATE KEY-----'''
|
||||
|
||||
TEST_OPENSSH_KEY_DATA_LOCKED = '''-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABALaWMfjc
|
||||
@@ -114,8 +113,7 @@ C6Oxl1Wsp3gPkK2yiuy8qcrvoEoJ25TeEhUGEAPWx2OuQJO/Lpq9aF/JJoqGwnBaXdCsi+
|
||||
5ig+ZMq5GKQtyydzyXImjlNEUH1w2prRDiGVEufANA5LSLCtqOLgDzXS62WUBjJBrQJVAM
|
||||
YpWz1tiZQoyv1RT3Y0O0Vwe2Z5AK3fVM0I5jWdiLrIErtcR4ULa6T56QtA52DufhKzINTR
|
||||
Vg9TtUBqfKIpRQikPSjm7vpY/Xnbc=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
'''
|
||||
-----END OPENSSH PRIVATE KEY-----'''
|
||||
|
||||
TEST_SSH_CERT_KEY = """-----BEGIN CERTIFICATE-----
|
||||
MIIDNTCCAh2gAwIBAgIBATALBgkqhkiG9w0BAQswSTEWMBQGA1UEAwwNV2luZG93
|
||||
|
||||
@@ -128,6 +128,7 @@ def test_two_organizations(resourced_organization, organizations, user, get):
|
||||
'teams': 0
|
||||
}
|
||||
|
||||
@pytest.mark.skip(reason="resolution planned for after RBAC merge")
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.skipif("True") # XXX: This needs to be implemented
|
||||
def test_JT_associated_with_project(organizations, project, user, get):
|
||||
|
||||
@@ -1970,7 +1970,7 @@ class InventoryUpdatesTest(BaseTransactionTest):
|
||||
self.check_inventory_source(inventory_source)
|
||||
self.assertFalse(self.group.all_hosts.filter(instance_id='').exists())
|
||||
|
||||
def test_update_from_openstack_v3(self):
|
||||
def test_update_from_openstack_with_domain(self):
|
||||
# Check that update works with Keystone v3 identity service
|
||||
api_url = getattr(settings, 'TEST_OPENSTACK_HOST_V3', '')
|
||||
api_user = getattr(settings, 'TEST_OPENSTACK_USER', '')
|
||||
@@ -1978,15 +1978,15 @@ class InventoryUpdatesTest(BaseTransactionTest):
|
||||
api_project = getattr(settings, 'TEST_OPENSTACK_PROJECT', '')
|
||||
api_domain = getattr(settings, 'TEST_OPENSTACK_DOMAIN', '')
|
||||
if not all([api_url, api_user, api_password, api_project, api_domain]):
|
||||
self.skipTest("No test openstack v3 credentials defined")
|
||||
self.skipTest("No test openstack credentials defined with a domain")
|
||||
self.create_test_license_file()
|
||||
credential = Credential.objects.create(kind='openstack_v3',
|
||||
credential = Credential.objects.create(kind='openstack',
|
||||
host=api_url,
|
||||
username=api_user,
|
||||
password=api_password,
|
||||
project=api_project,
|
||||
domain=api_domain)
|
||||
inventory_source = self.update_inventory_source(self.group, source='openstack_v3', credential=credential)
|
||||
inventory_source = self.update_inventory_source(self.group, source='openstack', credential=credential)
|
||||
self.check_inventory_source(inventory_source)
|
||||
self.assertFalse(self.group.all_hosts.filter(instance_id='').exists())
|
||||
|
||||
@@ -2034,27 +2034,3 @@ class InventoryCredentialTest(BaseTest):
|
||||
self.assertIn('password', response)
|
||||
self.assertIn('host', response)
|
||||
self.assertIn('project', response)
|
||||
|
||||
def test_openstack_v3_create_ok(self):
|
||||
data = {
|
||||
'kind': 'openstack_v3',
|
||||
'name': 'Best credential ever',
|
||||
'username': 'some_user',
|
||||
'password': 'some_password',
|
||||
'project': 'some_project',
|
||||
'host': 'some_host',
|
||||
'domain': 'some_domain',
|
||||
}
|
||||
self.post(self.url, data=data, expect=201, auth=self.get_super_credentials())
|
||||
|
||||
def test_openstack_v3_create_fail_required_fields(self):
|
||||
data = {
|
||||
'kind': 'openstack_v3',
|
||||
'name': 'Best credential ever',
|
||||
}
|
||||
response = self.post(self.url, data=data, expect=400, auth=self.get_super_credentials())
|
||||
self.assertIn('username', response)
|
||||
self.assertIn('password', response)
|
||||
self.assertIn('host', response)
|
||||
self.assertIn('project', response)
|
||||
self.assertIn('domain', response)
|
||||
|
||||
Reference in New Issue
Block a user