生成并下载API网关SDK使用terraform的方法如何?

huangapple go评论69阅读模式
英文:

How to generate and download API gateway SDKwith terraform?

问题

I want to generate an API Gateway SDK with terraform automatically. Unfortunately, I'm always getting an error.
I am using the following code to generate the SDK:

data "aws_api_gateway_sdk" "example" {
  rest_api_id = aws_api_gateway_stage.example.rest_api_id
  stage_name  = aws_api_gateway_stage.example.stage_name
  sdk_type    = "javascript"
}

As an output in the tfstate file, I am getting:

{
  "mode": "data",
  "type": "aws_api_gateway_sdk",
  "name": "example",
  "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
  "instances": [
    {
      "schema_version": 0,
      "attributes": {
        "body": "PK\u0003\u0004\u..........00",
        "content_disposition": "attachment; filename=\"null-2023-04-18T22:00:16Z-javascript.zip\"",
        "content_type": "application/octet-stream",
        "id": "REST_ID:dev:javascript",
        "parameters": null,
        "rest_api_id": "REST_ID",
        "sdk_type": "javascript",
        "stage_name": "dev"
      },
      "sensitive_attributes": []
    }
  ]
},

I tried various ways to extract/save this body file - local-exec, archive_file, local_file, but none of them gave the desired output - a valid SDK zip file on my local filesystem.

Did I misunderstand something, or what could possibly go wrong?

英文:

I want to generate an API Gateway SDK with terraform automatically. Unfortunately, I getting always an error.
I am using following code to generate the SDK:

data "aws_api_gateway_sdk" "example" {
  rest_api_id = aws_api_gateway_stage.example.rest_api_id
  stage_name  = aws_api_gateway_stage.example.stage_name
  sdk_type    = "javascript"
}

As an output in the tfstate file I am getting:

    {
      "mode": "data",
      "type": "aws_api_gateway_sdk",
      "name": "example",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "body": "PK\u0003\u0004\u..........00",
            "content_disposition": "attachment; filename=\"null-2023-04-18T22:00:16Z-javascript.zip\"",
            "content_type": "application/octet-stream",
            "id": "REST_ID:dev:javascript",
            "parameters": null,
            "rest_api_id": "REST_ID",
            "sdk_type": "javascript",
            "stage_name": "dev"
          },
          "sensitive_attributes": []
        }
      ]
    },

I tried various ways to extract/save this body file - local-exec, archive_file, local_file, but none of them gave the desired output - a valid sdk zip file on my local filesystem.

Did misunderstood something or what could possibly go wrong?

答案1

得分: 1

This provider feature seems to be flawed: it's trying to return the raw content of a .zip file as a Terraform string value, but that's impossible because Terraform strings are sequences of unicode characters, not sequences of bytes. .zip is a binary format, so it isn't valid to represent the content of such a file as a unicode string.

Therefore I don't think it will be possible to achieve your goal using this data source, until the design of the data source is fixed by the provider development team in a new release. I suggest opening a bug report issue in the hashicorp/aws provider's GitHub repository.

The typical way for a Terraform provider to return binary content into the Terraform configuration would be to return it as a base64-encoded string. If this data source hypothetically offered another attribute named body_base64 which included a base64-encoded version of the zip file then you'd be able to write a configuration like this:

data "aws_api_gateway_sdk" "example" {
  rest_api_id = aws_api_gateway_stage.example.rest_api_id
  stage_name  = aws_api_gateway_stage.example.stage_name
  sdk_type    = "javascript"
}

# NOTE: This will not work at the time of writing, because
# the provider does not offer a body_base64 attribute from
# the data source. This is a hypothetical approach that
# could be used if the provider team changes the design
# of the data source to include this attribute.
resource "local_file" "example" {
  filename       = var.sdk_output_filename
  content_base64 = data.aws_api_gateway_sdk.example
}

However, Terraform isn't really designed for dealing with local files on your system and prefers to only deal with remote API objects. Even if the design of this data source were fixed as I described above, I would not typically expect to be solving this problem within Terraform, and would instead use Terraform only to describe the API, and use a separate process outside of Terraform to generate its SDK.

The fact that this is an unusual problem to solve with Terraform may explain why so far nobody noticed and reported that this data source has a flawed design.

英文:

