代码之家  ›  专栏  ›  技术社区  ›  Chris DaMour

获取terraform null_resource local exec以运行powershell安装模块

  •  0
  • Chris DaMour  · 技术社区  · 6 年前

    # 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可用,但这只有通过安装模块SqlServer out-of-band w/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"]
      }
    

    错误:运行命令“安装模块”的错误-名称SQLServer - Access许可证- SkIPPuxierCherk-力-允许CulbBerb-范围CurrutUnter;():退出状态1。输出:安装模块:在模块“PowerShellGet”中找到“Install 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是否在某种程度上妨碍了这里。。。

    0 回复  |  直到 6 年前
        1
  •  2
  •   pijemcolu    6 年前

    编辑:

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

    我不确定您需要powershell运行的底层基础结构。你好像在用powershell 6。

    我还使用一个空的提供者资源,调用一个脚本,传入参数,然后创建一个用户。这样做的一个优点是,我知道作为触发器命令运行的是哪个powershell版本(core) pwsh .

    我将向您展示如何创建空资源和脚本片段,希望它能有所帮助。

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

    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 = "$%@&*()"
    }