简体   繁体   English

如何使用 terraform 将生命周期规则添加到 S3 存储桶?

[英]How to add lifecycle rules to an S3 bucket using terraform?

I am using Terraform to create a bucket in S3 and I want to add "folders" and lifecycle rules to it.我正在使用 Terraform 在 S3 中创建一个存储桶,我想向其中添加“文件夹”和生命周期规则。

I can create the bucket (using an "aws_s3_bucket" resource).我可以创建存储桶(使用“aws_s3_bucket”资源)。

I can create the bucket and define my lifecycle rules within the same "aws_s3_bucket" resource, ie.我可以在同一个“aws_s3_bucket”资源中创建存储桶并定义我的生命周期规则,即。 at creation time.在创建时。

I can add "folders" to the bucket (I know they aren't really folders, but they are presented to the client systems as if they were... :-) ), using an "aws_s3_bucket_object" resource, ie.我可以使用“aws_s3_bucket_object”资源将“文件夹”添加到存储桶中(我知道它们不是真正的文件夹,但它们会呈现给客户端系统,就好像它们是......:-))。 after bucket creation.创建存储桶后。

All good...都好...

But I want to be able to add lifecycle rules AFTER I've created the bucket, but I get an error telling me the bucket already exists.但我希望能够在创建存储桶后添加生命周期规则,但我收到一条错误消息,提示我该存储桶已存在。 (Actually I want to be able to subsequently add folders and corresponding lifecycle rules as and when required.) (实际上,我希望能够在需要时添加文件夹和相应的生命周期规则。)

Now, I can add lifecycle rules to an existing bucket in the AWS GUI, so I know it is a reasonable thing to want to do.现在,我可以在 AWS GUI 中向现有存储桶添加生命周期规则,所以我知道这是一件合理的事情。

But is there a way of doing it with Terraform?但是有没有办法用 Terraform 做到这一点?

Am I missing something?我错过了什么吗?

resource "aws_s3_bucket" "bucket" {
    bucket      = "${replace(var.tags["Name"],"/_/","-")}"
    region      = "${var.aws_region}"

    #tags                = "${merge(var.tags, map("Name", "${var.tags["Name"]}"))}"
    tags                = "${merge(var.tags, map("Name", "${replace(var.tags["Name"],"/_/","-")}"))}"
}


resource "aws_s3_bucket" "bucket_quarterly" {
    bucket      = "${aws_s3_bucket.bucket.id}"
    #region      = "${var.aws_region}"

    lifecycle_rule {
        id      = "quarterly_retention"
        prefix  = "quarterly/"
        enabled = true

        expiration {
            days = 92
        }
    }

}


resource "aws_s3_bucket" "bucket_permanent" {
    bucket      = "${aws_s3_bucket.bucket.id}"
    #region      = "${var.aws_region}"

    lifecycle_rule {
        id      = "permanent_retention"
        enabled = true
        prefix  = "permanent/"

        transition {
            days            = 1
            storage_class   = "GLACIER"
        }
    }

}


resource "aws_s3_bucket_object" "quarterly" {
    bucket  = "${aws_s3_bucket.bucket.id}"
    #bucket  = "${var.bucket_id}"
    acl     = "private"
    key     = "quarterly"
    source  = "/dev/null"
}


resource "aws_s3_bucket_object" "permanent" {
    bucket  = "${aws_s3_bucket.bucket.id}"
    #bucket  = "${var.bucket_id}"
    acl     = "private"
    key     = "permanent"
    source  = "/dev/null"
}

I expect to have a bucket with 2 lifecycle rules, but I get the following error:我希望有一个包含 2 个生命周期规则的存储桶,但出现以下错误:

Error: Error applying plan:错误:应用计划时出错:

2 error(s) occurred:

* module.s3.aws_s3_bucket.bucket_quarterly: 1 error(s) occurred:

* aws_s3_bucket.bucket_quarterly: Error creating S3 bucket: BucketAlreadyOwnedByYou: Your previous request to create the named bucket succeeded and you already own it.
    status code: 409, request id: EFE9C62B25341478, host id: hcsCNracNrpTJZ4QdU0AV2wNm/FqhYSEY4KieQ+zSHNsj6AUR69XvPF+0BiW4ZOpfgIoqwFoXkI=
* module.s3.aws_s3_bucket.bucket_permanent: 1 error(s) occurred:

* aws_s3_bucket.bucket_permanent: Error creating S3 bucket: BucketAlreadyOwnedByYou: Your previous request to create the named bucket succeeded and you already own it.
    status code: 409, request id: 7DE1B1A36138A614, host id: 8jB6l7d6Hc6CZFgQSLQRMJg4wtvnrSL6Yp5R4RScq+GtuMW+6rkN39bcTUwQhzxeI7jRStgLXSc=

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.

Lets first break down whats happening and how we can overcome this issue.让我们首先分解正在发生的事情以及我们如何克服这个问题。 Each time you define a resource "aws_s3_bucket" , terraform will attempt to create a bucket with the parameters specified.每次定义resource "aws_s3_bucket" ,terraform 都会尝试使用指定的参数创建存储桶。 If you want to attach a lifecycle policy to a bucket, do it where you define the bucket, eg:如果要将生命周期策略附加到存储桶,请在定义存储桶的位置执行此操作,例如:

resource "aws_s3_bucket" "quarterly" {
    bucket  = "quarterly_bucket_name"
    #bucket  = "${var.bucket_id}"
    acl     = "private"
    lifecycle_rule {
        id      = "quarterly_retention"
        prefix  = "folder/"
        enabled = true

        expiration {
            days = 92
        }
    }
}

resource "aws_s3_bucket" "permanent" {
    bucket  = "perm_bucket_name"
    acl     = "private"
    lifecycle_rule {
        id      = "permanent_retention"
        enabled = true
        prefix  = "permanent/"

        transition {
            days            = 1
            storage_class   = "GLACIER"
        }
    }
}

A bucket can have multiple lifecycle_rule blocks on it.一个bucket上可以有多个lifecycle_rule块。 If you want to define the lifecycle rules as external blocks, you can do it in this way:如果要将生命周期规则定义为外部块,可以通过以下方式进行:

// example of what the variable would look like:
variable "lifecycle_rules" {
  type = "list"
  default = []
}

// example of what the assignment would look like:
lifecycle_rules = [{
  id = "cleanup"
  prefix = ""
  enabled = true
  expiration = [{
    days = 1
  }]
}, {...}, {...} etc...]

// example what the usage would look like
resource "aws_s3_bucket" "quarterly" {
    bucket  = "quarterly_bucket_name"
    #bucket  = "${var.bucket_id}"
    acl     = "private"
    source  = "/dev/null"
    lifecycle_rule = [ "${var.lifecycle_rules}" ]
}

Note: the implementation above of having an external lifecycle policy isn't really the best way to do it, but the only way.注意:上面的外部生命周期策略的实现并不是最好的方法,而是唯一的方法。 You pretty much trick terraform into accepting the list of maps, which happens to be the same type as lifecycle_rule, so it works.您几乎可以欺骗 terraform 接受地图列表,该列表恰好与 Lifecycle_rule 类型相同,因此它可以工作。 Ideally, Terraform should have it's own resource block for lifecycle rules, but it doesn't.理想情况下,Terraform 应该有自己的生命周期规则resource块,但它没有。

Edit: why have separate resource blocks when we now have dynamic blocks!编辑:当我们现在有动态块时,为什么还要有单独的资源块! Woohoo呜呼

As far as I am aware, you cannot make a lifecycle policy separately.据我所知,您不能单独制定生命周期策略。

Someone raised a PR for a resource to be created to allow you to do so, but looks like it is still open: https://github.com/terraform-providers/terraform-provider-aws/issues/6188有人为要创建的资源提出了 PR 以允许您这样做,但看起来它仍然是开放的: https : //github.com/terraform-providers/terraform-provider-aws/issues/6188


As for your error, I believe the reason you're getting the error is because:至于您的错误,我相信您收到错误的原因是:

  • resource "aws_s3_bucket" "bucket"

Creates a bucket with a particular name.创建具有特定名称的存储桶。

  • resource "aws_s3_bucket" "bucket_quarterly"

References bucket = "${aws_s3_bucket.bucket.id}" and therefore tries to create a bucket with the same name as the previous resource (which cannot be done as names are unique).引用bucket = "${aws_s3_bucket.bucket.id}"并因此尝试创建一个与前一个资源同名的存储桶(由于名称是唯一的,所以不能这样做)。

  • resource "aws_s3_bucket" "bucket_permanent"

Similarly, this resource references bucket = "${aws_s3_bucket.bucket.id}" and therefore tries to create a bucket with the same name as the first resource (which cannot be done as names are unique).类似地,此资源引用了bucket = "${aws_s3_bucket.bucket.id}" ,因此尝试创建一个与第一个资源同名的存储桶(由于名称是唯一的,因此无法完成)。


You mentioned I expect to have a bucket with 2 lifecycle rules but in your above code you are creating 3 separate s3 buckets (one without a lifecycle, and 2 with a lifecycle) and two objects (folders) that are being placed into the s3 bucket without a lifecycle policy.您提到I expect to have a bucket with 2 lifecycle rules但在上面的代码中,您正在创建 3 个单独的 s3 存储桶(一个没有生命周期,2 个有生命周期)和两个被放入 s3 存储桶的对象(文件夹)没有生命周期策略。

Thanks for the info (I like the idea of the list to separate the rules from the resource).感谢您提供信息(我喜欢将规则与资源分开的列表的想法)。

The issue was that I didn't appreciate that you could define lifecycle rules within the resource AND change them subsequently, so I was trying to figure out how to define them separately...问题是我不明白您可以在资源中定义生命周期规则并随后更改它们,所以我试图弄清楚如何分别定义它们......

All that's required is to specify them in the resource and do terraform apply, then you can edit it and add/amend/remove lifecycle_rules items and just do terraform apply again to apply the changes.所需要做的就是在资源中指定它们并执行 terraform apply,然后您可以编辑它并添加/修改/删除生命周期规则项,然后再次执行 terraform apply 以应用更改。

    source "aws_s3_bucket" "my_s3_bucket" {
       bucket = local.s3_bucket_name
    
    }



    
    resource "aws_s3_bucket_acl" "my_s3_bucket_acl" {
      bucket = aws_s3_bucket.my_s3_bucket.arn
    
      lifecycle {
        prevent_destroy = true
      }
    }


    
    resource "aws_s3_bucket_versioning" "my_s3_bucket_versioning" {
      bucket = aws_s3_bucket.my_s3_bucket.arn
      versioning_configuration {
        status = true
      }
    }
    



    resource "aws_s3_bucket_server_side_encryption_configuration" "my_s3-bucket_encryption" {
      bucket = aws_s3_bucket.my_s3_bucket.arn
      rule {
        apply_server_side_encryption_by_default {
          sse_algorithm = "AES256"
        }
      }

}

resource "aws_s3_bucket_lifecycle_configuration" "my_s3_bucket_lifecycle_config" {
  bucket = aws_s3_bucket.my_s3_bucket.arn
  rule {
    id     = "dev_lifecycle_7_days"
    status = true

    abort_incomplete_multipart_upload {
      days_after_initiation = 30
    }
    noncurrent_version_expiration {
      noncurrent_days = 1
    }
    transition {
      storage_class = "STANDARD_IA"
      days = 30
    }
    expiration {
      days = 30
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM