`CommonConfig` explicitly takes Azure SDK credential, client option and additional provider configs from caller (#346)

* `CommonConfig` takes Azure SDK credential and client option from caller

* `CommonConfig` adds `ProviderConfigs` to allow module users to specify additional provider configs explicitly (instead of via env var)

* pass gosec
This commit is contained in:
magodo 2023-01-30 14:31:38 +08:00 коммит произвёл GitHub
Родитель 29cbc41d25
Коммит 69274d834a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 412 добавлений и 242 удалений

18
go.mod
Просмотреть файл

@ -3,8 +3,8 @@ module github.com/Azure/aztfy
go 1.19
require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.3
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.0.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0
github.com/charmbracelet/bubbles v0.14.0
@ -18,8 +18,8 @@ require (
github.com/hashicorp/terraform-exec v0.17.2
github.com/hexops/gotextdiff v1.0.3
github.com/magodo/armid v0.0.0-20220923023118-aec41eaf7370
github.com/magodo/azlist v0.0.0-20230118083100-39d50ebb1596
github.com/magodo/aztft v0.3.1-0.20230106111449-dcd315087da2
github.com/magodo/azlist v0.0.0-20230129022211-862464772b00
github.com/magodo/aztft v0.3.1-0.20230129030008-95c799252ad3
github.com/magodo/spinner v0.0.0-20220720073946-50f31b2dc5a6
github.com/magodo/textinput v0.0.0-20210913072708-7d24f2b4b0c0
github.com/magodo/tfadd v0.10.1-0.20230106064825-378b3ebb9a4e
@ -27,14 +27,14 @@ require (
github.com/magodo/workerpool v0.0.0-20230119025400-40192d2716ea
github.com/mitchellh/go-wordwrap v1.0.0
github.com/muesli/reflow v0.3.0
github.com/stretchr/testify v1.8.0
github.com/stretchr/testify v1.8.1
github.com/tidwall/gjson v1.14.1
github.com/urfave/cli/v2 v2.16.3
github.com/urfave/cli/v2 v2.24.1
github.com/zclconf/go-cty v1.11.0
)
require (
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/alertsmanagement/armalertsmanagement v0.6.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/apimanagement/armapimanagement v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appplatform/armappplatform v1.1.0-beta.1 // indirect
@ -67,7 +67,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/streamanalytics/armstreamanalytics v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/synapse/armsynapse v0.5.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/timeseriesinsights/armtimeseriesinsights v1.0.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1 // indirect
github.com/agext/levenshtein v1.2.2 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
@ -76,7 +76,7 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/golang-jwt/jwt v3.2.1+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect

39
go.sum
Просмотреть файл

@ -1,9 +1,9 @@
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.3 h1:8LoU8N2lIUzkmstvwXvVfniMZlFbesfT2AmA1aqvRr8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.3/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0 h1:VuHAcMq8pU1IWNT/m5yRaGqbK0BiQKHT8X4DTp9CHdI=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0/go.mod h1:tZoQYdDZNOiIjdSn0dVWVfl0NEPGOJqVLzSrcFk4Is0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 h1:T8quHYlUGyb/oqtSTwqlCr1ilJHrDv+ZtpSfo+hm1BU=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1/go.mod h1:gLa1CL2RNE4s7M3yopJ/p0iq5DdY6Yv5ZUt9MTRZOQM=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 h1:+5VZ72z0Qan5Bog5C+ZkgSqUbeVUd9wgtHOrIKuc5b8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/alertsmanagement/armalertsmanagement v0.6.0 h1:pks1dpbMetOpU0LLAMGqQWDmf6KH3YaZZFbvLdczkLY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/alertsmanagement/armalertsmanagement v0.6.0/go.mod h1:ScVCRUj/xrIX0/L+CPzpgFBB3kHuE0OfT7ZkKJL4tFg=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/apimanagement/armapimanagement v1.0.0 h1:Ai3+BE11JvwQ2PxLGNKAfMNSceYXjeijReLJiCouO6o=
@ -74,8 +74,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/synapse/armsynapse v0.5.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/synapse/armsynapse v0.5.0/go.mod h1:0LrLPHG/bVyQWENxWqSj2ycnnrpTjeSFrKuWymCBceM=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/timeseriesinsights/armtimeseriesinsights v1.0.0 h1:6zhHj/nA0VfUglOeV8geEXVw/XGAqsAyKjDK2B5gctE=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/timeseriesinsights/armtimeseriesinsights v1.0.0/go.mod h1:BJ1j39YchhMI91ICCnhfdwPe4bN59SdA4vYWd0bfF+g=
github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1 h1:BWe8a+f/t+7KY7zH2mqygeUD0t8hNFXe08p1Pb3/jKE=
github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1 h1:oPdPEZFSbl7oSPEAIPMPBMUmiL+mqgzBJwM/9qYcwNg=
github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1/go.mod h1:4qFor3D/HDsvBME35Xy9rwW9DecL+M2sNw1ybjPtwA0=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
@ -126,9 +126,8 @@ github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6
github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
@ -136,7 +135,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
@ -192,10 +190,10 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magodo/armid v0.0.0-20220923023118-aec41eaf7370 h1:n8RrB7jcZ9lQE7tyF2a7AEJ3Ux/E6E6FTeZLfgadPmg=
github.com/magodo/armid v0.0.0-20220923023118-aec41eaf7370/go.mod h1:rR8E7zfGMbmfnSQvrkFiWYdhrfTqsVSltelnZB09BwA=
github.com/magodo/azlist v0.0.0-20230118083100-39d50ebb1596 h1:LsiNgiXcXFU7vJQRR+YeZCk0W4rVo5QfXxcg2wLxf3o=
github.com/magodo/azlist v0.0.0-20230118083100-39d50ebb1596/go.mod h1:r1a269lM5tSby3J7PaEUZQCKWgCLKz9KSWgs7u6fR/M=
github.com/magodo/aztft v0.3.1-0.20230106111449-dcd315087da2 h1:WxZPV+s4O53tQ0rSlBhzpP5lDwzmCDocg+TuICOK6XA=
github.com/magodo/aztft v0.3.1-0.20230106111449-dcd315087da2/go.mod h1:UfUEt4CnhydYUqLTu7kmmx7CfFmQC9Y6cbyC87YA5VQ=
github.com/magodo/azlist v0.0.0-20230129022211-862464772b00 h1:b4qcRg5vLTkYLKN7V3C0tTiJh2bBk+Quag6s/OsNI8U=
github.com/magodo/azlist v0.0.0-20230129022211-862464772b00/go.mod h1:pkK04XFrJfiki47pbsmEBUAW/fbF2OiFhK37gq4TzOk=
github.com/magodo/aztft v0.3.1-0.20230129030008-95c799252ad3 h1:coH6vuc+p76SJ0mqJYEfny376wsJsME7RJEo1+xWlpM=
github.com/magodo/aztft v0.3.1-0.20230129030008-95c799252ad3/go.mod h1:UfwvfmEBgNL+dBbljeOHnuHEWILBDMZdH8NZ8wO41iQ=
github.com/magodo/spinner v0.0.0-20220720073946-50f31b2dc5a6 h1:CElHO4hPXC+Eivy8sUC/WrnH3jmQzdF2x0lEXBEYul8=
github.com/magodo/spinner v0.0.0-20220720073946-50f31b2dc5a6/go.mod h1:Cn4fFwFH/Ddw9sjWPeSS72bNaxbM+FRXf7pkGEDReq8=
github.com/magodo/textinput v0.0.0-20210913072708-7d24f2b4b0c0 h1:aNtr4iNv/tex2t8W1u3scAoNHEnFlTKhNNHOpYStqbs=
@ -230,7 +228,6 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
github.com/muesli/cancelreader v0.2.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
@ -263,22 +260,24 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo=
github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/urfave/cli/v2 v2.16.3 h1:gHoFIwpPjoyIMbJp/VFd+/vuD0dAgFK4B6DpEMFJfQk=
github.com/urfave/cli/v2 v2.16.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
github.com/urfave/cli/v2 v2.24.1 h1:/QYYr7g0EhwXEML8jO+8OYt5trPnLHS0p3mrgExJ5NU=
github.com/urfave/cli/v2 v2.24.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=

Просмотреть файл

@ -1,107 +1,37 @@
package client
import (
"fmt"
"os"
"strings"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
)
type ClientBuilder struct {
credential azcore.TokenCredential
opt *arm.ClientOptions
}
func NewClientBuilder() (*ClientBuilder, error) {
env := "public"
if v := os.Getenv("ARM_ENVIRONMENT"); v != "" {
env = v
}
var cloudCfg cloud.Configuration
switch strings.ToLower(env) {
case "public":
cloudCfg = cloud.AzurePublic
case "usgovernment":
cloudCfg = cloud.AzureGovernment
case "china":
cloudCfg = cloud.AzureChina
default:
return nil, fmt.Errorf("unknown environment specified: %q", env)
}
// Maps the auth related environment variables used in the provider to what azidentity honors.
if v, ok := os.LookupEnv("ARM_TENANT_ID"); ok {
// #nosec G104
os.Setenv("AZURE_TENANT_ID", v)
}
if v, ok := os.LookupEnv("ARM_CLIENT_ID"); ok {
// #nosec G104
os.Setenv("AZURE_CLIENT_ID", v)
}
if v, ok := os.LookupEnv("ARM_CLIENT_SECRET"); ok {
// #nosec G104
os.Setenv("AZURE_CLIENT_SECRET", v)
}
if v, ok := os.LookupEnv("ARM_CLIENT_CERTIFICATE_PATH"); ok {
// #nosec G104
os.Setenv("AZURE_CLIENT_CERTIFICATE_PATH", v)
}
cred, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{
ClientOptions: policy.ClientOptions{
Cloud: cloudCfg,
},
TenantID: os.Getenv("ARM_TENANT_ID"),
})
if err != nil {
return nil, fmt.Errorf("failed to obtain a credential: %v", err)
}
return &ClientBuilder{
credential: cred,
opt: &arm.ClientOptions{
ClientOptions: policy.ClientOptions{
Cloud: cloudCfg,
Telemetry: policy.TelemetryOptions{
ApplicationID: "aztfy",
Disabled: false,
},
Logging: policy.LogOptions{
IncludeBody: true,
},
},
},
}, nil
Credential azcore.TokenCredential
Opt arm.ClientOptions
}
func (b *ClientBuilder) NewKeyvaultKeysClient(subscriptionId string) (*armkeyvault.KeysClient, error) {
return armkeyvault.NewKeysClient(
subscriptionId,
b.credential,
b.opt,
b.Credential,
&b.Opt,
)
}
func (b *ClientBuilder) NewKeyvaultSecretsClient(subscriptionId string) (*armkeyvault.SecretsClient, error) {
return armkeyvault.NewSecretsClient(
subscriptionId,
b.credential,
b.opt,
b.Credential,
&b.Opt,
)
}
func (b *ClientBuilder) NewResourcesClient(subscriptionId string) (*armresources.Client, error) {
return armresources.NewClient(
subscriptionId,
b.credential,
b.opt,
b.Credential,
&b.Opt,
)
}

Просмотреть файл

@ -16,6 +16,8 @@ import (
"github.com/Azure/aztfy/internal/client"
"github.com/Azure/aztfy/internal/resmap"
"github.com/Azure/aztfy/internal/utils"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclwrite"
@ -62,17 +64,20 @@ type BaseMeta interface {
var _ BaseMeta = &baseMeta{}
type baseMeta struct {
subscriptionId string
rootdir string
outdir string
tf *tfexec.Terraform
resourceClient *armresources.Client
devProvider bool
backendType string
backendConfig []string
fullConfig bool
parallelism int
hclOnly bool
subscriptionId string
azureSDKCred azcore.TokenCredential
azureSDKClientOpt arm.ClientOptions
rootdir string
outdir string
tf *tfexec.Terraform
resourceClient *armresources.Client
devProvider bool
backendType string
backendConfig []string
providerConfig map[string]string
fullConfig bool
parallelism int
hclOnly bool
// The module address prefix in the resource addr. E.g. module.mod1.module.mod2.azurerm_resource_group.test.
// This is an empty string if module path is not specified.
@ -184,10 +189,10 @@ func NewBaseMeta(cfg config.CommonConfig) (*baseMeta, error) {
importBaseDirs = append(importBaseDirs, dir)
}
// Construct client builder
b, err := client.NewClientBuilder()
if err != nil {
return nil, fmt.Errorf("building authorizer: %w", err)
// Construct Azure resources client
b := client.ClientBuilder{
Credential: cfg.AzureSDKCredential,
Opt: cfg.AzureSDKClientOption,
}
resClient, err := b.NewResourcesClient(cfg.SubscriptionId)
if err != nil {
@ -205,19 +210,22 @@ func NewBaseMeta(cfg config.CommonConfig) (*baseMeta, error) {
os.Setenv("ARM_SKIP_PROVIDER_REGISTRATION", "true")
meta := &baseMeta{
subscriptionId: cfg.SubscriptionId,
rootdir: rootdir,
outdir: cfg.OutputDir,
resourceClient: resClient,
devProvider: cfg.DevProvider,
backendType: cfg.BackendType,
backendConfig: cfg.BackendConfig,
fullConfig: cfg.FullConfig,
parallelism: cfg.Parallelism,
useSafeFilename: cfg.Append,
hclOnly: cfg.HCLOnly,
importBaseDirs: importBaseDirs,
importModuleDirs: importModuleDirs,
subscriptionId: cfg.SubscriptionId,
azureSDKCred: cfg.AzureSDKCredential,
azureSDKClientOpt: cfg.AzureSDKClientOption,
rootdir: rootdir,
outdir: cfg.OutputDir,
resourceClient: resClient,
devProvider: cfg.DevProvider,
backendType: cfg.BackendType,
backendConfig: cfg.BackendConfig,
providerConfig: cfg.ProviderConfig,
fullConfig: cfg.FullConfig,
parallelism: cfg.Parallelism,
useSafeFilename: cfg.Append,
hclOnly: cfg.HCLOnly,
importBaseDirs: importBaseDirs,
importModuleDirs: importModuleDirs,
moduleAddr: moduleAddr,
moduleDir: moduleDir,
@ -447,7 +455,7 @@ func (meta baseMeta) generateCfg(ctx context.Context, l ImportList, cfgTrans ...
return meta.generateConfig(cfginfos)
}
func (meta *baseMeta) terraformConfig(backendType string) string {
func (meta *baseMeta) buildTerraformConfig(backendType string) string {
if meta.devProvider {
return fmt.Sprintf(`terraform {
backend %q {}
@ -467,11 +475,15 @@ func (meta *baseMeta) terraformConfig(backendType string) string {
`, backendType, azurerm.ProviderSchemaInfo.Version)
}
func (meta *baseMeta) providerConfig() string {
func (meta *baseMeta) buildProviderConfig() string {
lines := []string{" features {}"}
for k, v := range meta.providerConfig {
lines = append(lines, fmt.Sprintf(" %s = %s", k, v))
}
return fmt.Sprintf(`provider "azurerm" {
features {}
%s
}
`)
`, strings.Join(lines, "\n"))
}
func (meta baseMeta) filenameTerraformSetting() string {
@ -557,7 +569,7 @@ func (meta *baseMeta) initProvider(ctx context.Context) error {
log.Printf("[INFO] Output directory doesn't contain provider setting, create one then")
cfgFile := filepath.Join(meta.outdir, meta.filenameProviderSetting())
// #nosec G306
if err := os.WriteFile(cfgFile, []byte(meta.providerConfig()), 0644); err != nil {
if err := os.WriteFile(cfgFile, []byte(meta.buildProviderConfig()), 0644); err != nil {
return fmt.Errorf("error creating provider config: %w", err)
}
}
@ -566,7 +578,7 @@ func (meta *baseMeta) initProvider(ctx context.Context) error {
log.Printf("[INFO] Output directory doesn't contain terraform required provider setting, create one then")
cfgFile := filepath.Join(meta.outdir, meta.filenameTerraformSetting())
// #nosec G306
if err := os.WriteFile(cfgFile, []byte(meta.terraformConfig(meta.backendType)), 0644); err != nil {
if err := os.WriteFile(cfgFile, []byte(meta.buildTerraformConfig(meta.backendType)), 0644); err != nil {
return fmt.Errorf("error creating terraform config: %w", err)
}
}
@ -590,12 +602,12 @@ func (meta *baseMeta) initProvider(ctx context.Context) error {
wp.AddTask(func() (interface{}, error) {
providerFile := filepath.Join(meta.importBaseDirs[i], "provider.tf")
// #nosec G306
if err := os.WriteFile(providerFile, []byte(meta.providerConfig()), 0644); err != nil {
if err := os.WriteFile(providerFile, []byte(meta.buildProviderConfig()), 0644); err != nil {
return nil, fmt.Errorf("error creating provider config: %w", err)
}
terraformFile := filepath.Join(meta.importBaseDirs[i], "terraform.tf")
// #nosec G306
if err := os.WriteFile(terraformFile, []byte(meta.terraformConfig("local")), 0644); err != nil {
if err := os.WriteFile(terraformFile, []byte(meta.buildTerraformConfig("local")), 0644); err != nil {
return nil, fmt.Errorf("error creating terraform config: %w", err)
}
log.Printf(`[DEBUG] Run "terraform init" for the import directory %s`, meta.importBaseDirs[i])

Просмотреть файл

@ -60,7 +60,7 @@ func (meta *MetaQuery) ListResource(ctx context.Context) (ImportList, error) {
}
log.Printf("[DEBUG] Azure Resource set map to TF resource set")
rl := rset.ToTFResources(meta.parallelism)
rl := rset.ToTFResources(meta.parallelism, meta.azureSDKCred, meta.azureSDKClientOpt)
var l ImportList
for i, res := range rl {
@ -89,7 +89,14 @@ func (meta *MetaQuery) ListResource(ctx context.Context) (ImportList, error) {
}
func (meta MetaQuery) queryResourceSet(ctx context.Context, predicate string, recursive bool) (*resourceset.AzureResourceSet, error) {
result, err := azlist.List(ctx, meta.subscriptionId, predicate, &azlist.Option{Parallelism: meta.parallelism, Recursive: recursive})
result, err := azlist.List(ctx, predicate,
azlist.Option{
SubscriptionId: meta.subscriptionId,
Cred: meta.azureSDKCred,
ClientOpt: meta.azureSDKClientOpt,
Parallelism: meta.parallelism,
Recursive: recursive,
})
if err != nil {
return nil, fmt.Errorf("listing resource set: %v", err)
}

Просмотреть файл

@ -52,7 +52,7 @@ func (meta *MetaResource) ListResource(_ context.Context) (ImportList, error) {
},
}
log.Printf("[DEBUG] Azure Resource set map to TF resource set")
rl := resourceSet.ToTFResources(meta.parallelism)
rl := resourceSet.ToTFResources(meta.parallelism, meta.azureSDKCred, meta.azureSDKClientOpt)
// This is to record known resource types. In case there is a known resource type and there comes another same typed resource,
// then we need to modify the resource name. Otherwise, there will be a resource address conflict.
@ -81,7 +81,11 @@ func (meta *MetaResource) ListResource(_ context.Context) (ImportList, error) {
// In this case, users can use the `--type` option to manually specify the TF resource type.
if meta.ResourceType != "" {
if meta.AzureId.Equal(res.AzureId) {
tfid, err := aztft.QueryId(meta.AzureId.String(), meta.ResourceType, true)
tfid, err := aztft.QueryId(meta.AzureId.String(), meta.ResourceType,
&aztft.APIOption{
Cred: meta.azureSDKCred,
ClientOption: meta.azureSDKClientOpt,
})
if err != nil {
return nil, err
}

Просмотреть файл

@ -55,7 +55,7 @@ func (meta *MetaResourceGroup) ListResource(ctx context.Context) (ImportList, er
}
log.Printf("[DEBUG] Azure Resource set map to TF resource set")
rl := rset.ToTFResources(meta.parallelism)
rl := rset.ToTFResources(meta.parallelism, meta.azureSDKCred, meta.azureSDKClientOpt)
var l ImportList
for i, res := range rl {
@ -82,7 +82,14 @@ func (meta *MetaResourceGroup) ListResource(ctx context.Context) (ImportList, er
}
func (meta MetaResourceGroup) queryResourceSet(ctx context.Context, rg string) (*resourceset.AzureResourceSet, error) {
result, err := azlist.List(ctx, meta.subscriptionId, fmt.Sprintf("resourceGroup =~ %q", rg), &azlist.Option{Parallelism: meta.parallelism, Recursive: true})
result, err := azlist.List(ctx, fmt.Sprintf("resourceGroup =~ %q", rg),
azlist.Option{
SubscriptionId: meta.subscriptionId,
Cred: meta.azureSDKCred,
ClientOpt: meta.azureSDKClientOpt,
Parallelism: meta.parallelism,
Recursive: true,
})
if err != nil {
return nil, fmt.Errorf("listing resource set: %v", err)
}

Просмотреть файл

@ -4,6 +4,8 @@ import (
"sort"
"github.com/Azure/aztfy/pkg/log"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/magodo/armid"
"github.com/magodo/aztft/aztft"
@ -24,7 +26,7 @@ type PesudoResourceInfo struct {
TFId string
}
func (rset AzureResourceSet) ToTFResources(parallelism int) []TFResource {
func (rset AzureResourceSet) ToTFResources(parallelism int, cred azcore.TokenCredential, clientOpt arm.ClientOptions) []TFResource {
tfresources := []TFResource{}
wp := workerpool.NewWorkPool(parallelism)
@ -73,7 +75,12 @@ func (rset AzureResourceSet) ToTFResources(parallelism int) []TFResource {
for _, res := range rset.Resources {
res := res
wp.AddTask(func() (interface{}, error) {
tftypes, tfids, exact, err := aztft.QueryTypeAndId(res.Id.String(), true)
tftypes, tfids, exact, err := aztft.QueryTypeAndId(res.Id.String(),
&aztft.APIOption{
Cred: cred,
ClientOption: clientOpt,
},
)
return result{
resid: res.Id,
tftypes: tftypes,

Просмотреть файл

@ -14,7 +14,9 @@ import (
var _ Case = CaseKeyVaultNestedItems{}
type CaseKeyVaultNestedItems struct{}
type CaseKeyVaultNestedItems struct {
B client.ClientBuilder
}
func (CaseKeyVaultNestedItems) Tpl(d test.Data) string {
return fmt.Sprintf(`
@ -124,11 +126,8 @@ func (CaseKeyVaultNestedItems) Total() int {
return 5
}
func (CaseKeyVaultNestedItems) getItems(d test.Data) (keyId, secretId, certId string, err error) {
b, err := client.NewClientBuilder()
if err != nil {
return "", "", "", err
}
func (c CaseKeyVaultNestedItems) getItems(d test.Data) (keyId, secretId, certId string, err error) {
b := c.B
subid := os.Getenv("ARM_SUBSCRIPTION_ID")
ctx := context.Background()
{

Просмотреть файл

@ -1,4 +1,4 @@
package main
package query
import (
"context"
@ -83,16 +83,20 @@ resource "azurerm_subnet" "test" {
t.Logf("Sleep for %v to wait for the just created resources be recorded in ARG\n", delay)
time.Sleep(delay)
cred, clientOpt := test.BuildCredAndClientOpt(t)
// Import in non-recursive mode
aztfyDir := t.TempDir()
cfg := internalconfig.NonInteractiveModeConfig{
Config: config.Config{
CommonConfig: config.CommonConfig{
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 1,
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
AzureSDKCredential: cred,
AzureSDKClientOption: *clientOpt,
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 1,
},
ResourceNamePattern: "res-",
ARGPredicate: fmt.Sprintf(`resourceGroup =~ "%s" and type =~ "microsoft.network/virtualnetworks"`, d.RandomRgName()),

Просмотреть файл

@ -3,12 +3,14 @@ package resmap
import (
"context"
"encoding/json"
internalconfig "github.com/Azure/aztfy/internal/config"
"os"
"path/filepath"
"testing"
"time"
"github.com/Azure/aztfy/internal/client"
internalconfig "github.com/Azure/aztfy/internal/config"
"github.com/Azure/aztfy/pkg/config"
"github.com/Azure/aztfy/internal"
@ -66,14 +68,18 @@ func runCase(t *testing.T, d test.Data, c cases.Case) {
require.NoError(t, err)
require.NoError(t, os.WriteFile(mapFile, bMapping, 0644))
cred, clientOpt := test.BuildCredAndClientOpt(t)
cfg := internalconfig.NonInteractiveModeConfig{
Config: config.Config{
CommonConfig: config.CommonConfig{
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 1,
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
AzureSDKCredential: cred,
AzureSDKClientOption: *clientOpt,
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 1,
},
MappingFile: mapFile,
},
@ -110,7 +116,8 @@ func TestApplicationInsightWebTest(t *testing.T) {
func TestKeyVaultNestedItems(t *testing.T) {
t.Parallel()
test.Precheck(t)
c, d := cases.CaseKeyVaultNestedItems{}, test.NewData()
cred, opt := test.BuildCredAndClientOpt(t)
c, d := cases.CaseKeyVaultNestedItems{B: client.ClientBuilder{Credential: cred, Opt: *opt}}, test.NewData()
runCase(t, d, c)
}

Просмотреть файл

@ -3,12 +3,14 @@ package resource
import (
"context"
"fmt"
internalconfig "github.com/Azure/aztfy/internal/config"
"os"
"path/filepath"
"testing"
"time"
"github.com/Azure/aztfy/internal/client"
internalconfig "github.com/Azure/aztfy/internal/config"
"github.com/Azure/aztfy/pkg/config"
"github.com/Azure/aztfy/internal"
@ -62,15 +64,20 @@ func runCase(t *testing.T, d test.Data, c cases.Case) {
if err != nil {
t.Fatalf("failed to get resource ids: %v", err)
}
cred, clientOpt := test.BuildCredAndClientOpt(t)
for idx, rctx := range l {
cfg := internalconfig.NonInteractiveModeConfig{
Config: config.Config{
CommonConfig: config.CommonConfig{
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 1,
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
AzureSDKCredential: cred,
AzureSDKClientOption: *clientOpt,
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 1,
},
ResourceId: rctx.AzureId,
TFResourceName: fmt.Sprintf("res-%d", idx),
@ -111,7 +118,8 @@ func TestApplicationInsightWebTest(t *testing.T) {
func TestKeyVaultNestedItems(t *testing.T) {
t.Parallel()
test.Precheck(t)
c, d := cases.CaseKeyVaultNestedItems{}, test.NewData()
cred, opt := test.BuildCredAndClientOpt(t)
c, d := cases.CaseKeyVaultNestedItems{B: client.ClientBuilder{Credential: cred, Opt: *opt}}, test.NewData()
runCase(t, d, c)
}

Просмотреть файл

@ -3,11 +3,12 @@ package resourcegroup
import (
"context"
"fmt"
internalconfig "github.com/Azure/aztfy/internal/config"
"os"
"path/filepath"
"testing"
internalconfig "github.com/Azure/aztfy/internal/config"
"github.com/Azure/aztfy/pkg/config"
"github.com/Azure/aztfy/internal/test"
@ -77,14 +78,19 @@ resource "azurerm_resource_group" "test3" {
// Import the first resource group
aztfyDir := t.TempDir()
cred, clientOpt := test.BuildCredAndClientOpt(t)
cfg := internalconfig.NonInteractiveModeConfig{
Config: config.Config{
CommonConfig: config.CommonConfig{
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 1,
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
AzureSDKCredential: cred,
AzureSDKClientOption: *clientOpt,
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 1,
},
ResourceNamePattern: "t1",
},

Просмотреть файл

@ -2,12 +2,14 @@ package resourcegroup
import (
"context"
internalconfig "github.com/Azure/aztfy/internal/config"
"os"
"path/filepath"
"testing"
"time"
"github.com/Azure/aztfy/internal/client"
internalconfig "github.com/Azure/aztfy/internal/config"
"github.com/Azure/aztfy/pkg/config"
"github.com/Azure/aztfy/internal"
@ -56,14 +58,18 @@ func runCase(t *testing.T, d test.Data, c cases.Case) {
aztfyDir := t.TempDir()
cred, clientOpt := test.BuildCredAndClientOpt(t)
cfg := internalconfig.NonInteractiveModeConfig{
Config: config.Config{
CommonConfig: config.CommonConfig{
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 10,
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
AzureSDKCredential: cred,
AzureSDKClientOption: *clientOpt,
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 10,
},
ResourceGroupName: d.RandomRgName(),
ResourceNamePattern: "res-",
@ -101,7 +107,8 @@ func TestApplicationInsightWebTest(t *testing.T) {
func TestKeyVaultNestedItems(t *testing.T) {
t.Parallel()
test.Precheck(t)
c, d := cases.CaseKeyVaultNestedItems{}, test.NewData()
cred, opt := test.BuildCredAndClientOpt(t)
c, d := cases.CaseKeyVaultNestedItems{B: client.ClientBuilder{Credential: cred, Opt: *opt}}, test.NewData()
runCase(t, d, c)
}

Просмотреть файл

@ -3,11 +3,12 @@ package resourcegroup
import (
"context"
"fmt"
internalconfig "github.com/Azure/aztfy/internal/config"
"os"
"path/filepath"
"testing"
internalconfig "github.com/Azure/aztfy/internal/config"
"github.com/Azure/aztfy/pkg/config"
"github.com/Azure/aztfy/internal/test"
@ -105,16 +106,20 @@ module "sub-module" {
t.Fatalf("terraform init failed: %v", err)
}
cred, clientOpt := test.BuildCredAndClientOpt(t)
cfg := internalconfig.NonInteractiveModeConfig{
Config: config.Config{
CommonConfig: config.CommonConfig{
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 1,
Append: true,
ModulePath: "", // Import to the root module
SubscriptionId: os.Getenv("ARM_SUBSCRIPTION_ID"),
AzureSDKCredential: cred,
AzureSDKClientOption: *clientOpt,
OutputDir: aztfyDir,
BackendType: "local",
DevProvider: true,
Parallelism: 1,
Append: true,
ModulePath: "", // Import to the root module
},
},
PlainUI: true,

Просмотреть файл

@ -12,6 +12,11 @@ import (
"text/template"
"github.com/Azure/aztfy/internal/resmap"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/hashicorp/go-version"
install "github.com/hashicorp/hc-install"
"github.com/hashicorp/hc-install/fs"
@ -42,6 +47,61 @@ func Precheck(t *testing.T) {
}
}
func BuildCredAndClientOpt(t *testing.T) (azcore.TokenCredential, *arm.ClientOptions) {
env := "public"
if v := os.Getenv("ARM_ENVIRONMENT"); v != "" {
env = v
}
var cloudCfg cloud.Configuration
switch strings.ToLower(env) {
case "public":
cloudCfg = cloud.AzurePublic
case "usgovernment":
cloudCfg = cloud.AzureGovernment
case "china":
cloudCfg = cloud.AzureChina
default:
t.Fatalf("unknown environment specified: %q", env)
}
// #nosec G104
os.Setenv("AZURE_TENANT_ID", os.Getenv("ARM_TENANT_ID"))
// #nosec G104
os.Setenv("AZURE_CLIENT_ID", os.Getenv("ARM_CLIENT_ID"))
// #nosec G104
os.Setenv("AZURE_CLIENT_SECRET", os.Getenv("ARM_CLIENT_SECRET"))
// #nosec G104
os.Setenv("AZURE_CLIENT_CERTIFICATE_PATH", os.Getenv("ARM_CLIENT_CERTIFICATE_PATH"))
clientOpt := &arm.ClientOptions{
ClientOptions: policy.ClientOptions{
Cloud: cloudCfg,
Telemetry: policy.TelemetryOptions{
ApplicationID: "aztfy",
Disabled: false,
},
Logging: policy.LogOptions{
IncludeBody: true,
},
},
}
cred, err := azidentity.NewClientSecretCredential(
os.Getenv("ARM_TENANT_ID"),
os.Getenv("ARM_CLIENT_ID"),
os.Getenv("ARM_CLIENT_SECRET"),
&azidentity.ClientSecretCredentialOptions{
ClientOptions: clientOpt.ClientOptions,
},
)
if err != nil {
t.Fatalf("failed to obtain a credential: %v", err)
}
return cred, clientOpt
}
func EnsureTF(t *testing.T) string {
i := install.NewInstaller()
execPath, err := i.Ensure(context.Background(), []src.Source{

182
main.go
Просмотреть файл

@ -25,7 +25,12 @@ import (
"github.com/Azure/aztfy/internal"
"github.com/Azure/aztfy/internal/ui"
"github.com/Azure/aztfy/internal/utils"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/urfave/cli/v2"
)
@ -370,20 +375,27 @@ The output directory is not empty. Please choose one of actions below:
return fmt.Errorf("invalid resource id: %v", err)
}
cred, clientOpt, err := buildAzureSDKCredAndClientOpt()
if err != nil {
return err
}
// Initialize the config
cfg := config.Config{
CommonConfig: config.CommonConfig{
SubscriptionId: flagSubscriptionId,
OutputDir: flagOutputDir,
Append: flagAppend,
DevProvider: flagDevProvider,
ContinueOnError: flagContinue,
BackendType: flagBackendType,
BackendConfig: flagBackendConfig.Value(),
FullConfig: flagFullConfig,
Parallelism: flagParallelism,
HCLOnly: flagHCLOnly,
ModulePath: flagModulePath,
SubscriptionId: flagSubscriptionId,
AzureSDKCredential: cred,
AzureSDKClientOption: *clientOpt,
OutputDir: flagOutputDir,
Append: flagAppend,
DevProvider: flagDevProvider,
ContinueOnError: flagContinue,
BackendType: flagBackendType,
BackendConfig: flagBackendConfig.Value(),
FullConfig: flagFullConfig,
Parallelism: flagParallelism,
HCLOnly: flagHCLOnly,
ModulePath: flagModulePath,
},
ResourceId: resId,
TFResourceName: flagResName,
@ -410,20 +422,27 @@ The output directory is not empty. Please choose one of actions below:
rg := c.Args().First()
cred, clientOpt, err := buildAzureSDKCredAndClientOpt()
if err != nil {
return err
}
// Initialize the config
cfg := config.Config{
CommonConfig: config.CommonConfig{
SubscriptionId: flagSubscriptionId,
OutputDir: flagOutputDir,
Append: flagAppend,
DevProvider: flagDevProvider,
ContinueOnError: flagContinue,
BackendType: flagBackendType,
BackendConfig: flagBackendConfig.Value(),
FullConfig: flagFullConfig,
Parallelism: flagParallelism,
HCLOnly: flagHCLOnly,
ModulePath: flagModulePath,
SubscriptionId: flagSubscriptionId,
AzureSDKCredential: cred,
AzureSDKClientOption: *clientOpt,
OutputDir: flagOutputDir,
Append: flagAppend,
DevProvider: flagDevProvider,
ContinueOnError: flagContinue,
BackendType: flagBackendType,
BackendConfig: flagBackendConfig.Value(),
FullConfig: flagFullConfig,
Parallelism: flagParallelism,
HCLOnly: flagHCLOnly,
ModulePath: flagModulePath,
},
ResourceGroupName: rg,
ResourceNamePattern: flagPattern,
@ -449,20 +468,27 @@ The output directory is not empty. Please choose one of actions below:
predicate := c.Args().First()
cred, clientOpt, err := buildAzureSDKCredAndClientOpt()
if err != nil {
return err
}
// Initialize the config
cfg := config.Config{
CommonConfig: config.CommonConfig{
SubscriptionId: flagSubscriptionId,
OutputDir: flagOutputDir,
Append: flagAppend,
DevProvider: flagDevProvider,
ContinueOnError: flagContinue,
BackendType: flagBackendType,
BackendConfig: flagBackendConfig.Value(),
FullConfig: flagFullConfig,
Parallelism: flagParallelism,
HCLOnly: flagHCLOnly,
ModulePath: flagModulePath,
SubscriptionId: flagSubscriptionId,
AzureSDKCredential: cred,
AzureSDKClientOption: *clientOpt,
OutputDir: flagOutputDir,
Append: flagAppend,
DevProvider: flagDevProvider,
ContinueOnError: flagContinue,
BackendType: flagBackendType,
BackendConfig: flagBackendConfig.Value(),
FullConfig: flagFullConfig,
Parallelism: flagParallelism,
HCLOnly: flagHCLOnly,
ModulePath: flagModulePath,
},
ARGPredicate: predicate,
ResourceNamePattern: flagPattern,
@ -489,20 +515,27 @@ The output directory is not empty. Please choose one of actions below:
mapFile := c.Args().First()
cred, clientOpt, err := buildAzureSDKCredAndClientOpt()
if err != nil {
return err
}
// Initialize the config
cfg := config.Config{
CommonConfig: config.CommonConfig{
SubscriptionId: flagSubscriptionId,
OutputDir: flagOutputDir,
Append: flagAppend,
DevProvider: flagDevProvider,
ContinueOnError: flagContinue,
BackendType: flagBackendType,
BackendConfig: flagBackendConfig.Value(),
FullConfig: flagFullConfig,
Parallelism: flagParallelism,
HCLOnly: flagHCLOnly,
ModulePath: flagModulePath,
SubscriptionId: flagSubscriptionId,
AzureSDKCredential: cred,
AzureSDKClientOption: *clientOpt,
OutputDir: flagOutputDir,
Append: flagAppend,
DevProvider: flagDevProvider,
ContinueOnError: flagContinue,
BackendType: flagBackendType,
BackendConfig: flagBackendConfig.Value(),
FullConfig: flagFullConfig,
Parallelism: flagParallelism,
HCLOnly: flagHCLOnly,
ModulePath: flagModulePath,
},
MappingFile: mapFile,
}
@ -571,6 +604,67 @@ func initLog(path string, level hclog.Level) error {
return nil
}
// buildAzureSDKCredAndClientOpt builds the Azure SDK credential and client option from multiple sources (i.e. environment variables, MSI, Azure CLI).
func buildAzureSDKCredAndClientOpt() (azcore.TokenCredential, *arm.ClientOptions, error) {
env := "public"
if v := os.Getenv("ARM_ENVIRONMENT"); v != "" {
env = v
}
var cloudCfg cloud.Configuration
switch strings.ToLower(env) {
case "public":
cloudCfg = cloud.AzurePublic
case "usgovernment":
cloudCfg = cloud.AzureGovernment
case "china":
cloudCfg = cloud.AzureChina
default:
return nil, nil, fmt.Errorf("unknown environment specified: %q", env)
}
// Maps the auth related environment variables used in the provider to what azidentity honors
if v, ok := os.LookupEnv("ARM_TENANT_ID"); ok {
// #nosec G104
os.Setenv("AZURE_TENANT_ID", v)
}
if v, ok := os.LookupEnv("ARM_CLIENT_ID"); ok {
// #nosec G104
os.Setenv("AZURE_CLIENT_ID", v)
}
if v, ok := os.LookupEnv("ARM_CLIENT_SECRET"); ok {
// #nosec G104
os.Setenv("AZURE_CLIENT_SECRET", v)
}
if v, ok := os.LookupEnv("ARM_CLIENT_CERTIFICATE_PATH"); ok {
// #nosec G104
os.Setenv("AZURE_CLIENT_CERTIFICATE_PATH", v)
}
clientOpt := &arm.ClientOptions{
ClientOptions: policy.ClientOptions{
Cloud: cloudCfg,
Telemetry: policy.TelemetryOptions{
ApplicationID: "aztfy",
Disabled: false,
},
Logging: policy.LogOptions{
IncludeBody: true,
},
},
}
cred, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{
ClientOptions: clientOpt.ClientOptions,
TenantID: os.Getenv("ARM_TENANT_ID"),
})
if err != nil {
return nil, nil, fmt.Errorf("failed to obtain a credential: %v", err)
}
return cred, clientOpt, nil
}
func subscriptionIdFromCLI() (string, error) {
var stderr bytes.Buffer
var stdout bytes.Buffer

Просмотреть файл

@ -1,8 +1,17 @@
package config
import (
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
)
type CommonConfig struct {
// SubscriptionId specifies the user's Azure subscription id.
SubscriptionId string
// AzureSDKCredential specifies the Azure SDK token credential
AzureSDKCredential azcore.TokenCredential
// AzureSDKClientOption specifies the Azure SDK client option
AzureSDKClientOption arm.ClientOptions
// OutputDir specifies the Terraform working directory for aztfy to import resources and generate TF configs.
OutputDir string
// Append specifies whether this run is in append mode, in which case aztfy will generate some "safe" file name to avoid conflicts to usre's existing files.
@ -15,6 +24,11 @@ type CommonConfig struct {
BackendType string
// BackendConfig specifies an array of Terraform backend configs.
BackendConfig []string
// ProviderConfig specifies key value pairs that will be expanded to the terraform-provider-azurerm settings (i.e. `azurerm {}` block)
// Currently, only the top level attribute whose type is string is supported.
// This is not used directly by aztfy binary as the provider configs can be set by environment variable already.
// While it is useful for module users that want support multi-users scenarios in one process (in which case changing env vars affect the whole process).
ProviderConfig map[string]string
// FullConfig specifies whether to export all (non computed-only) Terarform properties when generating TF configs.
FullConfig bool
// Parallelism specifies the parallelism for the process