diff --git a/Makefile b/Makefile index 71c93c7..4c6b6fc 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ PROJECT_REPO := github.com/linode/$(PROJECT_NAME) export TERRAFORM_VERSION := 1.5.5 export TERRAFORM_PROVIDER_SOURCE := linode/linode -export TERRAFORM_PROVIDER_VERSION := 2.20.0 +export TERRAFORM_PROVIDER_VERSION := 2.20.1 export TERRAFORM_PROVIDER_DOWNLOAD_NAME := terraform-provider-linode export TERRAFORM_NATIVE_PROVIDER_BINARY := terraform-provider-linode_v$(TERRAFORM_PROVIDER_VERSION) export TERRAFORM_PROVIDER_REPO := https://github.com/linode/terraform-provider-linode diff --git a/cluster/images/provider-linode/Dockerfile b/cluster/images/provider-linode/Dockerfile index 84c445e..0b66de4 100644 --- a/cluster/images/provider-linode/Dockerfile +++ b/cluster/images/provider-linode/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.16.2 +FROM alpine:3.19.1 RUN apk --no-cache add ca-certificates bash ARG TARGETOS @@ -8,41 +8,6 @@ ADD "bin/${TARGETOS}_${TARGETARCH}/provider" /usr/local/bin/provider ENV USER_ID=65532 -# Setup Terraform environment - -## Provider-dependent configuration -ARG TERRAFORM_VERSION -ARG TERRAFORM_PROVIDER_SOURCE -ARG TERRAFORM_PROVIDER_VERSION -ARG TERRAFORM_PROVIDER_DOWNLOAD_NAME -ARG TERRAFORM_NATIVE_PROVIDER_BINARY -## End of - Provider-dependent configuration - -ENV PLUGIN_DIR /terraform/provider-mirror/registry.terraform.io/${TERRAFORM_PROVIDER_SOURCE}/${TERRAFORM_PROVIDER_VERSION}/${TARGETOS}_${TARGETARCH} -ENV TF_CLI_CONFIG_FILE /terraform/.terraformrc -ENV TF_FORK 0 - -RUN mkdir -p ${PLUGIN_DIR} - -ADD https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_${TARGETOS}_${TARGETARCH}.zip /tmp -ADD https://releases.hashicorp.com/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}/${TERRAFORM_PROVIDER_VERSION}/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}_${TERRAFORM_PROVIDER_VERSION}_${TARGETOS}_${TARGETARCH}.zip /tmp -ADD terraformrc.hcl ${TF_CLI_CONFIG_FILE} - -RUN unzip /tmp/terraform_${TERRAFORM_VERSION}_${TARGETOS}_${TARGETARCH}.zip -d /usr/local/bin \ - && chmod +x /usr/local/bin/terraform \ - && rm /tmp/terraform_${TERRAFORM_VERSION}_${TARGETOS}_${TARGETARCH}.zip \ - && unzip /tmp/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}_${TERRAFORM_PROVIDER_VERSION}_${TARGETOS}_${TARGETARCH}.zip -d ${PLUGIN_DIR} \ - && chmod +x ${PLUGIN_DIR}/* \ - && rm /tmp/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}_${TERRAFORM_PROVIDER_VERSION}_${TARGETOS}_${TARGETARCH}.zip \ - && chown -R ${USER_ID}:${USER_ID} /terraform -# End of - Setup Terraform environment - -# Provider controller needs these environment variable at runtime -ENV TERRAFORM_VERSION ${TERRAFORM_VERSION} -ENV TERRAFORM_PROVIDER_SOURCE ${TERRAFORM_PROVIDER_SOURCE} -ENV TERRAFORM_PROVIDER_VERSION ${TERRAFORM_PROVIDER_VERSION} -ENV TERRAFORM_NATIVE_PROVIDER_PATH ${PLUGIN_DIR}/${TERRAFORM_NATIVE_PROVIDER_BINARY} - USER ${USER_ID} EXPOSE 8080 diff --git a/cluster/images/provider-linode/Makefile b/cluster/images/provider-linode/Makefile index 82944e8..cfe2c3a 100755 --- a/cluster/images/provider-linode/Makefile +++ b/cluster/images/provider-linode/Makefile @@ -23,15 +23,9 @@ img.publish: img.build.shared: @cp Dockerfile $(IMAGE_TEMP_DIR) || $(FAIL) - @cp terraformrc.hcl $(IMAGE_TEMP_DIR) || $(FAIL) @cp -r $(OUTPUT_DIR)/bin/ $(IMAGE_TEMP_DIR)/bin || $(FAIL) @docker buildx build $(BUILD_ARGS) \ --platform $(IMAGE_PLATFORMS) \ - --build-arg TERRAFORM_VERSION=$(TERRAFORM_VERSION) \ - --build-arg TERRAFORM_PROVIDER_SOURCE=$(TERRAFORM_PROVIDER_SOURCE) \ - --build-arg TERRAFORM_PROVIDER_VERSION=$(TERRAFORM_PROVIDER_VERSION) \ - --build-arg TERRAFORM_PROVIDER_DOWNLOAD_NAME=$(TERRAFORM_PROVIDER_DOWNLOAD_NAME) \ - --build-arg TERRAFORM_NATIVE_PROVIDER_BINARY=$(TERRAFORM_NATIVE_PROVIDER_BINARY) \ -t $(IMAGE) \ $(IMAGE_TEMP_DIR) || $(FAIL) diff --git a/cluster/images/provider-linode/terraformrc.hcl b/cluster/images/provider-linode/terraformrc.hcl deleted file mode 100644 index 022203c..0000000 --- a/cluster/images/provider-linode/terraformrc.hcl +++ /dev/null @@ -1,9 +0,0 @@ -provider_installation { - filesystem_mirror { - path = "/terraform/provider-mirror" - include = ["*/*"] - } - direct { - exclude = ["*/*"] - } -} diff --git a/cmd/provider/main.go b/cmd/provider/main.go index 2cffad1..56a778a 100644 --- a/cmd/provider/main.go +++ b/cmd/provider/main.go @@ -16,9 +16,11 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/logging" "github.com/crossplane/crossplane-runtime/pkg/ratelimiter" + "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" + "github.com/crossplane/crossplane-runtime/pkg/statemetrics" + tjcontroller "github.com/crossplane/upjet/pkg/controller" - "github.com/crossplane/upjet/pkg/terraform" "gopkg.in/alecthomas/kingpin.v2" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -26,6 +28,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics" "github.com/linode/provider-linode/apis" "github.com/linode/provider-linode/apis/v1alpha1" @@ -37,24 +40,23 @@ import ( func main() { var ( - app = kingpin.New(filepath.Base(os.Args[0]), "Linode support for Crossplane.").DefaultEnvars() - debug = app.Flag("debug", "Run with debug logging.").Short('d').Bool() - syncInterval = app.Flag("sync", "Sync interval controls how often all resources will be double checked for drift.").Short('s').Default("1h").Duration() - pollInterval = app.Flag("poll", "Poll interval controls how often an individual resource should be checked for drift.").Default("10m").Duration() - leaderElection = app.Flag("leader-election", "Use leader election for the controller manager.").Short('l').Default("false").OverrideDefaultFromEnvar("LEADER_ELECTION").Bool() - maxReconcileRate = app.Flag("max-reconcile-rate", "The global maximum rate per second at which resources may be checked for drift from the desired state.").Default("100").Int() - pluginProcessTTL = app.Flag("provider-ttl", "TTL for the native plugin processes before they are replaced. Changing the default may increase memory consumption.").Default("100").Int() - + app = kingpin.New(filepath.Base(os.Args[0]), "Linode support for Crossplane.").DefaultEnvars() + debug = app.Flag("debug", "Run with debug logging.").Short('d').Bool() + syncInterval = app.Flag("sync", "Sync interval controls how often all resources will be double checked for drift.").Short('s').Default("1h").Duration() + pollInterval = app.Flag("poll", "Poll interval controls how often an individual resource should be checked for drift.").Default("10m").Duration() + leaderElection = app.Flag("leader-election", "Use leader election for the controller manager.").Short('l').Default("false").OverrideDefaultFromEnvar("LEADER_ELECTION").Bool() + maxReconcileRate = app.Flag("max-reconcile-rate", "The global maximum rate per second at which resources may be checked for drift from the desired state.").Default("100").Int() + _ = app.Flag("provider-ttl", "DEPRECATED: TTL for the native plugin processes before they are replaced. Changing the default may increase memory consumption.").Default("100").Int() + pollStateMetricInterval = app.Flag("poll-state-metric", "State metric recording interval").Default("5s").Duration() namespace = app.Flag("namespace", "Namespace used to set as default scope in default secret store config.").Default("crossplane-system").Envar("POD_NAMESPACE").String() enableExternalSecretStores = app.Flag("enable-external-secret-stores", "Enable support for ExternalSecretStores.").Default("false").Envar("ENABLE_EXTERNAL_SECRET_STORES").Bool() essTLSCertsPath = app.Flag("ess-tls-cert-dir", "Path of ESS TLS certificates.").Envar("ESS_TLS_CERTS_DIR").String() enableManagementPolicies = app.Flag("enable-management-policies", "Enable support for Management Policies.").Default("true").Envar("ENABLE_MANAGEMENT_POLICIES").Bool() ) - setupConfig := &clients.SetupConfig{} - setupConfig.TerraformVersion = app.Flag("terraform-version", "Terraform version.").Required().Envar("TERRAFORM_VERSION").String() - setupConfig.NativeProviderSource = app.Flag("terraform-provider-source", "Terraform provider source.").Required().Envar("TERRAFORM_PROVIDER_SOURCE").String() - setupConfig.NativeProviderVersion = app.Flag("terraform-provider-version", "Terraform provider version.").Required().Envar("TERRAFORM_PROVIDER_VERSION").String() - setupConfig.NativeProviderPath = app.Flag("terraform-native-provider-path", "Terraform native provider path for shared execution.").Default("").Envar("TERRAFORM_NATIVE_PROVIDER_PATH").String() + _ = app.Flag("terraform-version", "DEPRECATED: Terraform version.").Envar("TERRAFORM_VERSION").String() + _ = app.Flag("terraform-provider-source", "DEPRECATED: Terraform provider source.").Envar("TERRAFORM_PROVIDER_SOURCE").String() + _ = app.Flag("terraform-provider-version", "DEPRECATED: Terraform provider version.").Envar("TERRAFORM_PROVIDER_VERSION").String() + _ = app.Flag("terraform-native-provider-path", "DEPRECATED: Terraform native provider path for shared execution.").Default("").Envar("TERRAFORM_NATIVE_PROVIDER_PATH").String() kingpin.MustParse(app.Parse(os.Args[1:])) @@ -84,22 +86,20 @@ func main() { kingpin.FatalIfError(err, "Cannot create controller manager") kingpin.FatalIfError(apis.AddToScheme(mgr.GetScheme()), "Cannot add Linode APIs to scheme") - // if the native Terraform provider plugin's path is not configured via - // the env. variable TERRAFORM_NATIVE_PROVIDER_PATH or - // the `--terraform-native-provider-path` command-line option, - // we do not use the shared gRPC server and default to the regular - // Terraform CLI behaviour (of forking a plugin process per invocation). - // This removes some complexity for setting up development environments. - setupConfig.DefaultScheduler = terraform.NewNoOpProviderScheduler() - if len(*setupConfig.NativeProviderPath) != 0 { - setupConfig.DefaultScheduler = terraform.NewSharedProviderScheduler(log, *pluginProcessTTL, - terraform.WithSharedProviderOptions(terraform.WithNativeProviderPath(*setupConfig.NativeProviderPath), terraform.WithNativeProviderName("registry.terraform.io/"+*setupConfig.NativeProviderSource))) - } + mm := managed.NewMRMetricRecorder() + sm := statemetrics.NewMRStateMetrics() + metrics.Registry.MustRegister(mm) + metrics.Registry.MustRegister(sm) + + mo := xpcontroller.MetricOptions{ + PollStateMetricInterval: *pollStateMetricInterval, + MRMetrics: mm, + MRStateMetrics: sm, + } ctx := context.Background() provider, err := config.GetProvider(ctx, false) kingpin.FatalIfError(err, "Cannot initialize the provider configuration") - setupConfig.TerraformProvider = provider.TerraformProvider o := tjcontroller.Options{ Options: xpcontroller.Options{ Logger: log, @@ -107,9 +107,10 @@ func main() { PollInterval: *pollInterval, MaxConcurrentReconciles: *maxReconcileRate, Features: &feature.Flags{}, + MetricOptions: &mo, }, Provider: provider, - SetupFn: clients.TerraformSetupBuilder(*setupConfig.TerraformVersion, *setupConfig.NativeProviderSource, *setupConfig.NativeProviderVersion, provider.TerraformProvider, setupConfig.DefaultScheduler), + SetupFn: clients.TerraformSetupBuilder(provider.TerraformProvider), PollJitter: pollJitter, OperationTrackerStore: tjcontroller.NewOperationStore(log), } @@ -119,8 +120,6 @@ func main() { log.Info("Beta feature enabled", "flag", features.EnableBetaManagementPolicies) } - o.WorkspaceStore = terraform.NewWorkspaceStore(log, terraform.WithDisableInit(len(*setupConfig.NativeProviderPath) != 0), terraform.WithProcessReportInterval(*pollInterval), terraform.WithFeatures(o.Features)) - if *enableExternalSecretStores { o.SecretStoreConfigGVK = &v1alpha1.StoreConfigGroupVersionKind log.Info("Alpha feature enabled", "flag", features.EnableAlphaExternalSecretStores) diff --git a/internal/clients/linode.go b/internal/clients/linode.go index 7c4f8bc..f899c0e 100644 --- a/internal/clients/linode.go +++ b/internal/clients/linode.go @@ -50,16 +50,9 @@ type SetupConfig struct { // TerraformSetupBuilder builds Terraform a terraform.SetupFn function which // returns Terraform provider setup configuration -func TerraformSetupBuilder(version, providerSource, providerVersion string, tfProvider *schema.Provider, scheduler terraform.ProviderScheduler) terraform.SetupFn { +func TerraformSetupBuilder(tfProvider *schema.Provider) terraform.SetupFn { return func(ctx context.Context, client client.Client, mg resource.Managed) (terraform.Setup, error) { - ps := terraform.Setup{ - Version: version, - Requirement: terraform.ProviderRequirement{ - Source: providerSource, - Version: providerVersion, - }, - Scheduler: scheduler, - } + ps := terraform.Setup{} configRef := mg.GetProviderConfigReference() if configRef == nil {