Skip to content

Latest commit

 

History

History
138 lines (94 loc) · 10.2 KB

add_new_resource.md

File metadata and controls

138 lines (94 loc) · 10.2 KB

Adding support for a new resource

terraform-validator vs config-validator

At its core, terraform-validator is a thin layer on top of config-validator, a shared library that takes in a policy library and a set of CAI assets and reports back any violations of the specified policies.

terraform-validator consumes a Terraform plan and uses it to build CAI Assets, which then get run through config-validator. These built Assets only exist locally, in memory.

Adding a new constraint template

If an existing bundle (for example, CIS v1.1) doesn't support a check you need, please consider contributing a new constraint template to the policy-library repository.

Getting a terraform resource name from a GCP resource name

The first step in determining if a GCP resource is supported is to figure out the name of the corresponding Terraform resource. You can often do this by searching for the GCP resource name in the Terraform google provider documentation.

How to add support for a new resource

A resource is "supported" by terraform-validator if it has an entry in resource_converters.go. For example, you could search resource_converters.go for google_compute_disk to see if that resource is supported.

Adding support for a resource has four steps:

  1. Make changes to Magic Modules to add any necessary code to terraform-google-conversion.
  2. Add tests for the new resource to terraform-validator, and run them against a locally-generated copy of terraform-google-conversion.
  3. Make PRs for Magic Modules & terraform-validator with your changes. The reviewer will double-check that your code works and then merge the Magic Modules PR.
  4. Once the Magic Modules PR is merged, it will automatically update terraform-google-conversion with your changes. Update your terraform-validator PR to use the new version of terraform-google.conversion.

Each of these is discussed in more detail below.

Note: terraform-validator can only support resources that are supported by the GA terraform provider, not beta resources.

1. Magic Modules

Magic Modules uses a shared code base to generate terraform-google-conversion and the google and google-beta Terraform providers. Most Terraform resources are represented as yaml files which are grouped by product. Each product has an api.yaml file (which defines the basic API schema) and a terraform.yaml file (which defines any terraform-specific overrides.) A terraform.yaml file can specify exclude_validator: true on a resource to skip terraform-google-conversion autogeneration, or exclude_resource: true to skip autogeneration for both terraform-google-conversion and the providers.

Auto-generating terraform-google-conversion code based on yaml files is strongly preferred. If this does not automatically add an entry to resource_converters.go, you can manually add an entry to resource_converters.go.erb using the autogenerated resource converter function.

Handwritten converters

If an autogenerated converter is not possible, you can instead place a handwritten file in the magic-modules/mmv1/third_party/validator folder. Most resources will only need a resource converter with a conversion func, which should look something like:

// The type comes from https://cloud.google.com/asset-inventory/docs/supported-asset-types
const WhateverResourceAssetType string = "compute.googleapis.com/Route"

func resourceConverterWhateverResource() ResourceConverter {
	return ResourceConverter{
		AssetType: WhateverResourceAssetType,
		Convert:   GetWhateverResourceCaiObject,

	}
}

func GetWhateverResourceCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	// This function does basic conversion of a Terraform resource to a CAI Asset.
	// The asset path (name) will substitute in variables from the Terraform resource.
	// The format should match what is specified at https://cloud.google.com/asset-inventory/docs/supported-asset-types
	name, err := assetName(d, config, "//whatever.googleapis.com/projects/{{project}}/whatevers/{{name}}")
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetWhateverResourceApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: WhateverResourceAssetType,
			Resource: &AssetResource{
				Version:              "v1",  // or whatever the correct version is
				DiscoveryDocumentURI: "https://www.googleapis.com/path/to/rest/api/docs",
				DiscoveryName:        "Whatever",  // The term used to refer to this resource by the official documentation
				Data:                 obj,
			},
		}}, nil
	} else {
		return []Asset{}, err
	}
}

func GetWhateverResourceApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	obj := make(map[string]interface{})

	// copy values from the terraform resource to obj
	// return any errors encountered
	// ...

	return obj, nil
}

You will also need to add an entry to resource_converters.go.erb, which is used to generate the resource_converters.go file in terraform-google-conversion. Each entry in resource_converters.go.erb maps a terraform resource name to a function that returns a ResourceConverter - in your case, resourceConverterWhateverResource.

To generate terraform-google-conversion code locally, run the following from the root of the magic-modules repository:

make validator OUTPUT_PATH="/path/to/your/terraform-google-conversion"

You can then run make test inside your terraform-google-conversion repository to make sure those tests pass.

2. Terraform Validator tests

Now that you have a local copy of terraform-google-conversion that has been generated from Magic Modules, you need to make Terraform Validator use it for local testing. You can do this with a replace directive:

replace github.com/GoogleCloudPlatform/terraform-google-conversion => /path/to/your/terraform-google-conversion

You can now build the binary (with make build) and test it. One way to do this would be to create a test project following the instructions in the policy library user guide (but using the binary you just built.) It's easiest to use a GCPAlwaysViolatesConstraintV1 constraint for testing new resources; this is what the tests do. terraform-validator convert tfplan.json can show you what terraform-validator thinks the converted Asset looks like.

Be sure to add test cases to test/cli_test.go and test/read_test.go. The test names refer to files in testdata/templates. You will generally need to add the following files:

  • A .tf file.
  • A .tfplan.json file.
  • A .json file (representing the output of terraform-validator convert)

See Getting started for details on running tests.

Try to get your tests passing locally before proceeding. (But you can also go ahead and open PRs if you're running into issues you can't figure out how to resolve.)

3. Make PRs

Now that you have your code working locally, open PRs for Magic Modules and terraform-validator. The reviewer will make sure your code works as expected.

For the Magic Modules PR, the most important check is terraform-google-conversion-test - as long as that's passing, you're probably fine. If it is failing, go back to step 1 and try running make test for terraform-google-conversion to reproduce & fix the failure.

For terraform-validator, the CI tests will not pass at this point, because the terraform-google-conversion dependency has not yet been updated. As long as the tests are passing locally for you, it should be fine.

4. Update terraform-google-conversion dependency

After the Magic Modules PR is merged, and the terraform-google-conversion repository contains your changes, update the terraform-google-conversion dependency in your terraform-validator PR. This command will make the necessary changes:

go get github.com/GoogleCloudPlatform/terraform-google-conversion

If the CI tests are still failing after you make this change, double-check that you're able to run make test locally inside the terraform-validator repository using the updated (not replaced) dependency.