mirror of
https://github.com/ansible/awx.git
synced 2026-01-09 15:02:07 -03:30
Implement project pulling from Azure DevOps using Service Principals (#14628)
* Credential Lookup with multiple types Allow looking up a credential with one of multiple type IDs. * Allow Azure cred for SCM Allow selecting an Azure Resource Manager credential for Git-based SCMs. This is in order to enable using Azure Service Principals for project updates. * Implement Azure Service Principal Git This adds support for using an Azure Service Principal for project updates. --------- Signed-off-by: Patrick Uiterwijk <patrick@puiterwijk.org>
This commit is contained in:
parent
727278aaa3
commit
2e2cd7f2de
@ -160,8 +160,8 @@ class ProjectOptions(models.Model):
|
||||
if self.scm_type == 'insights':
|
||||
if cred.kind != 'insights':
|
||||
raise ValidationError(_("Credential kind must be 'insights'."))
|
||||
elif cred.kind != 'scm':
|
||||
raise ValidationError(_("Credential kind must be 'scm'."))
|
||||
elif cred.kind != 'scm' and cred.kind != 'azure_rm':
|
||||
raise ValidationError(_("Credential kind must be 'scm' or 'azure_rm'." % cred.kind))
|
||||
try:
|
||||
if self.scm_type == 'insights':
|
||||
self.scm_url = settings.INSIGHTS_URL_BASE
|
||||
|
||||
@ -1239,6 +1239,9 @@ class RunProjectUpdate(BaseTask):
|
||||
|
||||
return scm_url, extra_vars
|
||||
|
||||
def build_credentials_list(self, instance):
|
||||
return [instance.credential]
|
||||
|
||||
def build_inventory(self, instance, private_data_dir):
|
||||
return 'localhost,'
|
||||
|
||||
|
||||
@ -38,6 +38,26 @@
|
||||
tags:
|
||||
- update_git
|
||||
block:
|
||||
- name: Get Azure access token
|
||||
when: "lookup('ansible.builtin.env', 'AZURE_CLIENT_ID') != ''"
|
||||
register: azure_token
|
||||
no_log: True
|
||||
check_mode: false
|
||||
azure.azcollection.azure_rm_accesstoken_info:
|
||||
scopes:
|
||||
# This is the audience for Azure DevOps, as per
|
||||
# https://learn.microsoft.com/en-us/rest/api/azure/devops/tokens/
|
||||
- 499b84ac-1321-427f-aa17-267ca6975798/.default
|
||||
|
||||
- name: Define git environment variables
|
||||
when: "azure_token is not skipped"
|
||||
no_log: True
|
||||
ansible.builtin.set_fact:
|
||||
git_environment:
|
||||
GIT_CONFIG_COUNT: 1
|
||||
GIT_CONFIG_KEY_0: http.extraHeader
|
||||
GIT_CONFIG_VALUE_0: "Authorization: Bearer {{ azure_token.access_token }}"
|
||||
|
||||
- name: Update project using git
|
||||
ansible.builtin.git:
|
||||
dest: "{{ project_path | quote }}"
|
||||
@ -47,6 +67,7 @@
|
||||
force: "{{ scm_clean }}"
|
||||
track_submodules: "{{ scm_track_submodules | default(omit) }}"
|
||||
accept_hostkey: "{{ scm_accept_hostkey | default(omit) }}"
|
||||
environment: "{{ git_environment | default({}) }}"
|
||||
register: git_result
|
||||
|
||||
- name: Set the git repository version
|
||||
|
||||
@ -32,6 +32,7 @@ const QS_CONFIG = getQSConfig('credentials', {
|
||||
function CredentialLookup({
|
||||
autoPopulate,
|
||||
credentialTypeId,
|
||||
credentialTypeIds,
|
||||
credentialTypeKind,
|
||||
credentialTypeNamespace,
|
||||
fieldName,
|
||||
@ -61,6 +62,9 @@ function CredentialLookup({
|
||||
const typeIdParams = credentialTypeId
|
||||
? { credential_type: credentialTypeId }
|
||||
: {};
|
||||
const typeIdsParams = credentialTypeIds
|
||||
? { credential_type__in: credentialTypeIds.join() }
|
||||
: {};
|
||||
const typeKindParams = credentialTypeKind
|
||||
? { credential_type__kind: credentialTypeKind }
|
||||
: {};
|
||||
@ -72,6 +76,7 @@ function CredentialLookup({
|
||||
CredentialsAPI.read(
|
||||
mergeParams(params, {
|
||||
...typeIdParams,
|
||||
...typeIdsParams,
|
||||
...typeKindParams,
|
||||
...typeNamespaceParams,
|
||||
})
|
||||
@ -101,6 +106,7 @@ function CredentialLookup({
|
||||
autoPopulate,
|
||||
autoPopulateLookup,
|
||||
credentialTypeId,
|
||||
credentialTypeIds,
|
||||
credentialTypeKind,
|
||||
credentialTypeNamespace,
|
||||
history.location.search,
|
||||
|
||||
@ -33,6 +33,11 @@ const fetchCredentials = async (credential) => {
|
||||
results: [scmCredentialType],
|
||||
},
|
||||
},
|
||||
{
|
||||
data: {
|
||||
results: [azurermCredentialType],
|
||||
},
|
||||
},
|
||||
{
|
||||
data: {
|
||||
results: [insightsCredentialType],
|
||||
@ -45,13 +50,14 @@ const fetchCredentials = async (credential) => {
|
||||
},
|
||||
] = await Promise.all([
|
||||
CredentialTypesAPI.read({ kind: 'scm' }),
|
||||
CredentialTypesAPI.read({ namespace: 'azure_rm' }),
|
||||
CredentialTypesAPI.read({ name: 'Insights' }),
|
||||
CredentialTypesAPI.read({ kind: 'cryptography' }),
|
||||
]);
|
||||
|
||||
if (!credential) {
|
||||
return {
|
||||
scm: { typeId: scmCredentialType.id },
|
||||
scm: { typeIds: [scmCredentialType.id, azurermCredentialType.id] },
|
||||
insights: { typeId: insightsCredentialType.id },
|
||||
cryptography: { typeId: cryptographyCredentialType.id },
|
||||
};
|
||||
@ -60,8 +66,12 @@ const fetchCredentials = async (credential) => {
|
||||
const { credential_type_id } = credential;
|
||||
return {
|
||||
scm: {
|
||||
typeId: scmCredentialType.id,
|
||||
value: credential_type_id === scmCredentialType.id ? credential : null,
|
||||
typeIds: [scmCredentialType.id, azurermCredentialType.id],
|
||||
value:
|
||||
credential_type_id === scmCredentialType.id ||
|
||||
credential_type_id === azurermCredentialType.id
|
||||
? credential
|
||||
: null,
|
||||
},
|
||||
insights: {
|
||||
typeId: insightsCredentialType.id,
|
||||
@ -367,13 +377,13 @@ function ProjectForm({ project, submitError, ...props }) {
|
||||
});
|
||||
const [scmTypeOptions, setScmTypeOptions] = useState(null);
|
||||
const [credentials, setCredentials] = useState({
|
||||
scm: { typeId: null, value: null },
|
||||
scm: { typeIds: null, value: null },
|
||||
insights: { typeId: null, value: null },
|
||||
cryptography: { typeId: null, value: null },
|
||||
});
|
||||
const [signatureValidationCredentials, setSignatureValidationCredentials] =
|
||||
useState({
|
||||
scm: { typeId: null, value: null },
|
||||
scm: { typeIds: null, value: null },
|
||||
insights: { typeId: null, value: null },
|
||||
cryptography: { typeId: null, value: null },
|
||||
});
|
||||
|
||||
@ -52,7 +52,7 @@ export const ScmCredentialFormField = ({
|
||||
|
||||
return (
|
||||
<CredentialLookup
|
||||
credentialTypeId={credential.typeId}
|
||||
credentialTypeIds={credential.typeIds}
|
||||
label={t`Source Control Credential`}
|
||||
value={credential.value}
|
||||
onChange={onCredentialChange}
|
||||
|
||||
@ -50,7 +50,7 @@ class Project(HasCopy, HasCreate, HasNotifications, UnifiedJobTemplate):
|
||||
def create_payload(self, name='', description='', scm_type='git', scm_url='', scm_branch='', organization=Organization, credential=None, **kwargs):
|
||||
if credential:
|
||||
if isinstance(credential, Credential):
|
||||
if credential.ds.credential_type.namespace not in ('scm', 'insights'):
|
||||
if credential.ds.credential_type.namespace not in ('scm', 'insights', 'azure_rm'):
|
||||
credential = None # ignore incompatible credential from HasCreate dependency injection
|
||||
elif credential in (Credential,):
|
||||
credential = (Credential, dict(credential_type=(True, dict(kind='scm'))))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user