amazon-web-services - 在 UserData 中实现 If 函数

标签 amazon-web-services aws-cloudformation

我试图了解是否可以在 UserData 中使用 If 函数。当我使用下面的 CloudFormation 模板时,一切都会按预期执行。

    Type: 'AWS::EC2::Instance'
    Properties:
        <OMIT>
        BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeSize: 50
        - !If [VolumeCreationCondition, {DeviceName: xvdh, Ebs:{VolumeSize: 150, VolumeType: st1}}, !Ref AWS::NoValue]
        UserData:
          !Base64 |
            <powershell>
            Install-WindowsFeature Net-Framework-Core;
            Initialize-Disk 1;
            New-Partition -DiskNumber 1 -AssignDriveLetter -UseMaximumSize | Format-Volume -FileSystem NTFS -NewFileSystemLabel Video;
            & "C:\Program Files\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1" -a fetch-config -m ec2 -s -c ssm:WindowsAgentConfig
            </powershell>

但是,当我引入 2 个新的 If 条件时,不会执行任何 PowerShell 命令。

    Type: 'AWS::EC2::Instance'
    Properties:
        <OMIT>
        BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeSize: 50
        - !If [VolumeCreationCondition, {DeviceName: xvdh, Ebs:{VolumeSize: 150, VolumeType: st1}}, !Ref AWS::NoValue]
        UserData:
          !Base64 |
            <powershell>
            Install-WindowsFeature Net-Framework-Core;
            !If [VolumeCreationCondition, Initialize-Disk 1;, !Ref AWS::NoValue]
            !If [VolumeCreationCondition, New-Partition -DiskNumber 1 -AssignDriveLetter -UseMaximumSize | Format-Volume -FileSystem NTFS -NewFileSystemLabel Video;, !Ref AWS::NoValue]
            & "C:\Program Files\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1" -a fetch-config -m ec2 -s -c ssm:WindowsAgentConfig
            </powershell>

这不是 VolumeCreationCondition 的问题,因为它在这里工作正常。

!If [VolumeCreationCondition, {DeviceName: xvdh, Ebs:{VolumeSize: 150, VolumeType: st1}}, !Ref AWS::NoValue]

引用AWS Condition functions时我找不到任何语法问题。我的场景的唯一解决方案是将条件应用于此 EC2 资源吗?这并不理想,因为我还有其他几个资源引用此 EC2,这意味着我也必须对所有这些资源实现条件。

最佳答案

您不能在 PowerShell 脚本内使用 CloudFormation IF 语句。
事实上,在任何 userdata 脚本中。

我不了解 PowerShell,但我会向您展示如何使用 Bash 执行您想要的操作。只需遵循相同的方法即可。

Type: 'AWS::EC2::Instance'
    Properties:
        <OMIT>
        BlockDeviceMappings:
        - DeviceName: /dev/sda1
            Ebs:
            VolumeSize: 50
        - !If [VolumeCreationCondition, {DeviceName: xvdh, Ebs:{VolumeSize: 150, VolumeType: st1}}, !Ref AWS::NoValue]
        UserData:
            Fn::Base64: !Sub |
            #!/bin/bash
            
            export need_to_init="${VolumeCreationCondition}"
            if [[ "${need_to_init}" != "" ]]
            then
                # "Run your command to init disk here"
            fi

您不能直接在用户数据脚本中使用 CloudFormation 条件。
请参阅下面尝试使用它的示例。

Parameters:
  Production:
    Type: String
    Default: ''

Conditions:
  CreateProdResources: !Not [!Equals [!Ref Production, '']]

Resources:
  CloudNetPingTargetInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: amzn2-ami-hvm-2.0.20210427.0-x86_64-gp2
      NetworkInterfaces:
        - DeviceIndex: '0'
          DeleteOnTermination: true
          SubnetId: subnet-11111c86
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash

          export PRODUCTION="${CreateProdResources}"
          if [[ "$PRODUCTION" != "" ]]
          then
            echo "##### IS PRODUCTION"
          fi

看看我们验证模板时会发生什么:

$ aws cloudformation validate-template --template-body file://test.yaml

An error occurred (ValidationError) when calling the ValidateTemplate operation: Template format error: Unresolved resource dependencies [CreateProdResources] in the Resources block of the template

但是您可以在脚本中执行与 CloudFormation 条件相同的逻辑。请参阅下面的内容。

Parameters:
  Production:
    Type: String
    Default: ''

Conditions:
  CreateProdResources: !Not [!Equals [!Ref Production, '']]

Resources:
  CloudNetPingTargetInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: amzn2-ami-hvm-2.0.20210427.0-x86_64-gp2
      NetworkInterfaces:
        - DeviceIndex: '0'
          DeleteOnTermination: true
          SubnetId: subnet-11111c86
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash

          export PRODUCTION="${Production}"
          if [[ "$PRODUCTION" != "" ]]
          then
            echo "##### IS PRODUCTION"
          fi
      

现在当我验证时,它可以工作。

$ aws cloudformation validate-template --template-body file://test.yaml
{
    "Parameters": [
        {
            "ParameterKey": "Production",
            "DefaultValue": "",
            "NoEcho": false
        }
    ]
}

诀窍是使用 CloudFormation Sub 函数使用 CloudFormation 参数中的值创建脚本变量。

关于amazon-web-services - 在 UserData 中实现 If 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67452923/

相关文章:

java - 我想用 Java 代码在浏览器上打开链接或 URL

postgresql - Azure PostgreSQL 外部数据包装器 postgres_fdw

amazon-web-services - AWS Elastic Beanstalk 问题无法在所有服务器上部署

amazon-web-services - 在 Cloudformation 中使用 SNS 进行代码构建通知

amazon-web-services - AWS - 使用 CloudFormation 将数据从一个 S3 存储桶移动到另一个 S3 存储桶

java - 了解 AWS 开发工具包 Java 2.x(异步与同步)HTTP 客户端

php - 限制对 amazon s3 文件的访问,只允许登录用户访问

amazon-web-services - CloudFormation 从 CodePipeline 传递参数

aws-lambda - 将预训练模型从 CloudFormation 部署到 SageMaker Endpoint

amazon-web-services - Cloudformation YAML 自定义变量