|
| 1 | +# How to Unify API Mappers and Fuzzers for Existing Resources |
| 2 | + |
| 3 | +This guide provides a step-by-step process for refactoring and unifying the API, mapper, and fuzzer for existing resources. The goal is to leverage the auto-generation tools as much as possible, reduce manual code, and ensure consistency across different API versions. |
| 4 | + |
| 5 | +## 1. Start with `generate.sh` |
| 6 | + |
| 7 | +The unification process begins with the `generate.sh` script located in the `apis/<service>/<version>` directory (e.g., `apis/dataproc/v1alpha1/`). This script is the source of truth for the auto-generation process. |
| 8 | + |
| 9 | +### Verify and Correct `generate.sh` |
| 10 | + |
| 11 | +1. **Check for Existence**: Ensure a `generate.sh` script exists for each version of the service you are unifying (e.g., `v1alpha1`, `v1beta1`). If it doesn't exist, create one using a known good example like `apis/bigquerybiglake/v1alpha1/generate.sh` as a template. |
| 12 | + |
| 13 | +2. **Verify Resource List**: Open the `generate.sh` script and check the `--resource` flags in the `go run . generate-types` command. This list should accurately reflect all the resources defined within that API version directory. Add or remove `--resource` flags as necessary. |
| 14 | + |
| 15 | +3. **Check Output Directory**: Ensure the final `go run ... goimports` command is writing to the correct controller directory, which should be `pkg/controller/direct/<service>/`. |
| 16 | + |
| 17 | +A corrected `generate.sh` for a `v1alpha1` service might look like this: |
| 18 | + |
| 19 | +```bash |
| 20 | +#!/bin/bash |
| 21 | +# ... (license header) |
| 22 | +set -o errexit |
| 23 | +set -o nounset |
| 24 | +set -o pipefail |
| 25 | + |
| 26 | +REPO_ROOT="$(git rev-parse --show-toplevel)" |
| 27 | +cd ${REPO_ROOT}/dev/tools/controllerbuilder |
| 28 | + |
| 29 | +go run . generate-types \ |
| 30 | + --service google.cloud.myservice.v1 \ |
| 31 | + --api-version "myservice.cnrm.cloud.google.com/v1alpha1" \ |
| 32 | + --resource MyResourceOne:ResourceOne \ |
| 33 | + --resource MyResourceTwo:ResourceTwo |
| 34 | + |
| 35 | +go run . generate-mapper \ |
| 36 | + --service google.cloud.myservice.v1 \ |
| 37 | + --api-version "myservice.cnrm.cloud.google.com/v1alpha1" |
| 38 | + |
| 39 | +cd ${REPO_ROOT} |
| 40 | +dev/tasks/generate-crds |
| 41 | + |
| 42 | +go run -mod=readonly golang.org/x/tools/cmd/goimports@latest -w pkg/controller/direct/myservice/ |
| 43 | +``` |
| 44 | + |
| 45 | +## 2. Rely on Auto-Generated Mappers |
| 46 | + |
| 47 | +The primary goal of unification is to remove as much manual mapping logic as possible and rely on the code generated by `generate-mapper`. |
| 48 | + |
| 49 | +1. **Run `generate.sh`**: Execute the script for each API version you are unifying. This will create or update the `types.mapper.go` file in the controller directory (`pkg/controller/direct/<service>/`). |
| 50 | + |
| 51 | +2. **Identify Manual Mappers**: Look for manually written mapper functions in files like `<resource>_mapper.go`. These are the functions you want to replace. |
| 52 | + |
| 53 | +3. **Replace with Generated Functions**: Update your controller and fuzzer code to call the new, auto-generated functions from `types.mapper.go` instead of the old manual ones. |
| 54 | + |
| 55 | +4. **Delete Old Code**: Once all references to the manual mapper functions have been removed, you can delete the `<resource>_mapper.go` file or remove the now-unused functions from it. |
| 56 | + |
| 57 | +## 3. Handling Multi-Version Services |
| 58 | + |
| 59 | +When a service has multiple API versions (e.g., `v1alpha1` and `v1beta1`), the mapper needs to handle potential differences in the resource schemas. |
| 60 | + |
| 61 | +### Use the `--multiversion` Flag |
| 62 | + |
| 63 | +For the newer version of the API (e.g., `v1beta1`), add the `--multiversion` flag to the `generate-mapper` command in its `generate.sh` script. |
| 64 | + |
| 65 | +Example for `apis/myservice/v1beta1/generate.sh`: |
| 66 | +```bash |
| 67 | +# ... |
| 68 | +go run . generate-mapper \ |
| 69 | + --multiversion \ |
| 70 | + --service google.cloud.myservice.v1 \ |
| 71 | + --api-version "myservice.cnrm.cloud.google.com/v1beta1" |
| 72 | +# ... |
| 73 | +``` |
| 74 | + |
| 75 | +When this flag is used, the generator will create version-specific mapping functions to avoid conflicts. The function names will have the version injected into their name, for example: |
| 76 | +* `MyResourceSpec_v1beta1_ToProto(...)` |
| 77 | +* `MyResourceSpec_v1alpha1_FromProto(...)` |
| 78 | + |
| 79 | +**Note**: If the `--multiversion` flag is *not* used (typically for services with only one version), the generated function names will **not** have a version in them (e.g., `MyResourceSpec_ToProto(...)`). |
| 80 | + |
| 81 | +## 4. Update Fuzzer and Controller Code |
| 82 | + |
| 83 | +After re-generating the mappers, you must update your fuzzer and controller files to use the correct function names. |
| 84 | + |
| 85 | +1. **Ensure Fuzzer File Exists**: Ensure each CRD being unified has a corresponding `_fuzzer.go` file. If one does not exist, create it by copying from a similar resource and adapting it. |
| 86 | + |
| 87 | +2. **Update `*_fuzzer.go`**: Go to `pkg/controller/direct/<service>/<resource>_fuzzer.go` and update the `fuzztesting.NewKRMTypedFuzzer` call to use the new generated function names. |
| 88 | + |
| 89 | + * If you used `--multiversion`, the names will be version-specific. |
| 90 | + * If you did not use `--multiversion`, the names will be generic. |
| 91 | + |
| 92 | + **Example with `--multiversion`:** |
| 93 | + ```go |
| 94 | + // For the v1beta1 fuzzer |
| 95 | + f := fuzztesting.NewKRMTypedFuzzer(&pb.MyResource{}, |
| 96 | + MyResourceSpec_v1beta1_FromProto, MyResourceSpec_v1beta1_ToProto, |
| 97 | + MyResourceObservedState_v1beta1_FromProto, MyResourceObservedState_v1beta1_ToProto, |
| 98 | + ) |
| 99 | + ``` |
| 100 | + |
| 101 | + **Example without `--multiversion`:** |
| 102 | + ```go |
| 103 | + f := fuzztesting.NewKRMTypedFuzzer(&pb.MyResource{}, |
| 104 | + MyResourceSpec_FromProto, MyResourceSpec_ToProto, |
| 105 | + MyResourceObservedState_FromProto, MyResourceObservedState_ToProto, |
| 106 | + ) |
| 107 | + ``` |
| 108 | + |
| 109 | +3. **Update `*_controller.go`**: Search for any remaining usages of the old function names in your controller logic (`pkg/controller/direct/<service>/<resource>_controller.go`) and update them to point to the new generated functions. |
| 110 | + |
| 111 | +By following these steps, you can systematically unify the API definitions, mappers, and fuzzers for existing resources, leading to a more maintainable and consistent codebase. |
0 commit comments