Запуск команд git против других репозиториев
В настоящее время я создаю конвейер для DevOps Azure, чтобы проверить и применить конфигурацию Terraform к другой подписке.
В моей конфигурации terraform используются модули, которые "размещены" в других репозиториях того же проекта Azure DevOps, что и конфигурация terraform.
К сожалению, когда я пытаюсь выполнить terraform init
чтобы получить эти модули, конвейерная задача "зависает" там в ожидании ввода учетных данных.
Как рекомендовано в документации конвейера по запуску команд Git в скрипте, я попытался добавить checkout
шаг с persistCredentials:true
приписывать.
Из того, что я вижу в журнале задачи (см. Ниже), информация об учетных данных добавляется специально к текущему репо и не может использоваться для других репо.
Команда выполняется при добавленииpersistCredentials:true
2018-10-22T14:06:54.4347764Z ##[command]git config http.https://my-org@dev.azure.com/my-org/my-project/_git/my-repo.extraheader "AUTHORIZATION: bearer ***"
Вывод задачи инициализации terraform
2018-10-22T14:09:24.1711473Z terraform init -input=false
2018-10-22T14:09:24.2761016Z Initializing modules...
2018-10-22T14:09:24.2783199Z - module.my-module
2018-10-22T14:09:24.2786455Z Getting source "git::https://my-org@dev.azure.com/my-org/my-project/_git/my-module-repo?ref=1.0.2"
Как настроить учетные данные git для работы с другими репозиториями?
7 ответов
У меня была такая же проблема, в итоге я сделал токенизацию SYSTEM_ACCESSTOKEN
в конфигурации терраформ. Я использовал задачу Tokenzization в Azure DevOps, где__
префикс и суффикс используются для идентификации и замены токенов фактическими переменными (они настраиваются, но я считаю, что двойные подчеркивания лучше всего не мешают любому имеющемуся у меня коду)
- task: qetza.replacetokens.replacetokens-task.replacetokens@3
displayName: 'Replace tokens'
inputs:
targetFiles: |
**/*.tfvars
**/*.tf
tokenPrefix: '__'
tokenSuffix: '__'
Что-то типа find $(Build.SourcesDirectory)/ -type f -name 'main.tf' -exec sed -i 's~__SYSTEM_ACCESSTOKEN__~$(System.AccessToken)~g' {} \;
также будет работать, если у вас нет возможности устанавливать собственные расширения в свою организацию DevOps.
Мой terraform main.tf выглядит так:
module "app" {
source = "git::https://token:__SYSTEM_ACCESSTOKEN__@dev.azure.com/actualOrgName/actualProjectName/_git/TerraformModules//azure/app-service?ref=__app-service-module-ver__"
....
}
Это не красиво, но выполняет свою работу. Источник модуля (на момент написания) не поддерживает ввод переменных из terraform. Итак, что мы можем сделать, так это использовать Terrafile, это проект с открытым исходным кодом, помогающий не отставать от модулей и различных версий одного и того же модуля, который вы можете использовать, сохраняя простой файл YAML рядом с вашим кодом. Кажется, что он больше не поддерживается, но он просто работает: https://github.com/coretech/terrafile мой пример Terrafile:
app:
source: "https://token:__SYSTEM_ACCESSTOKEN__@dev.azure.com/actualOrgName/actualProjectName/_git/TerraformModules"
version: "feature/handle-twitter"
app-stable:
source: "https://token:__SYSTEM_ACCESSTOKEN__@dev.azure.com/actualOrgName/actualProjectName/_git/TerraformModules"
version: "1.0.5"
Terrafile по умолчанию загружает ваши модули в каталог./vendor, чтобы вы могли указать источник вашего модуля на что-то вроде:
module "app" {
source = "./vendor/modules/app-stable/azure/app_service"
....
}
Теперь вам просто нужно выяснить, как выполнить terrafile
в каталоге, где находится Terrafile. Мой пример azure.pipelines.yml:
- script: curl -L https://github.com/coretech/terrafile/releases/download/v0.6/terrafile_0.6_Linux_x86_64.tar.gz | tar xz -C $(Agent.ToolsDirectory)
displayName: Install Terrafile
- script: |
cd $(Build.Repository.LocalPath)
$(Agent.ToolsDirectory)/terrafile
displayName: Download required modules
У вас есть по существу два способа сделать это.
Предварительное условие
Убедитесь, что вы прочитали и, в зависимости от ваших потребностей, применили раздел « Включить сценарии для запуска команд Git » в документе «Выполнение команд Git в сценарии».
Решение №1: динамически вставить
System.AccessToken
(или PAT, но я бы не рекомендовал) во время выполнения конвейера
Вы можете сделать это либо:
- вставка заменяющего токена, такого как
__SYSTEM_ACCESSTOKEN__
в вашем коде (как предлагает Нильсас ) и используйте код замены токена илиqetza.replacetokens.replacetokens-task.replacetokens
задача вставить значение. Недостатком этого решения является то, что вам также придется заменить токен при локальном запуске. - используя некоторый код для замены всех
git::https://dev.azure.com
текст сgit::https://YOUR_ACCESS_TOKEN@dev.azure.com
.
Я использовал второй подход, используя следующий сценарий задачи bash (он ищет файлы, но вы можете адаптироваться к файлам без особых изменений):
- bash: |
find $(Build.SourcesDirectory)/ -type f -name 'terragrunt.hcl' -exec sed -i 's~git::https://dev.azure.com~git::https://$(System.AccessToken)@dev.azure.com~g' {} \;
Абу Белай предлагает сценарий PowerShell для выполнения чего-то подобного.
Однако этот тип решения не работает, если модули в вашем репозитории модулей называют себя модулями в другом репо, как это было в нашем случае.
Решение № 2: глобальное добавление токена доступа в URL-адрес ваших репозиториев модулей
Таким образом, все репозитории модулей, вызываемые непосредственно вашим кодом или косвенно вызываемые кодом вызываемых модулей, смогут использовать ваш токен доступа. Я сделал это, добавив следующий шаг перед вашим /
terragrunt
звонки:
- bash: |
git config --global http.https://dev.azure.com/<your-org>/<your-first-repo-project>/_git/<your-first-repo>.extraheader "AUTHORIZATION: bearer $(System.AccessToken)"
git config --global http.https://dev.azure.com/<your-org>/<your-second-repo-project>/_git/<your-second-repo>.extraheader "AUTHORIZATION: bearer $(System.AccessToken)"
Вам нужно будет установить для каждого из вызываемых репозиториев.
Имейте в виду, что вам может понадобиться отключить
terraform
вызовы, если ваш конвейер устанавливает несколько раз для одного и того же работника. Это потому что
git
можно спутать с несколькими
extraheader
декларация. Вы делаете это, добавляя к следующему шагу:
- bash: |
git config --global --unset-all http.https://dev.azure.com/<your-org>/<your-first-repo-project>/_git/<your-first-repo>.extraheader
git config --global --unset-all http.https://dev.azure.com/<your-org>/<your-second-repo-project>/_git/<your-second-repo>.extraheader
Я сделал это
_ado_token.ps1
# used in Azure DevOps to allow terrform to auth with Azure DevOps GIT repos
$tfmodules = Get-ChildItem $PSScriptRoot -Recurse -Filter "*.tf"
foreach ($tfmodule in $tfmodules) {
$content = [System.IO.File]::ReadAllText($tfmodule.FullName).Replace("git::https://myorg@","git::https://" + $env:SYSTEM_ACCESSTOKEN +"@")
[System.IO.File]::WriteAllText($tfmodule.FullName, $content)
}
azure-pipelines.yml
- task: PowerShell@2
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
filePath: '_ado_token.ps1'
pwsh: true
displayName: '_ado_token.ps1'
Это сценарий:
У вас есть два репозитория git в одном проекте.
содержит код модуля terraform.
содержит код terraform, который указывает (с определенным тегом, например1.0.0
) в качестве источника модуля.
Yaml вашего конвейера находится в формате .
Тогда вот как ваш модульный блокRepo2
будет выглядеть так:
module "alz" {
source = "git::https://dev.azure.com/<org>/<project>/_git/Repo1?ref=<tag>"
.
.
}
В вашем конвейере Azure
Сначала вы объявите ресурс репозитория дляRepo1
:
resources:
repositories:
- repository: Repo1
type: git
name: "<project>/Repo1"
Затем извлеките оба репозитория в конвейере, но сохраните учетные данные для repo2.
# Checkout Repo2
- checkout : self
# Checkout Repo1
- checkout : Repo1
persistCredentials: 'true'
Даже если вы избежите очередиpersistCredentials: 'true'
, обязательно проверьте оба репозитория. Если вы просто оформляете заказself
, то есть только Repo2, он может не работать при получении данных из Repo1 и выдаст ошибку:
│ remote: TF401019: The Git repository with name or identifier
│ Repo1 does not exist or you do not have
│ permissions for the operation you are attempting.
Теперь установите учетные данные, т. е. System.AccessToken передterraform init
. Вы можете сделать это двумя способами.
Опция 1:
- bash: |
git config --global http.https://dev.azure.com/<org>/<project>/_git/Repo1.extraheader "AUTHORIZATION: bearer $(System.AccessToken)"
displayName: Set Credential
# Terraform Init
- task: TerraformTaskV4@4
inputs:
provider: 'azurerm'
command: 'init'
workingDirectory: '$(working_dir)'
backendServiceArm: $(sc_tf_backend)
backendAzureRmResourceGroupName: $(backendRGName)
backendAzureRmStorageAccountName: $(backendSAName)
backendAzureRmContainerName: $(backendContainerName)
backendAzureRmKey: $(backendBlobKey)
Вариант 2:
- bash: |
MY_TOKEN=$(System.AccessToken)
git config --global url."https://${MY_TOKEN}@dev.azure.com".insteadOf "https://dev.azure.com"
displayName: Set Credential
# Terraform Init
- task: TerraformTaskV4@4
inputs:
provider: 'azurerm'
command: 'init'
workingDirectory: '$(working_dir)'
backendServiceArm: $(sc_tf_backend)
backendAzureRmResourceGroupName: $(backendRGName)
backendAzureRmStorageAccountName: $(backendSAName)
backendAzureRmContainerName: $(backendContainerName)
backendAzureRmKey: $(backendBlobKey)
Насколько я понимаю, лучший способ сделать это точно такой же, как и с любым другим поставщиком Git. Только для Azure DevOps я когда-либо сталкивался с
- script: |
MY_TOKEN=foobar
git config --global url."https://${MY_TOKEN}@dev.azure.com".insteadOf "https://dev.azure.com"
Я решил проблему, создав шаблон конвейера, который запускает встроенный скрипт powershell. Затем я извлекаю шаблон в качестве шаблона Pipeline как «ресурс» при использовании любого модуля terraform из другого репозитория. Сценарий выполнит рекурсивный поиск всех файлов .tf. Затем используйте регулярное выражение для обновления всех URL-адресов источника модуля.
Я выбрал REGEX, а не токенизацию URL-адреса модуля, потому что это гарантирует, что модули могут быть загружены на машине разработки без каких-либо изменений в исходном коде.
parameters:
- name: terraform_directory
type: string
steps:
- task: PowerShell@2
displayName: Tokenize TF-Module Sources
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
targetType: 'inline'
script: |
$regex = "https://*(.+)dev.azure.com"
$tokenized_url = "https://token:$($env:SYSTEM_ACCESSTOKEN)@dev.azure.com"
Write-Host "Recursive Search in ${{ parameters.terraform_directory }}"
$tffiles = Get-ChildItem -Path "${{ parameters.terraform_directory }}" -Filter "*main.tf" -Recurse -Force
Write-Host "Found $($tffiles.Count) files ending with 'main.tf'"
if ($tffiles) { Write-Host $tffiles }
$tffiles | % {
Write-Host "Updating file $($_.FullName)"
$content = Get-Content $_.FullName
Write-Host "Replace Strings: $($content | Select-String -Pattern $regex)"
$content -replace $regex, $tokenized_url | Set-Content $_.FullName -Force
Write-Host "Updated content"
Write-Host (Get-Content $_.FullName)
}
Я не думаю, что ты можешь. Обычно вы создаете другую сборку и ссылаетесь на артефакты из этой сборки, чтобы использовать ее в своем текущем определении. Таким образом, вам не нужно подключаться к другому Git-репозиторию