【问题标题】:Getting terraform null_resource local-exec to run a powershell install-module让 terraform null_resource local-exec 运行 powershell install-module
【发布时间】:2020-03-22 05:43:01
【问题描述】:

这可能是邪恶的,但为了在我们的 azure db 中设置托管身份,我们正在使用 null_resource,如下所示:

# https://www.terraform.io/docs/providers/null/resource.html
# This technique was stolen from https://stackoverflow.com/a/54523391/442773
resource "null_resource" "create-sql-user" {

  triggers = {
    db = azurerm_sql_database.x.id
  }

  # https://www.terraform.io/docs/provisioners/local-exec.html
  provisioner "local-exec" {

    # https://docs.microsoft.com/en-us/powershell/module/sqlserver/Invoke-Sqlcmd?view=sqlserver-ps
    # Adding the Managed Identity to the database as a user and assign it the roles of db_datareader and db_datawriter
    # NOTE: This is using the executing users credentials to connect to the db, this may not work if this is executed from a service principal within a devops pipeline
    # NOTE: this requires powershell to have the SqlServer module installed.  We tried a bunch of things to make it so it'd auto install the module but couldn't get it to work
    command = <<EOF
     Invoke-Sqlcmd `
       -Query "CREATE USER [${azurerm_app_service.x.name}] FROM EXTERNAL PROVIDER; ALTER ROLE db_datareader ADD MEMBER [${azurerm_app_service.x.name}]; ALTER ROLE db_datawriter ADD MEMBER [${azurerm_app_service.x.name}];" `
       -ConnectionString "Server=tcp:${azurerm_sql_server.x.fully_qualified_domain_name},1433;Initial Catalog=${azurerm_sql_database.x.name};Persist Security Info=False;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Authentication=Active Directory Integrated;" `
    EOF

    interpreter = ["PowerShell", "-Command"]
  }

}

问题是需要有 Invoke-Sqlcmd 可用,但只有 Install-Module SqlServer 带外带 terraform 才存在。我在命令中尝试了一些不同的东西来实现这一点。喜欢:

  # https://www.terraform.io/docs/provisioners/local-exec.html
  provisioner "local-exec" {

    # https://docs.microsoft.com/en-us/powershell/module/sqlserver/Invoke-Sqlcmd?view=sqlserver-ps
    # Adding the Managed Identity to the database as a user and assign it the roles of db_datareader and db_datawriter
    command = "Install-Module -Name SqlServer -AcceptLicense -SkipPublisherCheck -Force -AllowClobber -Scope CurrentUser;"

    interpreter = ["PowerShell", "-ExecutionPolicy", "Bypass", "-Command"]
  }

错误:运行命令“Install-Module -Name SqlServer -AcceptLicense -SkipPublisherCheck -Force -AllowClobber -Scope CurrentUser;”时出错:退出状态 1。输出:Install-Module:在模块“PowerShellGet”,但无法加载该模块。有关详细信息,请运行“Import-Module PowerShellGet”。

所以切换命令到

command = "Import-Module PowerShellGet; Install-Module -Name SqlServer -AcceptLicense -SkipPublisherCheck -Force -AllowClobber -Scope CurrentUser;"

但这导致了这个输出

Error: Error running command 'Import-Module PowerShellGet; Install-Module -Name SqlServer -AcceptLicense -SkipPublisherCheck -Force -AllowClobber -Scope CurrentUser;': exit status 1. Output: Import-Module : The specified module 'C:\program
files\powershell\6\Modules\PackageManagement\fullclr\Microsoft.PackageManagement.dll' was not loaded because no valid
module file was found in any module directory.
At line:1 char:1
+ Import-Module PowerShellGet; Install-Module -Name SqlServer -AcceptLi ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (C:\program file...eManagement.dll:String) [Import-Module], FileNot
   FoundException
    + FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand

PackageManagement\Get-PackageProvider : The term 'PackageManagement\Get-PackageProvider' is not recognized as the name
of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included,
verify that the path is correct and try again.
At C:\program files\powershell\6\Modules\PowerShellGet\PSModule.psm1:2926 char:26
+ ...        $nugetProvider = PackageManagement\Get-PackageProvider -ErrorA ...
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (PackageManagement\Get-PackageProvider:String) [], CommandNotFoundExcept
   ion
    + FullyQualifiedErrorId : CommandNotFoundException

PackageManagement\Get-PackageProvider : The term 'PackageManagement\Get-PackageProvider' is not recognized as the name
of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included,
verify that the path is correct and try again.
At C:\program files\powershell\6\Modules\PowerShellGet\PSModule.psm1:2940 char:40
+ ... ailableNugetProviders = PackageManagement\Get-PackageProvider -Name $ ...
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (PackageManagement\Get-PackageProvider:String) [], CommandNotFoundExcept
   ion
    + FullyQualifiedErrorId : CommandNotFoundException

Exception calling "ShouldContinue" with "2" argument(s): "Object reference not set to an instance of an object."
At C:\program files\powershell\6\Modules\PowerShellGet\PSModule.psm1:3115 char:8
+     if($Force -or $psCmdlet.ShouldContinue($shouldContinueQueryMessag ...
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : NullReferenceException

Install-Module : NuGet provider is required to interact with NuGet-based repositories. Please ensure that '2.8.5.201'
or newer version of NuGet provider is installed.
At line:1 char:30
+ ... erShellGet; Install-Module -Name SqlServer -AcceptLicense -SkipPublis ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Install-Module], InvalidOperationException
    + FullyQualifiedErrorId : CouldNotInstallNuGetProvider,Install-Module

我想知道的一件事是,powershell 版本 6 和 5 是否会以某种方式阻碍这里...

【问题讨论】:

  • 再看问题。也许您使用的解释器是错误的。也许您可以使用pwsh 指定您要使用powershell 内核?我会编辑答案。

标签: powershell terraform


【解决方案1】:

编辑: 我相信你使用了错误的解释器,尝试将 Powershell 切换到 pwsh 以使用 powershell 6 作为解释器。

  provisioner "local-exec" {
    ...
    interpreter = ["pwsh", "-Command"]
    ...
  }

我不确定您需要运行 powershell 的底层基础架构。看来您使用的是 powershell 6。

我还使用空提供者资源,调用脚本,传入参数,然后创建用户。这样做的一个好处是我知道我正在运行哪个 powershell 版本(核心),因为触发命令是 pwsh

我将向您展示我是如何创建空资源和脚本的 sn-p 的,希望对您有所帮助。

用于调用负责创建用户的脚本的空资源

resource "null_resource" "create_sql_user" {
  provisioner "local-exec" {
    command     = ".'${path.module}\\scripts\\create-sql-user.ps1' -password \"${random_password.sql_password.result}\" -username \"${var.sql_username}\" -sqlSaConnectionString \"${var.sql_server_connectionstring}\" -databaseName \"${azurerm_sql_database.db.name}\" "
    interpreter = ["pwsh", "-Command"]
  }
  depends_on = [azurerm_sql_database.db]
}

创建-sql-user.ps1

[CmdletBinding()]
param (
    [Parameter(Mandatory = $true)]
    [string]
    $password,
    [Parameter(Mandatory = $true)]
    [string]
    $username,
    [Parameter(Mandatory = $true)]
    [string]
    $sqlSaConnectionString
)

Install-Module -Name SqlServer -Force

$sqlCmd = "CREATE LOGIN $username WITH PASSWORD = '$password'; ALTER LOGIN $username enable"
Invoke-Sqlcmd -ConnectionString $sqlSaConnectionString -Query $sqlCmd

...

附加:

在这种情况下,我使用随机资源生成 sql 密码。可以对用户名使用类似的方法:

resource "random_password" "sql_password" {
  length           = 54
  special          = true
  override_special = "$%@&*()"
}

【讨论】:

  • 抱歉花了一段时间才回过头来确认,但我使用 ps core 后效果好多了!
猜你喜欢
  • 2016-11-28
  • 2020-12-24
  • 1970-01-01
  • 2020-02-15
  • 2020-10-26
  • 2020-07-07
  • 2019-08-20
  • 2020-10-04
  • 2021-12-07
相关资源
最近更新 更多