This provider feature seems to be flawed: it's trying to return the raw content of a .zip file as a Terraform string value, but that's impossible because Terraform strings are sequences of unicode characters, not sequences of bytes. .zip is a binary format, so it isn't valid to represent the content of such a file as a unicode string.

Therefore I don't think it will be possible to achieve your goal using this data source, until the design of the data source is fixed by the provider development team in a new release. I suggest opening a bug report issue in the hashicorp/aws provider's GitHub repository.

The typical way for a Terraform provider to return binary content into the Terraform configuration would be to return it as a base64-encoded string. If this data source hypothetically offered another attribute named body_base64 which included a base64-encoded version of the zip file then you'd be able to write a configuration like this:

data "aws_api_gateway_sdk" "example" {
  rest_api_id = aws_api_gateway_stage.example.rest_api_id
  stage_name  = aws_api_gateway_stage.example.stage_name
  sdk_type    = "javascript"
}

# NOTE: This will not work at the time of writing, because
# the provider does not offer a body_base64 attribute from
# the data source. This is a hypothetical approach that
# could be used if the provider team changes the design
# of the data source to include this attribute.
resource "local_file" "example" {
  filename       = var.sdk_output_filename
  content_base64 = data.aws_api_gateway_sdk.example
}

However, Terraform isn't really designed for dealing with local files on your system and prefers to only deal with remote API objects. Even if the design of this data source were fixed as I described above, I would not typically expect to be solving this problem within Terraform, and would instead use Terraform only to describe the API, and use a separate process outside of Terraform to generate its SDK.

The fact that this is an unusual problem to solve with Terraform may explain why so far nobody noticed and reported that this data source has a flawed design.

答案2

得分: 0

I came to a conclusion/workaround.

The approach which I saw on many places didn't work for me.

...
data "aws_api_gateway_sdk" "example" {
  rest_api_id = aws_api_gateway_stage.example.rest_api_id
  stage_name  = aws_api_gateway_stage.example.stage_name
  sdk_type    = "javascript"
}

resource "local_file" "example_sdk" {
  filename = "example_sdk.zip"
  content = data.aws_api_gateway_sdk.example.body
}
...

With this approach I am always getting an unusable/corrupted zip file.

What I did instead is to download it with local-exec.

resource "null_resource" "extract_sdk" {
  triggers = {
    always_run = "${timestamp()}"
  }
  provisioner "local-exec" {
    command = "aws apigateway get-sdk --rest-api-id ${aws_api_gateway_stage.example.rest_api_id} --stage-name ${aws_api_gateway_stage.example.stage_name} --sdk-type javascript ./sdk.zip --profile myProfile"
  }
}

But to be honest, I don't like this approach because it's kinda "messy", and because someone already thought about the generating of SDKs with terraform and developed aws_api_gateway_sdk. And further more, if my credentials are not in the same region as the API gateway, this will not work, so i needed to include the --profile option, to specify the profile.

I would appreciate if someone would tell me where I am wrong and why the "native" terraform solution doesn't work.

英文:

I came to a conclusion/workaround.

The approach which I saw on many places didn't work for me.

...
data "aws_api_gateway_sdk" "example" {
  rest_api_id = aws_api_gateway_stage.example.rest_api_id
  stage_name  = aws_api_gateway_stage.example.stage_name
  sdk_type    = "javascript"
}

resource "local_file" "example_sdk" {
  filename = "example_sdk.zip"
  content = data.aws_api_gateway_sdk.example.body
}
...

With this approach I am always getting an unusable/corrupted zip file.

What I did instead is to download it with local-exec.

resource "null_resource" "extract_sdk" {
  triggers = {
    always_run = "${timestamp()}"
  }
  provisioner "local-exec" {
    command = "aws apigateway get-sdk --rest-api-id ${aws_api_gateway_stage.example.rest_api_id} --stage-name ${aws_api_gateway_stage.example.stage_name} --sdk-type javascript ./sdk.zip --profile myProfile"
  }
}

But to be honest, I don't like this approach because it's kinda "messy", and because someone already thought about the generating of SDKs with terraform and developed aws_api_gateway_sdk. And further more, if my credentials are not in the same region as the API gateway, this will not work, so i needed to include the --profile option, to specify the profile.

I would appreciate if someone would tell me where I am wrong and why the "native" terraform solution doesn't work.

huangapple
  • 本文由 发表于 2023年4月20日 07:25:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76059502.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定