mirror of
https://github.com/ansible/awx.git
synced 2026-05-12 20:07:37 -02:30
Merge pull request #3569 from ansible/inv_src_venv
Use inventory source model, as opposed to organization, for update custom virtualenv Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
This commit is contained in:
@@ -1950,7 +1950,7 @@ class InventorySourceOptionsSerializer(BaseSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
fields = ('*', 'source', 'source_path', 'source_script', 'source_vars', 'credential',
|
fields = ('*', 'source', 'source_path', 'source_script', 'source_vars', 'credential',
|
||||||
'source_regions', 'instance_filters', 'group_by', 'overwrite', 'overwrite_vars',
|
'source_regions', 'instance_filters', 'group_by', 'overwrite', 'overwrite_vars',
|
||||||
'timeout', 'verbosity')
|
'custom_virtualenv', 'timeout', 'verbosity')
|
||||||
|
|
||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(InventorySourceOptionsSerializer, self).get_related(obj)
|
res = super(InventorySourceOptionsSerializer, self).get_related(obj)
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.16 on 2019-03-28 17:56
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0065_v350_index_job_status'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='inventorysource',
|
||||||
|
name='custom_virtualenv',
|
||||||
|
field=models.CharField(blank=True, default=None, help_text='Local absolute file path containing a custom Python virtualenv to use', max_length=100, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1429,7 +1429,7 @@ class InventorySourceOptions(BaseModel):
|
|||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
class InventorySource(UnifiedJobTemplate, InventorySourceOptions, RelatedJobsMixin):
|
class InventorySource(UnifiedJobTemplate, InventorySourceOptions, CustomVirtualEnvMixin, RelatedJobsMixin):
|
||||||
|
|
||||||
SOFT_UNIQUE_TOGETHER = [('polymorphic_ctype', 'name', 'inventory')]
|
SOFT_UNIQUE_TOGETHER = [('polymorphic_ctype', 'name', 'inventory')]
|
||||||
|
|
||||||
@@ -1776,14 +1776,12 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin,
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def ansible_virtualenv_path(self):
|
def ansible_virtualenv_path(self):
|
||||||
|
if self.inventory_source and self.inventory_source.custom_virtualenv:
|
||||||
|
return self.inventory_source.custom_virtualenv
|
||||||
if self.inventory_source and self.inventory_source.source_project:
|
if self.inventory_source and self.inventory_source.source_project:
|
||||||
project = self.inventory_source.source_project
|
project = self.inventory_source.source_project
|
||||||
if project and project.custom_virtualenv:
|
if project and project.custom_virtualenv:
|
||||||
return project.custom_virtualenv
|
return project.custom_virtualenv
|
||||||
if self.inventory_source and self.inventory_source.inventory:
|
|
||||||
organization = self.inventory_source.inventory.organization
|
|
||||||
if organization and organization.custom_virtualenv:
|
|
||||||
return organization.custom_virtualenv
|
|
||||||
return settings.ANSIBLE_VENV_PATH
|
return settings.ANSIBLE_VENV_PATH
|
||||||
|
|
||||||
def cancel(self, job_explanation=None, is_chain=False):
|
def cancel(self, job_explanation=None, is_chain=False):
|
||||||
|
|||||||
@@ -4,16 +4,15 @@
|
|||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition',
|
export default ['$state', 'ConfigData', '$scope', 'SourcesFormDefinition', 'ParseTypeChange',
|
||||||
'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupsService',
|
'GenerateForm', 'inventoryData', 'GetChoices',
|
||||||
'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions',
|
'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions',
|
||||||
'rbacUiControlService', 'ToJSON', 'SourcesService', 'Empty',
|
'SourcesService', 'Empty', 'Wait', 'Rest', 'Alert', 'ProcessErrors',
|
||||||
'Wait', 'Rest', 'Alert', 'ProcessErrors', 'inventorySourcesOptions',
|
'inventorySourcesOptions', '$rootScope', 'i18n', 'InventorySourceModel', 'InventoryHostsStrings',
|
||||||
'$rootScope', 'i18n', 'InventorySourceModel', 'InventoryHostsStrings',
|
function($state, ConfigData, $scope, SourcesFormDefinition, ParseTypeChange,
|
||||||
function($state, $stateParams, $scope, SourcesFormDefinition, ParseTypeChange,
|
GenerateForm, inventoryData, GetChoices,
|
||||||
GenerateForm, inventoryData, GroupsService, GetChoices,
|
GetBasePath, CreateSelect2, GetSourceTypeOptions,
|
||||||
GetBasePath, CreateSelect2, GetSourceTypeOptions, rbacUiControlService,
|
SourcesService, Empty, Wait, Rest, Alert, ProcessErrors,
|
||||||
ToJSON, SourcesService, Empty, Wait, Rest, Alert, ProcessErrors,
|
|
||||||
inventorySourcesOptions,$rootScope, i18n, InventorySource, InventoryHostsStrings) {
|
inventorySourcesOptions,$rootScope, i18n, InventorySource, InventoryHostsStrings) {
|
||||||
|
|
||||||
let form = SourcesFormDefinition;
|
let form = SourcesFormDefinition;
|
||||||
@@ -22,6 +21,8 @@ export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition',
|
|||||||
GenerateForm.applyDefaults(form, $scope, true);
|
GenerateForm.applyDefaults(form, $scope, true);
|
||||||
$scope.canAdd = inventorySourcesOptions.actions.POST;
|
$scope.canAdd = inventorySourcesOptions.actions.POST;
|
||||||
$scope.envParseType = 'yaml';
|
$scope.envParseType = 'yaml';
|
||||||
|
const virtualEnvs = ConfigData.custom_virtualenvs || [];
|
||||||
|
$scope.custom_virtualenvs_options = virtualEnvs;
|
||||||
|
|
||||||
GetChoices({
|
GetChoices({
|
||||||
scope: $scope,
|
scope: $scope,
|
||||||
@@ -80,6 +81,12 @@ export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition',
|
|||||||
|
|
||||||
$scope.verbosity = $scope.verbosity_options[1];
|
$scope.verbosity = $scope.verbosity_options[1];
|
||||||
|
|
||||||
|
CreateSelect2({
|
||||||
|
element: '#inventory_source_custom_virtualenv',
|
||||||
|
multiple: false,
|
||||||
|
opts: $scope.custom_virtualenvs_options
|
||||||
|
});
|
||||||
|
|
||||||
GetSourceTypeOptions({
|
GetSourceTypeOptions({
|
||||||
scope: $scope,
|
scope: $scope,
|
||||||
variable: 'source_type_options'
|
variable: 'source_type_options'
|
||||||
@@ -279,9 +286,10 @@ export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition',
|
|||||||
update_on_launch: $scope.update_on_launch,
|
update_on_launch: $scope.update_on_launch,
|
||||||
verbosity: $scope.verbosity.value,
|
verbosity: $scope.verbosity.value,
|
||||||
update_cache_timeout: $scope.update_cache_timeout || 0,
|
update_cache_timeout: $scope.update_cache_timeout || 0,
|
||||||
|
custom_virtualenv: $scope.custom_virtualenv || null,
|
||||||
// comma-delimited strings
|
// comma-delimited strings
|
||||||
group_by: SourcesService.encodeGroupBy($scope.source, $scope.group_by),
|
group_by: SourcesService.encodeGroupBy($scope.source, $scope.group_by),
|
||||||
source_regions: _.map($scope.source_regions, 'value').join(',')
|
source_regions: _.map($scope.source_regions, 'value').join(','),
|
||||||
};
|
};
|
||||||
|
|
||||||
if ($scope.source) {
|
if ($scope.source) {
|
||||||
|
|||||||
@@ -25,6 +25,16 @@ export default {
|
|||||||
.then(function(res) {
|
.then(function(res) {
|
||||||
return res.data;
|
return res.data;
|
||||||
});
|
});
|
||||||
|
}],
|
||||||
|
ConfigData: ['ConfigService', 'ProcessErrors', 'i18n', (ConfigService, ProcessErrors, i18n) => {
|
||||||
|
return ConfigService.getConfig()
|
||||||
|
.then(response => response)
|
||||||
|
.catch(({data, status}) => {
|
||||||
|
ProcessErrors(null, data, status, null, {
|
||||||
|
hdr: i18n._('Error!'),
|
||||||
|
msg: i18n._('Failed to get config. GET returned status: ') + status
|
||||||
|
});
|
||||||
|
});
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,18 +8,20 @@ export default ['$state', '$scope', 'ParseVariableString', 'ParseTypeChange',
|
|||||||
'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions',
|
'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions',
|
||||||
'SourcesService', 'inventoryData', 'inventorySourcesOptions', 'Empty',
|
'SourcesService', 'inventoryData', 'inventorySourcesOptions', 'Empty',
|
||||||
'Wait', 'Rest', 'Alert', '$rootScope', 'i18n', 'InventoryHostsStrings',
|
'Wait', 'Rest', 'Alert', '$rootScope', 'i18n', 'InventoryHostsStrings',
|
||||||
'ProcessErrors', 'inventorySource', 'isNotificationAdmin',
|
'ProcessErrors', 'inventorySource', 'isNotificationAdmin', 'ConfigData',
|
||||||
function($state, $scope, ParseVariableString, ParseTypeChange,
|
function($state, $scope, ParseVariableString, ParseTypeChange,
|
||||||
GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions,
|
GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions,
|
||||||
SourcesService, inventoryData, inventorySourcesOptions, Empty,
|
SourcesService, inventoryData, inventorySourcesOptions, Empty,
|
||||||
Wait, Rest, Alert, $rootScope, i18n, InventoryHostsStrings,
|
Wait, Rest, Alert, $rootScope, i18n, InventoryHostsStrings,
|
||||||
ProcessErrors, inventorySource, isNotificationAdmin) {
|
ProcessErrors, inventorySource, isNotificationAdmin, ConfigData) {
|
||||||
|
|
||||||
const inventorySourceData = inventorySource.get();
|
const inventorySourceData = inventorySource.get();
|
||||||
|
|
||||||
$scope.projectBasePath = GetBasePath('projects') + '?not__status=never updated';
|
$scope.projectBasePath = GetBasePath('projects') + '?not__status=never updated';
|
||||||
$scope.canAdd = inventorySourcesOptions.actions.POST;
|
$scope.canAdd = inventorySourcesOptions.actions.POST;
|
||||||
$scope.isNotificationAdmin = isNotificationAdmin || false;
|
$scope.isNotificationAdmin = isNotificationAdmin || false;
|
||||||
|
const virtualEnvs = ConfigData.custom_virtualenvs || [];
|
||||||
|
$scope.custom_virtualenvs_options = virtualEnvs;
|
||||||
// instantiate expected $scope values from inventorySourceData
|
// instantiate expected $scope values from inventorySourceData
|
||||||
_.assign($scope,
|
_.assign($scope,
|
||||||
{credential: inventorySourceData.credential},
|
{credential: inventorySourceData.credential},
|
||||||
@@ -157,6 +159,12 @@ export default ['$state', '$scope', 'ParseVariableString', 'ParseTypeChange',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CreateSelect2({
|
||||||
|
element: '#inventory_source_custom_virtualenv',
|
||||||
|
multiple: false,
|
||||||
|
opts: $scope.custom_virtualenvs_options
|
||||||
|
});
|
||||||
|
|
||||||
initVerbositySelect();
|
initVerbositySelect();
|
||||||
|
|
||||||
$scope.$watch('verbosity', initVerbositySelect);
|
$scope.$watch('verbosity', initVerbositySelect);
|
||||||
@@ -329,6 +337,7 @@ export default ['$state', '$scope', 'ParseVariableString', 'ParseTypeChange',
|
|||||||
update_on_launch: $scope.update_on_launch,
|
update_on_launch: $scope.update_on_launch,
|
||||||
update_cache_timeout: $scope.update_cache_timeout || 0,
|
update_cache_timeout: $scope.update_cache_timeout || 0,
|
||||||
verbosity: $scope.verbosity.value,
|
verbosity: $scope.verbosity.value,
|
||||||
|
custom_virtualenv: $scope.custom_virtualenv || null,
|
||||||
// comma-delimited strings
|
// comma-delimited strings
|
||||||
group_by: SourcesService.encodeGroupBy($scope.source, $scope.group_by),
|
group_by: SourcesService.encodeGroupBy($scope.source, $scope.group_by),
|
||||||
source_regions: _.map($scope.source_regions, 'value').join(',')
|
source_regions: _.map($scope.source_regions, 'value').join(',')
|
||||||
|
|||||||
@@ -38,6 +38,16 @@ export default {
|
|||||||
msg: i18n._('Failed to get organizations for which this user is a notification administrator. GET returned ') + status
|
msg: i18n._('Failed to get organizations for which this user is a notification administrator. GET returned ') + status
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}],
|
||||||
|
ConfigData: ['ConfigService', 'ProcessErrors', 'i18n', (ConfigService, ProcessErrors, i18n) => {
|
||||||
|
return ConfigService.getConfig()
|
||||||
|
.then(response => response)
|
||||||
|
.catch(({data, status}) => {
|
||||||
|
ProcessErrors(null, data, status, null, {
|
||||||
|
hdr: i18n._('Error!'),
|
||||||
|
msg: i18n._('Failed to get config. GET returned status: ') + status
|
||||||
|
});
|
||||||
|
});
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,6 +56,19 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n){
|
|||||||
ngModel: 'source',
|
ngModel: 'source',
|
||||||
hasSubForm: true
|
hasSubForm: true
|
||||||
},
|
},
|
||||||
|
custom_virtualenv: {
|
||||||
|
label: i18n._('Ansible Environment'),
|
||||||
|
type: 'select',
|
||||||
|
defaultText: i18n._('Use Default Environment'),
|
||||||
|
ngOptions: 'venv for venv in custom_virtualenvs_options track by venv',
|
||||||
|
|
||||||
|
awPopOver: "<p>" + i18n._("Select the custom Python virtual environment for this inventory source sync to run on.") + "</p>",
|
||||||
|
dataTitle: i18n._('Ansible Environment'),
|
||||||
|
dataContainer: 'body',
|
||||||
|
dataPlacement: 'right',
|
||||||
|
ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)',
|
||||||
|
ngShow: 'custom_virtualenvs_options.length > 1'
|
||||||
|
},
|
||||||
credential: {
|
credential: {
|
||||||
label: i18n._('Credential'),
|
label: i18n._('Credential'),
|
||||||
type: 'lookup',
|
type: 'lookup',
|
||||||
|
|||||||
Reference in New Issue
Block a user