terranix icon indicating copy to clipboard operation
terranix copied to clipboard

Use Terraform attributes

Open eamsden opened this issue 4 years ago • 7 comments

Currently there appears to be no way to use attributes of a terraform resource or data source from terranix. For sophisticated setups, e.g. for setting up an integrated AWS S3 and CloudFront with an OAI, this is essential.

I propose the following and am willing to make a PR if the maintainer approves in principle:

[ ] * Add layers of submodule structure to the data and resource option, so that they always exist with a resource/data-source type and identifier. The submodule would include as a config underneath the identifier attribute a function which takes an attribute name, strips away config.resource or config.data, and the resource type from the Nix module path, and writes a Terraform string interpolation.

Thus it becomes possible to write e.g.

with config; resource."aws_s3_bucket"."my_s3_bucket".attribute "arn" and receive the string output from Nix "${my_s3_bucket.arn}" (note that we are escaping Nix's string interpolation because we want the "${...}" form to appear in the JSON output for consumption by Terraform.)

This could be extended to easily support input/output/local variables once a proof-of-concept was evaluated.

eamsden avatar Sep 22 '20 11:09 eamsden

Very good idea. Feel free to create a pull request, I'm happy to merge it. I had similar ideas when I initialized the terranix project, but I couldn't come up with a proper solution.

mrVanDalo avatar Sep 23 '20 19:09 mrVanDalo

@eamsden may you proved config.nix with what you are trying to achieve?

dzmitry-lahoda avatar Jan 28 '23 22:01 dzmitry-lahoda

I believe one may do in terranix all one can do in terraform. But he will use strings, instead of referencing attr sets via atrribute names. So errors will not be detected by nix evaluator/instantiate, but by terraform validate.

What can be improved if package during build will run check with validate.

dzmitry-lahoda avatar Jan 28 '23 23:01 dzmitry-lahoda

if this item about making lazy attr sets which allow to refer attributes via nix, not via strings, then it would be great.

dzmitry-lahoda avatar Jan 29 '23 00:01 dzmitry-lahoda

just applied this well

{ config, lib, options, specialArgs }:
let var = options.variable;
in rec {
  variable = {
    PROJECT = {
      type = "string";
      description = "Google Cloud Project ID";
    };
    IMAGE_FILE = {
      type = "string";
      description = "NixOS image file for Google Cloud";
    };
  };

  resource = {
    local_file.test_import = {
      filename = "test_import.txt";
      content = "Hello";
    };
    google_service_account = {
      default = {
        account_id = "\${ var.PROJECT }-account";
        project = "\${ var.PROJECT }";
      };
    };

    time_sleep = {
      google_service_account-default = {
        depends_on = [ "resource.google_service_account.default" ];
        create_duration = "30s";
      };
    };

    google_compute_address = { static = { name = "ipv4-address"; }; };

    google_storage_bucket = {
      gce-image = {
        name = "\${var.PROJECT}-gce-image";
        location = "US";
        force_destroy = true;
      };
    };

    google_compute_image = {
      gce-image = {
        name = "gce-image";
        raw_disk = {
          source = "\${resource.google_storage_bucket_object.gce-image-gz.self_link}";
        };
      };

    };

    google_storage_bucket_object = {
      gce-image-gz = {
        name = "\${var.PROJECT}-image.tar.gz";
        source = "\${var.IMAGE_FILE}";
        bucket = "\${resource.google_storage_bucket.gce-image.name}";
      };
    };

  };

  provider = {
    google = {
      region = "us-central1";
      zone = "us-central1-c";
      project = "\${ var.PROJECT }";
    };
  };
}


        gce = nixos-generators.nixosGenerate {
          system = "x86_64-linux";
          modules = [ ./modules/gce.nix ];

          format = "gce";
        };

        apply = pkgs.writeShellApplication {
          name = "apply";
          text = ''            
            TF_VAR_IMAGE_FILE="$(find ${self.packages.x86_64-linux.gce} -type f)"
            TF_VAR_PROJECT="composablefi"
            export TF_VAR_IMAGE_FILE
            export TF_VAR_PROJECT
            cd terraform/layers/05
            if [[ -e config.tf.json ]]; then rm -f config.tf.json; fi
            cp ${self.packages.${system}.tfconfig} config.tf.json \
              && ${pkgs.terraform}/bin/terraform init \
              && ${pkgs.terraform}/bin/terraform apply -auto-approve
          '';
        };

see that bucket = "\${resource.google_storage_bucket.gce-image.name}"; is well working reference

dzmitry-lahoda avatar Jan 29 '23 00:01 dzmitry-lahoda

I would prefer that somehow (sure, I do not know magic, yet), I can type like:

     bucket = state.resource.google_storage_bucket.gce-image.name;

may be it could read the nix of module, and provide recursive state with all attributes if finds.

and during module evaluation (when tf json is generated), it may somehow detect such attr set references, and replace with stings.

dzmitry-lahoda avatar Jan 29 '23 00:01 dzmitry-lahoda

Initial implementation (one that uses config.<attr> as a function) has been merged in #59. The state. attribute seems a bit harder to do, I'll consider it in the future :)

mdarocha avatar Jun 14 '23 20:06 mdarocha