mirror of
https://github.com/ansible/awx.git
synced 2026-03-04 10:11:05 -03:30
Merge pull request #1279 from AlanCoding/822_keystone_v3_OS_cred
Add OpenStack V3 credential type
This commit is contained in:
@@ -1484,7 +1484,8 @@ class CredentialSerializer(BaseSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Credential
|
model = Credential
|
||||||
fields = ('*', 'user', 'team', 'kind', 'cloud', 'host', 'username',
|
fields = ('*', 'user', 'team', 'kind', 'cloud', 'host', 'username',
|
||||||
'password', 'security_token', 'project', 'ssh_key_data', 'ssh_key_unlock',
|
'password', 'security_token', 'project', 'domain',
|
||||||
|
'ssh_key_data', 'ssh_key_unlock',
|
||||||
'become_method', 'become_username', 'become_password',
|
'become_method', 'become_username', 'become_password',
|
||||||
'vault_password')
|
'vault_password')
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Copyright (c) 2015 Ansible, Inc.
|
# Copyright (c) 2015 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
CLOUD_PROVIDERS = ('azure', 'ec2', 'gce', 'rax', 'vmware', 'openstack')
|
CLOUD_PROVIDERS = ('azure', 'ec2', 'gce', 'rax', 'vmware', 'openstack', 'openstack_v3')
|
||||||
SCHEDULEABLE_PROVIDERS = CLOUD_PROVIDERS + ('custom',)
|
SCHEDULEABLE_PROVIDERS = CLOUD_PROVIDERS + ('custom',)
|
||||||
|
|||||||
19
awx/main/migrations/0007_v300_credential_domain_field.py
Normal file
19
awx/main/migrations/0007_v300_credential_domain_field.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0006_v300_create_system_job_templates'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='credential',
|
||||||
|
name='domain',
|
||||||
|
field=models.CharField(default=b'', help_text='The identifier for the domain.', max_length=100, verbose_name='Domain', blank=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -56,7 +56,7 @@ PERMISSION_TYPE_CHOICES = [
|
|||||||
(PERM_JOBTEMPLATE_CREATE, _('Create a Job Template')),
|
(PERM_JOBTEMPLATE_CREATE, _('Create a Job Template')),
|
||||||
]
|
]
|
||||||
|
|
||||||
CLOUD_INVENTORY_SOURCES = ['ec2', 'rax', 'vmware', 'gce', 'azure', 'openstack', 'custom']
|
CLOUD_INVENTORY_SOURCES = ['ec2', 'rax', 'vmware', 'gce', 'azure', 'openstack', 'openstack_v3', 'custom']
|
||||||
|
|
||||||
VERBOSITY_CHOICES = [
|
VERBOSITY_CHOICES = [
|
||||||
(0, '0 (Normal)'),
|
(0, '0 (Normal)'),
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
|
|||||||
('gce', _('Google Compute Engine')),
|
('gce', _('Google Compute Engine')),
|
||||||
('azure', _('Microsoft Azure')),
|
('azure', _('Microsoft Azure')),
|
||||||
('openstack', _('OpenStack')),
|
('openstack', _('OpenStack')),
|
||||||
|
('openstack_v3', _('OpenStack V3')),
|
||||||
]
|
]
|
||||||
|
|
||||||
BECOME_METHOD_CHOICES = [
|
BECOME_METHOD_CHOICES = [
|
||||||
@@ -114,6 +115,13 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
|
|||||||
verbose_name=_('Project'),
|
verbose_name=_('Project'),
|
||||||
help_text=_('The identifier for the project.'),
|
help_text=_('The identifier for the project.'),
|
||||||
)
|
)
|
||||||
|
domain = models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
max_length=100,
|
||||||
|
verbose_name=_('Domain'),
|
||||||
|
help_text=_('The identifier for the domain.'),
|
||||||
|
)
|
||||||
ssh_key_data = models.TextField(
|
ssh_key_data = models.TextField(
|
||||||
blank=True,
|
blank=True,
|
||||||
default='',
|
default='',
|
||||||
@@ -203,10 +211,19 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
|
|||||||
host = self.host or ''
|
host = self.host or ''
|
||||||
if not host and self.kind == 'vmware':
|
if not host and self.kind == 'vmware':
|
||||||
raise ValidationError('Host required for VMware credential.')
|
raise ValidationError('Host required for VMware credential.')
|
||||||
if not host and self.kind == 'openstack':
|
if not host and self.kind in ('openstack', 'openstack_v3'):
|
||||||
raise ValidationError('Host required for OpenStack credential.')
|
raise ValidationError('Host required for OpenStack credential.')
|
||||||
return host
|
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
|
||||||
|
|
||||||
def clean_username(self):
|
def clean_username(self):
|
||||||
username = self.username or ''
|
username = self.username or ''
|
||||||
if not username and self.kind == 'aws':
|
if not username and self.kind == 'aws':
|
||||||
@@ -216,7 +233,7 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
|
|||||||
'credential.')
|
'credential.')
|
||||||
if not username and self.kind == 'vmware':
|
if not username and self.kind == 'vmware':
|
||||||
raise ValidationError('Username required for VMware credential.')
|
raise ValidationError('Username required for VMware credential.')
|
||||||
if not username and self.kind == 'openstack':
|
if not username and self.kind in ('openstack', 'openstack_v3'):
|
||||||
raise ValidationError('Username required for OpenStack credential.')
|
raise ValidationError('Username required for OpenStack credential.')
|
||||||
return username
|
return username
|
||||||
|
|
||||||
@@ -228,13 +245,13 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
|
|||||||
raise ValidationError('API key required for Rackspace credential.')
|
raise ValidationError('API key required for Rackspace credential.')
|
||||||
if not password and self.kind == 'vmware':
|
if not password and self.kind == 'vmware':
|
||||||
raise ValidationError('Password required for VMware credential.')
|
raise ValidationError('Password required for VMware credential.')
|
||||||
if not password and self.kind == 'openstack':
|
if not password and self.kind in ('openstack', 'openstack_v3'):
|
||||||
raise ValidationError('Password or API key required for OpenStack credential.')
|
raise ValidationError('Password or API key required for OpenStack credential.')
|
||||||
return password
|
return password
|
||||||
|
|
||||||
def clean_project(self):
|
def clean_project(self):
|
||||||
project = self.project or ''
|
project = self.project or ''
|
||||||
if self.kind == 'openstack' and not project:
|
if self.kind in ('openstack', 'openstack_v3') and not project:
|
||||||
raise ValidationError('Project name required for OpenStack credential.')
|
raise ValidationError('Project name required for OpenStack credential.')
|
||||||
return project
|
return project
|
||||||
|
|
||||||
|
|||||||
@@ -748,6 +748,7 @@ class InventorySourceOptions(BaseModel):
|
|||||||
('azure', _('Microsoft Azure')),
|
('azure', _('Microsoft Azure')),
|
||||||
('vmware', _('VMware vCenter')),
|
('vmware', _('VMware vCenter')),
|
||||||
('openstack', _('OpenStack')),
|
('openstack', _('OpenStack')),
|
||||||
|
('openstack_v3', _('OpenStack V3')),
|
||||||
('custom', _('Custom Script')),
|
('custom', _('Custom Script')),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -976,6 +977,11 @@ class InventorySourceOptions(BaseModel):
|
|||||||
"""I don't think openstack has regions"""
|
"""I don't think openstack has regions"""
|
||||||
return [('all', 'All')]
|
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):
|
def clean_credential(self):
|
||||||
if not self.source:
|
if not self.source:
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -706,12 +706,14 @@ class RunJob(BaseTask):
|
|||||||
if credential.ssh_key_data not in (None, ''):
|
if credential.ssh_key_data not in (None, ''):
|
||||||
private_data[cred_name] = decrypt_field(credential, 'ssh_key_data') or ''
|
private_data[cred_name] = decrypt_field(credential, 'ssh_key_data') or ''
|
||||||
|
|
||||||
if job.cloud_credential and job.cloud_credential.kind == 'openstack':
|
if job.cloud_credential and job.cloud_credential.kind in ('openstack', 'openstack_v3'):
|
||||||
credential = job.cloud_credential
|
credential = job.cloud_credential
|
||||||
openstack_auth = dict(auth_url=credential.host,
|
openstack_auth = dict(auth_url=credential.host,
|
||||||
username=credential.username,
|
username=credential.username,
|
||||||
password=decrypt_field(credential, "password"),
|
password=decrypt_field(credential, "password"),
|
||||||
project_name=credential.project)
|
project_name=credential.project)
|
||||||
|
if credential.domain not in (None, ''):
|
||||||
|
openstack_auth['domain_name'] = credential.domain
|
||||||
openstack_data = {
|
openstack_data = {
|
||||||
'clouds': {
|
'clouds': {
|
||||||
'devstack': {
|
'devstack': {
|
||||||
@@ -796,7 +798,7 @@ class RunJob(BaseTask):
|
|||||||
env['VMWARE_USER'] = cloud_cred.username
|
env['VMWARE_USER'] = cloud_cred.username
|
||||||
env['VMWARE_PASSWORD'] = decrypt_field(cloud_cred, 'password')
|
env['VMWARE_PASSWORD'] = decrypt_field(cloud_cred, 'password')
|
||||||
env['VMWARE_HOST'] = cloud_cred.host
|
env['VMWARE_HOST'] = cloud_cred.host
|
||||||
elif cloud_cred and cloud_cred.kind == 'openstack':
|
elif cloud_cred and cloud_cred.kind in ('openstack', 'openstack_v3'):
|
||||||
env['OS_CLIENT_CONFIG_FILE'] = kwargs.get('private_data_files', {}).get('cloud_credential', '')
|
env['OS_CLIENT_CONFIG_FILE'] = kwargs.get('private_data_files', {}).get('cloud_credential', '')
|
||||||
|
|
||||||
# Set environment variables related to scan jobs
|
# Set environment variables related to scan jobs
|
||||||
@@ -1145,12 +1147,14 @@ class RunInventoryUpdate(BaseTask):
|
|||||||
credential = inventory_update.credential
|
credential = inventory_update.credential
|
||||||
return dict(cloud_credential=decrypt_field(credential, 'ssh_key_data'))
|
return dict(cloud_credential=decrypt_field(credential, 'ssh_key_data'))
|
||||||
|
|
||||||
if inventory_update.source == 'openstack':
|
if inventory_update.source in ('openstack', 'openstack_v3'):
|
||||||
credential = inventory_update.credential
|
credential = inventory_update.credential
|
||||||
openstack_auth = dict(auth_url=credential.host,
|
openstack_auth = dict(auth_url=credential.host,
|
||||||
username=credential.username,
|
username=credential.username,
|
||||||
password=decrypt_field(credential, "password"),
|
password=decrypt_field(credential, "password"),
|
||||||
project_name=credential.project)
|
project_name=credential.project)
|
||||||
|
if credential.domain not in (None, ''):
|
||||||
|
openstack_auth['domain_name'] = credential.domain
|
||||||
private_state = str(inventory_update.source_vars_dict.get('private', 'true'))
|
private_state = str(inventory_update.source_vars_dict.get('private', 'true'))
|
||||||
# Retrieve cache path from inventory update vars if available,
|
# Retrieve cache path from inventory update vars if available,
|
||||||
# otherwise create a temporary cache path only for this update.
|
# otherwise create a temporary cache path only for this update.
|
||||||
@@ -1298,7 +1302,7 @@ class RunInventoryUpdate(BaseTask):
|
|||||||
env['GCE_PROJECT'] = passwords.get('source_project', '')
|
env['GCE_PROJECT'] = passwords.get('source_project', '')
|
||||||
env['GCE_PEM_FILE_PATH'] = cloud_credential
|
env['GCE_PEM_FILE_PATH'] = cloud_credential
|
||||||
env['GCE_ZONE'] = inventory_update.source_regions
|
env['GCE_ZONE'] = inventory_update.source_regions
|
||||||
elif inventory_update.source == 'openstack':
|
elif inventory_update.source in ('openstack', 'openstack_v3'):
|
||||||
env['OS_CLIENT_CONFIG_FILE'] = cloud_credential
|
env['OS_CLIENT_CONFIG_FILE'] = cloud_credential
|
||||||
elif inventory_update.source == 'file':
|
elif inventory_update.source == 'file':
|
||||||
# FIXME: Parse source_env to dict, update env.
|
# FIXME: Parse source_env to dict, update env.
|
||||||
@@ -1341,6 +1345,11 @@ class RunInventoryUpdate(BaseTask):
|
|||||||
# to a shorter variable. :)
|
# to a shorter variable. :)
|
||||||
src = inventory_update.source
|
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
|
# Get the path to the inventory plugin, and append it to our
|
||||||
# arguments.
|
# arguments.
|
||||||
plugin_path = self.get_path_to('..', 'plugins', 'inventory',
|
plugin_path = self.get_path_to('..', 'plugins', 'inventory',
|
||||||
|
|||||||
@@ -2068,6 +2068,26 @@ class InventoryUpdatesTest(BaseTransactionTest):
|
|||||||
self.check_inventory_source(inventory_source)
|
self.check_inventory_source(inventory_source)
|
||||||
self.assertFalse(self.group.all_hosts.filter(instance_id='').exists())
|
self.assertFalse(self.group.all_hosts.filter(instance_id='').exists())
|
||||||
|
|
||||||
|
def test_update_from_openstack_v3(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', '')
|
||||||
|
api_password = getattr(settings, 'TEST_OPENSTACK_PASSWORD', '')
|
||||||
|
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.create_test_license_file()
|
||||||
|
credential = Credential.objects.create(kind='openstack_v3',
|
||||||
|
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)
|
||||||
|
self.check_inventory_source(inventory_source)
|
||||||
|
self.assertFalse(self.group.all_hosts.filter(instance_id='').exists())
|
||||||
|
|
||||||
def test_update_from_azure(self):
|
def test_update_from_azure(self):
|
||||||
source_username = getattr(settings, 'TEST_AZURE_USERNAME', '')
|
source_username = getattr(settings, 'TEST_AZURE_USERNAME', '')
|
||||||
source_key_data = getattr(settings, 'TEST_AZURE_KEY_DATA', '')
|
source_key_data = getattr(settings, 'TEST_AZURE_KEY_DATA', '')
|
||||||
@@ -2112,3 +2132,27 @@ class InventoryCredentialTest(BaseTest):
|
|||||||
self.assertIn('password', response)
|
self.assertIn('password', response)
|
||||||
self.assertIn('host', response)
|
self.assertIn('host', response)
|
||||||
self.assertIn('project', 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)
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ export default
|
|||||||
"host": {
|
"host": {
|
||||||
labelBind: 'hostLabel',
|
labelBind: 'hostLabel',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
ngShow: "kind.value == 'vmware' || kind.value == 'openstack'",
|
ngShow: "kind.value == 'vmware' || kind.value == 'openstack' || kind.value === 'openstack_v3'",
|
||||||
awPopOverWatch: "hostPopOver",
|
awPopOverWatch: "hostPopOver",
|
||||||
awPopOver: "set in helpers/credentials",
|
awPopOver: "set in helpers/credentials",
|
||||||
dataTitle: 'Host',
|
dataTitle: 'Host',
|
||||||
@@ -243,7 +243,7 @@ export default
|
|||||||
"password": {
|
"password": {
|
||||||
labelBind: 'passwordLabel',
|
labelBind: 'passwordLabel',
|
||||||
type: 'sensitive',
|
type: 'sensitive',
|
||||||
ngShow: "kind.value == 'scm' || kind.value == 'vmware' || kind.value == 'openstack'",
|
ngShow: "kind.value == 'scm' || kind.value == 'vmware' || kind.value == 'openstack' || kind.value == 'openstack_v3'",
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
ask: false,
|
ask: false,
|
||||||
@@ -338,7 +338,7 @@ export default
|
|||||||
"project": {
|
"project": {
|
||||||
labelBind: 'projectLabel',
|
labelBind: 'projectLabel',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
ngShow: "kind.value == 'gce' || kind.value == 'openstack'",
|
ngShow: "kind.value == 'gce' || kind.value == 'openstack' || kind.value == 'openstack_v3'",
|
||||||
awPopOverWatch: "projectPopOver",
|
awPopOverWatch: "projectPopOver",
|
||||||
awPopOver: "set in helpers/credentials",
|
awPopOver: "set in helpers/credentials",
|
||||||
dataTitle: 'Project ID',
|
dataTitle: 'Project ID',
|
||||||
@@ -352,6 +352,23 @@ export default
|
|||||||
},
|
},
|
||||||
subForm: 'credentialSubForm'
|
subForm: 'credentialSubForm'
|
||||||
},
|
},
|
||||||
|
"domain": {
|
||||||
|
labelBind: 'domainLabel',
|
||||||
|
type: 'text',
|
||||||
|
ngShow: "kind.value == 'openstack_v3'",
|
||||||
|
awPopOverWatch: "domainPopOver",
|
||||||
|
awPopOver: "set in helpers/credentials",
|
||||||
|
dataTitle: 'Domain Name',
|
||||||
|
dataPlacement: 'right',
|
||||||
|
dataContainer: "body",
|
||||||
|
addRequired: false,
|
||||||
|
editRequired: false,
|
||||||
|
awRequiredWhen: {
|
||||||
|
variable: 'domain_required',
|
||||||
|
init: false
|
||||||
|
},
|
||||||
|
subForm: 'credentialSubForm'
|
||||||
|
},
|
||||||
"vault_password": {
|
"vault_password": {
|
||||||
label: "Vault Password",
|
label: "Vault Password",
|
||||||
type: 'sensitive',
|
type: 'sensitive',
|
||||||
|
|||||||
@@ -169,7 +169,8 @@ export default
|
|||||||
label: 'Source Variables', //"{{vars_label}}" ,
|
label: 'Source Variables', //"{{vars_label}}" ,
|
||||||
|
|
||||||
ngShow: "source && (source.value == 'vmware' || " +
|
ngShow: "source && (source.value == 'vmware' || " +
|
||||||
"source.value == 'openstack')",
|
"source.value == 'openstack' || " +
|
||||||
|
"source.value == 'openstack_v3')",
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
class: 'Form-textAreaLabel',
|
class: 'Form-textAreaLabel',
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ angular.module('CredentialsHelper', ['Utilities'])
|
|||||||
scope.username_required = false; // JT-- added username_required b/c mutliple 'kinds' need username to be required (GCE)
|
scope.username_required = false; // JT-- added username_required b/c mutliple 'kinds' need username to be required (GCE)
|
||||||
scope.key_required = false; // JT -- doing the same for key and project
|
scope.key_required = false; // JT -- doing the same for key and project
|
||||||
scope.project_required = false;
|
scope.project_required = false;
|
||||||
|
scope.domain_required = false;
|
||||||
scope.subscription_required = false;
|
scope.subscription_required = false;
|
||||||
scope.key_description = "Paste the contents of the SSH private key file.";
|
scope.key_description = "Paste the contents of the SSH private key file.";
|
||||||
scope.key_hint= "drag and drop an SSH private key file on the field below";
|
scope.key_hint= "drag and drop an SSH private key file on the field below";
|
||||||
@@ -69,9 +70,11 @@ angular.module('CredentialsHelper', ['Utilities'])
|
|||||||
scope.password_required = false;
|
scope.password_required = false;
|
||||||
scope.hostLabel = '';
|
scope.hostLabel = '';
|
||||||
scope.projectLabel = '';
|
scope.projectLabel = '';
|
||||||
|
scope.domainLabel = '';
|
||||||
scope.project_required = false;
|
scope.project_required = false;
|
||||||
scope.passwordLabel = 'Password (API Key)';
|
scope.passwordLabel = 'Password (API Key)';
|
||||||
scope.projectPopOver = "<p>The project value</p>";
|
scope.projectPopOver = "<p>The project value</p>";
|
||||||
|
scope.domainPopOver = "<p>The domain name</p>";
|
||||||
scope.hostPopOver = "<p>The host value</p>";
|
scope.hostPopOver = "<p>The host value</p>";
|
||||||
|
|
||||||
if (!Empty(scope.kind)) {
|
if (!Empty(scope.kind)) {
|
||||||
@@ -133,6 +136,22 @@ angular.module('CredentialsHelper', ['Utilities'])
|
|||||||
" as the username.</p>";
|
" as the username.</p>";
|
||||||
scope.hostPopOver = "<p>The host to authenticate with." +
|
scope.hostPopOver = "<p>The host to authenticate with." +
|
||||||
"<br />For example, https://openstack.business.com/v2.0/";
|
"<br />For example, https://openstack.business.com/v2.0/";
|
||||||
|
case 'openstack_v3':
|
||||||
|
scope.hostLabel = "Host (Authentication URL)";
|
||||||
|
scope.projectLabel = "Project (Tenet Name/ID)";
|
||||||
|
scope.domainLabel = "Domain Name";
|
||||||
|
scope.password_required = true;
|
||||||
|
scope.project_required = true;
|
||||||
|
scope.domain_required = true;
|
||||||
|
scope.host_required = true;
|
||||||
|
scope.username_required = true;
|
||||||
|
scope.projectPopOver = "<p>This is the tenant name " +
|
||||||
|
"or tenant id. This value is usually the same " +
|
||||||
|
" as the username.</p>";
|
||||||
|
scope.hostPopOver = "<p>The host to authenticate with." +
|
||||||
|
"<br />For example, https://openstack.business.com/v3</p>";
|
||||||
|
scope.domainPopOver = "<p>Domain used for Keystone v3 " +
|
||||||
|
"<br />identity service.</p>";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -305,7 +305,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
|||||||
field_id: 'source_extra_vars', onReady: callback });
|
field_id: 'source_extra_vars', onReady: callback });
|
||||||
}
|
}
|
||||||
if(scope.source.value==="vmware" ||
|
if(scope.source.value==="vmware" ||
|
||||||
scope.source.value==="openstack"){
|
scope.source.value==="openstack" ||
|
||||||
|
scope.source.value==="openstack_v3"){
|
||||||
scope.inventory_variables = (Empty(scope.source_vars)) ? "---" : scope.source_vars;
|
scope.inventory_variables = (Empty(scope.source_vars)) ? "---" : scope.source_vars;
|
||||||
ParseTypeChange({ scope: scope, variable: 'inventory_variables', parse_variable: form.fields.inventory_variables.parseTypeName,
|
ParseTypeChange({ scope: scope, variable: 'inventory_variables', parse_variable: form.fields.inventory_variables.parseTypeName,
|
||||||
field_id: 'source_inventory_variables', onReady: callback });
|
field_id: 'source_inventory_variables', onReady: callback });
|
||||||
@@ -315,7 +316,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
|||||||
scope.source.value==='gce' ||
|
scope.source.value==='gce' ||
|
||||||
scope.source.value === 'azure' ||
|
scope.source.value === 'azure' ||
|
||||||
scope.source.value === 'vmware' ||
|
scope.source.value === 'vmware' ||
|
||||||
scope.source.value === 'openstack') {
|
scope.source.value === 'openstack' ||
|
||||||
|
scope.source.value === 'openstack_v3') {
|
||||||
if (scope.source.value === 'ec2') {
|
if (scope.source.value === 'ec2') {
|
||||||
kind = 'aws';
|
kind = 'aws';
|
||||||
} else {
|
} else {
|
||||||
@@ -924,7 +926,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
|||||||
ParseTypeChange({ scope: sources_scope, variable: 'source_vars', parse_variable: SourceForm.fields.source_vars.parseTypeName,
|
ParseTypeChange({ scope: sources_scope, variable: 'source_vars', parse_variable: SourceForm.fields.source_vars.parseTypeName,
|
||||||
field_id: 'source_source_vars', onReady: waitStop });
|
field_id: 'source_source_vars', onReady: waitStop });
|
||||||
} else if (sources_scope.source && (sources_scope.source.value === 'vmware' ||
|
} else if (sources_scope.source && (sources_scope.source.value === 'vmware' ||
|
||||||
sources_scope.source.value === 'openstack')) {
|
sources_scope.source.value === 'openstack' ||
|
||||||
|
sources_scope.source.value === 'openstack_v3')) {
|
||||||
Wait('start');
|
Wait('start');
|
||||||
ParseTypeChange({ scope: sources_scope, variable: 'inventory_variables', parse_variable: SourceForm.fields.inventory_variables.parseTypeName,
|
ParseTypeChange({ scope: sources_scope, variable: 'inventory_variables', parse_variable: SourceForm.fields.inventory_variables.parseTypeName,
|
||||||
field_id: 'source_inventory_variables', onReady: waitStop });
|
field_id: 'source_inventory_variables', onReady: waitStop });
|
||||||
@@ -1303,7 +1306,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sources_scope.source && (sources_scope.source.value === 'vmware' ||
|
if (sources_scope.source && (sources_scope.source.value === 'vmware' ||
|
||||||
sources_scope.source.value === 'openstack')) {
|
sources_scope.source.value === 'openstack' ||
|
||||||
|
sources_scope.source.value === 'openstack_v3')) {
|
||||||
data.source_vars = ToJSON(sources_scope.envParseType, sources_scope.inventory_variables, true);
|
data.source_vars = ToJSON(sources_scope.envParseType, sources_scope.inventory_variables, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ export default
|
|||||||
},{
|
},{
|
||||||
name: "OpenStack",
|
name: "OpenStack",
|
||||||
value: "openstack"
|
value: "openstack"
|
||||||
|
},{
|
||||||
|
name: "OpenStack V3",
|
||||||
|
value: "openstack_v3"
|
||||||
}],
|
}],
|
||||||
sourceModel: 'inventory_source',
|
sourceModel: 'inventory_source',
|
||||||
sourceField: 'source',
|
sourceField: 'source',
|
||||||
@@ -84,7 +87,7 @@ export default
|
|||||||
has_external_source: {
|
has_external_source: {
|
||||||
label: 'Has external source?',
|
label: 'Has external source?',
|
||||||
searchType: 'in',
|
searchType: 'in',
|
||||||
searchValue: 'ec2,rax,vmware,azure,gce,openstack',
|
searchValue: 'ec2,rax,vmware,azure,gce,openstack,openstack_v3',
|
||||||
searchOnly: true,
|
searchOnly: true,
|
||||||
sourceModel: 'inventory_source',
|
sourceModel: 'inventory_source',
|
||||||
sourceField: 'source'
|
sourceField: 'source'
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ export default
|
|||||||
},{
|
},{
|
||||||
name: "OpenStack",
|
name: "OpenStack",
|
||||||
value: "openstack"
|
value: "openstack"
|
||||||
|
},{
|
||||||
|
name: "OpenStack V3",
|
||||||
|
value: "openstack_v3"
|
||||||
}],
|
}],
|
||||||
sourceModel: 'inventory_source',
|
sourceModel: 'inventory_source',
|
||||||
sourceField: 'source',
|
sourceField: 'source',
|
||||||
@@ -59,7 +62,7 @@ export default
|
|||||||
has_external_source: {
|
has_external_source: {
|
||||||
label: 'Has external source?',
|
label: 'Has external source?',
|
||||||
searchType: 'in',
|
searchType: 'in',
|
||||||
searchValue: 'ec2,rax,vmware,azure,gce,openstack',
|
searchValue: 'ec2,rax,vmware,azure,gce,openstack,openstack_v3',
|
||||||
searchOnly: true,
|
searchOnly: true,
|
||||||
sourceModel: 'inventory_source',
|
sourceModel: 'inventory_source',
|
||||||
sourceField: 'source'
|
sourceField: 'source'
|
||||||
|
|||||||
Reference in New Issue
Block a user