github.com/crossplane/upjet@v1.3.0/docs/adding-support-for-management-policies.md (about)

     1  <!--
     2  SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
     3  
     4  SPDX-License-Identifier: CC-BY-4.0
     5  -->
     6  
     7  # Adding Support for Management Policies and initProvider
     8  
     9  ## Regenerating a provider with Management Policies
    10  
    11  Check out the provider repo, e.g., upbound/provider-aws, and go to the project
    12  directory on your local machine.
    13  
    14  1. Generate with management policy and update crossplane-runtime dependency:
    15  
    16      ```bash
    17      # Consume the latest crossplane-tools:
    18      go get github.com/crossplane/crossplane-tools@master
    19      go mod tidy
    20      # Generate getters/setters for management policies
    21      make generate
    22      
    23      # Consume the latest crossplane-runtime:
    24      go get github.com/crossplane/crossplane-runtime@master
    25      go mod tidy
    26      ```
    27  
    28  1. Introduce a feature flag for `Management Policies`.
    29  
    30      Add the feature flag definition into the `internal/features/features.go`
    31      file.
    32  
    33      ```diff
    34      diff --git a/internal/features/features.go b/internal/features/features.go
    35      index 9c6b1fc8..de261ca4 100644
    36      --- a/internal/features/features.go
    37      +++ b/internal/features/features.go
    38      @@ -12,4 +12,9 @@ const (
    39              // External Secret Stores. See the below design for more details.
    40              // https://github.com/crossplane/crossplane/blob/390ddd/design/design-doc-external-secret-stores.md
    41              EnableAlphaExternalSecretStores feature.Flag = "EnableAlphaExternalSecretStores"
    42      +
    43      +       // EnableAlphaManagementPolicies enables alpha support for
    44      +       // Management Policies. See the below design for more details.
    45      +       // https://github.com/crossplane/crossplane/pull/3531
    46      +       EnableAlphaManagementPolicies feature.Flag = "EnableAlphaManagementPolicies"
    47       )
    48      ```
    49  
    50     Add the actual flag in `cmd/provider/main.go` file and pass the flag to the
    51     workspace store:
    52  
    53      ```diff
    54      diff --git a/cmd/provider/main.go b/cmd/provider/main.go
    55      index 669b01f9..a60df983 100644
    56      --- a/cmd/provider/main.go
    57      +++ b/cmd/provider/main.go
    58      @@ -48,6 +48,7 @@ func main() {
    59  
    60                      namespace                  = app.Flag("namespace", "Namespace used to set as default scope in default secret store config.").Default("crossplane-system").Envar("POD_NAMESPACE").String()
    61                      enableExternalSecretStores = app.Flag("enable-external-secret-stores", "Enable support for ExternalSecretStores.").Default("false").Envar("ENABLE_EXTERNAL_SECRET_STORES").Bool()
    62      +               enableManagementPolicies   = app.Flag("enable-management-policies", "Enable support for Management Policies.").Default("false").Envar("ENABLE_MANAGEMENT_POLICIES").Bool()
    63              )
    64  
    65              kingpin.MustParse(app.Parse(os.Args[1:]))
    66      @@ -122,6 +123,11 @@ func main() {
    67                      })), "cannot create default store config")
    68              }
    69                          terraform.WithSharedProviderOptions(terraform.WithNativeProviderPath(*setupConfig.NativeProviderPath), terraform.WithNativeProviderName("registry.terraform.io/"+*setupConfig.NativeProviderSource)))
    70          }
    71  
    72     +       featureFlags := &feature.Flags{}
    73             o := tjcontroller.Options{
    74                     Options: xpcontroller.Options{
    75                             Logger:                  log,
    76                             GlobalRateLimiter:       ratelimiter.NewGlobal(*maxReconcileRate),
    77                             PollInterval:            *pollInterval,
    78                             MaxConcurrentReconciles: *maxReconcileRate,
    79     -                       Features:                &feature.Flags{},
    80     +                       Features:                featureFlags,
    81                     },
    82  
    83                     Provider:       config.GetProvider(),
    84         -           WorkspaceStore: terraform.NewWorkspaceStore(log, terraform.WithDisableInit(len(*setupConfig.NativeProviderPath) != 0), terraform.WithProcessReportInterval(*pollInterval)),
    85         +           WorkspaceStore: terraform.NewWorkspaceStore(log, terraform.WithDisableInit(len(*setupConfig.NativeProviderPath) != 0), terraform.WithProcessReportInterval(*pollInterval), terraform.WithFeatures(featureFlags)),
    86                     SetupFn:        clients.SelectTerraformSetup(log, setupConfig),
    87                     EventHandler:   eventHandler,
    88             }
    89  
    90         +      if *enableManagementPolicies {
    91         +              o.Features.Enable(features.EnableAlphaManagementPolicies)
    92         +              log.Info("Alpha feature enabled", "flag", features.EnableAlphaManagementPolicies)
    93         +      }
    94         +
    95                 kingpin.FatalIfError(controller.Setup(mgr, o), "Cannot setup AWS controllers")
    96                 kingpin.FatalIfError(mgr.Start(ctrl.SetupSignalHandler()), "Cannot start controller manager")
    97          }
    98         ```
    99  
   100  > [!NOTE]
   101  > If the provider was already updated to support observe-only resources, just
   102    add the feature flag to the `workspaceStore`.
   103  
   104  1. Generate with the latest upjet and management policies:
   105  
   106      ```bash
   107      # Bump to the latest upjet
   108      go get github.com/crossplane/upjet@main
   109      go mod tidy
   110      ```
   111  
   112     Enable management policies in the generator by adding
   113     `config.WithFeaturesPackage` option:
   114  
   115      ```diff
   116      diff --git a/config/provider.go b/config/provider.go
   117      index 964883670..1c06a53e2 100644
   118      --- a/config/provider.go
   119      +++ b/config/provider.go
   120      @@ -141,6 +141,7 @@ func GetProvider() *config.Provider {
   121                    config.WithReferenceInjectors([]config.ReferenceInjector{reference.NewInjector(modulePath)}),
   122                    config.WithSkipList(skipList),
   123                    config.WithBasePackages(BasePackages),
   124      +             config.WithFeaturesPackage("internal/features"),
   125                    config.WithDefaultResourceOptions(
   126                            GroupKindOverrides(),
   127                            KindOverrides(),
   128      ```
   129  
   130     Generate:
   131  
   132      ```bash
   133      make generate
   134      ```
   135  
   136  ## Testing: Locally Running the Provider with Management Policies Enabled
   137  
   138  1. Create a fresh Kubernetes cluster.
   139  1. Apply all of the provider's CRDs with `kubectl apply -f package/crds`.
   140  1. Run the provider with `--enable-management-policies`.
   141  
   142     You can update the `run` target in the Makefile as below
   143  
   144      ```diff
   145      diff --git a/Makefile b/Makefile
   146      index d529a0d6..84411669 100644
   147      --- a/Makefile
   148      +++ b/Makefile
   149      @@ -111,7 +111,7 @@ submodules:
   150       run: go.build
   151              @$(INFO) Running Crossplane locally out-of-cluster . . .
   152              @# To see other arguments that can be provided, run the command with --help instead
   153      -       UPBOUND_CONTEXT="local" $(GO_OUT_DIR)/provider --debug
   154      +       UPBOUND_CONTEXT="local" $(GO_OUT_DIR)/provider --debug --enable-management-policies
   155      ```
   156  
   157      and run with:
   158  
   159      ```shell
   160      make run
   161      ```
   162  
   163  1. Create some resources in the provider's management console and try observing
   164  them by creating a managed resource with `managementPolicies: ["Observe"]`.
   165  
   166      For example:
   167  
   168      ```yaml
   169      apiVersion: rds.aws.upbound.io/v1beta1
   170      kind: Instance
   171      metadata:
   172        name: an-existing-dbinstance
   173      spec:
   174        managementPolicies: ["Observe"]
   175        forProvider:
   176          region: us-west-1
   177      ```
   178  
   179      You should see the managed resource is ready & synced:
   180  
   181      ```bash
   182      NAME                              READY   SYNCED   EXTERNAL-NAME                     AGE
   183      an-existing-dbinstance            True    True     an-existing-dbinstance            3m
   184      ```
   185  
   186      and the `status.atProvider` is updated with the actual state of the resource:
   187  
   188      ```bash
   189      kubectl get instance.rds.aws.upbound.io an-existing-dbinstance -o yaml
   190      ```
   191  
   192  > [!NOTE]
   193  > You need the `terraform` executable installed on your local machine.
   194  
   195  1. Create a managed resource without `LateInitialize` like
   196  `managementPolicies: ["Observe", "Create", "Update", "Delete"]` with
   197  `spec.initProvider` fields to see the provider create the resource with
   198  combining `spec.initProvider` and `spec.forProvider` fields:
   199  
   200     For example:
   201  
   202     ```yaml
   203     apiVersion: dynamodb.aws.upbound.io/v1beta1
   204     kind: Table
   205     metadata:
   206       name: example
   207     annotations:
   208       meta.upbound.io/example-id: dynamodb/v1beta1/table
   209     spec:
   210      managementPolicies: ["Observe", "Create", "Update", "Delete"]
   211      initProvider:
   212        writeCapacity: 20
   213        readCapacity: 19
   214      forProvider:
   215        region: us-west-1
   216        attribute:
   217        - name: UserId
   218          type: S
   219        - name: GameTitle
   220          type: S
   221        - name: TopScore
   222          type: "N"
   223        billingMode: PROVISIONED
   224        globalSecondaryIndex:
   225          - hashKey: GameTitle
   226            name: GameTitleIndex
   227            nonKeyAttributes:
   228              - UserId
   229            projectionType: INCLUDE
   230            rangeKey: TopScore
   231            readCapacity: 10
   232            writeCapacity: 10
   233            hashKey: UserId
   234            rangeKey: GameTitle
   235     ```
   236  
   237     You should see the managed resource is ready & synced:
   238  
   239      ```bash
   240      NAME                              READY   SYNCED   EXTERNAL-NAME                     AGE
   241      example                           True    True     example                           3m
   242      ```
   243  
   244     and the `status.atProvider` is updated with the actual state of the resource,
   245     including the `initProvider` fields:
   246  
   247      ```bash
   248      kubectl get tables.dynamodb.aws.upbound.io example  -o yaml
   249      ```
   250  
   251     As the late initialization is skipped, the `spec.forProvider` should be the
   252     same when we created the resource.
   253  
   254     In the provider console, you should see that the resource was created with
   255     the values in the `initProvider` field.