Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Terraform可以监视目录中的更改吗?_Terraform - Fatal编程技术网

Terraform可以监视目录中的更改吗?

Terraform可以监视目录中的更改吗?,terraform,Terraform,我想监视一个文件目录,如果其中一个文件发生更改,则重新上载并运行一些其他任务。我以前的解决方案涉及监视单个文件,但这很容易出错,因为有些文件可能会被遗忘: resource "null_resource" "deploy_files" { triggers = { file1 = "${sha1(file("my-dir/file1"))}" file2 = "${sha1(file("my-dir/file2"))}" file3 = "${sha1(fil

我想监视一个文件目录,如果其中一个文件发生更改,则重新上载并运行一些其他任务。我以前的解决方案涉及监视单个文件,但这很容易出错,因为有些文件可能会被遗忘:

resource "null_resource" "deploy_files" {    
  triggers = {
    file1 = "${sha1(file("my-dir/file1"))}"
    file2 = "${sha1(file("my-dir/file2"))}"
    file3 = "${sha1(file("my-dir/file3"))}"
    # have I forgotten one?
  }

  # Copy files then run a remote script.
  provisioner "file" { ... }
  provisioner "remote-exec: { ... }
}
我的下一个解决方案是在一个资源中获取目录结构的哈希,并在第二个资源中使用此哈希作为触发器:

resource "null_resource" "watch_dir" {
  triggers = {
    always = "${uuid()}"
  }

  provisioner "local-exec" {
    command = "find my-dir  -type f -print0 | xargs -0 sha1sum | sha1sum > mydir-checksum"
  }
}


resource "null_resource" "deploy_files" {    
  triggers = {
    file1 = "${sha1(file("mydir-checksum"))}"
  }

  # Copy files then run a remote script.
  provisioner "file" { ... }
  provisioner "remote-exec: { ... }
}
这可以正常工作,但对
mydir校验和的更改只有在第一次
apply
之后才会被拾取。所以我需要应用两次,这不是很好。这有点混乱


我看不到更明显的方法来监视整个目录中的内容更改。有没有一种标准的方法可以做到这一点?

Terraform似乎没有提供任何目录树遍历功能,因此我能想到的唯一解决方案是使用某种外部工具来实现这一点,如Make:

all: tf.plan

tf.plan: hash *.tf
        terraform plan -o $@

hash: some/dir
        find $^ -type f -exec sha1sum {} + > $@

.PHONY: all hash
然后在地形文件中:

resource "null_resource" "deploy_files" {    
  triggers = {
    file1 = "${file("hash")}"
  }

  # Copy files then run a remote script.
  provisioner "file" { ... }
  provisioner "remote-exec: { ... }
}

我也有同样的需求,我使用资源以以下方式实现了它:

  • 编写了一个脚本,使用
    md5sum

    #!/bin/bash
    #
    # This script calculates the MD5 checksum on a directory
    #
    
    # Exit if any of the intermediate steps fail
    set -e
    
    # Extract "DIRECTORY" argument from the input into
    # DIRECTORY shell variables.
    # jq will ensure that the values are properly quoted
    # and escaped for consumption by the shell.
    eval "$(jq -r '@sh "DIRECTORY=\(.directory)"')"
    
    # Placeholder for whatever data-fetching logic your script implements
    CHECKSUM=`find ${DIRECTORY} -type f | LC_ALL=C sort | xargs shasum -a 256 | awk '{ n=split ($2, tokens, /\//); print $1 " " tokens[n]} ' |  shasum -a 256 | awk '{ print $1 }'`
    
    # Safely produce a JSON object containing the result value.
    # jq will ensure that the value is properly quoted
    # and escaped to produce a valid JSON string.
    jq -n --arg checksum "$CHECKSUM" '{"checksum":$checksum}'
    
  • 创建
    数据。外部
    如下

    data "external" "trigger" {
      program = ["${path.module}/dirhash.sh"]
    
      query {
        directory = "${path.module}/<YOUR_DIR_PATH_TO_WATCH>"
      }
    }
    
PS:脚本依赖于
jq

更新: 更新了校验和计算逻辑,以消除查找对不同平台的影响。

您可以使用:


当且仅当存档的哈希已更改时,才会重新配置空资源。每当
source\u dir
(在本例中为
data/
)的内容更改时,将在刷新期间重建存档。

我将此用于GCP中的云函数,其中云函数仅取决于文件名,因此,我需要在任何文件更改时强制更改文件名,否则会污染每次部署的云功能。我使用局部变量解决了这个问题,因此没有像
archive\u文件
解决方案那样创建额外的文件。需要注意的是,您需要硬编码文件名,这在某些用例中可能是可以接受的

locals {
  # Hard code a list of files in the dir
  cfn_files = [
    "cfn/requirements.txt",
    "cfn/main.py",
  ]

  # Get the MD5 of each file in the directory
  cfn_md5sums = [for f in local.cfn_files : filemd5(f)]

  # Join the MD5 sums together and take the MD5 of all of them
  # Effectively checksumming the pieces of the dir you care about
  cfn_dirchecksum = md5(join("-", local.cfn_md5sums))
}
...

data "archive_file" "cfn" {
  type        = "zip"
  source_dir = "cfn"
  output_path = "cfn/build/${local.cfn_dirchecksum}.zip"
}
resource "google_storage_bucket_object" "archive" {
  name   = data.archive_file.cfn.output_path
  bucket = google_storage_bucket.cfn_bucket.name
  source = data.archive_file.cfn.output_path
}
...
resource "google_cloudfunctions_function" "function" {
  project     = var.project_id
  region      = var.region
  runtime     = "python37"

  source_archive_bucket = google_storage_bucket.cfn_bucket.name
  source_archive_object = google_storage_bucket_object.archive.name
...
}

在Terraform 0.12及更高版本中,可以使用a、a和其中一个哈希函数来计算目录中文件的组合校验和:

> sha1(join("", [for f in fileset(path.cwd, "*"): filesha1(f)]))
"77e0b2785eb7405ea5b3b610c33c3aa2dccb90ea"
上面的代码将为当前目录中与名称模式匹配的每个文件计算一个
sha1
校验和,将校验和合并到一个字符串中,最后为结果字符串计算一个校验和。因此,
null\u资源
示例如下所示,上面的表达式作为触发器:

resource "null_resource" "deploy_files" {    
  triggers = {
    dir_sha1 = sha1(join("", [for f in fileset("my-dir", "*"): filesha1(f)]))
  }

  provisioner "file" { ... }
  provisioner "remote-exec: { ... }
}

请注意,
fileset(“my dir”,“*”)
不考虑
my dir
子目录中的文件。如果您想包含这些的校验和,请使用名称模式
**
而不是
*

来生成哈希,然后将其用作触发器?因为我不知道还有其他的解决办法。另外
find my dir-type f-exec sha1sum+
应该更快。你是说
make
作为一个外部脚本在terraform之前运行?这是一个有趣的问题,我从来没有以这种方式使用过terraform。但我想知道这是否只是Terraform没有做的事情——它管理基础设施;文件系统处理似乎是二等公民。我可能会建议您在Terraform周围使用一个包装器脚本,以根据您的需要对其进行塑造。@Joe是的。您可以让
make
任务检查并生成目录的sum文件,然后将该文件内容用作触发器。谢谢。同意,这一点没有得到直接支持可能是一个暗示。但是有很多例子涉及到查看文件,而查看文件目录也没什么不同。有问题的文件是Docker Stack部署文件和支持配置,我认为它们位于Terraform区域。谢谢你的回答。我会考虑的。太棒了,非常感谢。我看到了外部资源的东西,然后我看到了JSON需求,并将其忽略。我会尝试一下这种方法。@Joe,我已经更新了校验和逻辑,以消除平台上的
find
效应。请看一看。谢谢我用这个已经有一段时间了。它工作得非常好。干得好,真有意思!我认为这取决于输出压缩字节相对于输入的确定性/可重复性。这是一个偶然的结果还是拉链的稳定性被定义了?同意,我没有考虑过。幸运的是,我的实现没有向zip文件本身添加时间戳或任何东西,但即使是更新的zip文件的时间戳,也会使数据无效、更改哈希并使资源无效。如果要访问上层目录中的文件,还需要将其传递给filesha1函数。您可以使用本地文件来避免重复。例如:[对于文件集中的f(“${path.module}/./website”、“*”):filesha1(${path.module}/./website/${f}”)]如果您对tf模块的内容执行此操作,如何从该操作中排除隐藏文件/状态文件?
> sha1(join("", [for f in fileset(path.cwd, "*"): filesha1(f)]))
"77e0b2785eb7405ea5b3b610c33c3aa2dccb90ea"
resource "null_resource" "deploy_files" {    
  triggers = {
    dir_sha1 = sha1(join("", [for f in fileset("my-dir", "*"): filesha1(f)]))
  }

  provisioner "file" { ... }
  provisioner "remote-exec: { ... }
}