diff --git a/Makefile b/Makefile index c692c0b..918f5b2 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # ==================================================================================== # Setup Project -PROJECT_NAME ?= provider-upjet-azapi +PROJECT_NAME ?= provider-azapi PROJECT_REPO ?= github.com/upbound/$(PROJECT_NAME) export TERRAFORM_VERSION ?= 1.5.7 @@ -14,10 +14,11 @@ export TERRAFORM_PROVIDER_SOURCE ?= Azure/azapi export TERRAFORM_PROVIDER_REPO ?= https://github.com/Azure/terraform-provider-azapi export TERRAFORM_PROVIDER_VERSION ?= 1.12.1 export TERRAFORM_PROVIDER_DOWNLOAD_NAME ?= terraform-provider-azapi -export TERRAFORM_PROVIDER_DOWNLOAD_URL_PREFIX ?= https://github.com/Azure/$(TERRAFORM_PROVIDER_DOWNLOAD_NAME)/releases/download/$(TERRAFORM_PROVIDER_VERSION) +export TERRAFORM_PROVIDER_DOWNLOAD_URL_PREFIX ?= https://github.com/Azure/$(TERRAFORM_PROVIDER_DOWNLOAD_NAME)/releases/download/v$(TERRAFORM_PROVIDER_VERSION) export TERRAFORM_NATIVE_PROVIDER_BINARY ?= terraform-provider-azapi_v1.12.1 export TERRAFORM_DOCS_PATH ?= docs/resources + PLATFORMS ?= linux_amd64 linux_arm64 # -include will silently skip missing files, which allows us @@ -56,7 +57,7 @@ GO_SUBDIRS += cmd internal apis KIND_VERSION = v0.15.0 UP_VERSION = v0.28.0 UP_CHANNEL = stable -UPTEST_VERSION = v0.5.0 +UPTEST_VERSION = v1.1.2 -include build/makelib/k8s_tools.mk # ==================================================================================== @@ -92,7 +93,7 @@ fallthrough: submodules # NOTE(hasheddan): we force image building to happen prior to xpkg build so that # we ensure image is present in daemon. -xpkg.build.provider-upjet-azapi: do.build.images +xpkg.build.provider-azapi: do.build.images # NOTE(hasheddan): we ensure up is installed prior to running platform-specific # build steps in parallel to avoid encountering an installation race condition. diff --git a/README.md b/README.md index 23d7999..e69edb4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Provider AzAPI -`provider-upjet-azapi` is a [Crossplane](https://crossplane.io/) provider that +Provider Upjet-AzAPI is a [Crossplane](https://crossplane.io/) provider that is built using [Upjet](https://github.com/crossplane/upjet) code generation tools and exposes XRM-conformant managed resources for the AzAPI API. @@ -8,9 +8,9 @@ AzAPI API. ## Getting Started Install the provider by using the following command after changing the image tag -to the [latest release](https://marketplace.upbound.io/providers/upbound/provider-upjet-azapi): +to the [latest release](https://marketplace.upbound.io/providers/upbound/provider-azapi): ``` -up ctp provider install upbound/provider-upjet-azapi:v0.1.0 +up ctp provider install upbound/provider-azapi:v0.1.0 ``` Alternatively, you can use declarative installation: @@ -19,15 +19,15 @@ cat < +// +// SPDX-License-Identifier: Apache-2.0 -// Package v1alpha1 contains the core resources of the upjet-azapi jet provider. +// Package v1alpha1 contains the core resources of the azapi jet provider. // +kubebuilder:object:generate=true -// +groupName=upjet-azapi.upbound.io +// +groupName=azapi.upbound.io // +versionName=v1alpha1 package v1alpha1 diff --git a/apis/v1alpha1/register.go b/apis/v1alpha1/register.go index c16b716..aab2df4 100644 --- a/apis/v1alpha1/register.go +++ b/apis/v1alpha1/register.go @@ -1,6 +1,6 @@ -/* -Copyright 2021 Upbound Inc. -*/ +// SPDX-FileCopyrightText: 2024 The Crossplane Authors +// +// SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -13,7 +13,7 @@ import ( // Package type metadata. const ( - Group = "upjet-azapi.upbound.io" + Group = "azapi.upbound.io" Version = "v1alpha1" ) diff --git a/apis/v1alpha1/types.go b/apis/v1alpha1/types.go index b29f8ab..b1401bc 100644 --- a/apis/v1alpha1/types.go +++ b/apis/v1alpha1/types.go @@ -1,6 +1,6 @@ -/* -Copyright 2021 Upbound Inc. -*/ +// SPDX-FileCopyrightText: 2024 The Crossplane Authors +// +// SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -22,11 +22,11 @@ type StoreConfigStatus struct { // +kubebuilder:object:root=true -// A StoreConfig configures how upjet-azapi controller should store connection details. +// A StoreConfig configures how azapi controller should store connection details. // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" // +kubebuilder:printcolumn:name="TYPE",type="string",JSONPath=".spec.type" // +kubebuilder:printcolumn:name="DEFAULT-SCOPE",type="string",JSONPath=".spec.defaultScope" -// +kubebuilder:resource:scope=Cluster,categories={crossplane,store,upjet-azapi} +// +kubebuilder:resource:scope=Cluster,categories={crossplane,store,azapi} // +kubebuilder:subresource:status type StoreConfig struct { metav1.TypeMeta `json:",inline"` diff --git a/apis/v1beta1/doc.go b/apis/v1beta1/doc.go index 83e1056..160c869 100644 --- a/apis/v1beta1/doc.go +++ b/apis/v1beta1/doc.go @@ -1,9 +1,9 @@ -/* -Copyright 2022 Upbound Inc. -*/ +// SPDX-FileCopyrightText: 2024 The Crossplane Authors +// +// SPDX-License-Identifier: Apache-2.0 -// Package v1beta1 contains the core resources of the upjet-azapi upjet provider. +// Package v1beta1 contains the core resources of the azapi upjet provider. // +kubebuilder:object:generate=true -// +groupName=upjet-azapi.upbound.io +// +groupName=azapi.upbound.io // +versionName=v1beta1 package v1beta1 diff --git a/apis/v1beta1/register.go b/apis/v1beta1/register.go index ac99e09..878cdff 100644 --- a/apis/v1beta1/register.go +++ b/apis/v1beta1/register.go @@ -13,7 +13,7 @@ import ( // Package type metadata. const ( - Group = "upjet-azapi.upbound.io" + Group = "azapi.upbound.io" Version = "v1beta1" ) diff --git a/apis/v1beta1/types.go b/apis/v1beta1/types.go index d3a7519..da5786d 100644 --- a/apis/v1beta1/types.go +++ b/apis/v1beta1/types.go @@ -14,46 +14,12 @@ import ( type ProviderConfigSpec struct { // Credentials required to authenticate to this provider. Credentials ProviderCredentials `json:"credentials"` - - // ClientID is the user-assigned managed identity's ID - // when Credentials.Source is `InjectedIdentity`. If unset and - // Credentials.Source is `InjectedIdentity`, then a system-assigned - // managed identity is used. - // +optional - ClientID *string `json:"clientID,omitempty"` - - // SubscriptionID is the Azure subscription ID to be used. - // If unset, subscription ID from Credentials will be used. - // Required if Credentials.Source is InjectedIdentity. - // +kubebuilder:validation:Optional - SubscriptionID *string `json:"subscriptionID,omitempty"` - - // TenantID is the Azure AD tenant ID to be used. - // If unset, tenant ID from Credentials will be used. - // Required if Credentials.Source is InjectedIdentity. - // +kubebuilder:validation:Optional - TenantID *string `json:"tenantID,omitempty"` - - // MSIEndpoint is the optional path to a custom endpoint for - // Managed Service Identity. - // +kubebuilder:validation:Optional - MSIEndpoint *string `json:"msiEndpoint,omitempty"` - - // The Cloud Environment which should be used. Possible values are "public", - // "usgovernment", "german", and "china". Defaults to "public". - // +kubebuilder:validation:Optional - Environment *string `json:"environment,omitempty"` - - // OIDCTokenFilePath is the optional path to a token file - // that allows to access a managed identity. - // +kubebuilder:validation:Optional - OidcTokenFilePath *string `json:"oidcTokenFilePath,omitempty"` } // ProviderCredentials required to authenticate. type ProviderCredentials struct { // Source of the provider credentials. - // +kubebuilder:validation:Enum=None;Secret;UserAssignedManagedIdentity;SystemAssignedManagedIdentity;OIDCTokenFile;Upbound;Filesystem + // +kubebuilder:validation:Enum=None;Secret;InjectedIdentity;Environment;Filesystem Source xpv1.CredentialsSource `json:"source"` xpv1.CommonCredentialSelectors `json:",inline"` @@ -66,13 +32,12 @@ type ProviderConfigStatus struct { // +kubebuilder:object:root=true -// A ProviderConfig configures the Azure provider. +// A ProviderConfig configures a AzAPI provider. // +kubebuilder:subresource:status // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" // +kubebuilder:printcolumn:name="SECRET-NAME",type="string",JSONPath=".spec.credentials.secretRef.name",priority=1 // +kubebuilder:resource:scope=Cluster -// +kubebuilder:resource:scope=Cluster,categories={crossplane,providerconfig,azure} -// +kubebuilder:storageversion +// +kubebuilder:resource:scope=Cluster,categories={crossplane,provider,azapi} type ProviderConfig struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -97,9 +62,7 @@ type ProviderConfigList struct { // +kubebuilder:printcolumn:name="CONFIG-NAME",type="string",JSONPath=".providerConfigRef.name" // +kubebuilder:printcolumn:name="RESOURCE-KIND",type="string",JSONPath=".resourceRef.kind" // +kubebuilder:printcolumn:name="RESOURCE-NAME",type="string",JSONPath=".resourceRef.name" -// Please replace `PROVIDER-NAME` with your actual provider name, like `aws`, `azure`, `gcp`, `alibaba` -// +kubebuilder:resource:scope=Cluster,categories={crossplane,providerconfig,azure} -// +kubebuilder:storageversion +// +kubebuilder:resource:scope=Cluster,categories={crossplane,provider,azapi} type ProviderConfigUsage struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/apis/v1beta1/zz_generated.deepcopy.go b/apis/v1beta1/zz_generated.deepcopy.go index 20d1650..40fe57c 100644 --- a/apis/v1beta1/zz_generated.deepcopy.go +++ b/apis/v1beta1/zz_generated.deepcopy.go @@ -75,36 +75,6 @@ func (in *ProviderConfigList) DeepCopyObject() runtime.Object { func (in *ProviderConfigSpec) DeepCopyInto(out *ProviderConfigSpec) { *out = *in in.Credentials.DeepCopyInto(&out.Credentials) - if in.ClientID != nil { - in, out := &in.ClientID, &out.ClientID - *out = new(string) - **out = **in - } - if in.SubscriptionID != nil { - in, out := &in.SubscriptionID, &out.SubscriptionID - *out = new(string) - **out = **in - } - if in.TenantID != nil { - in, out := &in.TenantID, &out.TenantID - *out = new(string) - **out = **in - } - if in.MSIEndpoint != nil { - in, out := &in.MSIEndpoint, &out.MSIEndpoint - *out = new(string) - **out = **in - } - if in.Environment != nil { - in, out := &in.Environment, &out.Environment - *out = new(string) - **out = **in - } - if in.OidcTokenFilePath != nil { - in, out := &in.OidcTokenFilePath, &out.OidcTokenFilePath - *out = new(string) - **out = **in - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigSpec. diff --git a/apis/zz_register.go b/apis/zz_register.go index 2ae90b9..aa49d5c 100755 --- a/apis/zz_register.go +++ b/apis/zz_register.go @@ -10,9 +10,9 @@ package apis import ( "k8s.io/apimachinery/pkg/runtime" - v1alpha1 "github.com/upbound/provider-upjet-azapi/apis/resource/v1alpha1" - v1alpha1apis "github.com/upbound/provider-upjet-azapi/apis/v1alpha1" - v1beta1 "github.com/upbound/provider-upjet-azapi/apis/v1beta1" + v1alpha1 "github.com/upbound/provider-azapi/apis/resources/v1alpha1" + v1alpha1apis "github.com/upbound/provider-azapi/apis/v1alpha1" + v1beta1 "github.com/upbound/provider-azapi/apis/v1beta1" ) func init() { diff --git a/cluster/images/provider-upjet-azapi/Dockerfile b/cluster/images/provider-azapi/Dockerfile similarity index 83% rename from cluster/images/provider-upjet-azapi/Dockerfile rename to cluster/images/provider-azapi/Dockerfile index 5782acb..801c8a4 100644 --- a/cluster/images/provider-upjet-azapi/Dockerfile +++ b/cluster/images/provider-azapi/Dockerfile @@ -27,15 +27,15 @@ 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 ${TERRAFORM_PROVIDER_DOWNLOAD_URL_PREFIX}/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}_${TERRAFORM_PROVIDER_VERSION}_${TARGETOS}_${TARGETARCH}.zip /tmp +ADD ${TERRAFORM_PROVIDER_DOWNLOAD_URL_PREFIX}/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}_v${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} \ + && unzip /tmp/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}_v${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 \ + && rm /tmp/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}_v${TERRAFORM_PROVIDER_VERSION}_${TARGETOS}_${TARGETARCH}.zip \ && chown -R ${USER_ID}:${USER_ID} /terraform # End of - Setup Terraform environment diff --git a/cluster/images/provider-upjet-azapi/Makefile b/cluster/images/provider-azapi/Makefile similarity index 100% rename from cluster/images/provider-upjet-azapi/Makefile rename to cluster/images/provider-azapi/Makefile diff --git a/cluster/images/provider-upjet-azapi/terraformrc.hcl b/cluster/images/provider-azapi/terraformrc.hcl similarity index 100% rename from cluster/images/provider-upjet-azapi/terraformrc.hcl rename to cluster/images/provider-azapi/terraformrc.hcl diff --git a/cluster/test/setup.sh b/cluster/test/setup.sh index 044cbd0..2425dce 100755 --- a/cluster/test/setup.sh +++ b/cluster/test/setup.sh @@ -13,7 +13,7 @@ ${KUBECTL} -n upbound-system wait --for=condition=Available deployment --all --t echo "Creating a default provider config..." cat < -// -// SPDX-License-Identifier: Apache-2.0 +/* +Copyright 2021 Upbound Inc. +*/ package main import ( "context" - "fmt" - "io" - "log" "os" "path/filepath" "time" - xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" "github.com/crossplane/crossplane-runtime/pkg/certificates" + + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/logging" @@ -23,7 +21,7 @@ import ( "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/controller/conversion" + "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" @@ -32,67 +30,39 @@ import ( "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/metrics" - "sigs.k8s.io/controller-runtime/pkg/webhook" - - "github.com/upbound/provider-upjet-azapi/apis" - "github.com/upbound/provider-upjet-azapi/apis/v1alpha1" - "github.com/upbound/provider-upjet-azapi/config" - resolverapis "github.com/upbound/provider-upjet-azapi/internal/apis" - "github.com/upbound/provider-upjet-azapi/internal/clients" - "github.com/upbound/provider-upjet-azapi/internal/controller" - "github.com/upbound/provider-upjet-azapi/internal/features" -) -const ( - webhookTLSCertDirEnvVar = "WEBHOOK_TLS_CERT_DIR" - tlsServerCertDirEnvVar = "TLS_SERVER_CERTS_DIR" - certsDirEnvVar = "CERTS_DIR" - tlsServerCertDir = "/tls/server" + "github.com/upbound/provider-azapi/apis" + "github.com/upbound/provider-azapi/apis/v1alpha1" + "github.com/upbound/provider-azapi/config" + "github.com/upbound/provider-azapi/internal/clients" + "github.com/upbound/provider-azapi/internal/controller" + "github.com/upbound/provider-azapi/internal/features" ) func main() { var ( - app = kingpin.New(filepath.Base(os.Args[0]), "Terraform based Crossplane provider for AzAPI").DefaultEnvars() - deprecationAction = func(flagName string) kingpin.Action { - return func(c *kingpin.ParseContext) error { - _, err := fmt.Fprintf(os.Stderr, "warning: Command-line flag %q is deprecated and no longer used. It will be removed in a future release. Please remove it from all of your configurations (ControllerConfigs, etc.).\n", flagName) - kingpin.FatalIfError(err, "Failed to print the deprecation notice.") - return nil - } - } + app = kingpin.New(filepath.Base(os.Args[0]), "Terraform based Crossplane provider for AzAPI").DefaultEnvars() debug = app.Flag("debug", "Run with debug logging.").Short('d').Bool() syncPeriod = app.Flag("sync", "Controller manager sync period such as 300ms, 1.5h, or 2h45m").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() pollStateMetricInterval = app.Flag("poll-state-metric", "State metric recording interval").Default("5s").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 checked for drift from the desired state.").Default("10").Int() - // now deprecated command-line arguments with the Terraform SDK-based upjet architecture - _ = app.Flag("terraform-version", "[DEPRECATED: This option is no longer used and it will be removed in a future release.] Terraform version.").Envar("TERRAFORM_VERSION").Hidden().Action(deprecationAction("terraform-version")).String() - _ = app.Flag("terraform-provider-version", "[DEPRECATED: This option is no longer used and it will be removed in a future release.] Terraform provider version.").Envar("TERRAFORM_PROVIDER_VERSION").Hidden().Action(deprecationAction("terraform-provider-version")).String() - _ = app.Flag("terraform-native-provider-path", "[DEPRECATED: This option is no longer used and it will be removed in a future release.] Terraform native provider path for shared execution.").Default("").Envar("TERRAFORM_NATIVE_PROVIDER_PATH").Hidden().Action(deprecationAction("terraform-native-provider-path")).String() - _ = app.Flag("terraform-provider-source", "[DEPRECATED: This option is no longer used and it will be removed in a future release.] Terraform provider source.").Envar("TERRAFORM_PROVIDER_SOURCE").Hidden().Action(deprecationAction("terraform-provider-source")).String() - _ = app.Flag("provider-ttl", "[DEPRECATED: This option is no longer used and it will be removed in a future release.] TTL for the native plugin processes before they are replaced. Changing the default may increase memory consumption.").Default("100").Hidden().Action(deprecationAction("provider-ttl")).Int() + 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("10").Int() + + terraformVersion = app.Flag("terraform-version", "Terraform version.").Required().Envar("TERRAFORM_VERSION").String() + providerSource = app.Flag("terraform-provider-source", "Terraform provider source.").Required().Envar("TERRAFORM_PROVIDER_SOURCE").String() + providerVersion = app.Flag("terraform-provider-version", "Terraform provider version.").Required().Envar("TERRAFORM_PROVIDER_VERSION").String() 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() - - certsDirSet = false - // we record whether the command-line option "--certs-dir" was supplied - // in the registered PreAction for the flag. - certsDir = app.Flag("certs-dir", "The directory that contains the server key and certificate.").Default(tlsServerCertDir).Envar(certsDirEnvVar).PreAction(func(_ *kingpin.ParseContext) error { - certsDirSet = true - return nil - }).String() + essTLSCertsPath = app.Flag("ess-tls-cert-dir", "Path of ESS TLS certificates.").Envar("ESS_TLS_CERTS_DIR").String() ) kingpin.MustParse(app.Parse(os.Args[1:])) - log.Default().SetOutput(io.Discard) - ctrl.SetLogger(zap.New(zap.WriteTo(io.Discard))) zl := zap.New(zap.UseDevMode(*debug)) - logr := logging.NewLogrLogger(zl.WithName("provider-upjet-azapi")) + log := logging.NewLogrLogger(zl.WithName("provider-azapi")) if *debug { // The controller-runtime runs with a no-op logger by default. It is // *very* verbose even at info level, so we only provide it a real @@ -100,53 +70,23 @@ func main() { ctrl.SetLogger(zl) } - // currently, we configure the jitter to be the 5% of the poll interval - pollJitter := time.Duration(float64(*pollInterval) * 0.05) - logr.Debug("Starting", "sync-period", syncPeriod.String(), - "poll-interval", pollInterval.String(), "poll-jitter", pollJitter, "max-reconcile-rate", *maxReconcileRate) + log.Debug("Starting", "sync-period", syncPeriod.String(), "poll-interval", pollInterval.String(), "max-reconcile-rate", *maxReconcileRate) cfg, err := ctrl.GetConfig() kingpin.FatalIfError(err, "Cannot get API server rest config") - // Get the TLS certs directory from the environment variables set by - // Crossplane if they're available. - // In older XP versions we used WEBHOOK_TLS_CERT_DIR, in newer versions - // we use TLS_SERVER_CERTS_DIR. If an explicit certs dir is not supplied - // via the command-line options, then these environment variables are used - // instead. - if !certsDirSet { - // backwards-compatibility concerns - xpCertsDir := os.Getenv(certsDirEnvVar) - if xpCertsDir == "" { - xpCertsDir = os.Getenv(tlsServerCertDirEnvVar) - } - if xpCertsDir == "" { - xpCertsDir = os.Getenv(webhookTLSCertDirEnvVar) - } - // we probably don't need this condition but just to be on the - // safe side, if we are missing any kingpin machinery details... - if xpCertsDir != "" { - *certsDir = xpCertsDir - } - } - mgr, err := ctrl.NewManager(cfg, ctrl.Options{ LeaderElection: *leaderElection, - LeaderElectionID: "crossplane-leader-election-provider-upjet-azapi", + LeaderElectionID: "crossplane-leader-election-provider-azapi", Cache: cache.Options{ SyncPeriod: syncPeriod, }, - WebhookServer: webhook.NewServer( - webhook.Options{ - CertDir: *certsDir, - }), LeaderElectionResourceLock: resourcelock.LeasesResourceLock, LeaseDuration: func() *time.Duration { d := 60 * time.Second; return &d }(), RenewDeadline: func() *time.Duration { d := 50 * time.Second; return &d }(), }) kingpin.FatalIfError(err, "Cannot create controller manager") kingpin.FatalIfError(apis.AddToScheme(mgr.GetScheme()), "Cannot add AzAPI APIs to scheme") - kingpin.FatalIfError(resolverapis.BuildScheme(apis.AddToSchemes), "Cannot register the AzAPI APIs with the API resolver's runtime scheme") metricRecorder := managed.NewMRMetricRecorder() stateMetrics := statemetrics.NewMRStateMetrics() @@ -154,12 +94,9 @@ func main() { metrics.Registry.MustRegister(metricRecorder) metrics.Registry.MustRegister(stateMetrics) - ctx := context.Background() - provider := config.GetProvider() - kingpin.FatalIfError(err, "Cannot initialize the provider configuration") o := tjcontroller.Options{ Options: xpcontroller.Options{ - Logger: logr, + Logger: log, GlobalRateLimiter: ratelimiter.NewGlobal(*maxReconcileRate), PollInterval: *pollInterval, MaxConcurrentReconciles: *maxReconcileRate, @@ -170,25 +107,21 @@ func main() { MRStateMetrics: stateMetrics, }, }, - Provider: provider, - SetupFn: clients.TerraformSetupBuilder(provider.TerraformProvider), - PollJitter: pollJitter, - OperationTrackerStore: tjcontroller.NewOperationStore(logr), - StartWebhooks: *certsDir != "", - } - - if *enableManagementPolicies { - o.Features.Enable(features.EnableBetaManagementPolicies) - logr.Info("Beta feature enabled", "flag", features.EnableBetaManagementPolicies) + Provider: config.GetProvider(), + // use the following WorkspaceStoreOption to enable the shared gRPC mode + // terraform.WithProviderRunner(terraform.NewSharedProvider(log, os.Getenv("TERRAFORM_NATIVE_PROVIDER_PATH"), terraform.WithNativeProviderArgs("-debuggable"))) + WorkspaceStore: terraform.NewWorkspaceStore(log), + SetupFn: clients.TerraformSetupBuilder(*terraformVersion, *providerSource, *providerVersion), } if *enableExternalSecretStores { + o.Features.Enable(features.EnableAlphaExternalSecretStores) o.SecretStoreConfigGVK = &v1alpha1.StoreConfigGroupVersionKind - logr.Info("Alpha feature enabled", "flag", features.EnableAlphaExternalSecretStores) + log.Info("Alpha feature enabled", "flag", features.EnableAlphaExternalSecretStores) o.ESSOptions = &tjcontroller.ESSOptions{} if *essTLSCertsPath != "" { - logr.Info("ESS TLS certificates path is set. Loading mTLS configuration.") + log.Info("ESS TLS certificates path is set. Loading mTLS configuration.") tCfg, err := certificates.LoadMTLSConfig(filepath.Join(*essTLSCertsPath, "ca.crt"), filepath.Join(*essTLSCertsPath, "tls.crt"), filepath.Join(*essTLSCertsPath, "tls.key"), false) kingpin.FatalIfError(err, "Cannot load ESS TLS config.") @@ -196,7 +129,7 @@ func main() { } // Ensure default store config exists. - kingpin.FatalIfError(resource.Ignore(kerrors.IsAlreadyExists, mgr.GetClient().Create(ctx, &v1alpha1.StoreConfig{ + kingpin.FatalIfError(resource.Ignore(kerrors.IsAlreadyExists, mgr.GetClient().Create(context.Background(), &v1alpha1.StoreConfig{ ObjectMeta: metav1.ObjectMeta{ Name: "default", }, @@ -210,7 +143,11 @@ func main() { })), "cannot create default store config") } - kingpin.FatalIfError(conversion.RegisterConversions(o.Provider), "Cannot initialize the webhook conversion registry") + if *enableManagementPolicies { + o.Features.Enable(features.EnableBetaManagementPolicies) + log.Info("Beta feature enabled", "flag", features.EnableBetaManagementPolicies) + } + kingpin.FatalIfError(controller.Setup(mgr, o), "Cannot setup AzAPI controllers") kingpin.FatalIfError(mgr.Start(ctrl.SetupSignalHandler()), "Cannot start controller manager") } diff --git a/config/provider.go b/config/provider.go index 9e43727..abbfc5d 100644 --- a/config/provider.go +++ b/config/provider.go @@ -9,13 +9,12 @@ import ( _ "embed" ujconfig "github.com/crossplane/upjet/pkg/config" - - "github.com/upbound/provider-upjet-azapi/config/resource" + "github.com/upbound/provider-azapi/config/resources" ) const ( - resourcePrefix = "upjet-azapi" - modulePath = "github.com/upbound/provider-upjet-azapi" + resourcePrefix = "azapi" + modulePath = "github.com/upbound/provider-azapi" ) //go:embed schema.json @@ -27,7 +26,7 @@ var providerMetadata string // GetProvider returns provider configuration func GetProvider() *ujconfig.Provider { pc := ujconfig.NewProvider([]byte(providerSchema), resourcePrefix, modulePath, []byte(providerMetadata), - ujconfig.WithRootGroup("upbound.io"), + ujconfig.WithRootGroup("azapi.upbound.io"), ujconfig.WithIncludeList(ExternalNameConfigured()), ujconfig.WithFeaturesPackage("internal/features"), ujconfig.WithDefaultResourceOptions( @@ -36,7 +35,7 @@ func GetProvider() *ujconfig.Provider { for _, configure := range []func(provider *ujconfig.Provider){ // add custom config functions - resource.Configure, + resources.Configure, } { configure(pc) } diff --git a/config/resource/config.go b/config/resources/config.go similarity index 56% rename from config/resource/config.go rename to config/resources/config.go index a3f22f2..7f81880 100644 --- a/config/resource/config.go +++ b/config/resources/config.go @@ -1,32 +1,28 @@ -// SPDX-FileCopyrightText: 2024 The Crossplane Authors -// -// SPDX-License-Identifier: CC0-1.0 +package resources -package resource +import "github.com/crossplane/upjet/pkg/config" -import ( - "github.com/crossplane/upjet/pkg/config" -) +const group = "resources" -// Configure configures resource group +// Configure configures individual resources by adding custom ResourceConfigurators. func Configure(p *config.Provider) { p.AddResourceConfigurator("azapi_data_plane_resource", func(r *config.Resource) { r.Kind = "DataPlaneResource" - r.ShortGroup = "resource" + r.ShortGroup = group }) - p.AddResourceConfigurator("azapi_resource", func(r *config.Resource) { r.Kind = "Resource" - r.ShortGroup = "resource" + r.ShortGroup = group }) - p.AddResourceConfigurator("azapi_resource_action", func(r *config.Resource) { r.Kind = "ResourceAction" - r.ShortGroup = "resource" + r.ShortGroup = group }) - p.AddResourceConfigurator("azapi_update_resource", func(r *config.Resource) { r.Kind = "UpdateResource" - r.ShortGroup = "resource" + r.ShortGroup = group + r.LateInitializer = config.LateInitializer{ + IgnoredFields: []string{"name", "parent_id"}, + } }) } diff --git a/examples-generated/resource/v1alpha1/dataplaneresource.yaml b/examples-generated/resources/v1alpha1/dataplaneresource.yaml similarity index 89% rename from examples-generated/resource/v1alpha1/dataplaneresource.yaml rename to examples-generated/resources/v1alpha1/dataplaneresource.yaml index fe645d6..ea55c1d 100644 --- a/examples-generated/resource/v1alpha1/dataplaneresource.yaml +++ b/examples-generated/resources/v1alpha1/dataplaneresource.yaml @@ -1,8 +1,8 @@ -apiVersion: resource.upbound.io/v1alpha1 +apiVersion: resources.azapi.upbound.io/v1alpha1 kind: DataPlaneResource metadata: annotations: - meta.upbound.io/example-id: resource/v1alpha1/dataplaneresource + meta.upbound.io/example-id: resources/v1alpha1/dataplaneresource labels: testing.upbound.io/example-name: dataset name: dataset diff --git a/examples/resource/v1alpha1/resource.yaml b/examples-generated/resources/v1alpha1/resource.yaml similarity index 87% rename from examples/resource/v1alpha1/resource.yaml rename to examples-generated/resources/v1alpha1/resource.yaml index ce35869..d9706c4 100644 --- a/examples/resource/v1alpha1/resource.yaml +++ b/examples-generated/resources/v1alpha1/resource.yaml @@ -1,8 +1,8 @@ -apiVersion: resource.upbound.io/v1alpha1 +apiVersion: resources.azapi.upbound.io/v1alpha1 kind: Resource metadata: annotations: - meta.upbound.io/example-id: resource/v1alpha1/resource + meta.upbound.io/example-id: resources/v1alpha1/resource labels: testing.upbound.io/example-name: example name: example diff --git a/examples/resource/v1alpha1/resourceaction.yaml b/examples-generated/resources/v1alpha1/resourceaction.yaml similarity index 74% rename from examples/resource/v1alpha1/resourceaction.yaml rename to examples-generated/resources/v1alpha1/resourceaction.yaml index 24e8f7d..992d522 100644 --- a/examples/resource/v1alpha1/resourceaction.yaml +++ b/examples-generated/resources/v1alpha1/resourceaction.yaml @@ -1,8 +1,8 @@ -apiVersion: resource.upbound.io/v1alpha1 +apiVersion: resources.azapi.upbound.io/v1alpha1 kind: ResourceAction metadata: annotations: - meta.upbound.io/example-id: resource/v1alpha1/resourceaction + meta.upbound.io/example-id: resources/v1alpha1/resourceaction labels: testing.upbound.io/example-name: start name: start diff --git a/examples-generated/resource/v1alpha1/updateresource.yaml b/examples-generated/resources/v1alpha1/updateresource.yaml similarity index 81% rename from examples-generated/resource/v1alpha1/updateresource.yaml rename to examples-generated/resources/v1alpha1/updateresource.yaml index ea76590..eb1ad46 100644 --- a/examples-generated/resource/v1alpha1/updateresource.yaml +++ b/examples-generated/resources/v1alpha1/updateresource.yaml @@ -1,8 +1,8 @@ -apiVersion: resource.upbound.io/v1alpha1 +apiVersion: resources.azapi.upbound.io/v1alpha1 kind: UpdateResource metadata: annotations: - meta.upbound.io/example-id: resource/v1alpha1/updateresource + meta.upbound.io/example-id: resources/v1alpha1/updateresource labels: testing.upbound.io/example-name: example name: example diff --git a/examples/install.yaml b/examples/install.yaml index 5dd2748..eb6130b 100644 --- a/examples/install.yaml +++ b/examples/install.yaml @@ -1,6 +1,6 @@ apiVersion: pkg.crossplane.io/v1 kind: Provider metadata: - name: provider-upjet-azapi + name: provider-azapi spec: - package: upbound/provider-upjet-azapi:v0.1.0 + package: upbound/provider-azapi:v0.1.0 diff --git a/examples/providerconfig/providerconfig.yaml b/examples/providerconfig/providerconfig.yaml index 9dbef9c..956db46 100644 --- a/examples/providerconfig/providerconfig.yaml +++ b/examples/providerconfig/providerconfig.yaml @@ -1,4 +1,4 @@ -apiVersion: upjet-azapi.upbound.io/v1beta1 +apiVersion: azapi.upbound.io/v1beta1 kind: ProviderConfig metadata: name: default @@ -7,5 +7,5 @@ spec: source: Secret secretRef: name: example-creds - namespace: upbound-system + namespace: crossplane-system key: credentials diff --git a/examples/providerconfig/secret.yaml.tmpl b/examples/providerconfig/secret.yaml.tmpl index 90c4ba2..6dfa5c8 100644 --- a/examples/providerconfig/secret.yaml.tmpl +++ b/examples/providerconfig/secret.yaml.tmpl @@ -2,12 +2,11 @@ apiVersion: v1 kind: Secret metadata: name: example-creds - namespace: upbound-system + namespace: crossplane-system type: Opaque stringData: credentials: | { - "clientId": "y0ur-cl1ent-1d", - "clientSecret": "y0ur-cl1ent-secr3t", - "tenantId": "y0ur-t3nat-1d" + "username": "admin", + "password": "t0ps3cr3t11" } diff --git a/examples/resource/v1alpha1/dataplaneresource.yaml b/examples/resources/v1alpha1/dataplaneresource.yaml similarity index 75% rename from examples/resource/v1alpha1/dataplaneresource.yaml rename to examples/resources/v1alpha1/dataplaneresource.yaml index fe645d6..2ecc1c2 100644 --- a/examples/resource/v1alpha1/dataplaneresource.yaml +++ b/examples/resources/v1alpha1/dataplaneresource.yaml @@ -1,8 +1,8 @@ -apiVersion: resource.upbound.io/v1alpha1 +apiVersion: resources.azapi.upbound.io/v1alpha1 kind: DataPlaneResource metadata: annotations: - meta.upbound.io/example-id: resource/v1alpha1/dataplaneresource + meta.upbound.io/example-id: resources/v1alpha1/dataplaneresource labels: testing.upbound.io/example-name: dataset name: dataset @@ -36,6 +36,6 @@ spec: } })} name: example-dataset - parentId: ${trimprefix(data.azurerm_synapse_workspace.example.connectivity_endpoints.dev, - "https://")} + parentId: exampleforazapi.dev.azuresynapse.net type: Microsoft.Synapse/workspaces/datasets@2020-12-01 +# This resource needs a valid parentId (trimprefix(data.azurerm_synapse_workspace.example.connectivity_endpoints.dev, "https://")) diff --git a/examples-generated/resource/v1alpha1/resource.yaml b/examples/resources/v1alpha1/resource.yaml similarity index 64% rename from examples-generated/resource/v1alpha1/resource.yaml rename to examples/resources/v1alpha1/resource.yaml index ce35869..30fc4a7 100644 --- a/examples-generated/resource/v1alpha1/resource.yaml +++ b/examples/resources/v1alpha1/resource.yaml @@ -1,8 +1,8 @@ -apiVersion: resource.upbound.io/v1alpha1 +apiVersion: resources.azapi.upbound.io/v1alpha1 kind: Resource metadata: annotations: - meta.upbound.io/example-id: resource/v1alpha1/resource + meta.upbound.io/example-id: resources/v1alpha1/resource labels: testing.upbound.io/example-name: example name: example @@ -17,12 +17,8 @@ spec: adminUserEnabled = true } })} - identity: - - identityIds: - - ${azurerm_user_assigned_identity.example.id} - type: SystemAssigned, UserAssigned - location: ${azurerm_resource_group.example.location} - name: registry1 + location: West Europe + name: registrytestupbound parentId: ${azurerm_resource_group.example.id} responseExportValues: - properties.loginServer @@ -30,3 +26,4 @@ spec: tags: Key: Value type: Microsoft.ContainerRegistry/registries@2020-11-01-preview +# This resource needs a valid parentId (resource group example id) diff --git a/examples-generated/resource/v1alpha1/resourceaction.yaml b/examples/resources/v1alpha1/resourceaction.yaml similarity index 61% rename from examples-generated/resource/v1alpha1/resourceaction.yaml rename to examples/resources/v1alpha1/resourceaction.yaml index 24e8f7d..034c5af 100644 --- a/examples-generated/resource/v1alpha1/resourceaction.yaml +++ b/examples/resources/v1alpha1/resourceaction.yaml @@ -1,16 +1,16 @@ -apiVersion: resource.upbound.io/v1alpha1 +apiVersion: resources.azapi.upbound.io/v1alpha1 kind: ResourceAction metadata: annotations: - meta.upbound.io/example-id: resource/v1alpha1/resourceaction + meta.upbound.io/example-id: resources/v1alpha1/resourceaction labels: testing.upbound.io/example-name: start name: start spec: forProvider: action: start - count: '${var.enabled ? 1 : 0}' resourceId: ${azurerm_spring_cloud_service.test.id} responseExportValues: - '*' type: Microsoft.AppPlatform/Spring@2022-05-01-preview +# This resource needs a valid resourceId (appplatform SpringCloudService id) diff --git a/examples/resource/v1alpha1/updateresource.yaml b/examples/resources/v1alpha1/updateresource.yaml similarity index 68% rename from examples/resource/v1alpha1/updateresource.yaml rename to examples/resources/v1alpha1/updateresource.yaml index ea76590..4d20a0b 100644 --- a/examples/resource/v1alpha1/updateresource.yaml +++ b/examples/resources/v1alpha1/updateresource.yaml @@ -1,8 +1,8 @@ -apiVersion: resource.upbound.io/v1alpha1 +apiVersion: resources.azapi.upbound.io/v1alpha1 kind: UpdateResource metadata: annotations: - meta.upbound.io/example-id: resource/v1alpha1/updateresource + meta.upbound.io/example-id: resources/v1alpha1/updateresource labels: testing.upbound.io/example-name: example name: example @@ -22,3 +22,4 @@ spec: })} resourceId: ${azurerm_lb.example.id} type: Microsoft.Network/loadBalancers@2021-03-01 +# This resource needs a valid resourceId (network LoadBalancer id) and depends on network LoadBalancerNatRule diff --git a/examples/storeconfig/vault.yaml b/examples/storeconfig/vault.yaml index e912843..0215b9c 100644 --- a/examples/storeconfig/vault.yaml +++ b/examples/storeconfig/vault.yaml @@ -1,4 +1,4 @@ -apiVersion: upjet-azapi.upbound.io/v1alpha1 +apiVersion: azapi.upbound.io/v1alpha1 kind: StoreConfig metadata: name: vault diff --git a/go.mod b/go.mod index 81e9931..5c86341 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/upbound/provider-upjet-azapi +module github.com/upbound/provider-azapi go 1.21 @@ -7,7 +7,6 @@ require ( github.com/crossplane/crossplane-runtime v1.16.0 github.com/crossplane/crossplane-tools v0.0.0-20240522174801-1ad3d4c87f21 github.com/crossplane/upjet v1.4.1 - github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0 github.com/pkg/errors v0.9.1 gopkg.in/alecthomas/kingpin.v2 v2.2.6 k8s.io/apimachinery v0.29.1 @@ -60,6 +59,7 @@ require ( github.com/hashicorp/terraform-plugin-framework v1.4.1 // indirect github.com/hashicorp/terraform-plugin-go v0.19.0 // indirect github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect + github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0 // indirect github.com/hashicorp/terraform-registry-address v0.2.2 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect diff --git a/internal/apis/scheme.go b/internal/apis/scheme.go deleted file mode 100644 index 05b2e64..0000000 --- a/internal/apis/scheme.go +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2024 The Crossplane Authors -// -// SPDX-License-Identifier: Apache-2.0 - -package apis - -import ( - "github.com/pkg/errors" - "k8s.io/apimachinery/pkg/runtime" -) - -var s = runtime.NewScheme() - -// BuildScheme builds the module's type registry using the specified -// runtime.SchemeBuilder. -func BuildScheme(sb runtime.SchemeBuilder) error { - return errors.Wrap(sb.AddToScheme(s), "failed to register the GVKs with the runtime scheme") -} diff --git a/internal/clients/azapi.go b/internal/clients/azapi.go new file mode 100644 index 0000000..e9bc894 --- /dev/null +++ b/internal/clients/azapi.go @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2024 The Crossplane Authors +// +// SPDX-License-Identifier: Apache-2.0 + +package clients + +import ( + "context" + "encoding/json" + + "github.com/crossplane/crossplane-runtime/pkg/resource" + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/crossplane/upjet/pkg/terraform" + + "github.com/upbound/provider-azapi/apis/v1beta1" +) + +const ( + // error messages + errNoProviderConfig = "no providerConfigRef provided" + errGetProviderConfig = "cannot get referenced ProviderConfig" + errTrackUsage = "cannot track ProviderConfig usage" + errExtractCredentials = "cannot extract credentials" + errUnmarshalCredentials = "cannot unmarshal azapi credentials as JSON" + keySubscriptionID = "subscriptionId" + keyClientID = "clientId" + keyClientSecret = "clientSecret" + keyTenantID = "tenantId" + keyTerraformSubscriptionID = "subscription_id" + keyTerraformClientID = "client_id" + keyTerraformClientSecret = "client_secret" + keyTerraformTenantID = "tenant_id" +) + +// TerraformSetupBuilder builds Terraform a terraform.SetupFn function which +// returns Terraform provider setup configuration +func TerraformSetupBuilder(version, providerSource, providerVersion string) 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, + }, + } + + configRef := mg.GetProviderConfigReference() + if configRef == nil { + return ps, errors.New(errNoProviderConfig) + } + pc := &v1beta1.ProviderConfig{} + if err := client.Get(ctx, types.NamespacedName{Name: configRef.Name}, pc); err != nil { + return ps, errors.Wrap(err, errGetProviderConfig) + } + + t := resource.NewProviderConfigUsageTracker(client, &v1beta1.ProviderConfigUsage{}) + if err := t.Track(ctx, mg); err != nil { + return ps, errors.Wrap(err, errTrackUsage) + } + + data, err := resource.CommonCredentialExtractor(ctx, pc.Spec.Credentials.Source, client, pc.Spec.Credentials.CommonCredentialSelectors) + if err != nil { + return ps, errors.Wrap(err, errExtractCredentials) + } + creds := map[string]string{} + if err := json.Unmarshal(data, &creds); err != nil { + return ps, errors.Wrap(err, errUnmarshalCredentials) + } + + // set provider configuration + ps.Configuration = map[string]any{} + if v, ok := creds[keySubscriptionID]; ok { + ps.Configuration[keyTerraformSubscriptionID] = v + } + if v, ok := creds[keyClientID]; ok { + ps.Configuration[keyTerraformClientID] = v + } + if v, ok := creds[keyClientSecret]; ok { + ps.Configuration[keyTerraformClientSecret] = v + } + if v, ok := creds[keyTenantID]; ok { + ps.Configuration[keyTerraformTenantID] = v + } + return ps, nil + } +} diff --git a/internal/clients/upjet-azapi.go b/internal/clients/upjet-azapi.go deleted file mode 100644 index 7940252..0000000 --- a/internal/clients/upjet-azapi.go +++ /dev/null @@ -1,183 +0,0 @@ -// SPDX-FileCopyrightText: 2024 The Crossplane Authors -// -// SPDX-License-Identifier: Apache-2.0 - -package clients - -import ( - "context" - "encoding/json" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - tfsdk "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" - xpresource "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/crossplane/upjet/pkg/terraform" - "github.com/pkg/errors" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/upbound/provider-upjet-azapi/apis/v1beta1" -) - -const ( - // error messages - errNoProviderConfig = "no providerConfigRef provided" - errGetProviderConfig = "cannot get referenced ProviderConfig" - errTrackUsage = "cannot track ProviderConfig usage" - errExtractCredentials = "cannot extract credentials" - errUnmarshalCredentials = "cannot unmarshal Azure credentials as JSON" - errTenantIDNotSet = "tenant ID must be set in ProviderConfig when credential source is InjectedIdentity, OIDCTokenFile" - errClientIDNotSet = "client ID must be set in ProviderConfig when credential source is OIDCTokenFile" - // Azure service principal credentials file JSON keys - keyAzureClientID = "clientId" - keyAzureClientSecret = "clientSecret" - keyAzureClientCert = "clientCertificate" - keyAzureClientCertPass = "clientCertificatePassword" - keyAzureTenantID = "tenantId" - // Terraform Provider configuration block keys - keyTerraformFeatures = "features" - keySkipProviderRegistration = "skip_provider_registration" - keyUseMSI = "use_msi" - keyClientID = "client_id" - keyTenantID = "tenant_id" - keyMSIEndpoint = "msi_endpoint" - keyClientSecret = "client_secret" - keyClientCert = "client_certificate" - keyClientCertPassword = "client_certificate_password" - keyEnvironment = "environment" - keyOidcTokenFilePath = "oidc_token_file_path" - keyUseOIDC = "use_oidc" - // Default OidcTokenFilePath - defaultOidcTokenFilePath = "/var/run/secrets/azure/tokens/azure-identity-token" -) - -var ( - credentialsSourceUserAssignedManagedIdentity xpv1.CredentialsSource = "UserAssignedManagedIdentity" - credentialsSourceSystemAssignedManagedIdentity xpv1.CredentialsSource = "SystemAssignedManagedIdentity" - credentialsSourceOIDCTokenFile xpv1.CredentialsSource = "OIDCTokenFile" -) - -// TerraformSetupBuilder returns Terraform setup with provider specific -// configuration like provider credentials used to connect to cloud APIs in the -// expected form of a Terraform provider. -func TerraformSetupBuilder(tfProvider *schema.Provider) terraform.SetupFn { //nolint:gocyclo - return func(ctx context.Context, client client.Client, mg xpresource.Managed) (terraform.Setup, error) { - ps := terraform.Setup{} - - configRef := mg.GetProviderConfigReference() - if configRef == nil { - return ps, errors.New(errNoProviderConfig) - } - pc := &v1beta1.ProviderConfig{} - if err := client.Get(ctx, types.NamespacedName{Name: configRef.Name}, pc); err != nil { - return ps, errors.Wrap(err, errGetProviderConfig) - } - - t := xpresource.NewProviderConfigUsageTracker(client, &v1beta1.ProviderConfigUsage{}) - if err := t.Track(ctx, mg); err != nil { - return ps, errors.Wrap(err, errTrackUsage) - } - - ps.Configuration = map[string]interface{}{ - keyTerraformFeatures: map[string]interface{}{}, - } - - var err error - switch pc.Spec.Credentials.Source { //nolint:exhaustive - case credentialsSourceSystemAssignedManagedIdentity, credentialsSourceUserAssignedManagedIdentity: - err = msiAuth(pc, &ps) - case credentialsSourceOIDCTokenFile: - err = oidcAuth(pc, &ps) - default: - err = spAuth(ctx, pc, &ps, client) - } - if err != nil { - return terraform.Setup{}, errors.Wrap(err, "failed to prepare terraform.Setup") - } - - return ps, errors.Wrap(configureNoForkAzureClient(ctx, &ps, *tfProvider), "failed to configure the no-fork Azure client") - } -} - -func configureNoForkAzureClient(ctx context.Context, ps *terraform.Setup, p schema.Provider) error { - diag := p.Configure(context.WithoutCancel(ctx), &tfsdk.ResourceConfig{ - Config: ps.Configuration, - }) - if diag != nil && diag.HasError() { - return errors.Errorf("failed to configure the provider: %v", diag) - } - ps.Meta = p.Meta() - return nil -} - -func spAuth(ctx context.Context, pc *v1beta1.ProviderConfig, ps *terraform.Setup, client client.Client) error { - data, err := xpresource.CommonCredentialExtractor(ctx, pc.Spec.Credentials.Source, client, pc.Spec.Credentials.CommonCredentialSelectors) - if err != nil { - return errors.Wrap(err, errExtractCredentials) - } - data = []byte(strings.TrimSpace(string(data))) - azureCreds := map[string]string{} - if err := json.Unmarshal(data, &azureCreds); err != nil { - return errors.Wrap(err, errUnmarshalCredentials) - } - // set credentials configuration - ps.Configuration[keyTenantID] = azureCreds[keyAzureTenantID] - ps.Configuration[keyClientID] = azureCreds[keyAzureClientID] - ps.Configuration[keyClientSecret] = azureCreds[keyAzureClientSecret] - if clientCert, ok := azureCreds[keyAzureClientCert]; ok { - ps.Configuration[keyClientCert] = clientCert - if clientCertPass, passwordOk := azureCreds[keyAzureClientCertPass]; passwordOk { - ps.Configuration[keyClientCertPassword] = clientCertPass - } - } - if pc.Spec.TenantID != nil { - ps.Configuration[keyTenantID] = *pc.Spec.TenantID - } - if pc.Spec.ClientID != nil { - ps.Configuration[keyClientID] = *pc.Spec.ClientID - } - if pc.Spec.Environment != nil { - ps.Configuration[keyEnvironment] = *pc.Spec.Environment - } - return nil -} - -func msiAuth(pc *v1beta1.ProviderConfig, ps *terraform.Setup) error { - if pc.Spec.TenantID == nil || len(*pc.Spec.TenantID) == 0 { - return errors.New(errTenantIDNotSet) - } - ps.Configuration[keyTenantID] = *pc.Spec.TenantID - ps.Configuration[keyUseMSI] = "true" - if pc.Spec.MSIEndpoint != nil { - ps.Configuration[keyMSIEndpoint] = *pc.Spec.MSIEndpoint - } - if pc.Spec.ClientID != nil { - ps.Configuration[keyClientID] = *pc.Spec.ClientID - } - if pc.Spec.Environment != nil { - ps.Configuration[keyEnvironment] = *pc.Spec.Environment - } - return nil -} - -func oidcAuth(pc *v1beta1.ProviderConfig, ps *terraform.Setup) error { - if pc.Spec.TenantID == nil || len(*pc.Spec.TenantID) == 0 { - return errors.New(errTenantIDNotSet) - } - if pc.Spec.ClientID == nil || len(*pc.Spec.ClientID) == 0 { - return errors.New(errClientIDNotSet) - } - // OIDC Token File Path defaults to a projected-volume path mounted in the pod running in the AKS cluster, when workload identity is enabled on the pod. - ps.Configuration[keyOidcTokenFilePath] = defaultOidcTokenFilePath - if pc.Spec.OidcTokenFilePath != nil { - ps.Configuration[keyOidcTokenFilePath] = *pc.Spec.OidcTokenFilePath - } - ps.Configuration[keyTenantID] = *pc.Spec.TenantID - ps.Configuration[keyClientID] = *pc.Spec.ClientID - ps.Configuration[keyUseOIDC] = "true" - return nil - -} diff --git a/internal/controller/providerconfig/config.go b/internal/controller/providerconfig/config.go index b49669e..dbf64b6 100644 --- a/internal/controller/providerconfig/config.go +++ b/internal/controller/providerconfig/config.go @@ -11,7 +11,7 @@ import ( "github.com/crossplane/upjet/pkg/controller" ctrl "sigs.k8s.io/controller-runtime" - "github.com/upbound/provider-upjet-azapi/apis/v1beta1" + "github.com/upbound/provider-azapi/apis/v1beta1" ) // Setup adds a controller that reconciles ProviderConfigs by accounting for diff --git a/internal/controller/resource/dataplaneresource/zz_controller.go b/internal/controller/resources/dataplaneresource/zz_controller.go similarity index 96% rename from internal/controller/resource/dataplaneresource/zz_controller.go rename to internal/controller/resources/dataplaneresource/zz_controller.go index 69bfc4c..2f8ef5c 100755 --- a/internal/controller/resource/dataplaneresource/zz_controller.go +++ b/internal/controller/resources/dataplaneresource/zz_controller.go @@ -21,8 +21,8 @@ import ( "github.com/pkg/errors" ctrl "sigs.k8s.io/controller-runtime" - v1alpha1 "github.com/upbound/provider-upjet-azapi/apis/resource/v1alpha1" - features "github.com/upbound/provider-upjet-azapi/internal/features" + v1alpha1 "github.com/upbound/provider-azapi/apis/resources/v1alpha1" + features "github.com/upbound/provider-azapi/internal/features" ) // Setup adds a controller that reconciles DataPlaneResource managed resources. diff --git a/internal/controller/resource/resource/zz_controller.go b/internal/controller/resources/resource/zz_controller.go similarity index 96% rename from internal/controller/resource/resource/zz_controller.go rename to internal/controller/resources/resource/zz_controller.go index 002ac18..3b7bc13 100755 --- a/internal/controller/resource/resource/zz_controller.go +++ b/internal/controller/resources/resource/zz_controller.go @@ -21,8 +21,8 @@ import ( "github.com/pkg/errors" ctrl "sigs.k8s.io/controller-runtime" - v1alpha1 "github.com/upbound/provider-upjet-azapi/apis/resource/v1alpha1" - features "github.com/upbound/provider-upjet-azapi/internal/features" + v1alpha1 "github.com/upbound/provider-azapi/apis/resources/v1alpha1" + features "github.com/upbound/provider-azapi/internal/features" ) // Setup adds a controller that reconciles Resource managed resources. diff --git a/internal/controller/resource/resourceaction/zz_controller.go b/internal/controller/resources/resourceaction/zz_controller.go similarity index 96% rename from internal/controller/resource/resourceaction/zz_controller.go rename to internal/controller/resources/resourceaction/zz_controller.go index 1207426..5a07e6f 100755 --- a/internal/controller/resource/resourceaction/zz_controller.go +++ b/internal/controller/resources/resourceaction/zz_controller.go @@ -21,8 +21,8 @@ import ( "github.com/pkg/errors" ctrl "sigs.k8s.io/controller-runtime" - v1alpha1 "github.com/upbound/provider-upjet-azapi/apis/resource/v1alpha1" - features "github.com/upbound/provider-upjet-azapi/internal/features" + v1alpha1 "github.com/upbound/provider-azapi/apis/resources/v1alpha1" + features "github.com/upbound/provider-azapi/internal/features" ) // Setup adds a controller that reconciles ResourceAction managed resources. diff --git a/internal/controller/resource/updateresource/zz_controller.go b/internal/controller/resources/updateresource/zz_controller.go similarity index 96% rename from internal/controller/resource/updateresource/zz_controller.go rename to internal/controller/resources/updateresource/zz_controller.go index 94662e2..adf7d28 100755 --- a/internal/controller/resource/updateresource/zz_controller.go +++ b/internal/controller/resources/updateresource/zz_controller.go @@ -21,8 +21,8 @@ import ( "github.com/pkg/errors" ctrl "sigs.k8s.io/controller-runtime" - v1alpha1 "github.com/upbound/provider-upjet-azapi/apis/resource/v1alpha1" - features "github.com/upbound/provider-upjet-azapi/internal/features" + v1alpha1 "github.com/upbound/provider-azapi/apis/resources/v1alpha1" + features "github.com/upbound/provider-azapi/internal/features" ) // Setup adds a controller that reconciles UpdateResource managed resources. diff --git a/internal/controller/zz_setup.go b/internal/controller/zz_setup.go index 4479c1d..8b5b9c2 100755 --- a/internal/controller/zz_setup.go +++ b/internal/controller/zz_setup.go @@ -9,11 +9,11 @@ import ( "github.com/crossplane/upjet/pkg/controller" - providerconfig "github.com/upbound/provider-upjet-azapi/internal/controller/providerconfig" - dataplaneresource "github.com/upbound/provider-upjet-azapi/internal/controller/resource/dataplaneresource" - resource "github.com/upbound/provider-upjet-azapi/internal/controller/resource/resource" - resourceaction "github.com/upbound/provider-upjet-azapi/internal/controller/resource/resourceaction" - updateresource "github.com/upbound/provider-upjet-azapi/internal/controller/resource/updateresource" + providerconfig "github.com/upbound/provider-azapi/internal/controller/providerconfig" + dataplaneresource "github.com/upbound/provider-azapi/internal/controller/resources/dataplaneresource" + resource "github.com/upbound/provider-azapi/internal/controller/resources/resource" + resourceaction "github.com/upbound/provider-azapi/internal/controller/resources/resourceaction" + updateresource "github.com/upbound/provider-azapi/internal/controller/resources/updateresource" ) // Setup creates all controllers with the supplied logger and adds them to diff --git a/package/crds/upjet-azapi.upbound.io_providerconfigs.yaml b/package/crds/azapi.upbound.io_providerconfigs.yaml similarity index 76% rename from package/crds/upjet-azapi.upbound.io_providerconfigs.yaml rename to package/crds/azapi.upbound.io_providerconfigs.yaml index 3054647..2341abd 100644 --- a/package/crds/upjet-azapi.upbound.io_providerconfigs.yaml +++ b/package/crds/azapi.upbound.io_providerconfigs.yaml @@ -4,14 +4,14 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.14.0 - name: providerconfigs.upjet-azapi.upbound.io + name: providerconfigs.azapi.upbound.io spec: - group: upjet-azapi.upbound.io + group: azapi.upbound.io names: categories: - crossplane - - providerconfig - - azure + - provider + - azapi kind: ProviderConfig listKind: ProviderConfigList plural: providerconfigs @@ -29,7 +29,7 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: A ProviderConfig configures the Azure provider. + description: A ProviderConfig configures a AzAPI provider. properties: apiVersion: description: |- @@ -51,13 +51,6 @@ spec: spec: description: A ProviderConfigSpec defines the desired state of a ProviderConfig. properties: - clientID: - description: |- - ClientID is the user-assigned managed identity's ID - when Credentials.Source is `InjectedIdentity`. If unset and - Credentials.Source is `InjectedIdentity`, then a system-assigned - managed identity is used. - type: string credentials: description: Credentials required to authenticate to this provider. properties: @@ -107,42 +100,13 @@ spec: enum: - None - Secret - - UserAssignedManagedIdentity - - SystemAssignedManagedIdentity - - OIDCTokenFile - - Upbound + - InjectedIdentity + - Environment - Filesystem type: string required: - source type: object - environment: - description: |- - The Cloud Environment which should be used. Possible values are "public", - "usgovernment", "german", and "china". Defaults to "public". - type: string - msiEndpoint: - description: |- - MSIEndpoint is the optional path to a custom endpoint for - Managed Service Identity. - type: string - oidcTokenFilePath: - description: |- - OIDCTokenFilePath is the optional path to a token file - that allows to access a managed identity. - type: string - subscriptionID: - description: |- - SubscriptionID is the Azure subscription ID to be used. - If unset, subscription ID from Credentials will be used. - Required if Credentials.Source is InjectedIdentity. - type: string - tenantID: - description: |- - TenantID is the Azure AD tenant ID to be used. - If unset, tenant ID from Credentials will be used. - Required if Credentials.Source is InjectedIdentity. - type: string required: - credentials type: object diff --git a/package/crds/upjet-azapi.upbound.io_providerconfigusages.yaml b/package/crds/azapi.upbound.io_providerconfigusages.yaml similarity index 92% rename from package/crds/upjet-azapi.upbound.io_providerconfigusages.yaml rename to package/crds/azapi.upbound.io_providerconfigusages.yaml index 5f10ef2..5f78720 100644 --- a/package/crds/upjet-azapi.upbound.io_providerconfigusages.yaml +++ b/package/crds/azapi.upbound.io_providerconfigusages.yaml @@ -4,14 +4,14 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.14.0 - name: providerconfigusages.upjet-azapi.upbound.io + name: providerconfigusages.azapi.upbound.io spec: - group: upjet-azapi.upbound.io + group: azapi.upbound.io names: categories: - crossplane - - providerconfig - - azure + - provider + - azapi kind: ProviderConfigUsage listKind: ProviderConfigUsageList plural: providerconfigusages @@ -34,9 +34,7 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - A ProviderConfigUsage indicates that a resource is using a ProviderConfig. - Please replace `PROVIDER-NAME` with your actual provider name, like `aws`, `azure`, `gcp`, `alibaba` + description: A ProviderConfigUsage indicates that a resource is using a ProviderConfig. properties: apiVersion: description: |- diff --git a/package/crds/upjet-azapi.upbound.io_storeconfigs.yaml b/package/crds/azapi.upbound.io_storeconfigs.yaml similarity index 97% rename from package/crds/upjet-azapi.upbound.io_storeconfigs.yaml rename to package/crds/azapi.upbound.io_storeconfigs.yaml index f0dd839..4e1ddcb 100644 --- a/package/crds/upjet-azapi.upbound.io_storeconfigs.yaml +++ b/package/crds/azapi.upbound.io_storeconfigs.yaml @@ -4,14 +4,14 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.14.0 - name: storeconfigs.upjet-azapi.upbound.io + name: storeconfigs.azapi.upbound.io spec: - group: upjet-azapi.upbound.io + group: azapi.upbound.io names: categories: - crossplane - store - - upjet-azapi + - azapi kind: StoreConfig listKind: StoreConfigList plural: storeconfigs @@ -31,8 +31,8 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: A StoreConfig configures how upjet-azapi controller should store - connection details. + description: A StoreConfig configures how azapi controller should store connection + details. properties: apiVersion: description: |- diff --git a/package/crds/resource.upbound.io_dataplaneresources.yaml b/package/crds/resources.azapi.upbound.io_dataplaneresources.yaml similarity index 99% rename from package/crds/resource.upbound.io_dataplaneresources.yaml rename to package/crds/resources.azapi.upbound.io_dataplaneresources.yaml index 8c4ec5d..bcd4106 100644 --- a/package/crds/resource.upbound.io_dataplaneresources.yaml +++ b/package/crds/resources.azapi.upbound.io_dataplaneresources.yaml @@ -4,14 +4,14 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.14.0 - name: dataplaneresources.resource.upbound.io + name: dataplaneresources.resources.azapi.upbound.io spec: - group: resource.upbound.io + group: resources.azapi.upbound.io names: categories: - crossplane - managed - - upjet-azapi + - azapi kind: DataPlaneResource listKind: DataPlaneResourceList plural: dataplaneresources diff --git a/package/crds/resource.upbound.io_resourceactions.yaml b/package/crds/resources.azapi.upbound.io_resourceactions.yaml similarity index 99% rename from package/crds/resource.upbound.io_resourceactions.yaml rename to package/crds/resources.azapi.upbound.io_resourceactions.yaml index 0f57106..73b7179 100644 --- a/package/crds/resource.upbound.io_resourceactions.yaml +++ b/package/crds/resources.azapi.upbound.io_resourceactions.yaml @@ -4,14 +4,14 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.14.0 - name: resourceactions.resource.upbound.io + name: resourceactions.resources.azapi.upbound.io spec: - group: resource.upbound.io + group: resources.azapi.upbound.io names: categories: - crossplane - managed - - upjet-azapi + - azapi kind: ResourceAction listKind: ResourceActionList plural: resourceactions diff --git a/package/crds/resource.upbound.io_resources.yaml b/package/crds/resources.azapi.upbound.io_resources.yaml similarity index 99% rename from package/crds/resource.upbound.io_resources.yaml rename to package/crds/resources.azapi.upbound.io_resources.yaml index 987a037..a543cff 100644 --- a/package/crds/resource.upbound.io_resources.yaml +++ b/package/crds/resources.azapi.upbound.io_resources.yaml @@ -4,14 +4,14 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.14.0 - name: resources.resource.upbound.io + name: resources.resources.azapi.upbound.io spec: - group: resource.upbound.io + group: resources.azapi.upbound.io names: categories: - crossplane - managed - - upjet-azapi + - azapi kind: Resource listKind: ResourceList plural: resources diff --git a/package/crds/resource.upbound.io_updateresources.yaml b/package/crds/resources.azapi.upbound.io_updateresources.yaml similarity index 99% rename from package/crds/resource.upbound.io_updateresources.yaml rename to package/crds/resources.azapi.upbound.io_updateresources.yaml index f6f9ad1..9e02043 100644 --- a/package/crds/resource.upbound.io_updateresources.yaml +++ b/package/crds/resources.azapi.upbound.io_updateresources.yaml @@ -4,14 +4,14 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.14.0 - name: updateresources.resource.upbound.io + name: updateresources.resources.azapi.upbound.io spec: - group: resource.upbound.io + group: resources.azapi.upbound.io names: categories: - crossplane - managed - - upjet-azapi + - azapi kind: UpdateResource listKind: UpdateResourceList plural: updateresources diff --git a/package/crossplane.yaml b/package/crossplane.yaml index f1ed227..4e18a94 100644 --- a/package/crossplane.yaml +++ b/package/crossplane.yaml @@ -1,4 +1,4 @@ apiVersion: meta.pkg.crossplane.io/v1 kind: Provider metadata: - name: provider-upjet-azapi + name: provider-azapi