├── extensions ├── icons │ ├── icon.svg │ └── USAGE.md ├── readme │ ├── readme.md │ └── USAGE.md └── release-notes │ ├── release_notes.md │ └── USAGE.md ├── internal ├── controller │ ├── doc.go │ ├── cluster │ │ ├── zz_setup.go │ │ ├── providerconfig │ │ │ └── config.go │ │ └── null │ │ │ └── resource │ │ │ └── zz_controller.go │ └── namespaced │ │ ├── zz_setup.go │ │ ├── providerconfig │ │ └── config.go │ │ └── null │ │ └── resource │ │ └── zz_controller.go ├── version │ └── version.go ├── features │ └── features.go └── clients │ └── template.go ├── examples ├── cluster │ ├── providerconfig │ │ ├── .gitignore │ │ ├── secret.yaml.tmpl │ │ └── providerconfig.yaml │ └── null │ │ └── resource.yaml ├── namespaced │ ├── providerconfig │ │ ├── .gitignore │ │ ├── secret.yaml.tmpl │ │ ├── clusterproviderconfig.yaml │ │ └── providerconfig.yaml │ └── null │ │ └── resource.yaml └── install.yaml ├── .gitmodules ├── CODE_OF_CONDUCT.md ├── renovate.json ├── hack ├── boilerplate.go.txt └── prepare.sh ├── .gitignore ├── package ├── crossplane.yaml └── crds │ ├── template.m.crossplane.io_providerconfigusages.yaml │ ├── template.crossplane.io_providerconfigusages.yaml │ ├── template.crossplane.io_providerconfigs.yaml │ ├── template.m.crossplane.io_providerconfigs.yaml │ ├── template.m.crossplane.io_clusterproviderconfigs.yaml │ └── null.template.m.crossplane.io_resources.yaml ├── apis ├── cluster │ ├── v1alpha1 │ │ ├── doc.go │ │ └── register.go │ ├── v1beta1 │ │ ├── doc.go │ │ ├── zz_generated.pculist.go │ │ ├── zz_generated.pc.go │ │ ├── zz_generated.pcu.go │ │ ├── register.go │ │ ├── types.go │ │ └── zz_generated.deepcopy.go │ ├── null │ │ └── v1alpha1 │ │ │ ├── zz_generated.conversion_hubs.go │ │ │ ├── zz_generated.managedlist.go │ │ │ ├── zz_groupversion_info.go │ │ │ ├── zz_generated.managed.go │ │ │ ├── zz_resource_terraformed.go │ │ │ ├── zz_resource_types.go │ │ │ └── zz_generated.deepcopy.go │ └── zz_register.go ├── namespaced │ ├── v1alpha1 │ │ ├── doc.go │ │ └── register.go │ ├── v1beta1 │ │ ├── doc.go │ │ ├── zz_generated.pculist.go │ │ ├── zz_generated.pcu.go │ │ ├── zz_generated.pc.go │ │ ├── register.go │ │ ├── types.go │ │ └── zz_generated.deepcopy.go │ ├── null │ │ └── v1alpha1 │ │ │ ├── zz_generated.conversion_hubs.go │ │ │ ├── zz_generated.managedlist.go │ │ │ ├── zz_groupversion_info.go │ │ │ ├── zz_generated.managed.go │ │ │ ├── zz_resource_terraformed.go │ │ │ ├── zz_resource_types.go │ │ │ └── zz_generated.deepcopy.go │ └── zz_register.go └── generate.go ├── cluster ├── images │ └── upjet-provider-template │ │ ├── terraformrc.hcl │ │ ├── Makefile │ │ └── Dockerfile └── test │ └── setup.sh ├── config ├── cluster │ └── null │ │ └── config.go ├── namespaced │ └── null │ │ └── config.go ├── external_name.go ├── provider-metadata.yaml ├── provider.go └── schema.json ├── OWNERS.md ├── .github ├── workflows │ ├── tag.yaml │ ├── backport.yml │ ├── publish-provider-package.yml │ ├── e2e.yaml │ └── ci.yml ├── PULL_REQUEST_TEMPLATE.md └── renovate.json5 ├── cmd └── generator │ └── main.go ├── examples-generated ├── cluster │ └── null │ │ └── v1alpha1 │ │ └── resource.yaml └── namespaced │ └── null │ └── v1alpha1 │ └── resource.yaml ├── CODEOWNERS ├── README.md ├── scripts └── version_diff.py ├── .golangci.yml └── go.mod /extensions/icons/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extensions/readme/readme.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extensions/release-notes/release_notes.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /internal/controller/doc.go: -------------------------------------------------------------------------------- 1 | package controller 2 | -------------------------------------------------------------------------------- /examples/cluster/providerconfig/.gitignore: -------------------------------------------------------------------------------- 1 | secret.yaml 2 | -------------------------------------------------------------------------------- /examples/namespaced/providerconfig/.gitignore: -------------------------------------------------------------------------------- 1 | secret.yaml 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "build"] 2 | path = build 3 | url = https://github.com/crossplane/build 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | 3 | Upjet is under [the Apache 2.0 license](LICENSE) with [notice](NOTICE). -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.cache 2 | /.work 3 | /_output 4 | cover.out 5 | /vendor 6 | /.vendor-new 7 | .DS_Store 8 | 9 | # ignore IDE folders 10 | .vscode/ 11 | .idea/ 12 | -------------------------------------------------------------------------------- /package/crossplane.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: meta.pkg.crossplane.io/v1 2 | kind: Provider 3 | metadata: 4 | name: upjet-provider-template 5 | spec: 6 | capabilities: 7 | - SafeStart 8 | -------------------------------------------------------------------------------- /examples/install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: pkg.crossplane.io/v1 2 | kind: Provider 3 | metadata: 4 | name: upjet-provider-template 5 | spec: 6 | package: xpkg.crossplane.io/crossplane/upjet-provider-template:v0.1.0 7 | -------------------------------------------------------------------------------- /apis/cluster/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | // Package v1alpha1 contains the core resources of the template jet provider. 2 | // +kubebuilder:object:generate=true 3 | // +groupName=template.crossplane.io 4 | // +versionName=v1alpha1 5 | package v1alpha1 6 | -------------------------------------------------------------------------------- /apis/cluster/v1beta1/doc.go: -------------------------------------------------------------------------------- 1 | // Package v1beta1 contains the core resources of the template upjet provider. 2 | // +kubebuilder:object:generate=true 3 | // +groupName=template.crossplane.io 4 | // +versionName=v1beta1 5 | package v1beta1 6 | -------------------------------------------------------------------------------- /apis/namespaced/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | // Package v1alpha1 contains the core resources of the template jet provider. 2 | // +kubebuilder:object:generate=true 3 | // +groupName=template.m.crossplane.io 4 | // +versionName=v1alpha1 5 | package v1alpha1 6 | -------------------------------------------------------------------------------- /apis/namespaced/v1beta1/doc.go: -------------------------------------------------------------------------------- 1 | // Package v1beta1 contains the core resources of the template upjet provider. 2 | // +kubebuilder:object:generate=true 3 | // +groupName=template.m.crossplane.io 4 | // +versionName=v1beta1 5 | package v1beta1 6 | -------------------------------------------------------------------------------- /cluster/images/upjet-provider-template/terraformrc.hcl: -------------------------------------------------------------------------------- 1 | provider_installation { 2 | filesystem_mirror { 3 | path = "/terraform/provider-mirror" 4 | include = ["*/*"] 5 | } 6 | direct { 7 | exclude = ["*/*"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /extensions/icons/USAGE.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | Replace `icon.svg` with an image of your choice to be used as an icon for this Provider. 4 | 5 | The image must: 6 | 7 | - be named `icon.svg` 8 | - have square dimensions 9 | - be a valid [SVG](https://www.svgviewer.dev/) -------------------------------------------------------------------------------- /extensions/release-notes/USAGE.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | Replace `release_notes.md` with a Markdown file of your choice to be used as release notes for your Provider. 4 | 5 | The file must: 6 | 7 | - be named `release_notes.md` 8 | - contain valid Markdown content 9 | -------------------------------------------------------------------------------- /examples/cluster/null/resource.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: null.template.crossplane.io/v1alpha1 2 | kind: Resource 3 | metadata: 4 | name: example 5 | spec: 6 | forProvider: 7 | triggers: 8 | example-trigger: example-value 9 | providerConfigRef: 10 | name: default -------------------------------------------------------------------------------- /examples/cluster/providerconfig/secret.yaml.tmpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: example-creds 5 | namespace: crossplane-system 6 | type: Opaque 7 | stringData: 8 | credentials: | 9 | { 10 | "username": "admin", 11 | "password": "t0ps3cr3t11" 12 | } 13 | -------------------------------------------------------------------------------- /examples/namespaced/providerconfig/secret.yaml.tmpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: example-creds 5 | namespace: crossplane-system 6 | type: Opaque 7 | stringData: 8 | credentials: | 9 | { 10 | "username": "admin", 11 | "password": "t0ps3cr3t11" 12 | } 13 | -------------------------------------------------------------------------------- /examples/namespaced/null/resource.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: null.template.m.crossplane.io/v1alpha1 2 | kind: Resource 3 | metadata: 4 | name: example-ns 5 | spec: 6 | forProvider: 7 | triggers: 8 | example-trigger: example-value-2 9 | providerConfigRef: 10 | kind: ClusterProviderConfig 11 | name: default -------------------------------------------------------------------------------- /examples/cluster/providerconfig/providerconfig.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: template.crossplane.io/v1beta1 2 | kind: ProviderConfig 3 | metadata: 4 | name: default 5 | spec: 6 | credentials: 7 | source: Secret 8 | secretRef: 9 | name: example-creds 10 | namespace: crossplane-system 11 | key: credentials 12 | -------------------------------------------------------------------------------- /extensions/readme/USAGE.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | Replace `readme.md` with a Markdown file of your choice to be used as a detailed README for this Provider. 4 | 5 | By default, the top-level README.md in the GitHub repo may be used. 6 | 7 | The file must: 8 | 9 | - be named `readme.md` 10 | - contain valid Markdown content 11 | -------------------------------------------------------------------------------- /examples/namespaced/providerconfig/clusterproviderconfig.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: template.m.crossplane.io/v1beta1 2 | kind: ClusterProviderConfig 3 | metadata: 4 | name: default 5 | spec: 6 | credentials: 7 | source: Secret 8 | secretRef: 9 | name: example-creds 10 | namespace: crossplane-system 11 | key: credentials 12 | -------------------------------------------------------------------------------- /apis/cluster/null/v1alpha1/zz_generated.conversion_hubs.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | package v1alpha1 8 | 9 | // Hub marks this type as a conversion hub. 10 | func (tr *Resource) Hub() {} 11 | -------------------------------------------------------------------------------- /apis/namespaced/null/v1alpha1/zz_generated.conversion_hubs.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | package v1alpha1 8 | 9 | // Hub marks this type as a conversion hub. 10 | func (tr *Resource) Hub() {} 11 | -------------------------------------------------------------------------------- /examples/namespaced/providerconfig/providerconfig.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: template.m.crossplane.io/v1beta1 2 | kind: ProviderConfig 3 | metadata: 4 | name: default 5 | namespace: crossplane-system 6 | spec: 7 | credentials: 8 | source: Secret 9 | secretRef: 10 | name: example-creds 11 | namespace: crossplane-system 12 | key: credentials 13 | -------------------------------------------------------------------------------- /config/cluster/null/config.go: -------------------------------------------------------------------------------- 1 | package null 2 | 3 | import ( 4 | ujconfig "github.com/crossplane/upjet/v2/pkg/config" 5 | ) 6 | 7 | // Configure configures the null group 8 | func Configure(p *ujconfig.Provider) { 9 | p.AddResourceConfigurator("null_resource", func(r *ujconfig.Resource) { 10 | r.Kind = "Resource" 11 | // And other overrides. 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /config/namespaced/null/config.go: -------------------------------------------------------------------------------- 1 | package null 2 | 3 | import ( 4 | ujconfig "github.com/crossplane/upjet/v2/pkg/config" 5 | ) 6 | 7 | // Configure configures the null group 8 | func Configure(p *ujconfig.Provider) { 9 | p.AddResourceConfigurator("null_resource", func(r *ujconfig.Resource) { 10 | r.Kind = "Resource" 11 | // And other overrides. 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /internal/version/version.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Package version contains the version of this provider 6 | package version 7 | 8 | // Version will be overridden with the current version at build time using the -X linker flag 9 | var Version = "0.0.0" 10 | -------------------------------------------------------------------------------- /OWNERS.md: -------------------------------------------------------------------------------- 1 | # OWNERS 2 | 3 | This page lists all maintainers for **this** repository. Each repository in the [Crossplane Contrib 4 | organization](https://github.com/crossplane-contrib/) will list their repository maintainers in their own 5 | `OWNERS.md` file. 6 | 7 | 8 | ## Maintainers 9 | 10 | * Full Name ([githubusername](https://github.com/githubusername)) 11 | 12 | See [CODEOWNERS](./CODEOWNERS) for automatic PR assignment. 13 | -------------------------------------------------------------------------------- /.github/workflows/tag.yaml: -------------------------------------------------------------------------------- 1 | name: Tag 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: 'Release version (e.g. v0.1.0)' 8 | required: true 9 | message: 10 | description: 'Tag message' 11 | required: true 12 | 13 | jobs: 14 | tag: 15 | uses: crossplane-contrib/provider-workflows/.github/workflows/tag.yml@main 16 | with: 17 | version: ${{ github.event.inputs.version }} 18 | message: ${{ github.event.inputs.message }} 19 | -------------------------------------------------------------------------------- /apis/cluster/null/v1alpha1/zz_generated.managedlist.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by angryjet. DO NOT EDIT. 6 | 7 | package v1alpha1 8 | 9 | import resource "github.com/crossplane/crossplane-runtime/v2/pkg/resource" 10 | 11 | // GetItems of this ResourceList. 12 | func (l *ResourceList) GetItems() []resource.Managed { 13 | items := make([]resource.Managed, len(l.Items)) 14 | for i := range l.Items { 15 | items[i] = &l.Items[i] 16 | } 17 | return items 18 | } 19 | -------------------------------------------------------------------------------- /apis/namespaced/null/v1alpha1/zz_generated.managedlist.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by angryjet. DO NOT EDIT. 6 | 7 | package v1alpha1 8 | 9 | import resource "github.com/crossplane/crossplane-runtime/v2/pkg/resource" 10 | 11 | // GetItems of this ResourceList. 12 | func (l *ResourceList) GetItems() []resource.Managed { 13 | items := make([]resource.Managed, len(l.Items)) 14 | for i := range l.Items { 15 | items[i] = &l.Items[i] 16 | } 17 | return items 18 | } 19 | -------------------------------------------------------------------------------- /apis/cluster/v1beta1/zz_generated.pculist.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by angryjet. DO NOT EDIT. 6 | 7 | package v1beta1 8 | 9 | import resource "github.com/crossplane/crossplane-runtime/v2/pkg/resource" 10 | 11 | // GetItems of this ProviderConfigUsageList. 12 | func (p *ProviderConfigUsageList) GetItems() []resource.ProviderConfigUsage { 13 | items := make([]resource.ProviderConfigUsage, len(p.Items)) 14 | for i := range p.Items { 15 | items[i] = &p.Items[i] 16 | } 17 | return items 18 | } 19 | -------------------------------------------------------------------------------- /apis/namespaced/v1beta1/zz_generated.pculist.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by angryjet. DO NOT EDIT. 6 | 7 | package v1beta1 8 | 9 | import resource "github.com/crossplane/crossplane-runtime/v2/pkg/resource" 10 | 11 | // GetItems of this ProviderConfigUsageList. 12 | func (p *ProviderConfigUsageList) GetItems() []resource.ProviderConfigUsage { 13 | items := make([]resource.ProviderConfigUsage, len(p.Items)) 14 | for i := range p.Items { 15 | items[i] = &p.Items[i] 16 | } 17 | return items 18 | } 19 | -------------------------------------------------------------------------------- /cmd/generator/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/crossplane/upjet/v2/pkg/pipeline" 9 | 10 | "github.com/crossplane/upjet-provider-template/config" 11 | ) 12 | 13 | func main() { 14 | if len(os.Args) < 2 || os.Args[1] == "" { 15 | panic("root directory is required to be given as argument") 16 | } 17 | rootDir := os.Args[1] 18 | absRootDir, err := filepath.Abs(rootDir) 19 | if err != nil { 20 | panic(fmt.Sprintf("cannot calculate the absolute path with %s", rootDir)) 21 | } 22 | pipeline.Run(config.GetProvider(), config.GetProviderNamespaced(), absRootDir) 23 | } 24 | -------------------------------------------------------------------------------- /apis/cluster/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ( 4 | "k8s.io/apimachinery/pkg/runtime/schema" 5 | "sigs.k8s.io/controller-runtime/pkg/scheme" 6 | ) 7 | 8 | // Package type metadata. 9 | const ( 10 | Group = "template.crossplane.io" 11 | Version = "v1alpha1" 12 | ) 13 | 14 | var ( 15 | // SchemeGroupVersion is group version used to register these objects 16 | SchemeGroupVersion = schema.GroupVersion{Group: Group, Version: Version} 17 | 18 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 19 | SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} 20 | ) 21 | 22 | func init() {} 23 | -------------------------------------------------------------------------------- /apis/namespaced/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ( 4 | "k8s.io/apimachinery/pkg/runtime/schema" 5 | "sigs.k8s.io/controller-runtime/pkg/scheme" 6 | ) 7 | 8 | // Package type metadata. 9 | const ( 10 | Group = "template.m.crossplane.io" 11 | Version = "v1alpha1" 12 | ) 13 | 14 | var ( 15 | // SchemeGroupVersion is group version used to register these objects 16 | SchemeGroupVersion = schema.GroupVersion{Group: Group, Version: Version} 17 | 18 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 19 | SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} 20 | ) 21 | 22 | func init() {} 23 | -------------------------------------------------------------------------------- /examples-generated/cluster/null/v1alpha1/resource.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: null.template.crossplane.io/v1alpha1 2 | kind: Resource 3 | metadata: 4 | annotations: 5 | meta.upbound.io/example-id: null/v1alpha1/resource 6 | labels: 7 | testing.upbound.io/example-name: cluster 8 | name: cluster 9 | spec: 10 | forProvider: 11 | connection: 12 | - host: ${element(aws_instance.cluster[*].public_ip, 0)} 13 | provisioner: 14 | remote-exec: 15 | - inline: 16 | - |- 17 | bootstrap-cluster.sh ${join(" ", 18 | aws_instance.cluster[*].private_ip)} 19 | triggers: 20 | cluster_instance_ids: ${join(",", aws_instance.cluster[*].id)} 21 | -------------------------------------------------------------------------------- /examples-generated/namespaced/null/v1alpha1/resource.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: null.template.m.crossplane.io/v1alpha1 2 | kind: Resource 3 | metadata: 4 | annotations: 5 | meta.upbound.io/example-id: null/v1alpha1/resource 6 | labels: 7 | testing.upbound.io/example-name: cluster 8 | name: cluster 9 | namespace: crossplane-system 10 | spec: 11 | forProvider: 12 | connection: 13 | - host: ${element(aws_instance.cluster[*].public_ip, 0)} 14 | provisioner: 15 | remote-exec: 16 | - inline: 17 | - |- 18 | bootstrap-cluster.sh ${join(" ", 19 | aws_instance.cluster[*].private_ip)} 20 | triggers: 21 | cluster_instance_ids: ${join(",", aws_instance.cluster[*].id)} 22 | -------------------------------------------------------------------------------- /internal/features/features.go: -------------------------------------------------------------------------------- 1 | package features 2 | 3 | import ( 4 | xpfeature "github.com/crossplane/crossplane-runtime/v2/pkg/feature" 5 | ) 6 | 7 | // Feature flags. 8 | const ( 9 | // EnableAlphaExternalSecretStores enables alpha support for 10 | // External Secret Stores. See the below design for more details. 11 | // https://github.com/crossplane/crossplane/blob/390ddd/design/design-doc-external-secret-stores.md 12 | EnableAlphaExternalSecretStores xpfeature.Flag = "EnableAlphaExternalSecretStores" 13 | 14 | // EnableBetaManagementPolicies enables beta support for 15 | // Management Policies. See the below design for more details. 16 | // https://github.com/crossplane/crossplane/pull/3531 17 | EnableBetaManagementPolicies xpfeature.Flag = xpfeature.EnableBetaManagementPolicies 18 | ) 19 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This file controls automatic PR reviewer assignment. See the following docs: 2 | # 3 | # * https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 4 | # * https://docs.github.com/en/organizations/organizing-members-into-teams/managing-code-review-settings-for-your-team 5 | # 6 | # The goal of this file is for most PRs to automatically and fairly have one 7 | # maintainer set as PR reviewers. All maintainers have permission to approve 8 | # and merge PRs. All PRs must be approved by at least one maintainer before being merged. 9 | # 10 | # Where possible, prefer explicitly specifying a maintainer who is a subject 11 | # matter expert for a particular part of the codebase rather than using a group. 12 | # 13 | # See also OWNERS.md for governance details 14 | 15 | # Fallback owners 16 | #* @username 17 | -------------------------------------------------------------------------------- /apis/cluster/v1beta1/zz_generated.pc.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by angryjet. DO NOT EDIT. 6 | 7 | package v1beta1 8 | 9 | import xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" 10 | 11 | // GetCondition of this ProviderConfig. 12 | func (p *ProviderConfig) GetCondition(ct xpv1.ConditionType) xpv1.Condition { 13 | return p.Status.GetCondition(ct) 14 | } 15 | 16 | // GetUsers of this ProviderConfig. 17 | func (p *ProviderConfig) GetUsers() int64 { 18 | return p.Status.Users 19 | } 20 | 21 | // SetConditions of this ProviderConfig. 22 | func (p *ProviderConfig) SetConditions(c ...xpv1.Condition) { 23 | p.Status.SetConditions(c...) 24 | } 25 | 26 | // SetUsers of this ProviderConfig. 27 | func (p *ProviderConfig) SetUsers(i int64) { 28 | p.Status.Users = i 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/backport.yml: -------------------------------------------------------------------------------- 1 | name: Backport 2 | 3 | on: 4 | # NOTE(negz): This is a risky target, but we run this action only when and if 5 | # a PR is closed, then filter down to specifically merged PRs. We also don't 6 | # invoke any scripts, etc from within the repo. I believe the fact that we'll 7 | # be able to review PRs before this runs makes this fairly safe. 8 | # https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ 9 | pull_request_target: 10 | types: [closed] 11 | 12 | jobs: 13 | open-pr: 14 | runs-on: ubuntu-latest 15 | if: github.event.pull_request.merged 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 19 | with: 20 | fetch-depth: 0 21 | 22 | - name: Open Backport PR 23 | uses: korthout/backport-action@c656f5d5851037b2b38fb5db2691a03fa229e3b2 # v4.0.1 24 | -------------------------------------------------------------------------------- /.github/workflows/publish-provider-package.yml: -------------------------------------------------------------------------------- 1 | name: Publish Provider Package 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: "Version string to use while publishing the package (e.g. v1.0.0-alpha.1)" 8 | default: '' 9 | required: false 10 | go-version: 11 | description: 'Go version to use if building needs to be done' 12 | default: '1.24' 13 | required: false 14 | 15 | jobs: 16 | publish-provider-package: 17 | uses: crossplane-contrib/provider-workflows/.github/workflows/publish-provider.yml@main 18 | with: 19 | repository: provider-template 20 | version: ${{ github.event.inputs.version }} 21 | go-version: ${{ github.event.inputs.go-version }} 22 | cleanup-disk: true 23 | secrets: 24 | GHCR_PAT: ${{ secrets.GITHUB_TOKEN }} 25 | XPKG_MIRROR_TOKEN: ${{ secrets.XPKG_MIRROR_TOKEN }} 26 | XPKG_MIRROR_ACCESS_ID: ${{ secrets.XPKG_MIRROR_ACCESS_ID }} 27 | -------------------------------------------------------------------------------- /apis/cluster/v1beta1/zz_generated.pcu.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by angryjet. DO NOT EDIT. 6 | 7 | package v1beta1 8 | 9 | import xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" 10 | 11 | // GetProviderConfigReference of this ProviderConfigUsage. 12 | func (p *ProviderConfigUsage) GetProviderConfigReference() xpv1.Reference { 13 | return p.ProviderConfigReference 14 | } 15 | 16 | // GetResourceReference of this ProviderConfigUsage. 17 | func (p *ProviderConfigUsage) GetResourceReference() xpv1.TypedReference { 18 | return p.ResourceReference 19 | } 20 | 21 | // SetProviderConfigReference of this ProviderConfigUsage. 22 | func (p *ProviderConfigUsage) SetProviderConfigReference(r xpv1.Reference) { 23 | p.ProviderConfigReference = r 24 | } 25 | 26 | // SetResourceReference of this ProviderConfigUsage. 27 | func (p *ProviderConfigUsage) SetResourceReference(r xpv1.TypedReference) { 28 | p.ResourceReference = r 29 | } 30 | -------------------------------------------------------------------------------- /apis/cluster/null/v1alpha1/zz_groupversion_info.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | // +kubebuilder:object:generate=true 8 | // +groupName=null.template.crossplane.io 9 | // +versionName=v1alpha1 10 | package v1alpha1 11 | 12 | import ( 13 | "k8s.io/apimachinery/pkg/runtime/schema" 14 | "sigs.k8s.io/controller-runtime/pkg/scheme" 15 | ) 16 | 17 | // Package type metadata. 18 | const ( 19 | CRDGroup = "null.template.crossplane.io" 20 | CRDVersion = "v1alpha1" 21 | ) 22 | 23 | var ( 24 | // CRDGroupVersion is the API Group Version used to register the objects 25 | CRDGroupVersion = schema.GroupVersion{Group: CRDGroup, Version: CRDVersion} 26 | 27 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 28 | SchemeBuilder = &scheme.Builder{GroupVersion: CRDGroupVersion} 29 | 30 | // AddToScheme adds the types in this group-version to the given scheme. 31 | AddToScheme = SchemeBuilder.AddToScheme 32 | ) 33 | -------------------------------------------------------------------------------- /apis/namespaced/null/v1alpha1/zz_groupversion_info.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | // +kubebuilder:object:generate=true 8 | // +groupName=null.template.m.crossplane.io 9 | // +versionName=v1alpha1 10 | package v1alpha1 11 | 12 | import ( 13 | "k8s.io/apimachinery/pkg/runtime/schema" 14 | "sigs.k8s.io/controller-runtime/pkg/scheme" 15 | ) 16 | 17 | // Package type metadata. 18 | const ( 19 | CRDGroup = "null.template.m.crossplane.io" 20 | CRDVersion = "v1alpha1" 21 | ) 22 | 23 | var ( 24 | // CRDGroupVersion is the API Group Version used to register the objects 25 | CRDGroupVersion = schema.GroupVersion{Group: CRDGroup, Version: CRDVersion} 26 | 27 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 28 | SchemeBuilder = &scheme.Builder{GroupVersion: CRDGroupVersion} 29 | 30 | // AddToScheme adds the types in this group-version to the given scheme. 31 | AddToScheme = SchemeBuilder.AddToScheme 32 | ) 33 | -------------------------------------------------------------------------------- /apis/namespaced/v1beta1/zz_generated.pcu.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by angryjet. DO NOT EDIT. 6 | 7 | package v1beta1 8 | 9 | import xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" 10 | 11 | // GetProviderConfigReference of this ProviderConfigUsage. 12 | func (p *ProviderConfigUsage) GetProviderConfigReference() xpv1.ProviderConfigReference { 13 | return p.ProviderConfigReference 14 | } 15 | 16 | // GetResourceReference of this ProviderConfigUsage. 17 | func (p *ProviderConfigUsage) GetResourceReference() xpv1.TypedReference { 18 | return p.ResourceReference 19 | } 20 | 21 | // SetProviderConfigReference of this ProviderConfigUsage. 22 | func (p *ProviderConfigUsage) SetProviderConfigReference(r xpv1.ProviderConfigReference) { 23 | p.ProviderConfigReference = r 24 | } 25 | 26 | // SetResourceReference of this ProviderConfigUsage. 27 | func (p *ProviderConfigUsage) SetResourceReference(r xpv1.TypedReference) { 28 | p.ResourceReference = r 29 | } 30 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ### Description of your changes 10 | 11 | 20 | Fixes # 21 | 22 | I have: 23 | 24 | - [ ] Read and followed Crossplane's [contribution process]. 25 | - [ ] Run `make reviewable test` to ensure this PR is ready for review. 26 | 27 | ### How has this code been tested 28 | 29 | 34 | 35 | [contribution process]: https://git.io/fj2m9 36 | -------------------------------------------------------------------------------- /apis/cluster/zz_register.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | // Package cluster contains Kubernetes API for the provider. 8 | package cluster 9 | 10 | import ( 11 | "k8s.io/apimachinery/pkg/runtime" 12 | 13 | v1alpha1 "github.com/crossplane/upjet-provider-template/apis/cluster/null/v1alpha1" 14 | v1alpha1cluster "github.com/crossplane/upjet-provider-template/apis/cluster/v1alpha1" 15 | v1beta1 "github.com/crossplane/upjet-provider-template/apis/cluster/v1beta1" 16 | ) 17 | 18 | func init() { 19 | // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back 20 | AddToSchemes = append(AddToSchemes, 21 | v1alpha1.SchemeBuilder.AddToScheme, 22 | v1alpha1cluster.SchemeBuilder.AddToScheme, 23 | v1beta1.SchemeBuilder.AddToScheme, 24 | ) 25 | } 26 | 27 | // AddToSchemes may be used to add all resources defined in the project to a Scheme 28 | var AddToSchemes runtime.SchemeBuilder 29 | 30 | // AddToScheme adds all Resources to the Scheme 31 | func AddToScheme(s *runtime.Scheme) error { 32 | return AddToSchemes.AddToScheme(s) 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Provider Template 2 | 3 | `upjet-provider-template` is a [Crossplane](https://crossplane.io/) provider 4 | template that is built using [Upjet](https://github.com/crossplane/upjet) code 5 | generation tools and exposes XRM-conformant managed resources for the Template 6 | API. 7 | 8 | ## Getting Started 9 | 10 | This template serves as a starting point for generating a new [Crossplane Provider](https://docs.crossplane.io/latest/packages/providers/) using the [`upjet`](https://github.com/crossplane/upjet) tooling. Please follow the guide linked below to generate a new Provider: 11 | 12 | https://github.com/crossplane/upjet/blob/main/docs/generating-a-provider.md 13 | 14 | ## Developing 15 | 16 | Run code-generation pipeline: 17 | ```console 18 | go run cmd/generator/main.go "$PWD" 19 | ``` 20 | 21 | Run against a Kubernetes cluster: 22 | 23 | ```console 24 | make run 25 | ``` 26 | 27 | Build, push, and install: 28 | 29 | ```console 30 | make all 31 | ``` 32 | 33 | Build binary: 34 | 35 | ```console 36 | make build 37 | ``` 38 | 39 | ## Report a Bug 40 | 41 | For filing bugs, suggesting improvements, or requesting new features, please 42 | open an [issue](https://github.com/crossplane/upjet-provider-template/issues). 43 | -------------------------------------------------------------------------------- /apis/namespaced/zz_register.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | // Package namespaced contains Kubernetes API for the provider. 8 | package namespaced 9 | 10 | import ( 11 | "k8s.io/apimachinery/pkg/runtime" 12 | 13 | v1alpha1 "github.com/crossplane/upjet-provider-template/apis/namespaced/null/v1alpha1" 14 | v1alpha1namespaced "github.com/crossplane/upjet-provider-template/apis/namespaced/v1alpha1" 15 | v1beta1 "github.com/crossplane/upjet-provider-template/apis/namespaced/v1beta1" 16 | ) 17 | 18 | func init() { 19 | // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back 20 | AddToSchemes = append(AddToSchemes, 21 | v1alpha1.SchemeBuilder.AddToScheme, 22 | v1alpha1namespaced.SchemeBuilder.AddToScheme, 23 | v1beta1.SchemeBuilder.AddToScheme, 24 | ) 25 | } 26 | 27 | // AddToSchemes may be used to add all resources defined in the project to a Scheme 28 | var AddToSchemes runtime.SchemeBuilder 29 | 30 | // AddToScheme adds all Resources to the Scheme 31 | func AddToScheme(s *runtime.Scheme) error { 32 | return AddToSchemes.AddToScheme(s) 33 | } 34 | -------------------------------------------------------------------------------- /internal/controller/cluster/zz_setup.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package controller 6 | 7 | import ( 8 | ctrl "sigs.k8s.io/controller-runtime" 9 | 10 | "github.com/crossplane/upjet/v2/pkg/controller" 11 | 12 | resource "github.com/crossplane/upjet-provider-template/internal/controller/cluster/null/resource" 13 | providerconfig "github.com/crossplane/upjet-provider-template/internal/controller/cluster/providerconfig" 14 | ) 15 | 16 | // Setup creates all controllers with the supplied logger and adds them to 17 | // the supplied manager. 18 | func Setup(mgr ctrl.Manager, o controller.Options) error { 19 | for _, setup := range []func(ctrl.Manager, controller.Options) error{ 20 | resource.Setup, 21 | providerconfig.Setup, 22 | } { 23 | if err := setup(mgr, o); err != nil { 24 | return err 25 | } 26 | } 27 | return nil 28 | } 29 | 30 | // SetupGated creates all controllers with the supplied logger and adds them to 31 | // the supplied manager gated. 32 | func SetupGated(mgr ctrl.Manager, o controller.Options) error { 33 | for _, setup := range []func(ctrl.Manager, controller.Options) error{ 34 | resource.SetupGated, 35 | providerconfig.SetupGated, 36 | } { 37 | if err := setup(mgr, o); err != nil { 38 | return err 39 | } 40 | } 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /internal/controller/namespaced/zz_setup.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package controller 6 | 7 | import ( 8 | ctrl "sigs.k8s.io/controller-runtime" 9 | 10 | "github.com/crossplane/upjet/v2/pkg/controller" 11 | 12 | resource "github.com/crossplane/upjet-provider-template/internal/controller/namespaced/null/resource" 13 | providerconfig "github.com/crossplane/upjet-provider-template/internal/controller/namespaced/providerconfig" 14 | ) 15 | 16 | // Setup creates all controllers with the supplied logger and adds them to 17 | // the supplied manager. 18 | func Setup(mgr ctrl.Manager, o controller.Options) error { 19 | for _, setup := range []func(ctrl.Manager, controller.Options) error{ 20 | resource.Setup, 21 | providerconfig.Setup, 22 | } { 23 | if err := setup(mgr, o); err != nil { 24 | return err 25 | } 26 | } 27 | return nil 28 | } 29 | 30 | // SetupGated creates all controllers with the supplied logger and adds them to 31 | // the supplied manager gated. 32 | func SetupGated(mgr ctrl.Manager, o controller.Options) error { 33 | for _, setup := range []func(ctrl.Manager, controller.Options) error{ 34 | resource.SetupGated, 35 | providerconfig.SetupGated, 36 | } { 37 | if err := setup(mgr, o); err != nil { 38 | return err 39 | } 40 | } 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /config/external_name.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/crossplane/upjet/v2/pkg/config" 5 | ) 6 | 7 | // ExternalNameConfigs contains all external name configurations for this 8 | // provider. 9 | var ExternalNameConfigs = map[string]config.ExternalName{ 10 | // Import requires using a randomly generated ID from provider: nl-2e21sda 11 | "null_resource": idWithStub(), 12 | } 13 | 14 | func idWithStub() config.ExternalName { 15 | e := config.IdentifierFromProvider 16 | e.GetExternalNameFn = func(tfstate map[string]any) (string, error) { 17 | en, _ := config.IDAsExternalName(tfstate) 18 | return en, nil 19 | } 20 | return e 21 | } 22 | 23 | // ExternalNameConfigurations applies all external name configs listed in the 24 | // table ExternalNameConfigs and sets the version of those resources to v1beta1 25 | // assuming they will be tested. 26 | func ExternalNameConfigurations() config.ResourceOption { 27 | return func(r *config.Resource) { 28 | if e, ok := ExternalNameConfigs[r.Name]; ok { 29 | r.ExternalName = e 30 | } 31 | } 32 | } 33 | 34 | // ExternalNameConfigured returns the list of all resources whose external name 35 | // is configured manually. 36 | func ExternalNameConfigured() []string { 37 | l := make([]string, len(ExternalNameConfigs)) 38 | i := 0 39 | for name := range ExternalNameConfigs { 40 | // $ is added to match the exact string since the format is regex. 41 | l[i] = name + "$" 42 | i++ 43 | } 44 | return l 45 | } 46 | -------------------------------------------------------------------------------- /apis/namespaced/v1beta1/zz_generated.pc.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by angryjet. DO NOT EDIT. 6 | 7 | package v1beta1 8 | 9 | import xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" 10 | 11 | // GetCondition of this ClusterProviderConfig. 12 | func (p *ClusterProviderConfig) GetCondition(ct xpv1.ConditionType) xpv1.Condition { 13 | return p.Status.GetCondition(ct) 14 | } 15 | 16 | // GetUsers of this ClusterProviderConfig. 17 | func (p *ClusterProviderConfig) GetUsers() int64 { 18 | return p.Status.Users 19 | } 20 | 21 | // SetConditions of this ClusterProviderConfig. 22 | func (p *ClusterProviderConfig) SetConditions(c ...xpv1.Condition) { 23 | p.Status.SetConditions(c...) 24 | } 25 | 26 | // SetUsers of this ClusterProviderConfig. 27 | func (p *ClusterProviderConfig) SetUsers(i int64) { 28 | p.Status.Users = i 29 | } 30 | 31 | // GetCondition of this ProviderConfig. 32 | func (p *ProviderConfig) GetCondition(ct xpv1.ConditionType) xpv1.Condition { 33 | return p.Status.GetCondition(ct) 34 | } 35 | 36 | // GetUsers of this ProviderConfig. 37 | func (p *ProviderConfig) GetUsers() int64 { 38 | return p.Status.Users 39 | } 40 | 41 | // SetConditions of this ProviderConfig. 42 | func (p *ProviderConfig) SetConditions(c ...xpv1.Condition) { 43 | p.Status.SetConditions(c...) 44 | } 45 | 46 | // SetUsers of this ProviderConfig. 47 | func (p *ProviderConfig) SetUsers(i int64) { 48 | p.Status.Users = i 49 | } 50 | -------------------------------------------------------------------------------- /cluster/test/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -aeuo pipefail 3 | 4 | echo "Running setup.sh" 5 | echo "Creating cloud credential secret..." 6 | ${KUBECTL} -n crossplane-system create secret generic provider-secret --from-literal=credentials="${UPTEST_CLOUD_CREDENTIALS}" --dry-run=client -o yaml | ${KUBECTL} apply -f - 7 | 8 | echo "Waiting until provider is healthy..." 9 | ${KUBECTL} wait provider.pkg --all --for condition=Healthy --timeout 5m 10 | 11 | echo "Waiting for all pods to come online..." 12 | ${KUBECTL} -n crossplane-system wait --for=condition=Available deployment --all --timeout=5m 13 | 14 | echo "Creating a default provider config..." 15 | cat < 7 | # example usage: version_diff.py config/generated.lst .work/schema.json.3.38.0 config/schema.json 8 | if __name__ == "__main__": 9 | base_path = sys.argv[2] 10 | bumped_path = sys.argv[3] 11 | print(f'Reporting schema changes between "{base_path}" as base version and "{bumped_path}" as bumped version') 12 | with open(sys.argv[1]) as f: 13 | resources = json.load(f) 14 | with open(base_path) as f: 15 | base = json.load(f) 16 | with open(bumped_path) as f: 17 | bump = json.load(f) 18 | 19 | provider_name = None 20 | for k in base["provider_schemas"]: 21 | # the first key is the provider name 22 | provider_name = k 23 | break 24 | if provider_name is None: 25 | print(f"Cannot extract the provider name from the base schema: {base_path}") 26 | sys.exit(-1) 27 | base_schemas = base["provider_schemas"][provider_name]["resource_schemas"] 28 | bumped_schemas = bump["provider_schemas"][provider_name]["resource_schemas"] 29 | 30 | for name in resources: 31 | try: 32 | if base_schemas[name]["version"] != bumped_schemas[name]["version"]: 33 | print(f'{name}:{base_schemas[name]["version"]}-{bumped_schemas[name]["version"]}') 34 | except KeyError as ke: 35 | print(f'{name} is not found in schema: {ke}') 36 | continue 37 | -------------------------------------------------------------------------------- /apis/generate.go: -------------------------------------------------------------------------------- 1 | //go:build generate 2 | // +build generate 3 | 4 | // NOTE: See the below link for details on what is happening here. 5 | // https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module 6 | 7 | // Remove existing CRDs 8 | //go:generate rm -rf ../package/crds 9 | 10 | // Remove generated files 11 | //go:generate bash -c "find . -iname 'zz_*' ! -iname 'zz_generated.managed*.go' -delete" 12 | //go:generate bash -c "find . -type d -empty -delete" 13 | //go:generate bash -c "find ../internal/controller -iname 'zz_*' -delete" 14 | //go:generate bash -c "find ../internal/controller -type d -empty -delete" 15 | //go:generate rm -rf ../examples-generated 16 | 17 | // Generate documentation from Terraform docs. 18 | //go:generate go run github.com/crossplane/upjet/v2/cmd/scraper -n ${TERRAFORM_PROVIDER_SOURCE} -r ../.work/${TERRAFORM_PROVIDER_SOURCE}/${TERRAFORM_DOCS_PATH} -o ../config/provider-metadata.yaml 19 | 20 | // Run Upjet generator 21 | //go:generate go run ../cmd/generator/main.go .. 22 | 23 | // Generate deepcopy methodsets and CRD manifests 24 | //go:generate go run -tags generate sigs.k8s.io/controller-tools/cmd/controller-gen object:headerFile=../hack/boilerplate.go.txt paths=./... crd:allowDangerousTypes=true,crdVersions=v1 output:artifacts:config=../package/crds 25 | 26 | // Generate crossplane-runtime methodsets (resource.Claim, etc) 27 | //go:generate go run -tags generate github.com/crossplane/crossplane-tools/cmd/angryjet generate-methodsets --header-file=../hack/boilerplate.go.txt ./... 28 | 29 | package apis 30 | 31 | import ( 32 | _ "sigs.k8s.io/controller-tools/cmd/controller-gen" //nolint:typecheck 33 | 34 | _ "github.com/crossplane/crossplane-tools/cmd/angryjet" //nolint:typecheck 35 | ) 36 | -------------------------------------------------------------------------------- /apis/namespaced/null/v1alpha1/zz_generated.managed.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by angryjet. DO NOT EDIT. 6 | 7 | package v1alpha1 8 | 9 | import xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" 10 | 11 | // GetCondition of this Resource. 12 | func (mg *Resource) GetCondition(ct xpv1.ConditionType) xpv1.Condition { 13 | return mg.Status.GetCondition(ct) 14 | } 15 | 16 | // GetManagementPolicies of this Resource. 17 | func (mg *Resource) GetManagementPolicies() xpv1.ManagementPolicies { 18 | return mg.Spec.ManagementPolicies 19 | } 20 | 21 | // GetProviderConfigReference of this Resource. 22 | func (mg *Resource) GetProviderConfigReference() *xpv1.ProviderConfigReference { 23 | return mg.Spec.ProviderConfigReference 24 | } 25 | 26 | // GetWriteConnectionSecretToReference of this Resource. 27 | func (mg *Resource) GetWriteConnectionSecretToReference() *xpv1.LocalSecretReference { 28 | return mg.Spec.WriteConnectionSecretToReference 29 | } 30 | 31 | // SetConditions of this Resource. 32 | func (mg *Resource) SetConditions(c ...xpv1.Condition) { 33 | mg.Status.SetConditions(c...) 34 | } 35 | 36 | // SetManagementPolicies of this Resource. 37 | func (mg *Resource) SetManagementPolicies(r xpv1.ManagementPolicies) { 38 | mg.Spec.ManagementPolicies = r 39 | } 40 | 41 | // SetProviderConfigReference of this Resource. 42 | func (mg *Resource) SetProviderConfigReference(r *xpv1.ProviderConfigReference) { 43 | mg.Spec.ProviderConfigReference = r 44 | } 45 | 46 | // SetWriteConnectionSecretToReference of this Resource. 47 | func (mg *Resource) SetWriteConnectionSecretToReference(r *xpv1.LocalSecretReference) { 48 | mg.Spec.WriteConnectionSecretToReference = r 49 | } 50 | -------------------------------------------------------------------------------- /cluster/images/upjet-provider-template/Makefile: -------------------------------------------------------------------------------- 1 | # ==================================================================================== 2 | # Setup Project 3 | 4 | include ../../../build/makelib/common.mk 5 | 6 | # ==================================================================================== 7 | # Options 8 | 9 | include ../../../build/makelib/imagelight.mk 10 | 11 | # ==================================================================================== 12 | # Targets 13 | 14 | img.build: 15 | @$(INFO) docker build $(IMAGE) 16 | @$(MAKE) BUILD_ARGS="--load" img.build.shared 17 | @$(OK) docker build $(IMAGE) 18 | 19 | img.publish: 20 | @$(INFO) Skipping image publish for $(IMAGE) 21 | @echo Publish is deferred to xpkg machinery 22 | @$(OK) Image publish skipped for $(IMAGE) 23 | 24 | img.build.shared: 25 | @cp Dockerfile $(IMAGE_TEMP_DIR) || $(FAIL) 26 | @cp terraformrc.hcl $(IMAGE_TEMP_DIR) || $(FAIL) 27 | @cp -r $(OUTPUT_DIR)/bin/ $(IMAGE_TEMP_DIR)/bin || $(FAIL) 28 | @docker buildx build $(BUILD_ARGS) \ 29 | --platform $(IMAGE_PLATFORMS) \ 30 | --build-arg TERRAFORM_VERSION=$(TERRAFORM_VERSION) \ 31 | --build-arg TERRAFORM_PROVIDER_SOURCE=$(TERRAFORM_PROVIDER_SOURCE) \ 32 | --build-arg TERRAFORM_PROVIDER_VERSION=$(TERRAFORM_PROVIDER_VERSION) \ 33 | --build-arg TERRAFORM_PROVIDER_DOWNLOAD_NAME=$(TERRAFORM_PROVIDER_DOWNLOAD_NAME) \ 34 | --build-arg TERRAFORM_PROVIDER_DOWNLOAD_URL_PREFIX=$(TERRAFORM_PROVIDER_DOWNLOAD_URL_PREFIX) \ 35 | --build-arg TERRAFORM_NATIVE_PROVIDER_BINARY=$(TERRAFORM_NATIVE_PROVIDER_BINARY) \ 36 | -t $(IMAGE) \ 37 | $(IMAGE_TEMP_DIR) || $(FAIL) 38 | 39 | img.promote: 40 | @$(INFO) Skipping image promotion from $(FROM_IMAGE) to $(TO_IMAGE) 41 | @echo Promote is deferred to xpkg machinery 42 | @$(OK) Image promotion skipped for $(FROM_IMAGE) to $(TO_IMAGE) 43 | -------------------------------------------------------------------------------- /internal/controller/cluster/providerconfig/config.go: -------------------------------------------------------------------------------- 1 | package providerconfig 2 | 3 | import ( 4 | "github.com/crossplane/crossplane-runtime/v2/pkg/event" 5 | "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/providerconfig" 6 | "github.com/crossplane/crossplane-runtime/v2/pkg/resource" 7 | "github.com/crossplane/upjet/v2/pkg/controller" 8 | ctrl "sigs.k8s.io/controller-runtime" 9 | 10 | "github.com/crossplane/upjet-provider-template/apis/cluster/v1beta1" 11 | ) 12 | 13 | // Setup adds a controller that reconciles ProviderConfigs by accounting for 14 | // their current usage. 15 | func Setup(mgr ctrl.Manager, o controller.Options) error { 16 | name := providerconfig.ControllerName(v1beta1.ProviderConfigGroupKind) 17 | 18 | of := resource.ProviderConfigKinds{ 19 | Config: v1beta1.ProviderConfigGroupVersionKind, 20 | Usage: v1beta1.ProviderConfigUsageGroupVersionKind, 21 | UsageList: v1beta1.ProviderConfigUsageListGroupVersionKind, 22 | } 23 | 24 | return ctrl.NewControllerManagedBy(mgr). 25 | Named(name). 26 | WithOptions(o.ForControllerRuntime()). 27 | For(&v1beta1.ProviderConfig{}). 28 | Watches(&v1beta1.ProviderConfigUsage{}, &resource.EnqueueRequestForProviderConfig{}). 29 | Complete(providerconfig.NewReconciler(mgr, of, 30 | providerconfig.WithLogger(o.Logger.WithValues("controller", name)), 31 | providerconfig.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))))) 32 | } 33 | 34 | // SetupGated adds a controller that reconciles ProviderConfigs by accounting for 35 | // their current usage. 36 | func SetupGated(mgr ctrl.Manager, o controller.Options) error { 37 | o.Gate.Register(func() { 38 | if err := Setup(mgr, o); err != nil { 39 | mgr.GetLogger().Error(err, "unable to setup reconcilers", "gvk", v1beta1.ProviderConfigGroupVersionKind.String()) 40 | } 41 | }, v1beta1.ProviderConfigGroupVersionKind, v1beta1.ProviderConfigUsageGroupVersionKind) 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /apis/cluster/null/v1alpha1/zz_generated.managed.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by angryjet. DO NOT EDIT. 6 | 7 | package v1alpha1 8 | 9 | import xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" 10 | 11 | // GetCondition of this Resource. 12 | func (mg *Resource) GetCondition(ct xpv1.ConditionType) xpv1.Condition { 13 | return mg.Status.GetCondition(ct) 14 | } 15 | 16 | // GetDeletionPolicy of this Resource. 17 | func (mg *Resource) GetDeletionPolicy() xpv1.DeletionPolicy { 18 | return mg.Spec.DeletionPolicy 19 | } 20 | 21 | // GetManagementPolicies of this Resource. 22 | func (mg *Resource) GetManagementPolicies() xpv1.ManagementPolicies { 23 | return mg.Spec.ManagementPolicies 24 | } 25 | 26 | // GetProviderConfigReference of this Resource. 27 | func (mg *Resource) GetProviderConfigReference() *xpv1.Reference { 28 | return mg.Spec.ProviderConfigReference 29 | } 30 | 31 | // GetWriteConnectionSecretToReference of this Resource. 32 | func (mg *Resource) GetWriteConnectionSecretToReference() *xpv1.SecretReference { 33 | return mg.Spec.WriteConnectionSecretToReference 34 | } 35 | 36 | // SetConditions of this Resource. 37 | func (mg *Resource) SetConditions(c ...xpv1.Condition) { 38 | mg.Status.SetConditions(c...) 39 | } 40 | 41 | // SetDeletionPolicy of this Resource. 42 | func (mg *Resource) SetDeletionPolicy(r xpv1.DeletionPolicy) { 43 | mg.Spec.DeletionPolicy = r 44 | } 45 | 46 | // SetManagementPolicies of this Resource. 47 | func (mg *Resource) SetManagementPolicies(r xpv1.ManagementPolicies) { 48 | mg.Spec.ManagementPolicies = r 49 | } 50 | 51 | // SetProviderConfigReference of this Resource. 52 | func (mg *Resource) SetProviderConfigReference(r *xpv1.Reference) { 53 | mg.Spec.ProviderConfigReference = r 54 | } 55 | 56 | // SetWriteConnectionSecretToReference of this Resource. 57 | func (mg *Resource) SetWriteConnectionSecretToReference(r *xpv1.SecretReference) { 58 | mg.Spec.WriteConnectionSecretToReference = r 59 | } 60 | -------------------------------------------------------------------------------- /apis/cluster/v1beta1/register.go: -------------------------------------------------------------------------------- 1 | package v1beta1 2 | 3 | import ( 4 | "reflect" 5 | 6 | "k8s.io/apimachinery/pkg/runtime/schema" 7 | "sigs.k8s.io/controller-runtime/pkg/scheme" 8 | ) 9 | 10 | // Package type metadata. 11 | const ( 12 | Group = "template.crossplane.io" 13 | Version = "v1beta1" 14 | ) 15 | 16 | var ( 17 | // SchemeGroupVersion is group version used to register these objects 18 | SchemeGroupVersion = schema.GroupVersion{Group: Group, Version: Version} 19 | 20 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 21 | SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} 22 | ) 23 | 24 | // ProviderConfig type metadata. 25 | var ( 26 | ProviderConfigKind = reflect.TypeOf(ProviderConfig{}).Name() 27 | ProviderConfigGroupKind = schema.GroupKind{Group: Group, Kind: ProviderConfigKind}.String() 28 | ProviderConfigKindAPIVersion = ProviderConfigKind + "." + SchemeGroupVersion.String() 29 | ProviderConfigGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigKind) 30 | ) 31 | 32 | // ProviderConfigUsage type metadata. 33 | var ( 34 | ProviderConfigUsageKind = reflect.TypeOf(ProviderConfigUsage{}).Name() 35 | ProviderConfigUsageGroupKind = schema.GroupKind{Group: Group, Kind: ProviderConfigUsageKind}.String() 36 | ProviderConfigUsageKindAPIVersion = ProviderConfigUsageKind + "." + SchemeGroupVersion.String() 37 | ProviderConfigUsageGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigUsageKind) 38 | 39 | ProviderConfigUsageListKind = reflect.TypeOf(ProviderConfigUsageList{}).Name() 40 | ProviderConfigUsageListGroupKind = schema.GroupKind{Group: Group, Kind: ProviderConfigUsageListKind}.String() 41 | ProviderConfigUsageListKindAPIVersion = ProviderConfigUsageListKind + "." + SchemeGroupVersion.String() 42 | ProviderConfigUsageListGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigUsageListKind) 43 | ) 44 | 45 | func init() { 46 | SchemeBuilder.Register(&ProviderConfig{}, &ProviderConfigList{}) 47 | SchemeBuilder.Register(&ProviderConfigUsage{}, &ProviderConfigUsageList{}) 48 | } 49 | -------------------------------------------------------------------------------- /config/provider-metadata.yaml: -------------------------------------------------------------------------------- 1 | name: hashicorp/null 2 | resources: 3 | null_resource: 4 | subCategory: "" 5 | description: The null_resource resource implements the standard resource lifecycle but takes no further action. On Terraform 1.4 and later, use the terraform_data resource type https://developer.hashicorp.com/terraform/language/resources/terraform-data instead. Terraform 1.9 and later support the moved configuration block from null_resource to terraform_data. The triggers argument allows specifying an arbitrary set of values that, when changed, will cause the resource to be replaced. 6 | name: null_resource 7 | title: null_resource Resource - terraform-provider-null 8 | examples: 9 | - name: cluster 10 | manifest: |- 11 | { 12 | "connection": [ 13 | { 14 | "host": "${element(aws_instance.cluster[*].public_ip, 0)}" 15 | } 16 | ], 17 | "provisioner": { 18 | "remote-exec": [ 19 | { 20 | "inline": [ 21 | "bootstrap-cluster.sh ${join(\" \",\n aws_instance.cluster[*].private_ip)}" 22 | ] 23 | } 24 | ] 25 | }, 26 | "triggers": { 27 | "cluster_instance_ids": "${join(\",\", aws_instance.cluster[*].id)}" 28 | } 29 | } 30 | dependencies: 31 | aws_instance.cluster: |- 32 | { 33 | "ami": "ami-0dcc1e21636832c5d", 34 | "count": 3, 35 | "instance_type": "m5.large" 36 | } 37 | argumentDocs: 38 | id: (String) This is set to a random value at create time. 39 | triggers: (Map of String) A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners. 40 | importStatements: [] 41 | -------------------------------------------------------------------------------- /cluster/images/upjet-provider-template/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.23.0 2 | RUN apk --no-cache add ca-certificates bash 3 | 4 | ARG TARGETOS 5 | ARG TARGETARCH 6 | 7 | ADD "bin/${TARGETOS}_${TARGETARCH}/provider" /usr/local/bin/provider 8 | 9 | ENV USER_ID=65532 10 | 11 | # Setup Terraform environment 12 | 13 | ## Provider-dependent configuration 14 | ARG TERRAFORM_VERSION 15 | ARG TERRAFORM_PROVIDER_SOURCE 16 | ARG TERRAFORM_PROVIDER_VERSION 17 | ARG TERRAFORM_PROVIDER_DOWNLOAD_NAME 18 | ARG TERRAFORM_NATIVE_PROVIDER_BINARY 19 | ARG TERRAFORM_PROVIDER_DOWNLOAD_URL_PREFIX 20 | 21 | ## End of - Provider-dependent configuration 22 | 23 | ENV PLUGIN_DIR=/terraform/provider-mirror/registry.terraform.io/${TERRAFORM_PROVIDER_SOURCE}/${TERRAFORM_PROVIDER_VERSION}/${TARGETOS}_${TARGETARCH} 24 | ENV TF_CLI_CONFIG_FILE=/terraform/.terraformrc 25 | ENV TF_FORK=0 26 | 27 | RUN mkdir -p ${PLUGIN_DIR} 28 | 29 | ADD https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_${TARGETOS}_${TARGETARCH}.zip /tmp 30 | ADD ${TERRAFORM_PROVIDER_DOWNLOAD_URL_PREFIX}/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}_${TERRAFORM_PROVIDER_VERSION}_${TARGETOS}_${TARGETARCH}.zip /tmp 31 | ADD terraformrc.hcl ${TF_CLI_CONFIG_FILE} 32 | 33 | RUN unzip /tmp/terraform_${TERRAFORM_VERSION}_${TARGETOS}_${TARGETARCH}.zip -d /usr/local/bin \ 34 | && chmod +x /usr/local/bin/terraform \ 35 | && rm /tmp/terraform_${TERRAFORM_VERSION}_${TARGETOS}_${TARGETARCH}.zip \ 36 | && unzip /tmp/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}_${TERRAFORM_PROVIDER_VERSION}_${TARGETOS}_${TARGETARCH}.zip -d ${PLUGIN_DIR} \ 37 | && chmod +x ${PLUGIN_DIR}/* \ 38 | && rm /tmp/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}_${TERRAFORM_PROVIDER_VERSION}_${TARGETOS}_${TARGETARCH}.zip \ 39 | && chown -R ${USER_ID}:${USER_ID} /terraform 40 | # End of - Setup Terraform environment 41 | 42 | # Provider controller needs these environment variable at runtime 43 | ENV TERRAFORM_VERSION=${TERRAFORM_VERSION} 44 | ENV TERRAFORM_PROVIDER_SOURCE=${TERRAFORM_PROVIDER_SOURCE} 45 | ENV TERRAFORM_PROVIDER_VERSION=${TERRAFORM_PROVIDER_VERSION} 46 | ENV TERRAFORM_NATIVE_PROVIDER_PATH=${PLUGIN_DIR}/${TERRAFORM_NATIVE_PROVIDER_BINARY} 47 | 48 | USER ${USER_ID} 49 | EXPOSE 8080 50 | 51 | ENTRYPOINT ["provider"] 52 | -------------------------------------------------------------------------------- /config/provider.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | // Note(turkenh): we are importing this to embed provider schema document 5 | _ "embed" 6 | 7 | ujconfig "github.com/crossplane/upjet/v2/pkg/config" 8 | 9 | nullCluster "github.com/crossplane/upjet-provider-template/config/cluster/null" 10 | nullNamespaced "github.com/crossplane/upjet-provider-template/config/namespaced/null" 11 | ) 12 | 13 | const ( 14 | resourcePrefix = "template" 15 | modulePath = "github.com/crossplane/upjet-provider-template" 16 | ) 17 | 18 | //go:embed schema.json 19 | var providerSchema string 20 | 21 | //go:embed provider-metadata.yaml 22 | var providerMetadata string 23 | 24 | // GetProvider returns provider configuration 25 | func GetProvider() *ujconfig.Provider { 26 | pc := ujconfig.NewProvider([]byte(providerSchema), resourcePrefix, modulePath, []byte(providerMetadata), 27 | ujconfig.WithRootGroup("template.crossplane.io"), 28 | ujconfig.WithIncludeList(ExternalNameConfigured()), 29 | ujconfig.WithFeaturesPackage("internal/features"), 30 | ujconfig.WithDefaultResourceOptions( 31 | ExternalNameConfigurations(), 32 | )) 33 | 34 | for _, configure := range []func(provider *ujconfig.Provider){ 35 | // add custom config functions 36 | nullCluster.Configure, 37 | } { 38 | configure(pc) 39 | } 40 | 41 | pc.ConfigureResources() 42 | return pc 43 | } 44 | 45 | // GetProviderNamespaced returns the namespaced provider configuration 46 | func GetProviderNamespaced() *ujconfig.Provider { 47 | pc := ujconfig.NewProvider([]byte(providerSchema), resourcePrefix, modulePath, []byte(providerMetadata), 48 | ujconfig.WithRootGroup("template.m.crossplane.io"), 49 | ujconfig.WithIncludeList(ExternalNameConfigured()), 50 | ujconfig.WithFeaturesPackage("internal/features"), 51 | ujconfig.WithDefaultResourceOptions( 52 | ExternalNameConfigurations(), 53 | ), 54 | ujconfig.WithExampleManifestConfiguration(ujconfig.ExampleManifestConfiguration{ 55 | ManagedResourceNamespace: "crossplane-system", 56 | })) 57 | 58 | for _, configure := range []func(provider *ujconfig.Provider){ 59 | // add custom config functions 60 | nullNamespaced.Configure, 61 | } { 62 | configure(pc) 63 | } 64 | 65 | pc.ConfigureResources() 66 | return pc 67 | } 68 | -------------------------------------------------------------------------------- /apis/namespaced/v1beta1/register.go: -------------------------------------------------------------------------------- 1 | package v1beta1 2 | 3 | import ( 4 | "reflect" 5 | 6 | "k8s.io/apimachinery/pkg/runtime/schema" 7 | "sigs.k8s.io/controller-runtime/pkg/scheme" 8 | ) 9 | 10 | // Package type metadata. 11 | const ( 12 | Group = "template.m.crossplane.io" 13 | Version = "v1beta1" 14 | ) 15 | 16 | var ( 17 | // SchemeGroupVersion is group version used to register these objects 18 | SchemeGroupVersion = schema.GroupVersion{Group: Group, Version: Version} 19 | 20 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 21 | SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} 22 | ) 23 | 24 | // ProviderConfig type metadata. 25 | var ( 26 | ProviderConfigKind = reflect.TypeOf(ProviderConfig{}).Name() 27 | ProviderConfigGroupKind = schema.GroupKind{Group: Group, Kind: ProviderConfigKind}.String() 28 | ProviderConfigKindAPIVersion = ProviderConfigKind + "." + SchemeGroupVersion.String() 29 | ProviderConfigGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigKind) 30 | ) 31 | 32 | // ClusterProviderConfig type metadata. 33 | var ( 34 | ClusterProviderConfigKind = reflect.TypeOf(ClusterProviderConfig{}).Name() 35 | ClusterProviderConfigGroupKind = schema.GroupKind{Group: Group, Kind: ClusterProviderConfigKind}.String() 36 | ClusterProviderConfigKindAPIVersion = ClusterProviderConfigKind + "." + SchemeGroupVersion.String() 37 | ClusterProviderConfigGroupVersionKind = SchemeGroupVersion.WithKind(ClusterProviderConfigKind) 38 | ) 39 | 40 | // ProviderConfigUsage type metadata. 41 | var ( 42 | ProviderConfigUsageKind = reflect.TypeOf(ProviderConfigUsage{}).Name() 43 | ProviderConfigUsageGroupKind = schema.GroupKind{Group: Group, Kind: ProviderConfigUsageKind}.String() 44 | ProviderConfigUsageKindAPIVersion = ProviderConfigUsageKind + "." + SchemeGroupVersion.String() 45 | ProviderConfigUsageGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigUsageKind) 46 | 47 | ProviderConfigUsageListKind = reflect.TypeOf(ProviderConfigUsageList{}).Name() 48 | ProviderConfigUsageListGroupKind = schema.GroupKind{Group: Group, Kind: ProviderConfigUsageListKind}.String() 49 | ProviderConfigUsageListKindAPIVersion = ProviderConfigUsageListKind + "." + SchemeGroupVersion.String() 50 | ProviderConfigUsageListGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigUsageListKind) 51 | ) 52 | 53 | func init() { 54 | SchemeBuilder.Register(&ProviderConfig{}, &ProviderConfigList{}) 55 | SchemeBuilder.Register(&ClusterProviderConfig{}, &ClusterProviderConfigList{}) 56 | SchemeBuilder.Register(&ProviderConfigUsage{}, &ProviderConfigUsageList{}) 57 | } 58 | -------------------------------------------------------------------------------- /config/schema.json: -------------------------------------------------------------------------------- 1 | {"format_version":"1.0","provider_schemas":{"registry.terraform.io/hashicorp/null":{"provider":{"version":0,"block":{"description_kind":"plain"}},"resource_schemas":{"null_resource":{"version":0,"block":{"attributes":{"id":{"type":"string","description":"This is set to a random value at create time.","description_kind":"plain","computed":true},"triggers":{"type":["map","string"],"description":"A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners.","description_kind":"plain","optional":true}},"description":"The `null_resource` resource implements the standard resource lifecycle but takes no further action. On Terraform 1.4 and later, use the [`terraform_data` resource type](https://developer.hashicorp.com/terraform/language/resources/terraform-data) instead. Terraform 1.9 and later support the `moved` configuration block from `null_resource` to `terraform_data`.\n\nThe `triggers` argument allows specifying an arbitrary set of values that, when changed, will cause the resource to be replaced.","description_kind":"plain"}}},"data_source_schemas":{"null_data_source":{"version":0,"block":{"attributes":{"has_computed_default":{"type":"string","description":"If set, its literal value will be stored and returned. If not, its value defaults to `\"default\"`. This argument exists primarily for testing and has little practical use.","description_kind":"plain","optional":true,"computed":true},"id":{"type":"string","description":"This attribute is only present for some legacy compatibility issues and should not be used. It will be removed in a future version.","description_kind":"plain","deprecated":true,"computed":true},"inputs":{"type":["map","string"],"description":"A map of arbitrary strings that is copied into the `outputs` attribute, and accessible directly for interpolation.","description_kind":"plain","optional":true},"outputs":{"type":["map","string"],"description":"After the data source is \"read\", a copy of the `inputs` map.","description_kind":"plain","computed":true},"random":{"type":"string","description":"A random value. This is primarily for testing and has little practical use; prefer the [hashicorp/random provider](https://registry.terraform.io/providers/hashicorp/random) for more practical random number use-cases.","description_kind":"plain","computed":true}},"description":"The `null_data_source` data source implements the standard data source lifecycle but does not\ninteract with any external APIs.\n\nHistorically, the `null_data_source` was typically used to construct intermediate values to re-use elsewhere in configuration. The\nsame can now be achieved using [locals](https://developer.hashicorp.com/terraform/language/values/locals) or the [terraform_data resource type](https://developer.hashicorp.com/terraform/language/resources/terraform-data) in Terraform 1.4 and later.","description_kind":"plain","deprecated":true}}}}}} 2 | -------------------------------------------------------------------------------- /apis/cluster/v1beta1/types.go: -------------------------------------------------------------------------------- 1 | package v1beta1 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | 6 | xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" 7 | ) 8 | 9 | // A ProviderConfigSpec defines the desired state of a ProviderConfig. 10 | type ProviderConfigSpec struct { 11 | // Credentials required to authenticate to this provider. 12 | Credentials ProviderCredentials `json:"credentials"` 13 | } 14 | 15 | // ProviderCredentials required to authenticate. 16 | type ProviderCredentials struct { 17 | // Source of the provider credentials. 18 | // +kubebuilder:validation:Enum=None;Secret;InjectedIdentity;Environment;Filesystem 19 | Source xpv1.CredentialsSource `json:"source"` 20 | 21 | xpv1.CommonCredentialSelectors `json:",inline"` 22 | } 23 | 24 | // A ProviderConfigStatus reflects the observed state of a ProviderConfig. 25 | type ProviderConfigStatus struct { 26 | xpv1.ProviderConfigStatus `json:",inline"` 27 | } 28 | 29 | // +kubebuilder:object:root=true 30 | 31 | // A ProviderConfig configures a Template provider. 32 | // +kubebuilder:subresource:status 33 | // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" 34 | // +kubebuilder:printcolumn:name="SECRET-NAME",type="string",JSONPath=".spec.credentials.secretRef.name",priority=1 35 | // +kubebuilder:resource:scope=Cluster 36 | // +kubebuilder:resource:scope=Cluster,categories={crossplane,provider,template} 37 | type ProviderConfig struct { 38 | metav1.TypeMeta `json:",inline"` 39 | metav1.ObjectMeta `json:"metadata,omitempty"` 40 | 41 | Spec ProviderConfigSpec `json:"spec"` 42 | Status ProviderConfigStatus `json:"status,omitempty"` 43 | } 44 | 45 | // +kubebuilder:object:root=true 46 | 47 | // ProviderConfigList contains a list of ProviderConfig. 48 | type ProviderConfigList struct { 49 | metav1.TypeMeta `json:",inline"` 50 | metav1.ListMeta `json:"metadata,omitempty"` 51 | Items []ProviderConfig `json:"items"` 52 | } 53 | 54 | // +kubebuilder:object:root=true 55 | 56 | // A ProviderConfigUsage indicates that a resource is using a ProviderConfig. 57 | // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" 58 | // +kubebuilder:printcolumn:name="CONFIG-NAME",type="string",JSONPath=".providerConfigRef.name" 59 | // +kubebuilder:printcolumn:name="RESOURCE-KIND",type="string",JSONPath=".resourceRef.kind" 60 | // +kubebuilder:printcolumn:name="RESOURCE-NAME",type="string",JSONPath=".resourceRef.name" 61 | // +kubebuilder:resource:scope=Cluster,categories={crossplane,provider,template} 62 | type ProviderConfigUsage struct { 63 | metav1.TypeMeta `json:",inline"` 64 | metav1.ObjectMeta `json:"metadata,omitempty"` 65 | 66 | xpv1.ProviderConfigUsage `json:",inline"` 67 | } 68 | 69 | // +kubebuilder:object:root=true 70 | 71 | // ProviderConfigUsageList contains a list of ProviderConfigUsage 72 | type ProviderConfigUsageList struct { 73 | metav1.TypeMeta `json:",inline"` 74 | metav1.ListMeta `json:"metadata,omitempty"` 75 | Items []ProviderConfigUsage `json:"items"` 76 | } 77 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | output: 3 | formats: 4 | text: 5 | path: stdout 6 | linters: 7 | enable: 8 | - asasalint 9 | - asciicheck 10 | - bidichk 11 | - bodyclose 12 | - contextcheck 13 | - durationcheck 14 | - errcheck 15 | - errchkjson 16 | - errorlint 17 | - exhaustive 18 | - gocheckcompilerdirectives 19 | - gochecksumtype 20 | - goconst 21 | - gocritic 22 | - gocyclo 23 | - gosec 24 | - gosmopolitan 25 | - govet 26 | - ineffassign 27 | - loggercheck 28 | - makezero 29 | - misspell 30 | - musttag 31 | - nakedret 32 | - nilerr 33 | - nilnesserr 34 | - noctx 35 | - prealloc 36 | - protogetter 37 | - reassign 38 | - recvcheck 39 | - rowserrcheck 40 | - spancheck 41 | - sqlclosecheck 42 | - staticcheck 43 | - testifylint 44 | - unconvert 45 | - unparam 46 | - unused 47 | - zerologlint 48 | settings: 49 | dupl: 50 | threshold: 100 51 | errcheck: 52 | check-type-assertions: false 53 | check-blank: false 54 | exclude-functions: 55 | - io/ioutil.ReadFile 56 | - io.Copy(*bytes.Buffer) 57 | - io.Copy(os.Stdout) 58 | goconst: 59 | min-len: 3 60 | min-occurrences: 5 61 | gocritic: 62 | enabled-tags: 63 | - performance 64 | settings: 65 | captLocal: 66 | paramsOnly: true 67 | rangeValCopy: 68 | sizeThreshold: 32 69 | gocyclo: 70 | min-complexity: 10 71 | lll: 72 | tab-width: 1 73 | nakedret: 74 | max-func-lines: 30 75 | prealloc: 76 | simple: true 77 | range-loops: true 78 | for-loops: false 79 | unparam: 80 | check-exported: false 81 | exclusions: 82 | generated: lax 83 | rules: 84 | - linters: 85 | - dupl 86 | - errcheck 87 | - gocyclo 88 | - gosec 89 | - scopelint 90 | - unparam 91 | path: _test(ing)?\.go 92 | - linters: 93 | - gocritic 94 | path: _test\.go 95 | text: (unnamedResult|exitAfterDefer) 96 | - linters: 97 | - gocritic 98 | text: '(hugeParam|rangeValCopy):' 99 | - linters: 100 | - staticcheck 101 | text: 'SA3000:' 102 | - linters: 103 | - gosec 104 | text: 'G101:' 105 | - linters: 106 | - gosec 107 | text: 'G104:' 108 | paths: 109 | - zz_\..+\.go$ 110 | - third_party$ 111 | - builtin$ 112 | - examples$ 113 | issues: 114 | max-issues-per-linter: 0 115 | max-same-issues: 0 116 | new: false 117 | formatters: 118 | enable: 119 | - gofmt 120 | - goimports 121 | settings: 122 | gofmt: 123 | simplify: true 124 | goimports: 125 | local-prefixes: 126 | - github.com/crossplane/upjet-provider-template 127 | exclusions: 128 | generated: lax 129 | paths: 130 | - zz_\..+\.go$ 131 | - third_party$ 132 | - builtin$ 133 | - examples$ 134 | -------------------------------------------------------------------------------- /internal/controller/namespaced/providerconfig/config.go: -------------------------------------------------------------------------------- 1 | package providerconfig 2 | 3 | import ( 4 | "github.com/crossplane/crossplane-runtime/v2/pkg/event" 5 | "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/providerconfig" 6 | "github.com/crossplane/crossplane-runtime/v2/pkg/resource" 7 | "github.com/crossplane/upjet/v2/pkg/controller" 8 | ctrl "sigs.k8s.io/controller-runtime" 9 | 10 | "github.com/crossplane/upjet-provider-template/apis/namespaced/v1beta1" 11 | ) 12 | 13 | // Setup adds a controller that reconciles ProviderConfigs and ClusterProviderConfigs 14 | // by accounting for their current usage. 15 | func Setup(mgr ctrl.Manager, o controller.Options) error { 16 | if err := setupCluster(mgr, o); err != nil { 17 | return err 18 | } 19 | return setupNamespaced(mgr, o) 20 | } 21 | 22 | // setupCluster adds a controller that reconciles ClusterProviderConfigs by accounting for 23 | // their current usage. 24 | func setupCluster(mgr ctrl.Manager, o controller.Options) error { 25 | name := providerconfig.ControllerName(v1beta1.ClusterProviderConfigGroupKind) 26 | 27 | of := resource.ProviderConfigKinds{ 28 | Config: v1beta1.ClusterProviderConfigGroupVersionKind, 29 | Usage: v1beta1.ProviderConfigUsageGroupVersionKind, 30 | UsageList: v1beta1.ProviderConfigUsageListGroupVersionKind, 31 | } 32 | 33 | return ctrl.NewControllerManagedBy(mgr). 34 | Named(name). 35 | WithOptions(o.ForControllerRuntime()). 36 | For(&v1beta1.ClusterProviderConfig{}). 37 | Watches(&v1beta1.ProviderConfigUsage{}, &resource.EnqueueRequestForProviderConfig{}). 38 | Complete(providerconfig.NewReconciler(mgr, of, 39 | providerconfig.WithLogger(o.Logger.WithValues("controller", name)), 40 | providerconfig.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))))) 41 | } 42 | 43 | // setupNamespaced adds a controller that reconciles ProviderConfigs by accounting for 44 | // their current usage. 45 | func setupNamespaced(mgr ctrl.Manager, o controller.Options) error { 46 | name := providerconfig.ControllerName(v1beta1.ProviderConfigGroupKind) 47 | 48 | of := resource.ProviderConfigKinds{ 49 | Config: v1beta1.ProviderConfigGroupVersionKind, 50 | Usage: v1beta1.ProviderConfigUsageGroupVersionKind, 51 | UsageList: v1beta1.ProviderConfigUsageListGroupVersionKind, 52 | } 53 | 54 | return ctrl.NewControllerManagedBy(mgr). 55 | Named(name). 56 | WithOptions(o.ForControllerRuntime()). 57 | For(&v1beta1.ProviderConfig{}). 58 | Watches(&v1beta1.ProviderConfigUsage{}, &resource.EnqueueRequestForProviderConfig{}). 59 | Complete(providerconfig.NewReconciler(mgr, of, 60 | providerconfig.WithLogger(o.Logger.WithValues("controller", name)), 61 | providerconfig.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))))) 62 | } 63 | 64 | // SetupGated adds a controller that reconciles ProviderConfigs and ClusterProviderConfigs 65 | // by accounting for their current usage. 66 | func SetupGated(mgr ctrl.Manager, o controller.Options) error { 67 | o.Gate.Register(func() { 68 | if err := Setup(mgr, o); err != nil { 69 | mgr.GetLogger().Error(err, "unable to setup reconcilers", "gvk", v1beta1.ClusterProviderConfigGroupVersionKind.String(), "gvk", v1beta1.ProviderConfigGroupVersionKind.String()) 70 | } 71 | }, v1beta1.ClusterProviderConfigGroupVersionKind, v1beta1.ProviderConfigGroupVersionKind, v1beta1.ProviderConfigUsageGroupVersionKind) 72 | return nil 73 | } 74 | -------------------------------------------------------------------------------- /package/crds/template.m.crossplane.io_providerconfigusages.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.19.0 7 | name: providerconfigusages.template.m.crossplane.io 8 | spec: 9 | group: template.m.crossplane.io 10 | names: 11 | categories: 12 | - crossplane 13 | - provider 14 | - template 15 | kind: ProviderConfigUsage 16 | listKind: ProviderConfigUsageList 17 | plural: providerconfigusages 18 | singular: providerconfigusage 19 | scope: Namespaced 20 | versions: 21 | - additionalPrinterColumns: 22 | - jsonPath: .metadata.creationTimestamp 23 | name: AGE 24 | type: date 25 | - jsonPath: .providerConfigRef.name 26 | name: CONFIG-NAME 27 | type: string 28 | - jsonPath: .resourceRef.kind 29 | name: RESOURCE-KIND 30 | type: string 31 | - jsonPath: .resourceRef.name 32 | name: RESOURCE-NAME 33 | type: string 34 | name: v1beta1 35 | schema: 36 | openAPIV3Schema: 37 | description: A ProviderConfigUsage indicates that a resource is using a ProviderConfig. 38 | properties: 39 | apiVersion: 40 | description: |- 41 | APIVersion defines the versioned schema of this representation of an object. 42 | Servers should convert recognized schemas to the latest internal value, and 43 | may reject unrecognized values. 44 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 45 | type: string 46 | kind: 47 | description: |- 48 | Kind is a string value representing the REST resource this object represents. 49 | Servers may infer this from the endpoint the client submits requests to. 50 | Cannot be updated. 51 | In CamelCase. 52 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 53 | type: string 54 | metadata: 55 | type: object 56 | providerConfigRef: 57 | description: ProviderConfigReference to the provider config being used. 58 | properties: 59 | kind: 60 | description: Kind of the referenced object. 61 | type: string 62 | name: 63 | description: Name of the referenced object. 64 | type: string 65 | required: 66 | - kind 67 | - name 68 | type: object 69 | resourceRef: 70 | description: ResourceReference to the managed resource using the provider 71 | config. 72 | properties: 73 | apiVersion: 74 | description: APIVersion of the referenced object. 75 | type: string 76 | kind: 77 | description: Kind of the referenced object. 78 | type: string 79 | name: 80 | description: Name of the referenced object. 81 | type: string 82 | uid: 83 | description: UID of the referenced object. 84 | type: string 85 | required: 86 | - apiVersion 87 | - kind 88 | - name 89 | type: object 90 | required: 91 | - providerConfigRef 92 | - resourceRef 93 | type: object 94 | served: true 95 | storage: true 96 | subresources: {} 97 | -------------------------------------------------------------------------------- /hack/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euox pipefail 3 | 4 | : ${PROVIDER_NAME_LOWER:=$(read -r -p "Lower case provider name (ex. github): " PROVIDER_NAME_LOWER; echo -n "${PROVIDER_NAME_LOWER}")} 5 | : ${PROVIDER_NAME_NORMAL:=$(read -r -p "Normal case provider name (ex. GitHub): " PROVIDER_NAME_NORMAL; echo -n "${PROVIDER_NAME_NORMAL}")} 6 | : ${ORGANIZATION_NAME:=$(read -r -p "Organization (e.g., my-org-name): " ORGANIZATION_NAME; echo -n "${ORGANIZATION_NAME}")} 7 | : ${CRD_ROOT_GROUP:=$(read -r -p "CRD rootGroup (e.g., crossplane.io): " CRD_ROOT_GROUP; echo -n "${CRD_ROOT_GROUP}")} 8 | 9 | REPLACE_FILES='./* ./.github :!build/** :!go.* :!hack/prepare.sh' 10 | # shellcheck disable=SC2086 11 | git grep -l 'template' -- ${REPLACE_FILES} | xargs sed -i.bak "s/upjet-provider-template/provider-${PROVIDER_NAME_LOWER}/g" 12 | # shellcheck disable=SC2086 13 | git grep -l 'template' -- ${REPLACE_FILES} | xargs sed -i.bak "s/template/${PROVIDER_NAME_LOWER}/g" 14 | # shellcheck disable=SC2086 15 | git grep -l "crossplane/provider-${PROVIDER_NAME_LOWER}" -- ${REPLACE_FILES} | xargs sed -i.bak "s|crossplane/provider-${PROVIDER_NAME_LOWER}|${ORGANIZATION_NAME}/provider-${PROVIDER_NAME_LOWER}|g" 16 | # shellcheck disable=SC2086 17 | git grep -l 'Template' -- ${REPLACE_FILES} | xargs sed -i.bak "s/Template/${PROVIDER_NAME_NORMAL}/g" 18 | # shellcheck disable=SC2086 19 | git grep -l "crossplane.io" -- "apis/cluster/v1*" | xargs sed -i.bak "s|crossplane.io|${CRD_ROOT_GROUP}|g" 20 | git grep -l "crossplane.io" -- "apis/namespaced/v1*" | xargs sed -i.bak "s|crossplane.io|${CRD_ROOT_GROUP}|g" 21 | # shellcheck disable=SC2086 22 | git grep -l "crossplane.io" -- "cluster/test/setup.sh" | xargs sed -i.bak "s|crossplane.io|${CRD_ROOT_GROUP}|g" 23 | # shellcheck disable=SC2086 24 | git grep -l "ujconfig\.WithRootGroup(\"${PROVIDER_NAME_LOWER}\.crossplane\.io\")" -- "config/provider.go" | xargs sed -i.bak "s|ujconfig.WithRootGroup(\"${PROVIDER_NAME_LOWER}\.crossplane\.io\")|ujconfig.WithRootGroup(\"${PROVIDER_NAME_LOWER}.${CRD_ROOT_GROUP}\")|g" 25 | git grep -l "ujconfig\.WithRootGroup(\"${PROVIDER_NAME_LOWER}\.m\.crossplane\.io\")" -- "config/provider.go" | xargs sed -i.bak "s|ujconfig.WithRootGroup(\"${PROVIDER_NAME_LOWER}\.m.crossplane\.io\")|ujconfig.WithRootGroup(\"${PROVIDER_NAME_LOWER}.m.${CRD_ROOT_GROUP}\")|g" 26 | 27 | # We need to be careful while replacing "template" keyword in go.mod as it could tamper 28 | # some imported packages under require section. 29 | sed -i.bak "s|crossplane/upjet-provider-template|${ORGANIZATION_NAME}/provider-${PROVIDER_NAME_LOWER}|g" go.mod 30 | sed -i.bak -e "s|PROJECT_REPO ?= github.com/crossplane/|PROJECT_REPO ?= github.com/${ORGANIZATION_NAME}/|g" -e "s|\(blob/main/internal/\)${PROVIDER_NAME_LOWER}s|\1templates|g" Makefile 31 | sed -i.bak "s/\[YEAR\]/$(date +%Y)/g" LICENSE 32 | 33 | # Clean up the .bak files created by sed 34 | git clean -fd 35 | 36 | git mv "internal/clients/template.go" "internal/clients/${PROVIDER_NAME_LOWER}.go" 37 | git mv "cluster/images/upjet-provider-template" "cluster/images/provider-${PROVIDER_NAME_LOWER}" 38 | 39 | # We need to remove this api folder otherwise first `make generate` fails with 40 | # the following error probably due to some optimizations in go generate with v1.17: 41 | # generate: open /Users/hasanturken/Workspace/crossplane-contrib/upjet-provider-template/apis/null/v1alpha1/zz_generated.deepcopy.go: no such file or directory 42 | rm -rf apis/cluster/null 43 | rm -rf apis/namespaced/null 44 | # remove the sample directory which was a configuration in the template 45 | rm -rf config/cluster/null 46 | rm -rf config/namespaced/null 47 | # remove the sample MR example from the template 48 | rm -rf examples/cluster/null 49 | rm -rf examples/namespaced/null 50 | -------------------------------------------------------------------------------- /apis/namespaced/v1beta1/types.go: -------------------------------------------------------------------------------- 1 | package v1beta1 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | 6 | xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" 7 | xpv2 "github.com/crossplane/crossplane-runtime/v2/apis/common/v2" 8 | ) 9 | 10 | // A ProviderConfigSpec defines the desired state of a ProviderConfig. 11 | type ProviderConfigSpec struct { 12 | // Credentials required to authenticate to this provider. 13 | Credentials ProviderCredentials `json:"credentials"` 14 | } 15 | 16 | // ProviderCredentials required to authenticate. 17 | type ProviderCredentials struct { 18 | // Source of the provider credentials. 19 | // +kubebuilder:validation:Enum=None;Secret;InjectedIdentity;Environment;Filesystem 20 | Source xpv1.CredentialsSource `json:"source"` 21 | 22 | xpv1.CommonCredentialSelectors `json:",inline"` 23 | } 24 | 25 | // A ProviderConfigStatus reflects the observed state of a ProviderConfig. 26 | type ProviderConfigStatus struct { 27 | xpv1.ProviderConfigStatus `json:",inline"` 28 | } 29 | 30 | // +kubebuilder:object:root=true 31 | 32 | // A ProviderConfig configures a Template provider. 33 | // +kubebuilder:subresource:status 34 | // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" 35 | // +kubebuilder:printcolumn:name="SECRET-NAME",type="string",JSONPath=".spec.credentials.secretRef.name",priority=1 36 | // +kubebuilder:resource:scope=Namespaced 37 | // +kubebuilder:resource:scope=Namespaced,categories={crossplane,provider,template} 38 | type ProviderConfig struct { 39 | metav1.TypeMeta `json:",inline"` 40 | metav1.ObjectMeta `json:"metadata,omitempty"` 41 | 42 | Spec ProviderConfigSpec `json:"spec"` 43 | Status ProviderConfigStatus `json:"status,omitempty"` 44 | } 45 | 46 | // +kubebuilder:object:root=true 47 | 48 | // ProviderConfigList contains a list of ProviderConfig. 49 | type ProviderConfigList struct { 50 | metav1.TypeMeta `json:",inline"` 51 | metav1.ListMeta `json:"metadata,omitempty"` 52 | Items []ProviderConfig `json:"items"` 53 | } 54 | 55 | // +kubebuilder:object:root=true 56 | 57 | // A ProviderConfigUsage indicates that a resource is using a ProviderConfig. 58 | // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" 59 | // +kubebuilder:printcolumn:name="CONFIG-NAME",type="string",JSONPath=".providerConfigRef.name" 60 | // +kubebuilder:printcolumn:name="RESOURCE-KIND",type="string",JSONPath=".resourceRef.kind" 61 | // +kubebuilder:printcolumn:name="RESOURCE-NAME",type="string",JSONPath=".resourceRef.name" 62 | // +kubebuilder:resource:scope=Namespaced,categories={crossplane,provider,template} 63 | type ProviderConfigUsage struct { 64 | metav1.TypeMeta `json:",inline"` 65 | metav1.ObjectMeta `json:"metadata,omitempty"` 66 | 67 | xpv2.TypedProviderConfigUsage `json:",inline"` 68 | } 69 | 70 | // +kubebuilder:object:root=true 71 | 72 | // ProviderConfigUsageList contains a list of ProviderConfigUsage 73 | type ProviderConfigUsageList struct { 74 | metav1.TypeMeta `json:",inline"` 75 | metav1.ListMeta `json:"metadata,omitempty"` 76 | Items []ProviderConfigUsage `json:"items"` 77 | } 78 | 79 | // +kubebuilder:object:root=true 80 | 81 | // A ClusterProviderConfig configures a Template provider. 82 | // +kubebuilder:subresource:status 83 | // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" 84 | // +kubebuilder:printcolumn:name="SECRET-NAME",type="string",JSONPath=".spec.credentials.secretRef.name",priority=1 85 | // +kubebuilder:resource:scope=Cluster 86 | // +kubebuilder:resource:scope=Cluster,categories={crossplane,provider,template} 87 | type ClusterProviderConfig struct { 88 | metav1.TypeMeta `json:",inline"` 89 | metav1.ObjectMeta `json:"metadata,omitempty"` 90 | 91 | Spec ProviderConfigSpec `json:"spec"` 92 | Status ProviderConfigStatus `json:"status,omitempty"` 93 | } 94 | 95 | // +kubebuilder:object:root=true 96 | 97 | // ClusterProviderConfigList contains a list of ProviderConfig. 98 | type ClusterProviderConfigList struct { 99 | metav1.TypeMeta `json:",inline"` 100 | metav1.ListMeta `json:"metadata,omitempty"` 101 | Items []ClusterProviderConfig `json:"items"` 102 | } 103 | -------------------------------------------------------------------------------- /internal/controller/cluster/null/resource/zz_controller.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | package resource 8 | 9 | import ( 10 | "time" 11 | 12 | "github.com/crossplane/crossplane-runtime/v2/pkg/event" 13 | xpfeature "github.com/crossplane/crossplane-runtime/v2/pkg/feature" 14 | "github.com/crossplane/crossplane-runtime/v2/pkg/ratelimiter" 15 | "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed" 16 | xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource" 17 | "github.com/crossplane/crossplane-runtime/v2/pkg/statemetrics" 18 | tjcontroller "github.com/crossplane/upjet/v2/pkg/controller" 19 | "github.com/crossplane/upjet/v2/pkg/controller/handler" 20 | "github.com/crossplane/upjet/v2/pkg/terraform" 21 | "github.com/pkg/errors" 22 | ctrl "sigs.k8s.io/controller-runtime" 23 | 24 | v1alpha1 "github.com/crossplane/upjet-provider-template/apis/cluster/null/v1alpha1" 25 | features "github.com/crossplane/upjet-provider-template/internal/features" 26 | ) 27 | 28 | // SetupGated adds a controller that reconciles Resource managed resources. 29 | func SetupGated(mgr ctrl.Manager, o tjcontroller.Options) error { 30 | o.Options.Gate.Register(func() { 31 | if err := Setup(mgr, o); err != nil { 32 | mgr.GetLogger().Error(err, "unable to setup reconciler", "gvk", v1alpha1.Resource_GroupVersionKind.String()) 33 | } 34 | }, v1alpha1.Resource_GroupVersionKind) 35 | return nil 36 | } 37 | 38 | // Setup adds a controller that reconciles Resource managed resources. 39 | func Setup(mgr ctrl.Manager, o tjcontroller.Options) error { 40 | name := managed.ControllerName(v1alpha1.Resource_GroupVersionKind.String()) 41 | var initializers managed.InitializerChain 42 | eventHandler := handler.NewEventHandler(handler.WithLogger(o.Logger.WithValues("gvk", v1alpha1.Resource_GroupVersionKind))) 43 | ac := tjcontroller.NewAPICallbacks(mgr, xpresource.ManagedKind(v1alpha1.Resource_GroupVersionKind), tjcontroller.WithEventHandler(eventHandler)) 44 | opts := []managed.ReconcilerOption{ 45 | managed.WithExternalConnecter(tjcontroller.NewConnector(mgr.GetClient(), o.WorkspaceStore, o.SetupFn, o.Provider.Resources["null_resource"], tjcontroller.WithLogger(o.Logger), tjcontroller.WithConnectorEventHandler(eventHandler), 46 | tjcontroller.WithCallbackProvider(ac), 47 | )), 48 | managed.WithLogger(o.Logger.WithValues("controller", name)), 49 | managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), 50 | managed.WithFinalizer(terraform.NewWorkspaceFinalizer(o.WorkspaceStore, xpresource.NewAPIFinalizer(mgr.GetClient(), managed.FinalizerName))), 51 | managed.WithTimeout(3 * time.Minute), 52 | managed.WithInitializers(initializers), 53 | managed.WithPollInterval(o.PollInterval), 54 | } 55 | if o.PollJitter != 0 { 56 | opts = append(opts, managed.WithPollJitterHook(o.PollJitter)) 57 | } 58 | if o.Features.Enabled(features.EnableBetaManagementPolicies) { 59 | opts = append(opts, managed.WithManagementPolicies()) 60 | } 61 | if o.MetricOptions != nil { 62 | opts = append(opts, managed.WithMetricRecorder(o.MetricOptions.MRMetrics)) 63 | } 64 | 65 | // register webhooks for the kind v1alpha1.Resource 66 | // if they're enabled. 67 | if o.StartWebhooks { 68 | if err := ctrl.NewWebhookManagedBy(mgr). 69 | For(&v1alpha1.Resource{}). 70 | Complete(); err != nil { 71 | return errors.Wrap(err, "cannot register webhook for the kind v1alpha1.Resource") 72 | } 73 | } 74 | 75 | if o.MetricOptions != nil && o.MetricOptions.MRStateMetrics != nil { 76 | stateMetricsRecorder := statemetrics.NewMRStateRecorder( 77 | mgr.GetClient(), o.Logger, o.MetricOptions.MRStateMetrics, &v1alpha1.ResourceList{}, o.MetricOptions.PollStateMetricInterval, 78 | ) 79 | if err := mgr.Add(stateMetricsRecorder); err != nil { 80 | return errors.Wrap(err, "cannot register MR state metrics recorder for kind v1alpha1.ResourceList") 81 | } 82 | } 83 | 84 | if o.Features.Enabled(xpfeature.EnableAlphaChangeLogs) { 85 | opts = append(opts, managed.WithChangeLogger(o.ChangeLogOptions.ChangeLogger)) 86 | } 87 | 88 | r := managed.NewReconciler(mgr, xpresource.ManagedKind(v1alpha1.Resource_GroupVersionKind), opts...) 89 | 90 | return ctrl.NewControllerManagedBy(mgr). 91 | Named(name). 92 | WithOptions(o.ForControllerRuntime()). 93 | WithEventFilter(xpresource.DesiredStateChanged()). 94 | Watches(&v1alpha1.Resource{}, eventHandler). 95 | Complete(ratelimiter.NewReconciler(name, r, o.GlobalRateLimiter)) 96 | } 97 | -------------------------------------------------------------------------------- /internal/controller/namespaced/null/resource/zz_controller.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | package resource 8 | 9 | import ( 10 | "time" 11 | 12 | "github.com/crossplane/crossplane-runtime/v2/pkg/event" 13 | xpfeature "github.com/crossplane/crossplane-runtime/v2/pkg/feature" 14 | "github.com/crossplane/crossplane-runtime/v2/pkg/ratelimiter" 15 | "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed" 16 | xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource" 17 | "github.com/crossplane/crossplane-runtime/v2/pkg/statemetrics" 18 | tjcontroller "github.com/crossplane/upjet/v2/pkg/controller" 19 | "github.com/crossplane/upjet/v2/pkg/controller/handler" 20 | "github.com/crossplane/upjet/v2/pkg/terraform" 21 | "github.com/pkg/errors" 22 | ctrl "sigs.k8s.io/controller-runtime" 23 | 24 | v1alpha1 "github.com/crossplane/upjet-provider-template/apis/namespaced/null/v1alpha1" 25 | features "github.com/crossplane/upjet-provider-template/internal/features" 26 | ) 27 | 28 | // SetupGated adds a controller that reconciles Resource managed resources. 29 | func SetupGated(mgr ctrl.Manager, o tjcontroller.Options) error { 30 | o.Options.Gate.Register(func() { 31 | if err := Setup(mgr, o); err != nil { 32 | mgr.GetLogger().Error(err, "unable to setup reconciler", "gvk", v1alpha1.Resource_GroupVersionKind.String()) 33 | } 34 | }, v1alpha1.Resource_GroupVersionKind) 35 | return nil 36 | } 37 | 38 | // Setup adds a controller that reconciles Resource managed resources. 39 | func Setup(mgr ctrl.Manager, o tjcontroller.Options) error { 40 | name := managed.ControllerName(v1alpha1.Resource_GroupVersionKind.String()) 41 | var initializers managed.InitializerChain 42 | eventHandler := handler.NewEventHandler(handler.WithLogger(o.Logger.WithValues("gvk", v1alpha1.Resource_GroupVersionKind))) 43 | ac := tjcontroller.NewAPICallbacks(mgr, xpresource.ManagedKind(v1alpha1.Resource_GroupVersionKind), tjcontroller.WithEventHandler(eventHandler)) 44 | opts := []managed.ReconcilerOption{ 45 | managed.WithExternalConnecter(tjcontroller.NewConnector(mgr.GetClient(), o.WorkspaceStore, o.SetupFn, o.Provider.Resources["null_resource"], tjcontroller.WithLogger(o.Logger), tjcontroller.WithConnectorEventHandler(eventHandler), 46 | tjcontroller.WithCallbackProvider(ac), 47 | )), 48 | managed.WithLogger(o.Logger.WithValues("controller", name)), 49 | managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), 50 | managed.WithFinalizer(terraform.NewWorkspaceFinalizer(o.WorkspaceStore, xpresource.NewAPIFinalizer(mgr.GetClient(), managed.FinalizerName))), 51 | managed.WithTimeout(3 * time.Minute), 52 | managed.WithInitializers(initializers), 53 | managed.WithPollInterval(o.PollInterval), 54 | } 55 | if o.PollJitter != 0 { 56 | opts = append(opts, managed.WithPollJitterHook(o.PollJitter)) 57 | } 58 | if o.Features.Enabled(features.EnableBetaManagementPolicies) { 59 | opts = append(opts, managed.WithManagementPolicies()) 60 | } 61 | if o.MetricOptions != nil { 62 | opts = append(opts, managed.WithMetricRecorder(o.MetricOptions.MRMetrics)) 63 | } 64 | 65 | // register webhooks for the kind v1alpha1.Resource 66 | // if they're enabled. 67 | if o.StartWebhooks { 68 | if err := ctrl.NewWebhookManagedBy(mgr). 69 | For(&v1alpha1.Resource{}). 70 | Complete(); err != nil { 71 | return errors.Wrap(err, "cannot register webhook for the kind v1alpha1.Resource") 72 | } 73 | } 74 | 75 | if o.MetricOptions != nil && o.MetricOptions.MRStateMetrics != nil { 76 | stateMetricsRecorder := statemetrics.NewMRStateRecorder( 77 | mgr.GetClient(), o.Logger, o.MetricOptions.MRStateMetrics, &v1alpha1.ResourceList{}, o.MetricOptions.PollStateMetricInterval, 78 | ) 79 | if err := mgr.Add(stateMetricsRecorder); err != nil { 80 | return errors.Wrap(err, "cannot register MR state metrics recorder for kind v1alpha1.ResourceList") 81 | } 82 | } 83 | 84 | if o.Features.Enabled(xpfeature.EnableAlphaChangeLogs) { 85 | opts = append(opts, managed.WithChangeLogger(o.ChangeLogOptions.ChangeLogger)) 86 | } 87 | 88 | r := managed.NewReconciler(mgr, xpresource.ManagedKind(v1alpha1.Resource_GroupVersionKind), opts...) 89 | 90 | return ctrl.NewControllerManagedBy(mgr). 91 | Named(name). 92 | WithOptions(o.ForControllerRuntime()). 93 | WithEventFilter(xpresource.DesiredStateChanged()). 94 | Watches(&v1alpha1.Resource{}, eventHandler). 95 | Complete(ratelimiter.NewReconciler(name, r, o.GlobalRateLimiter)) 96 | } 97 | -------------------------------------------------------------------------------- /apis/cluster/null/v1alpha1/zz_resource_terraformed.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | package v1alpha1 8 | 9 | import ( 10 | "dario.cat/mergo" 11 | "github.com/pkg/errors" 12 | 13 | "github.com/crossplane/upjet/v2/pkg/resource" 14 | "github.com/crossplane/upjet/v2/pkg/resource/json" 15 | ) 16 | 17 | // GetTerraformResourceType returns Terraform resource type for this Resource 18 | func (mg *Resource) GetTerraformResourceType() string { 19 | return "null_resource" 20 | } 21 | 22 | // GetConnectionDetailsMapping for this Resource 23 | func (tr *Resource) GetConnectionDetailsMapping() map[string]string { 24 | return nil 25 | } 26 | 27 | // GetObservation of this Resource 28 | func (tr *Resource) GetObservation() (map[string]any, error) { 29 | o, err := json.TFParser.Marshal(tr.Status.AtProvider) 30 | if err != nil { 31 | return nil, err 32 | } 33 | base := map[string]any{} 34 | return base, json.TFParser.Unmarshal(o, &base) 35 | } 36 | 37 | // SetObservation for this Resource 38 | func (tr *Resource) SetObservation(obs map[string]any) error { 39 | p, err := json.TFParser.Marshal(obs) 40 | if err != nil { 41 | return err 42 | } 43 | return json.TFParser.Unmarshal(p, &tr.Status.AtProvider) 44 | } 45 | 46 | // GetID returns ID of underlying Terraform resource of this Resource 47 | func (tr *Resource) GetID() string { 48 | if tr.Status.AtProvider.ID == nil { 49 | return "" 50 | } 51 | return *tr.Status.AtProvider.ID 52 | } 53 | 54 | // GetParameters of this Resource 55 | func (tr *Resource) GetParameters() (map[string]any, error) { 56 | p, err := json.TFParser.Marshal(tr.Spec.ForProvider) 57 | if err != nil { 58 | return nil, err 59 | } 60 | base := map[string]any{} 61 | return base, json.TFParser.Unmarshal(p, &base) 62 | } 63 | 64 | // SetParameters for this Resource 65 | func (tr *Resource) SetParameters(params map[string]any) error { 66 | p, err := json.TFParser.Marshal(params) 67 | if err != nil { 68 | return err 69 | } 70 | return json.TFParser.Unmarshal(p, &tr.Spec.ForProvider) 71 | } 72 | 73 | // GetInitParameters of this Resource 74 | func (tr *Resource) GetInitParameters() (map[string]any, error) { 75 | p, err := json.TFParser.Marshal(tr.Spec.InitProvider) 76 | if err != nil { 77 | return nil, err 78 | } 79 | base := map[string]any{} 80 | return base, json.TFParser.Unmarshal(p, &base) 81 | } 82 | 83 | // GetInitParameters of this Resource 84 | func (tr *Resource) GetMergedParameters(shouldMergeInitProvider bool) (map[string]any, error) { 85 | params, err := tr.GetParameters() 86 | if err != nil { 87 | return nil, errors.Wrapf(err, "cannot get parameters for resource \"%s/%s\"", tr.GetNamespace(), tr.GetName()) 88 | } 89 | if !shouldMergeInitProvider { 90 | return params, nil 91 | } 92 | 93 | initParams, err := tr.GetInitParameters() 94 | if err != nil { 95 | return nil, errors.Wrapf(err, "cannot get init parameters for resource \"%s/%s\"", tr.GetNamespace(), tr.GetName()) 96 | } 97 | 98 | // Note(lsviben): mergo.WithSliceDeepCopy is needed to merge the 99 | // slices from the initProvider to forProvider. As it also sets 100 | // overwrite to true, we need to set it back to false, we don't 101 | // want to overwrite the forProvider fields with the initProvider 102 | // fields. 103 | err = mergo.Merge(¶ms, initParams, mergo.WithSliceDeepCopy, func(c *mergo.Config) { 104 | c.Overwrite = false 105 | }) 106 | if err != nil { 107 | return nil, errors.Wrapf(err, "cannot merge spec.initProvider and spec.forProvider parameters for resource \"%s/%s\"", tr.GetNamespace(), tr.GetName()) 108 | } 109 | 110 | return params, nil 111 | } 112 | 113 | // LateInitialize this Resource using its observed tfState. 114 | // returns True if there are any spec changes for the resource. 115 | func (tr *Resource) LateInitialize(attrs []byte) (bool, error) { 116 | params := &ResourceParameters{} 117 | if err := json.TFParser.Unmarshal(attrs, params); err != nil { 118 | return false, errors.Wrap(err, "failed to unmarshal Terraform state parameters for late-initialization") 119 | } 120 | opts := []resource.GenericLateInitializerOption{resource.WithZeroValueJSONOmitEmptyFilter(resource.CNameWildcard)} 121 | 122 | li := resource.NewGenericLateInitializer(opts...) 123 | return li.LateInitialize(&tr.Spec.ForProvider, params) 124 | } 125 | 126 | // GetTerraformSchemaVersion returns the associated Terraform schema version 127 | func (tr *Resource) GetTerraformSchemaVersion() int { 128 | return 0 129 | } 130 | -------------------------------------------------------------------------------- /apis/namespaced/null/v1alpha1/zz_resource_terraformed.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | package v1alpha1 8 | 9 | import ( 10 | "dario.cat/mergo" 11 | "github.com/pkg/errors" 12 | 13 | "github.com/crossplane/upjet/v2/pkg/resource" 14 | "github.com/crossplane/upjet/v2/pkg/resource/json" 15 | ) 16 | 17 | // GetTerraformResourceType returns Terraform resource type for this Resource 18 | func (mg *Resource) GetTerraformResourceType() string { 19 | return "null_resource" 20 | } 21 | 22 | // GetConnectionDetailsMapping for this Resource 23 | func (tr *Resource) GetConnectionDetailsMapping() map[string]string { 24 | return nil 25 | } 26 | 27 | // GetObservation of this Resource 28 | func (tr *Resource) GetObservation() (map[string]any, error) { 29 | o, err := json.TFParser.Marshal(tr.Status.AtProvider) 30 | if err != nil { 31 | return nil, err 32 | } 33 | base := map[string]any{} 34 | return base, json.TFParser.Unmarshal(o, &base) 35 | } 36 | 37 | // SetObservation for this Resource 38 | func (tr *Resource) SetObservation(obs map[string]any) error { 39 | p, err := json.TFParser.Marshal(obs) 40 | if err != nil { 41 | return err 42 | } 43 | return json.TFParser.Unmarshal(p, &tr.Status.AtProvider) 44 | } 45 | 46 | // GetID returns ID of underlying Terraform resource of this Resource 47 | func (tr *Resource) GetID() string { 48 | if tr.Status.AtProvider.ID == nil { 49 | return "" 50 | } 51 | return *tr.Status.AtProvider.ID 52 | } 53 | 54 | // GetParameters of this Resource 55 | func (tr *Resource) GetParameters() (map[string]any, error) { 56 | p, err := json.TFParser.Marshal(tr.Spec.ForProvider) 57 | if err != nil { 58 | return nil, err 59 | } 60 | base := map[string]any{} 61 | return base, json.TFParser.Unmarshal(p, &base) 62 | } 63 | 64 | // SetParameters for this Resource 65 | func (tr *Resource) SetParameters(params map[string]any) error { 66 | p, err := json.TFParser.Marshal(params) 67 | if err != nil { 68 | return err 69 | } 70 | return json.TFParser.Unmarshal(p, &tr.Spec.ForProvider) 71 | } 72 | 73 | // GetInitParameters of this Resource 74 | func (tr *Resource) GetInitParameters() (map[string]any, error) { 75 | p, err := json.TFParser.Marshal(tr.Spec.InitProvider) 76 | if err != nil { 77 | return nil, err 78 | } 79 | base := map[string]any{} 80 | return base, json.TFParser.Unmarshal(p, &base) 81 | } 82 | 83 | // GetInitParameters of this Resource 84 | func (tr *Resource) GetMergedParameters(shouldMergeInitProvider bool) (map[string]any, error) { 85 | params, err := tr.GetParameters() 86 | if err != nil { 87 | return nil, errors.Wrapf(err, "cannot get parameters for resource \"%s/%s\"", tr.GetNamespace(), tr.GetName()) 88 | } 89 | if !shouldMergeInitProvider { 90 | return params, nil 91 | } 92 | 93 | initParams, err := tr.GetInitParameters() 94 | if err != nil { 95 | return nil, errors.Wrapf(err, "cannot get init parameters for resource \"%s/%s\"", tr.GetNamespace(), tr.GetName()) 96 | } 97 | 98 | // Note(lsviben): mergo.WithSliceDeepCopy is needed to merge the 99 | // slices from the initProvider to forProvider. As it also sets 100 | // overwrite to true, we need to set it back to false, we don't 101 | // want to overwrite the forProvider fields with the initProvider 102 | // fields. 103 | err = mergo.Merge(¶ms, initParams, mergo.WithSliceDeepCopy, func(c *mergo.Config) { 104 | c.Overwrite = false 105 | }) 106 | if err != nil { 107 | return nil, errors.Wrapf(err, "cannot merge spec.initProvider and spec.forProvider parameters for resource \"%s/%s\"", tr.GetNamespace(), tr.GetName()) 108 | } 109 | 110 | return params, nil 111 | } 112 | 113 | // LateInitialize this Resource using its observed tfState. 114 | // returns True if there are any spec changes for the resource. 115 | func (tr *Resource) LateInitialize(attrs []byte) (bool, error) { 116 | params := &ResourceParameters{} 117 | if err := json.TFParser.Unmarshal(attrs, params); err != nil { 118 | return false, errors.Wrap(err, "failed to unmarshal Terraform state parameters for late-initialization") 119 | } 120 | opts := []resource.GenericLateInitializerOption{resource.WithZeroValueJSONOmitEmptyFilter(resource.CNameWildcard)} 121 | 122 | li := resource.NewGenericLateInitializer(opts...) 123 | return li.LateInitialize(&tr.Spec.ForProvider, params) 124 | } 125 | 126 | // GetTerraformSchemaVersion returns the associated Terraform schema version 127 | func (tr *Resource) GetTerraformSchemaVersion() int { 128 | return 0 129 | } 130 | -------------------------------------------------------------------------------- /apis/cluster/null/v1alpha1/zz_resource_types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | package v1alpha1 8 | 9 | import ( 10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 | "k8s.io/apimachinery/pkg/runtime/schema" 12 | 13 | v1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" 14 | ) 15 | 16 | type ResourceInitParameters struct { 17 | 18 | // running any associated provisioners. 19 | // A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners. 20 | // +mapType=granular 21 | Triggers map[string]*string `json:"triggers,omitempty" tf:"triggers,omitempty"` 22 | } 23 | 24 | type ResourceObservation struct { 25 | 26 | // (String) This is set to a random value at create time. 27 | ID *string `json:"id,omitempty" tf:"id,omitempty"` 28 | 29 | // running any associated provisioners. 30 | // A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners. 31 | // +mapType=granular 32 | Triggers map[string]*string `json:"triggers,omitempty" tf:"triggers,omitempty"` 33 | } 34 | 35 | type ResourceParameters struct { 36 | 37 | // running any associated provisioners. 38 | // A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners. 39 | // +kubebuilder:validation:Optional 40 | // +mapType=granular 41 | Triggers map[string]*string `json:"triggers,omitempty" tf:"triggers,omitempty"` 42 | } 43 | 44 | // ResourceSpec defines the desired state of Resource 45 | type ResourceSpec struct { 46 | v1.ResourceSpec `json:",inline"` 47 | ForProvider ResourceParameters `json:"forProvider"` 48 | // THIS IS A BETA FIELD. It will be honored 49 | // unless the Management Policies feature flag is disabled. 50 | // InitProvider holds the same fields as ForProvider, with the exception 51 | // of Identifier and other resource reference fields. The fields that are 52 | // in InitProvider are merged into ForProvider when the resource is created. 53 | // The same fields are also added to the terraform ignore_changes hook, to 54 | // avoid updating them after creation. This is useful for fields that are 55 | // required on creation, but we do not desire to update them after creation, 56 | // for example because of an external controller is managing them, like an 57 | // autoscaler. 58 | InitProvider ResourceInitParameters `json:"initProvider,omitempty"` 59 | } 60 | 61 | // ResourceStatus defines the observed state of Resource. 62 | type ResourceStatus struct { 63 | v1.ResourceStatus `json:",inline"` 64 | AtProvider ResourceObservation `json:"atProvider,omitempty"` 65 | } 66 | 67 | // +kubebuilder:object:root=true 68 | // +kubebuilder:subresource:status 69 | // +kubebuilder:storageversion 70 | 71 | // Resource is the Schema for the Resources API. The null_resource resource implements the standard resource lifecycle but takes no further action.hashicorp. The triggers argument allows specifying an arbitrary set of values that, when changed, will cause the resource to be replaced. 72 | // +kubebuilder:printcolumn:name="SYNCED",type="string",JSONPath=".status.conditions[?(@.type=='Synced')].status" 73 | // +kubebuilder:printcolumn:name="READY",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status" 74 | // +kubebuilder:printcolumn:name="EXTERNAL-NAME",type="string",JSONPath=".metadata.annotations.crossplane\\.io/external-name" 75 | // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" 76 | // +kubebuilder:resource:scope=Cluster,categories={crossplane,managed,template} 77 | type Resource struct { 78 | metav1.TypeMeta `json:",inline"` 79 | metav1.ObjectMeta `json:"metadata,omitempty"` 80 | Spec ResourceSpec `json:"spec"` 81 | Status ResourceStatus `json:"status,omitempty"` 82 | } 83 | 84 | // +kubebuilder:object:root=true 85 | 86 | // ResourceList contains a list of Resources 87 | type ResourceList struct { 88 | metav1.TypeMeta `json:",inline"` 89 | metav1.ListMeta `json:"metadata,omitempty"` 90 | Items []Resource `json:"items"` 91 | } 92 | 93 | // Repository type metadata. 94 | var ( 95 | Resource_Kind = "Resource" 96 | Resource_GroupKind = schema.GroupKind{Group: CRDGroup, Kind: Resource_Kind}.String() 97 | Resource_KindAPIVersion = Resource_Kind + "." + CRDGroupVersion.String() 98 | Resource_GroupVersionKind = CRDGroupVersion.WithKind(Resource_Kind) 99 | ) 100 | 101 | func init() { 102 | SchemeBuilder.Register(&Resource{}, &ResourceList{}) 103 | } 104 | -------------------------------------------------------------------------------- /package/crds/template.crossplane.io_providerconfigusages.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.19.0 7 | name: providerconfigusages.template.crossplane.io 8 | spec: 9 | group: template.crossplane.io 10 | names: 11 | categories: 12 | - crossplane 13 | - provider 14 | - template 15 | kind: ProviderConfigUsage 16 | listKind: ProviderConfigUsageList 17 | plural: providerconfigusages 18 | singular: providerconfigusage 19 | scope: Cluster 20 | versions: 21 | - additionalPrinterColumns: 22 | - jsonPath: .metadata.creationTimestamp 23 | name: AGE 24 | type: date 25 | - jsonPath: .providerConfigRef.name 26 | name: CONFIG-NAME 27 | type: string 28 | - jsonPath: .resourceRef.kind 29 | name: RESOURCE-KIND 30 | type: string 31 | - jsonPath: .resourceRef.name 32 | name: RESOURCE-NAME 33 | type: string 34 | name: v1beta1 35 | schema: 36 | openAPIV3Schema: 37 | description: A ProviderConfigUsage indicates that a resource is using a ProviderConfig. 38 | properties: 39 | apiVersion: 40 | description: |- 41 | APIVersion defines the versioned schema of this representation of an object. 42 | Servers should convert recognized schemas to the latest internal value, and 43 | may reject unrecognized values. 44 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 45 | type: string 46 | kind: 47 | description: |- 48 | Kind is a string value representing the REST resource this object represents. 49 | Servers may infer this from the endpoint the client submits requests to. 50 | Cannot be updated. 51 | In CamelCase. 52 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 53 | type: string 54 | metadata: 55 | type: object 56 | providerConfigRef: 57 | description: ProviderConfigReference to the provider config being used. 58 | properties: 59 | name: 60 | description: Name of the referenced object. 61 | type: string 62 | policy: 63 | description: Policies for referencing. 64 | properties: 65 | resolution: 66 | default: Required 67 | description: |- 68 | Resolution specifies whether resolution of this reference is required. 69 | The default is 'Required', which means the reconcile will fail if the 70 | reference cannot be resolved. 'Optional' means this reference will be 71 | a no-op if it cannot be resolved. 72 | enum: 73 | - Required 74 | - Optional 75 | type: string 76 | resolve: 77 | description: |- 78 | Resolve specifies when this reference should be resolved. The default 79 | is 'IfNotPresent', which will attempt to resolve the reference only when 80 | the corresponding field is not present. Use 'Always' to resolve the 81 | reference on every reconcile. 82 | enum: 83 | - Always 84 | - IfNotPresent 85 | type: string 86 | type: object 87 | required: 88 | - name 89 | type: object 90 | resourceRef: 91 | description: ResourceReference to the managed resource using the provider 92 | config. 93 | properties: 94 | apiVersion: 95 | description: APIVersion of the referenced object. 96 | type: string 97 | kind: 98 | description: Kind of the referenced object. 99 | type: string 100 | name: 101 | description: Name of the referenced object. 102 | type: string 103 | uid: 104 | description: UID of the referenced object. 105 | type: string 106 | required: 107 | - apiVersion 108 | - kind 109 | - name 110 | type: object 111 | required: 112 | - providerConfigRef 113 | - resourceRef 114 | type: object 115 | served: true 116 | storage: true 117 | subresources: {} 118 | -------------------------------------------------------------------------------- /apis/namespaced/null/v1alpha1/zz_resource_types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // Code generated by upjet. DO NOT EDIT. 6 | 7 | package v1alpha1 8 | 9 | import ( 10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 | "k8s.io/apimachinery/pkg/runtime/schema" 12 | 13 | v1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" 14 | v2 "github.com/crossplane/crossplane-runtime/v2/apis/common/v2" 15 | ) 16 | 17 | type ResourceInitParameters struct { 18 | 19 | // running any associated provisioners. 20 | // A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners. 21 | // +mapType=granular 22 | Triggers map[string]*string `json:"triggers,omitempty" tf:"triggers,omitempty"` 23 | } 24 | 25 | type ResourceObservation struct { 26 | 27 | // (String) This is set to a random value at create time. 28 | ID *string `json:"id,omitempty" tf:"id,omitempty"` 29 | 30 | // running any associated provisioners. 31 | // A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners. 32 | // +mapType=granular 33 | Triggers map[string]*string `json:"triggers,omitempty" tf:"triggers,omitempty"` 34 | } 35 | 36 | type ResourceParameters struct { 37 | 38 | // running any associated provisioners. 39 | // A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners. 40 | // +kubebuilder:validation:Optional 41 | // +mapType=granular 42 | Triggers map[string]*string `json:"triggers,omitempty" tf:"triggers,omitempty"` 43 | } 44 | 45 | // ResourceSpec defines the desired state of Resource 46 | type ResourceSpec struct { 47 | v2.ManagedResourceSpec `json:",inline"` 48 | ForProvider ResourceParameters `json:"forProvider"` 49 | // THIS IS A BETA FIELD. It will be honored 50 | // unless the Management Policies feature flag is disabled. 51 | // InitProvider holds the same fields as ForProvider, with the exception 52 | // of Identifier and other resource reference fields. The fields that are 53 | // in InitProvider are merged into ForProvider when the resource is created. 54 | // The same fields are also added to the terraform ignore_changes hook, to 55 | // avoid updating them after creation. This is useful for fields that are 56 | // required on creation, but we do not desire to update them after creation, 57 | // for example because of an external controller is managing them, like an 58 | // autoscaler. 59 | InitProvider ResourceInitParameters `json:"initProvider,omitempty"` 60 | } 61 | 62 | // ResourceStatus defines the observed state of Resource. 63 | type ResourceStatus struct { 64 | v1.ResourceStatus `json:",inline"` 65 | AtProvider ResourceObservation `json:"atProvider,omitempty"` 66 | } 67 | 68 | // +kubebuilder:object:root=true 69 | // +kubebuilder:subresource:status 70 | // +kubebuilder:storageversion 71 | 72 | // Resource is the Schema for the Resources API. The null_resource resource implements the standard resource lifecycle but takes no further action.hashicorp. The triggers argument allows specifying an arbitrary set of values that, when changed, will cause the resource to be replaced. 73 | // +kubebuilder:printcolumn:name="SYNCED",type="string",JSONPath=".status.conditions[?(@.type=='Synced')].status" 74 | // +kubebuilder:printcolumn:name="READY",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status" 75 | // +kubebuilder:printcolumn:name="EXTERNAL-NAME",type="string",JSONPath=".metadata.annotations.crossplane\\.io/external-name" 76 | // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" 77 | // +kubebuilder:resource:scope=Namespaced,categories={crossplane,managed,template} 78 | type Resource struct { 79 | metav1.TypeMeta `json:",inline"` 80 | metav1.ObjectMeta `json:"metadata,omitempty"` 81 | Spec ResourceSpec `json:"spec"` 82 | Status ResourceStatus `json:"status,omitempty"` 83 | } 84 | 85 | // +kubebuilder:object:root=true 86 | 87 | // ResourceList contains a list of Resources 88 | type ResourceList struct { 89 | metav1.TypeMeta `json:",inline"` 90 | metav1.ListMeta `json:"metadata,omitempty"` 91 | Items []Resource `json:"items"` 92 | } 93 | 94 | // Repository type metadata. 95 | var ( 96 | Resource_Kind = "Resource" 97 | Resource_GroupKind = schema.GroupKind{Group: CRDGroup, Kind: Resource_Kind}.String() 98 | Resource_KindAPIVersion = Resource_Kind + "." + CRDGroupVersion.String() 99 | Resource_GroupVersionKind = CRDGroupVersion.WithKind(Resource_Kind) 100 | ) 101 | 102 | func init() { 103 | SchemeBuilder.Register(&Resource{}, &ResourceList{}) 104 | } 105 | -------------------------------------------------------------------------------- /internal/clients/template.go: -------------------------------------------------------------------------------- 1 | package clients 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | 7 | "github.com/crossplane/crossplane-runtime/v2/pkg/resource" 8 | "github.com/pkg/errors" 9 | "k8s.io/apimachinery/pkg/types" 10 | "sigs.k8s.io/controller-runtime/pkg/client" 11 | 12 | "github.com/crossplane/upjet/v2/pkg/terraform" 13 | 14 | clusterv1beta1 "github.com/crossplane/upjet-provider-template/apis/cluster/v1beta1" 15 | namespacedv1beta1 "github.com/crossplane/upjet-provider-template/apis/namespaced/v1beta1" 16 | ) 17 | 18 | const ( 19 | // error messages 20 | errNoProviderConfig = "no providerConfigRef provided" 21 | errGetProviderConfig = "cannot get referenced ProviderConfig" 22 | errTrackUsage = "cannot track ProviderConfig usage" 23 | errExtractCredentials = "cannot extract credentials" 24 | errUnmarshalCredentials = "cannot unmarshal template credentials as JSON" 25 | ) 26 | 27 | // TerraformSetupBuilder builds Terraform a terraform.SetupFn function which 28 | // returns Terraform provider setup configuration 29 | func TerraformSetupBuilder(version, providerSource, providerVersion string) terraform.SetupFn { 30 | return func(ctx context.Context, client client.Client, mg resource.Managed) (terraform.Setup, error) { 31 | ps := terraform.Setup{ 32 | Version: version, 33 | Requirement: terraform.ProviderRequirement{ 34 | Source: providerSource, 35 | Version: providerVersion, 36 | }, 37 | } 38 | 39 | pcSpec, err := resolveProviderConfig(ctx, client, mg) 40 | if err != nil { 41 | return terraform.Setup{}, errors.Wrap(err, "cannot resolve provider config") 42 | } 43 | 44 | data, err := resource.CommonCredentialExtractor(ctx, pcSpec.Credentials.Source, client, pcSpec.Credentials.CommonCredentialSelectors) 45 | if err != nil { 46 | return ps, errors.Wrap(err, errExtractCredentials) 47 | } 48 | creds := map[string]string{} 49 | if err := json.Unmarshal(data, &creds); err != nil { 50 | return ps, errors.Wrap(err, errUnmarshalCredentials) 51 | } 52 | 53 | // Set credentials in Terraform provider configuration. 54 | /*ps.Configuration = map[string]any{ 55 | "username": creds["username"], 56 | "password": creds["password"], 57 | }*/ 58 | return ps, nil 59 | } 60 | } 61 | 62 | func toSharedPCSpec(pc *clusterv1beta1.ProviderConfig) (*namespacedv1beta1.ProviderConfigSpec, error) { 63 | if pc == nil { 64 | return nil, nil 65 | } 66 | data, err := json.Marshal(pc.Spec) 67 | if err != nil { 68 | return nil, err 69 | } 70 | 71 | var mSpec namespacedv1beta1.ProviderConfigSpec 72 | err = json.Unmarshal(data, &mSpec) 73 | return &mSpec, err 74 | } 75 | 76 | func resolveProviderConfig(ctx context.Context, crClient client.Client, mg resource.Managed) (*namespacedv1beta1.ProviderConfigSpec, error) { 77 | switch managed := mg.(type) { 78 | case resource.LegacyManaged: 79 | return resolveLegacy(ctx, crClient, managed) 80 | case resource.ModernManaged: 81 | return resolveModern(ctx, crClient, managed) 82 | default: 83 | return nil, errors.New("resource is not a managed resource") 84 | } 85 | } 86 | 87 | func resolveLegacy(ctx context.Context, client client.Client, mg resource.LegacyManaged) (*namespacedv1beta1.ProviderConfigSpec, error) { 88 | configRef := mg.GetProviderConfigReference() 89 | if configRef == nil { 90 | return nil, errors.New(errNoProviderConfig) 91 | } 92 | pc := &clusterv1beta1.ProviderConfig{} 93 | if err := client.Get(ctx, types.NamespacedName{Name: configRef.Name}, pc); err != nil { 94 | return nil, errors.Wrap(err, errGetProviderConfig) 95 | } 96 | 97 | t := resource.NewLegacyProviderConfigUsageTracker(client, &clusterv1beta1.ProviderConfigUsage{}) 98 | if err := t.Track(ctx, mg); err != nil { 99 | return nil, errors.Wrap(err, errTrackUsage) 100 | } 101 | 102 | return toSharedPCSpec(pc) 103 | } 104 | 105 | func resolveModern(ctx context.Context, crClient client.Client, mg resource.ModernManaged) (*namespacedv1beta1.ProviderConfigSpec, error) { 106 | configRef := mg.GetProviderConfigReference() 107 | if configRef == nil { 108 | return nil, errors.New(errNoProviderConfig) 109 | } 110 | 111 | pcRuntimeObj, err := crClient.Scheme().New(namespacedv1beta1.SchemeGroupVersion.WithKind(configRef.Kind)) 112 | if err != nil { 113 | return nil, errors.Wrap(err, "unknown GVK for ProviderConfig") 114 | } 115 | pcObj, ok := pcRuntimeObj.(client.Object) 116 | if !ok { 117 | // This indicates a programming error, types are not properly generated 118 | return nil, errors.New(" is not an Object") 119 | } 120 | 121 | // Namespace will be ignored if the PC is a cluster-scoped type 122 | if err := crClient.Get(ctx, types.NamespacedName{Name: configRef.Name, Namespace: mg.GetNamespace()}, pcObj); err != nil { 123 | return nil, errors.Wrap(err, errGetProviderConfig) 124 | } 125 | 126 | var pcSpec namespacedv1beta1.ProviderConfigSpec 127 | pcu := &namespacedv1beta1.ProviderConfigUsage{} 128 | switch pc := pcObj.(type) { 129 | case *namespacedv1beta1.ProviderConfig: 130 | pcSpec = pc.Spec 131 | if pcSpec.Credentials.SecretRef != nil { 132 | pcSpec.Credentials.SecretRef.Namespace = mg.GetNamespace() 133 | } 134 | case *namespacedv1beta1.ClusterProviderConfig: 135 | pcSpec = pc.Spec 136 | default: 137 | return nil, errors.New("unknown provider config type") 138 | } 139 | t := resource.NewProviderConfigUsageTracker(crClient, pcu) 140 | if err := t.Track(ctx, mg); err != nil { 141 | return nil, errors.Wrap(err, errTrackUsage) 142 | } 143 | return &pcSpec, nil 144 | } 145 | -------------------------------------------------------------------------------- /apis/cluster/v1beta1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | 3 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | 7 | // Code generated by controller-gen. DO NOT EDIT. 8 | 9 | package v1beta1 10 | 11 | import ( 12 | runtime "k8s.io/apimachinery/pkg/runtime" 13 | ) 14 | 15 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 16 | func (in *ProviderConfig) DeepCopyInto(out *ProviderConfig) { 17 | *out = *in 18 | out.TypeMeta = in.TypeMeta 19 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 20 | in.Spec.DeepCopyInto(&out.Spec) 21 | in.Status.DeepCopyInto(&out.Status) 22 | } 23 | 24 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfig. 25 | func (in *ProviderConfig) DeepCopy() *ProviderConfig { 26 | if in == nil { 27 | return nil 28 | } 29 | out := new(ProviderConfig) 30 | in.DeepCopyInto(out) 31 | return out 32 | } 33 | 34 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 35 | func (in *ProviderConfig) DeepCopyObject() runtime.Object { 36 | if c := in.DeepCopy(); c != nil { 37 | return c 38 | } 39 | return nil 40 | } 41 | 42 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 43 | func (in *ProviderConfigList) DeepCopyInto(out *ProviderConfigList) { 44 | *out = *in 45 | out.TypeMeta = in.TypeMeta 46 | in.ListMeta.DeepCopyInto(&out.ListMeta) 47 | if in.Items != nil { 48 | in, out := &in.Items, &out.Items 49 | *out = make([]ProviderConfig, len(*in)) 50 | for i := range *in { 51 | (*in)[i].DeepCopyInto(&(*out)[i]) 52 | } 53 | } 54 | } 55 | 56 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigList. 57 | func (in *ProviderConfigList) DeepCopy() *ProviderConfigList { 58 | if in == nil { 59 | return nil 60 | } 61 | out := new(ProviderConfigList) 62 | in.DeepCopyInto(out) 63 | return out 64 | } 65 | 66 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 67 | func (in *ProviderConfigList) DeepCopyObject() runtime.Object { 68 | if c := in.DeepCopy(); c != nil { 69 | return c 70 | } 71 | return nil 72 | } 73 | 74 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 75 | func (in *ProviderConfigSpec) DeepCopyInto(out *ProviderConfigSpec) { 76 | *out = *in 77 | in.Credentials.DeepCopyInto(&out.Credentials) 78 | } 79 | 80 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigSpec. 81 | func (in *ProviderConfigSpec) DeepCopy() *ProviderConfigSpec { 82 | if in == nil { 83 | return nil 84 | } 85 | out := new(ProviderConfigSpec) 86 | in.DeepCopyInto(out) 87 | return out 88 | } 89 | 90 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 91 | func (in *ProviderConfigStatus) DeepCopyInto(out *ProviderConfigStatus) { 92 | *out = *in 93 | in.ProviderConfigStatus.DeepCopyInto(&out.ProviderConfigStatus) 94 | } 95 | 96 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigStatus. 97 | func (in *ProviderConfigStatus) DeepCopy() *ProviderConfigStatus { 98 | if in == nil { 99 | return nil 100 | } 101 | out := new(ProviderConfigStatus) 102 | in.DeepCopyInto(out) 103 | return out 104 | } 105 | 106 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 107 | func (in *ProviderConfigUsage) DeepCopyInto(out *ProviderConfigUsage) { 108 | *out = *in 109 | out.TypeMeta = in.TypeMeta 110 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 111 | in.ProviderConfigUsage.DeepCopyInto(&out.ProviderConfigUsage) 112 | } 113 | 114 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigUsage. 115 | func (in *ProviderConfigUsage) DeepCopy() *ProviderConfigUsage { 116 | if in == nil { 117 | return nil 118 | } 119 | out := new(ProviderConfigUsage) 120 | in.DeepCopyInto(out) 121 | return out 122 | } 123 | 124 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 125 | func (in *ProviderConfigUsage) DeepCopyObject() runtime.Object { 126 | if c := in.DeepCopy(); c != nil { 127 | return c 128 | } 129 | return nil 130 | } 131 | 132 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 133 | func (in *ProviderConfigUsageList) DeepCopyInto(out *ProviderConfigUsageList) { 134 | *out = *in 135 | out.TypeMeta = in.TypeMeta 136 | in.ListMeta.DeepCopyInto(&out.ListMeta) 137 | if in.Items != nil { 138 | in, out := &in.Items, &out.Items 139 | *out = make([]ProviderConfigUsage, len(*in)) 140 | for i := range *in { 141 | (*in)[i].DeepCopyInto(&(*out)[i]) 142 | } 143 | } 144 | } 145 | 146 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigUsageList. 147 | func (in *ProviderConfigUsageList) DeepCopy() *ProviderConfigUsageList { 148 | if in == nil { 149 | return nil 150 | } 151 | out := new(ProviderConfigUsageList) 152 | in.DeepCopyInto(out) 153 | return out 154 | } 155 | 156 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 157 | func (in *ProviderConfigUsageList) DeepCopyObject() runtime.Object { 158 | if c := in.DeepCopy(); c != nil { 159 | return c 160 | } 161 | return nil 162 | } 163 | 164 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 165 | func (in *ProviderCredentials) DeepCopyInto(out *ProviderCredentials) { 166 | *out = *in 167 | in.CommonCredentialSelectors.DeepCopyInto(&out.CommonCredentialSelectors) 168 | } 169 | 170 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderCredentials. 171 | func (in *ProviderCredentials) DeepCopy() *ProviderCredentials { 172 | if in == nil { 173 | return nil 174 | } 175 | out := new(ProviderCredentials) 176 | in.DeepCopyInto(out) 177 | return out 178 | } 179 | -------------------------------------------------------------------------------- /apis/cluster/null/v1alpha1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | 3 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | 7 | // Code generated by controller-gen. DO NOT EDIT. 8 | 9 | package v1alpha1 10 | 11 | import ( 12 | runtime "k8s.io/apimachinery/pkg/runtime" 13 | ) 14 | 15 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 16 | func (in *Resource) DeepCopyInto(out *Resource) { 17 | *out = *in 18 | out.TypeMeta = in.TypeMeta 19 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 20 | in.Spec.DeepCopyInto(&out.Spec) 21 | in.Status.DeepCopyInto(&out.Status) 22 | } 23 | 24 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resource. 25 | func (in *Resource) DeepCopy() *Resource { 26 | if in == nil { 27 | return nil 28 | } 29 | out := new(Resource) 30 | in.DeepCopyInto(out) 31 | return out 32 | } 33 | 34 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 35 | func (in *Resource) DeepCopyObject() runtime.Object { 36 | if c := in.DeepCopy(); c != nil { 37 | return c 38 | } 39 | return nil 40 | } 41 | 42 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 43 | func (in *ResourceInitParameters) DeepCopyInto(out *ResourceInitParameters) { 44 | *out = *in 45 | if in.Triggers != nil { 46 | in, out := &in.Triggers, &out.Triggers 47 | *out = make(map[string]*string, len(*in)) 48 | for key, val := range *in { 49 | var outVal *string 50 | if val == nil { 51 | (*out)[key] = nil 52 | } else { 53 | inVal := (*in)[key] 54 | in, out := &inVal, &outVal 55 | *out = new(string) 56 | **out = **in 57 | } 58 | (*out)[key] = outVal 59 | } 60 | } 61 | } 62 | 63 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceInitParameters. 64 | func (in *ResourceInitParameters) DeepCopy() *ResourceInitParameters { 65 | if in == nil { 66 | return nil 67 | } 68 | out := new(ResourceInitParameters) 69 | in.DeepCopyInto(out) 70 | return out 71 | } 72 | 73 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 74 | func (in *ResourceList) DeepCopyInto(out *ResourceList) { 75 | *out = *in 76 | out.TypeMeta = in.TypeMeta 77 | in.ListMeta.DeepCopyInto(&out.ListMeta) 78 | if in.Items != nil { 79 | in, out := &in.Items, &out.Items 80 | *out = make([]Resource, len(*in)) 81 | for i := range *in { 82 | (*in)[i].DeepCopyInto(&(*out)[i]) 83 | } 84 | } 85 | } 86 | 87 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceList. 88 | func (in *ResourceList) DeepCopy() *ResourceList { 89 | if in == nil { 90 | return nil 91 | } 92 | out := new(ResourceList) 93 | in.DeepCopyInto(out) 94 | return out 95 | } 96 | 97 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 98 | func (in *ResourceList) DeepCopyObject() runtime.Object { 99 | if c := in.DeepCopy(); c != nil { 100 | return c 101 | } 102 | return nil 103 | } 104 | 105 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 106 | func (in *ResourceObservation) DeepCopyInto(out *ResourceObservation) { 107 | *out = *in 108 | if in.ID != nil { 109 | in, out := &in.ID, &out.ID 110 | *out = new(string) 111 | **out = **in 112 | } 113 | if in.Triggers != nil { 114 | in, out := &in.Triggers, &out.Triggers 115 | *out = make(map[string]*string, len(*in)) 116 | for key, val := range *in { 117 | var outVal *string 118 | if val == nil { 119 | (*out)[key] = nil 120 | } else { 121 | inVal := (*in)[key] 122 | in, out := &inVal, &outVal 123 | *out = new(string) 124 | **out = **in 125 | } 126 | (*out)[key] = outVal 127 | } 128 | } 129 | } 130 | 131 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceObservation. 132 | func (in *ResourceObservation) DeepCopy() *ResourceObservation { 133 | if in == nil { 134 | return nil 135 | } 136 | out := new(ResourceObservation) 137 | in.DeepCopyInto(out) 138 | return out 139 | } 140 | 141 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 142 | func (in *ResourceParameters) DeepCopyInto(out *ResourceParameters) { 143 | *out = *in 144 | if in.Triggers != nil { 145 | in, out := &in.Triggers, &out.Triggers 146 | *out = make(map[string]*string, len(*in)) 147 | for key, val := range *in { 148 | var outVal *string 149 | if val == nil { 150 | (*out)[key] = nil 151 | } else { 152 | inVal := (*in)[key] 153 | in, out := &inVal, &outVal 154 | *out = new(string) 155 | **out = **in 156 | } 157 | (*out)[key] = outVal 158 | } 159 | } 160 | } 161 | 162 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceParameters. 163 | func (in *ResourceParameters) DeepCopy() *ResourceParameters { 164 | if in == nil { 165 | return nil 166 | } 167 | out := new(ResourceParameters) 168 | in.DeepCopyInto(out) 169 | return out 170 | } 171 | 172 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 173 | func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) { 174 | *out = *in 175 | in.ResourceSpec.DeepCopyInto(&out.ResourceSpec) 176 | in.ForProvider.DeepCopyInto(&out.ForProvider) 177 | in.InitProvider.DeepCopyInto(&out.InitProvider) 178 | } 179 | 180 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSpec. 181 | func (in *ResourceSpec) DeepCopy() *ResourceSpec { 182 | if in == nil { 183 | return nil 184 | } 185 | out := new(ResourceSpec) 186 | in.DeepCopyInto(out) 187 | return out 188 | } 189 | 190 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 191 | func (in *ResourceStatus) DeepCopyInto(out *ResourceStatus) { 192 | *out = *in 193 | in.ResourceStatus.DeepCopyInto(&out.ResourceStatus) 194 | in.AtProvider.DeepCopyInto(&out.AtProvider) 195 | } 196 | 197 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceStatus. 198 | func (in *ResourceStatus) DeepCopy() *ResourceStatus { 199 | if in == nil { 200 | return nil 201 | } 202 | out := new(ResourceStatus) 203 | in.DeepCopyInto(out) 204 | return out 205 | } 206 | -------------------------------------------------------------------------------- /apis/namespaced/null/v1alpha1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | 3 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | 7 | // Code generated by controller-gen. DO NOT EDIT. 8 | 9 | package v1alpha1 10 | 11 | import ( 12 | runtime "k8s.io/apimachinery/pkg/runtime" 13 | ) 14 | 15 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 16 | func (in *Resource) DeepCopyInto(out *Resource) { 17 | *out = *in 18 | out.TypeMeta = in.TypeMeta 19 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 20 | in.Spec.DeepCopyInto(&out.Spec) 21 | in.Status.DeepCopyInto(&out.Status) 22 | } 23 | 24 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resource. 25 | func (in *Resource) DeepCopy() *Resource { 26 | if in == nil { 27 | return nil 28 | } 29 | out := new(Resource) 30 | in.DeepCopyInto(out) 31 | return out 32 | } 33 | 34 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 35 | func (in *Resource) DeepCopyObject() runtime.Object { 36 | if c := in.DeepCopy(); c != nil { 37 | return c 38 | } 39 | return nil 40 | } 41 | 42 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 43 | func (in *ResourceInitParameters) DeepCopyInto(out *ResourceInitParameters) { 44 | *out = *in 45 | if in.Triggers != nil { 46 | in, out := &in.Triggers, &out.Triggers 47 | *out = make(map[string]*string, len(*in)) 48 | for key, val := range *in { 49 | var outVal *string 50 | if val == nil { 51 | (*out)[key] = nil 52 | } else { 53 | inVal := (*in)[key] 54 | in, out := &inVal, &outVal 55 | *out = new(string) 56 | **out = **in 57 | } 58 | (*out)[key] = outVal 59 | } 60 | } 61 | } 62 | 63 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceInitParameters. 64 | func (in *ResourceInitParameters) DeepCopy() *ResourceInitParameters { 65 | if in == nil { 66 | return nil 67 | } 68 | out := new(ResourceInitParameters) 69 | in.DeepCopyInto(out) 70 | return out 71 | } 72 | 73 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 74 | func (in *ResourceList) DeepCopyInto(out *ResourceList) { 75 | *out = *in 76 | out.TypeMeta = in.TypeMeta 77 | in.ListMeta.DeepCopyInto(&out.ListMeta) 78 | if in.Items != nil { 79 | in, out := &in.Items, &out.Items 80 | *out = make([]Resource, len(*in)) 81 | for i := range *in { 82 | (*in)[i].DeepCopyInto(&(*out)[i]) 83 | } 84 | } 85 | } 86 | 87 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceList. 88 | func (in *ResourceList) DeepCopy() *ResourceList { 89 | if in == nil { 90 | return nil 91 | } 92 | out := new(ResourceList) 93 | in.DeepCopyInto(out) 94 | return out 95 | } 96 | 97 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 98 | func (in *ResourceList) DeepCopyObject() runtime.Object { 99 | if c := in.DeepCopy(); c != nil { 100 | return c 101 | } 102 | return nil 103 | } 104 | 105 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 106 | func (in *ResourceObservation) DeepCopyInto(out *ResourceObservation) { 107 | *out = *in 108 | if in.ID != nil { 109 | in, out := &in.ID, &out.ID 110 | *out = new(string) 111 | **out = **in 112 | } 113 | if in.Triggers != nil { 114 | in, out := &in.Triggers, &out.Triggers 115 | *out = make(map[string]*string, len(*in)) 116 | for key, val := range *in { 117 | var outVal *string 118 | if val == nil { 119 | (*out)[key] = nil 120 | } else { 121 | inVal := (*in)[key] 122 | in, out := &inVal, &outVal 123 | *out = new(string) 124 | **out = **in 125 | } 126 | (*out)[key] = outVal 127 | } 128 | } 129 | } 130 | 131 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceObservation. 132 | func (in *ResourceObservation) DeepCopy() *ResourceObservation { 133 | if in == nil { 134 | return nil 135 | } 136 | out := new(ResourceObservation) 137 | in.DeepCopyInto(out) 138 | return out 139 | } 140 | 141 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 142 | func (in *ResourceParameters) DeepCopyInto(out *ResourceParameters) { 143 | *out = *in 144 | if in.Triggers != nil { 145 | in, out := &in.Triggers, &out.Triggers 146 | *out = make(map[string]*string, len(*in)) 147 | for key, val := range *in { 148 | var outVal *string 149 | if val == nil { 150 | (*out)[key] = nil 151 | } else { 152 | inVal := (*in)[key] 153 | in, out := &inVal, &outVal 154 | *out = new(string) 155 | **out = **in 156 | } 157 | (*out)[key] = outVal 158 | } 159 | } 160 | } 161 | 162 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceParameters. 163 | func (in *ResourceParameters) DeepCopy() *ResourceParameters { 164 | if in == nil { 165 | return nil 166 | } 167 | out := new(ResourceParameters) 168 | in.DeepCopyInto(out) 169 | return out 170 | } 171 | 172 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 173 | func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) { 174 | *out = *in 175 | in.ManagedResourceSpec.DeepCopyInto(&out.ManagedResourceSpec) 176 | in.ForProvider.DeepCopyInto(&out.ForProvider) 177 | in.InitProvider.DeepCopyInto(&out.InitProvider) 178 | } 179 | 180 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSpec. 181 | func (in *ResourceSpec) DeepCopy() *ResourceSpec { 182 | if in == nil { 183 | return nil 184 | } 185 | out := new(ResourceSpec) 186 | in.DeepCopyInto(out) 187 | return out 188 | } 189 | 190 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 191 | func (in *ResourceStatus) DeepCopyInto(out *ResourceStatus) { 192 | *out = *in 193 | in.ResourceStatus.DeepCopyInto(&out.ResourceStatus) 194 | in.AtProvider.DeepCopyInto(&out.AtProvider) 195 | } 196 | 197 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceStatus. 198 | func (in *ResourceStatus) DeepCopy() *ResourceStatus { 199 | if in == nil { 200 | return nil 201 | } 202 | out := new(ResourceStatus) 203 | in.DeepCopyInto(out) 204 | return out 205 | } 206 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/crossplane/upjet-provider-template 2 | 3 | go 1.24.11 4 | 5 | tool golang.org/x/tools/cmd/goimports 6 | 7 | require ( 8 | dario.cat/mergo v1.0.2 9 | github.com/alecthomas/kingpin/v2 v2.4.0 10 | github.com/crossplane/crossplane-runtime/v2 v2.1.0 11 | github.com/crossplane/crossplane-tools v0.0.0-20251017183449-dd4517244339 12 | github.com/crossplane/upjet/v2 v2.2.0 13 | github.com/pkg/errors v0.9.1 14 | google.golang.org/grpc v1.72.1 15 | k8s.io/api v0.34.3 16 | k8s.io/apiextensions-apiserver v0.34.3 17 | k8s.io/apimachinery v0.34.3 18 | k8s.io/client-go v0.34.3 19 | sigs.k8s.io/controller-runtime v0.22.4 20 | sigs.k8s.io/controller-tools v0.19.0 21 | ) 22 | 23 | require ( 24 | github.com/agext/levenshtein v1.2.3 // indirect 25 | github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect 26 | github.com/antchfx/htmlquery v1.2.4 // indirect 27 | github.com/antchfx/xpath v1.2.0 // indirect 28 | github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect 29 | github.com/beorn7/perks v1.0.1 // indirect 30 | github.com/blang/semver/v4 v4.0.0 // indirect 31 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 32 | github.com/dave/jennifer v1.7.1 // indirect 33 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 34 | github.com/emicklei/go-restful/v3 v3.12.2 // indirect 35 | github.com/evanphx/json-patch v5.9.11+incompatible // indirect 36 | github.com/evanphx/json-patch/v5 v5.9.11 // indirect 37 | github.com/fatih/camelcase v1.0.0 // indirect 38 | github.com/fatih/color v1.18.0 // indirect 39 | github.com/fsnotify/fsnotify v1.9.0 // indirect 40 | github.com/fxamacker/cbor/v2 v2.9.0 // indirect 41 | github.com/go-logr/logr v1.4.3 // indirect 42 | github.com/go-logr/zapr v1.3.0 // indirect 43 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 44 | github.com/go-openapi/jsonreference v0.21.0 // indirect 45 | github.com/go-openapi/swag v0.23.0 // indirect 46 | github.com/gobuffalo/flect v1.0.3 // indirect 47 | github.com/gogo/protobuf v1.3.2 // indirect 48 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 49 | github.com/golang/mock v1.6.0 // indirect 50 | github.com/golang/protobuf v1.5.4 // indirect 51 | github.com/google/btree v1.1.3 // indirect 52 | github.com/google/gnostic-models v0.7.0 // indirect 53 | github.com/google/go-cmp v0.7.0 // indirect 54 | github.com/google/uuid v1.6.0 // indirect 55 | github.com/hashicorp/go-cty v1.5.0 // indirect 56 | github.com/hashicorp/go-hclog v1.6.3 // indirect 57 | github.com/hashicorp/go-plugin v1.6.3 // indirect 58 | github.com/hashicorp/go-uuid v1.0.3 // indirect 59 | github.com/hashicorp/go-version v1.7.0 // indirect 60 | github.com/hashicorp/hcl/v2 v2.23.0 // indirect 61 | github.com/hashicorp/logutils v1.0.0 // indirect 62 | github.com/hashicorp/terraform-json v0.25.0 // indirect 63 | github.com/hashicorp/terraform-plugin-framework v1.15.0 // indirect 64 | github.com/hashicorp/terraform-plugin-go v0.28.0 // indirect 65 | github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect 66 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 // indirect 67 | github.com/hashicorp/terraform-registry-address v0.2.5 // indirect 68 | github.com/hashicorp/terraform-svchost v0.1.1 // indirect 69 | github.com/hashicorp/yamux v0.1.1 // indirect 70 | github.com/iancoleman/strcase v0.2.0 // indirect 71 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 72 | github.com/josharian/intern v1.0.0 // indirect 73 | github.com/json-iterator/go v1.1.12 // indirect 74 | github.com/mailru/easyjson v0.7.7 // indirect 75 | github.com/mattn/go-colorable v0.1.13 // indirect 76 | github.com/mattn/go-isatty v0.0.20 // indirect 77 | github.com/mitchellh/copystructure v1.2.0 // indirect 78 | github.com/mitchellh/go-ps v1.0.0 // indirect 79 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 80 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 81 | github.com/mitchellh/mapstructure v1.5.0 // indirect 82 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 83 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 84 | github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect 85 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 86 | github.com/muvaf/typewriter v0.0.0-20240614220100-70f9d4a54ea0 // indirect 87 | github.com/oklog/run v1.0.0 // indirect 88 | github.com/pmezard/go-difflib v1.0.0 // indirect 89 | github.com/prometheus/client_golang v1.22.0 // indirect 90 | github.com/prometheus/client_model v0.6.1 // indirect 91 | github.com/prometheus/common v0.62.0 // indirect 92 | github.com/prometheus/procfs v0.15.1 // indirect 93 | github.com/spf13/afero v1.12.0 // indirect 94 | github.com/spf13/cobra v1.9.1 // indirect 95 | github.com/spf13/pflag v1.0.7 // indirect 96 | github.com/tmccombs/hcl2json v0.3.3 // indirect 97 | github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect 98 | github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect 99 | github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 100 | github.com/x448/float16 v0.8.4 // indirect 101 | github.com/xhit/go-str2duration/v2 v2.1.0 // indirect 102 | github.com/yuin/goldmark v1.4.13 // indirect 103 | github.com/zclconf/go-cty v1.16.2 // indirect 104 | github.com/zclconf/go-cty-yaml v1.0.3 // indirect 105 | go.opentelemetry.io/otel v1.35.0 // indirect 106 | go.opentelemetry.io/otel/trace v1.35.0 // indirect 107 | go.uber.org/multierr v1.11.0 // indirect 108 | go.uber.org/zap v1.27.0 // indirect 109 | go.yaml.in/yaml/v2 v2.4.2 // indirect 110 | go.yaml.in/yaml/v3 v3.0.4 // indirect 111 | golang.org/x/mod v0.27.0 // indirect 112 | golang.org/x/net v0.43.0 // indirect 113 | golang.org/x/oauth2 v0.29.0 // indirect 114 | golang.org/x/sync v0.16.0 // indirect 115 | golang.org/x/sys v0.35.0 // indirect 116 | golang.org/x/term v0.34.0 // indirect 117 | golang.org/x/text v0.28.0 // indirect 118 | golang.org/x/time v0.11.0 // indirect 119 | golang.org/x/tools v0.36.0 // indirect 120 | gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect 121 | google.golang.org/appengine v1.6.8 // indirect 122 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect 123 | google.golang.org/protobuf v1.36.7 // indirect 124 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect 125 | gopkg.in/inf.v0 v0.9.1 // indirect 126 | gopkg.in/yaml.v2 v2.4.0 // indirect 127 | gopkg.in/yaml.v3 v3.0.1 // indirect 128 | k8s.io/code-generator v0.34.3 // indirect 129 | k8s.io/component-base v0.34.3 // indirect 130 | k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f // indirect 131 | k8s.io/klog/v2 v2.130.1 // indirect 132 | k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect 133 | k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect 134 | sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect 135 | sigs.k8s.io/randfill v1.0.0 // indirect 136 | sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect 137 | sigs.k8s.io/yaml v1.6.0 // indirect 138 | ) 139 | -------------------------------------------------------------------------------- /package/crds/template.crossplane.io_providerconfigs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.19.0 7 | name: providerconfigs.template.crossplane.io 8 | spec: 9 | group: template.crossplane.io 10 | names: 11 | categories: 12 | - crossplane 13 | - provider 14 | - template 15 | kind: ProviderConfig 16 | listKind: ProviderConfigList 17 | plural: providerconfigs 18 | singular: providerconfig 19 | scope: Cluster 20 | versions: 21 | - additionalPrinterColumns: 22 | - jsonPath: .metadata.creationTimestamp 23 | name: AGE 24 | type: date 25 | - jsonPath: .spec.credentials.secretRef.name 26 | name: SECRET-NAME 27 | priority: 1 28 | type: string 29 | name: v1beta1 30 | schema: 31 | openAPIV3Schema: 32 | description: A ProviderConfig configures a Template provider. 33 | properties: 34 | apiVersion: 35 | description: |- 36 | APIVersion defines the versioned schema of this representation of an object. 37 | Servers should convert recognized schemas to the latest internal value, and 38 | may reject unrecognized values. 39 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 40 | type: string 41 | kind: 42 | description: |- 43 | Kind is a string value representing the REST resource this object represents. 44 | Servers may infer this from the endpoint the client submits requests to. 45 | Cannot be updated. 46 | In CamelCase. 47 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 48 | type: string 49 | metadata: 50 | type: object 51 | spec: 52 | description: A ProviderConfigSpec defines the desired state of a ProviderConfig. 53 | properties: 54 | credentials: 55 | description: Credentials required to authenticate to this provider. 56 | properties: 57 | env: 58 | description: |- 59 | Env is a reference to an environment variable that contains credentials 60 | that must be used to connect to the provider. 61 | properties: 62 | name: 63 | description: Name is the name of an environment variable. 64 | type: string 65 | required: 66 | - name 67 | type: object 68 | fs: 69 | description: |- 70 | Fs is a reference to a filesystem location that contains credentials that 71 | must be used to connect to the provider. 72 | properties: 73 | path: 74 | description: Path is a filesystem path. 75 | type: string 76 | required: 77 | - path 78 | type: object 79 | secretRef: 80 | description: |- 81 | A SecretRef is a reference to a secret key that contains the credentials 82 | that must be used to connect to the provider. 83 | properties: 84 | key: 85 | description: The key to select. 86 | type: string 87 | name: 88 | description: Name of the secret. 89 | type: string 90 | namespace: 91 | description: Namespace of the secret. 92 | type: string 93 | required: 94 | - key 95 | - name 96 | - namespace 97 | type: object 98 | source: 99 | description: Source of the provider credentials. 100 | enum: 101 | - None 102 | - Secret 103 | - InjectedIdentity 104 | - Environment 105 | - Filesystem 106 | type: string 107 | required: 108 | - source 109 | type: object 110 | required: 111 | - credentials 112 | type: object 113 | status: 114 | description: A ProviderConfigStatus reflects the observed state of a ProviderConfig. 115 | properties: 116 | conditions: 117 | description: Conditions of the resource. 118 | items: 119 | description: A Condition that may apply to a resource. 120 | properties: 121 | lastTransitionTime: 122 | description: |- 123 | LastTransitionTime is the last time this condition transitioned from one 124 | status to another. 125 | format: date-time 126 | type: string 127 | message: 128 | description: |- 129 | A Message containing details about this condition's last transition from 130 | one status to another, if any. 131 | type: string 132 | observedGeneration: 133 | description: |- 134 | ObservedGeneration represents the .metadata.generation that the condition was set based upon. 135 | For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date 136 | with respect to the current state of the instance. 137 | format: int64 138 | type: integer 139 | reason: 140 | description: A Reason for this condition's last transition from 141 | one status to another. 142 | type: string 143 | status: 144 | description: Status of this condition; is it currently True, 145 | False, or Unknown? 146 | type: string 147 | type: 148 | description: |- 149 | Type of this condition. At most one of each condition type may apply to 150 | a resource at any point in time. 151 | type: string 152 | required: 153 | - lastTransitionTime 154 | - reason 155 | - status 156 | - type 157 | type: object 158 | type: array 159 | x-kubernetes-list-map-keys: 160 | - type 161 | x-kubernetes-list-type: map 162 | users: 163 | description: Users of this provider configuration. 164 | format: int64 165 | type: integer 166 | type: object 167 | required: 168 | - spec 169 | type: object 170 | served: true 171 | storage: true 172 | subresources: 173 | status: {} 174 | -------------------------------------------------------------------------------- /package/crds/template.m.crossplane.io_providerconfigs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.19.0 7 | name: providerconfigs.template.m.crossplane.io 8 | spec: 9 | group: template.m.crossplane.io 10 | names: 11 | categories: 12 | - crossplane 13 | - provider 14 | - template 15 | kind: ProviderConfig 16 | listKind: ProviderConfigList 17 | plural: providerconfigs 18 | singular: providerconfig 19 | scope: Namespaced 20 | versions: 21 | - additionalPrinterColumns: 22 | - jsonPath: .metadata.creationTimestamp 23 | name: AGE 24 | type: date 25 | - jsonPath: .spec.credentials.secretRef.name 26 | name: SECRET-NAME 27 | priority: 1 28 | type: string 29 | name: v1beta1 30 | schema: 31 | openAPIV3Schema: 32 | description: A ProviderConfig configures a Template provider. 33 | properties: 34 | apiVersion: 35 | description: |- 36 | APIVersion defines the versioned schema of this representation of an object. 37 | Servers should convert recognized schemas to the latest internal value, and 38 | may reject unrecognized values. 39 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 40 | type: string 41 | kind: 42 | description: |- 43 | Kind is a string value representing the REST resource this object represents. 44 | Servers may infer this from the endpoint the client submits requests to. 45 | Cannot be updated. 46 | In CamelCase. 47 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 48 | type: string 49 | metadata: 50 | type: object 51 | spec: 52 | description: A ProviderConfigSpec defines the desired state of a ProviderConfig. 53 | properties: 54 | credentials: 55 | description: Credentials required to authenticate to this provider. 56 | properties: 57 | env: 58 | description: |- 59 | Env is a reference to an environment variable that contains credentials 60 | that must be used to connect to the provider. 61 | properties: 62 | name: 63 | description: Name is the name of an environment variable. 64 | type: string 65 | required: 66 | - name 67 | type: object 68 | fs: 69 | description: |- 70 | Fs is a reference to a filesystem location that contains credentials that 71 | must be used to connect to the provider. 72 | properties: 73 | path: 74 | description: Path is a filesystem path. 75 | type: string 76 | required: 77 | - path 78 | type: object 79 | secretRef: 80 | description: |- 81 | A SecretRef is a reference to a secret key that contains the credentials 82 | that must be used to connect to the provider. 83 | properties: 84 | key: 85 | description: The key to select. 86 | type: string 87 | name: 88 | description: Name of the secret. 89 | type: string 90 | namespace: 91 | description: Namespace of the secret. 92 | type: string 93 | required: 94 | - key 95 | - name 96 | - namespace 97 | type: object 98 | source: 99 | description: Source of the provider credentials. 100 | enum: 101 | - None 102 | - Secret 103 | - InjectedIdentity 104 | - Environment 105 | - Filesystem 106 | type: string 107 | required: 108 | - source 109 | type: object 110 | required: 111 | - credentials 112 | type: object 113 | status: 114 | description: A ProviderConfigStatus reflects the observed state of a ProviderConfig. 115 | properties: 116 | conditions: 117 | description: Conditions of the resource. 118 | items: 119 | description: A Condition that may apply to a resource. 120 | properties: 121 | lastTransitionTime: 122 | description: |- 123 | LastTransitionTime is the last time this condition transitioned from one 124 | status to another. 125 | format: date-time 126 | type: string 127 | message: 128 | description: |- 129 | A Message containing details about this condition's last transition from 130 | one status to another, if any. 131 | type: string 132 | observedGeneration: 133 | description: |- 134 | ObservedGeneration represents the .metadata.generation that the condition was set based upon. 135 | For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date 136 | with respect to the current state of the instance. 137 | format: int64 138 | type: integer 139 | reason: 140 | description: A Reason for this condition's last transition from 141 | one status to another. 142 | type: string 143 | status: 144 | description: Status of this condition; is it currently True, 145 | False, or Unknown? 146 | type: string 147 | type: 148 | description: |- 149 | Type of this condition. At most one of each condition type may apply to 150 | a resource at any point in time. 151 | type: string 152 | required: 153 | - lastTransitionTime 154 | - reason 155 | - status 156 | - type 157 | type: object 158 | type: array 159 | x-kubernetes-list-map-keys: 160 | - type 161 | x-kubernetes-list-type: map 162 | users: 163 | description: Users of this provider configuration. 164 | format: int64 165 | type: integer 166 | type: object 167 | required: 168 | - spec 169 | type: object 170 | served: true 171 | storage: true 172 | subresources: 173 | status: {} 174 | -------------------------------------------------------------------------------- /package/crds/template.m.crossplane.io_clusterproviderconfigs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.19.0 7 | name: clusterproviderconfigs.template.m.crossplane.io 8 | spec: 9 | group: template.m.crossplane.io 10 | names: 11 | categories: 12 | - crossplane 13 | - provider 14 | - template 15 | kind: ClusterProviderConfig 16 | listKind: ClusterProviderConfigList 17 | plural: clusterproviderconfigs 18 | singular: clusterproviderconfig 19 | scope: Cluster 20 | versions: 21 | - additionalPrinterColumns: 22 | - jsonPath: .metadata.creationTimestamp 23 | name: AGE 24 | type: date 25 | - jsonPath: .spec.credentials.secretRef.name 26 | name: SECRET-NAME 27 | priority: 1 28 | type: string 29 | name: v1beta1 30 | schema: 31 | openAPIV3Schema: 32 | description: A ClusterProviderConfig configures a Template provider. 33 | properties: 34 | apiVersion: 35 | description: |- 36 | APIVersion defines the versioned schema of this representation of an object. 37 | Servers should convert recognized schemas to the latest internal value, and 38 | may reject unrecognized values. 39 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 40 | type: string 41 | kind: 42 | description: |- 43 | Kind is a string value representing the REST resource this object represents. 44 | Servers may infer this from the endpoint the client submits requests to. 45 | Cannot be updated. 46 | In CamelCase. 47 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 48 | type: string 49 | metadata: 50 | type: object 51 | spec: 52 | description: A ProviderConfigSpec defines the desired state of a ProviderConfig. 53 | properties: 54 | credentials: 55 | description: Credentials required to authenticate to this provider. 56 | properties: 57 | env: 58 | description: |- 59 | Env is a reference to an environment variable that contains credentials 60 | that must be used to connect to the provider. 61 | properties: 62 | name: 63 | description: Name is the name of an environment variable. 64 | type: string 65 | required: 66 | - name 67 | type: object 68 | fs: 69 | description: |- 70 | Fs is a reference to a filesystem location that contains credentials that 71 | must be used to connect to the provider. 72 | properties: 73 | path: 74 | description: Path is a filesystem path. 75 | type: string 76 | required: 77 | - path 78 | type: object 79 | secretRef: 80 | description: |- 81 | A SecretRef is a reference to a secret key that contains the credentials 82 | that must be used to connect to the provider. 83 | properties: 84 | key: 85 | description: The key to select. 86 | type: string 87 | name: 88 | description: Name of the secret. 89 | type: string 90 | namespace: 91 | description: Namespace of the secret. 92 | type: string 93 | required: 94 | - key 95 | - name 96 | - namespace 97 | type: object 98 | source: 99 | description: Source of the provider credentials. 100 | enum: 101 | - None 102 | - Secret 103 | - InjectedIdentity 104 | - Environment 105 | - Filesystem 106 | type: string 107 | required: 108 | - source 109 | type: object 110 | required: 111 | - credentials 112 | type: object 113 | status: 114 | description: A ProviderConfigStatus reflects the observed state of a ProviderConfig. 115 | properties: 116 | conditions: 117 | description: Conditions of the resource. 118 | items: 119 | description: A Condition that may apply to a resource. 120 | properties: 121 | lastTransitionTime: 122 | description: |- 123 | LastTransitionTime is the last time this condition transitioned from one 124 | status to another. 125 | format: date-time 126 | type: string 127 | message: 128 | description: |- 129 | A Message containing details about this condition's last transition from 130 | one status to another, if any. 131 | type: string 132 | observedGeneration: 133 | description: |- 134 | ObservedGeneration represents the .metadata.generation that the condition was set based upon. 135 | For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date 136 | with respect to the current state of the instance. 137 | format: int64 138 | type: integer 139 | reason: 140 | description: A Reason for this condition's last transition from 141 | one status to another. 142 | type: string 143 | status: 144 | description: Status of this condition; is it currently True, 145 | False, or Unknown? 146 | type: string 147 | type: 148 | description: |- 149 | Type of this condition. At most one of each condition type may apply to 150 | a resource at any point in time. 151 | type: string 152 | required: 153 | - lastTransitionTime 154 | - reason 155 | - status 156 | - type 157 | type: object 158 | type: array 159 | x-kubernetes-list-map-keys: 160 | - type 161 | x-kubernetes-list-type: map 162 | users: 163 | description: Users of this provider configuration. 164 | format: int64 165 | type: integer 166 | type: object 167 | required: 168 | - spec 169 | type: object 170 | served: true 171 | storage: true 172 | subresources: 173 | status: {} 174 | -------------------------------------------------------------------------------- /.github/workflows/e2e.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 The Crossplane Authors 2 | # 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | name: End to End Testing 6 | 7 | on: 8 | issue_comment: 9 | types: [created] 10 | 11 | env: 12 | GO_VERSION: "1.24" 13 | 14 | jobs: 15 | check-permissions: 16 | runs-on: ubuntu-latest 17 | outputs: 18 | permission: ${{ steps.check-permissions.outputs.permission }} 19 | steps: 20 | - name: Get Commenter Permissions 21 | id: check-permissions 22 | run: | 23 | echo "Trigger keyword: '/test-examples'" 24 | echo "Go version: ${{ env.GO_VERSION }}" 25 | 26 | REPO=${{ github.repository }} 27 | COMMENTER=${{ github.event.comment.user.login }} 28 | 29 | # Fetch the commenter's repo-level permission grant 30 | GRANTED=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ 31 | -H "Accept: application/vnd.github.v3+json" \ 32 | "https://api.github.com/repos/$REPO/collaborators/$COMMENTER/permission" | jq -r .permission) 33 | 34 | # Make it accessible in the workflow via a job output -- cannot use env 35 | echo "User $COMMENTER has $GRANTED permissions" 36 | echo "permission=$GRANTED" >> "$GITHUB_OUTPUT" 37 | 38 | get-example-list: 39 | needs: check-permissions 40 | if: ${{ (needs.check-permissions.outputs.permission == 'admin' || needs.check-permissions.outputs.permission == 'write') && github.event.issue.pull_request != null && contains(github.event.comment.body, '/test-examples')}} 41 | runs-on: ubuntu-latest 42 | outputs: 43 | example_list: ${{ steps.get-example-list-name.outputs.example-list }} 44 | example_hash: ${{ steps.get-example-list-name.outputs.example-hash }} 45 | 46 | steps: 47 | - name: Checkout 48 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 49 | with: 50 | submodules: true 51 | 52 | - name: Checkout PR 53 | id: checkout-pr 54 | env: 55 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 56 | run: | 57 | gh pr checkout ${{ github.event.issue.number }} 58 | git submodule update --init --recursive 59 | OUTPUT=$(git log -1 --format='%H') 60 | echo "commit-sha=$OUTPUT" >> $GITHUB_OUTPUT 61 | 62 | 63 | - name: Prepare The Example List 64 | env: 65 | COMMENT: ${{ github.event.comment.body }} 66 | id: get-example-list-name 67 | run: | 68 | PATHS=$(echo $COMMENT | sed 's/^.*\/test-examples="//g' | cut -d '"' -f 1 | sed 's/,/ /g') 69 | EXAMPLE_LIST="" 70 | for P in $PATHS; do EXAMPLE_LIST="${EXAMPLE_LIST},$(find $P -name '*.yaml' | tr '\n' ',')"; done 71 | 72 | sudo apt-get -y install coreutils 73 | COUNT=$(echo ${EXAMPLE_LIST:1} | grep -o ".yaml" | wc -l) 74 | if [ $COUNT -gt 1 ]; then EXAMPLE_HASH=$(echo ${EXAMPLE_LIST} | md5sum | cut -f1 -d" "); else EXAMPLE_HASH=$(echo ${EXAMPLE_LIST:1} | sed 's/.$//'); fi 75 | 76 | echo "Examples: ${EXAMPLE_LIST:1}" 77 | echo "Example Hash: ${EXAMPLE_HASH}" 78 | 79 | echo "example-list=${EXAMPLE_LIST:1}" >> $GITHUB_OUTPUT 80 | echo "example-hash=${EXAMPLE_HASH}" >> $GITHUB_OUTPUT 81 | 82 | 83 | - name: Create Pending Status Check 84 | env: 85 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 86 | run: | 87 | gh api \ 88 | --method POST \ 89 | -H "Accept: application/vnd.github+json" \ 90 | /repos/${{ github.repository }}/statuses/${{ steps.checkout-pr.outputs.commit-sha }} \ 91 | -f state='pending' \ 92 | -f target_url='https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' \ 93 | -f description='Running...' \ 94 | -f context="Uptest-${{ steps.get-example-list-name.outputs.example-hash }}" 95 | 96 | uptest: 97 | needs: 98 | - check-permissions 99 | - get-example-list 100 | if: ${{ (needs.check-permissions.outputs.permission == 'admin' || needs.check-permissions.outputs.permission == 'write') && github.event.issue.pull_request != null && contains(github.event.comment.body, '/test-examples')}} 101 | runs-on: ubuntu-latest 102 | 103 | steps: 104 | - name: Cleanup Disk 105 | uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 106 | with: 107 | large-packages: false 108 | swap-storage: false 109 | 110 | - name: Setup QEMU 111 | uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 112 | with: 113 | platforms: all 114 | 115 | - name: Checkout 116 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 117 | with: 118 | submodules: true 119 | 120 | - name: Setup Go 121 | uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 122 | with: 123 | go-version: ${{ env.GO_VERSION }} 124 | 125 | - name: Checkout PR 126 | id: checkout-pr 127 | env: 128 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 129 | run: | 130 | gh pr checkout ${{ github.event.issue.number }} 131 | git submodule update --init --recursive 132 | OUTPUT=$(git log -1 --format='%H') 133 | echo "commit-sha=$OUTPUT" >> $GITHUB_OUTPUT 134 | 135 | 136 | - name: Vendor Dependencies 137 | run: make vendor vendor.check 138 | 139 | - name: Run Uptest 140 | id: run-uptest 141 | env: 142 | UPTEST_CLOUD_CREDENTIALS: ${{ secrets.UPTEST_CLOUD_CREDENTIALS }} 143 | UPTEST_EXAMPLE_LIST: ${{ needs.get-example-list.outputs.example_list }} 144 | UPTEST_TEST_DIR: ./_output/controlplane-dump 145 | UPTEST_DATASOURCE_PATH: .work/uptest-datasource.yaml 146 | UPTEST_UPDATE_PARAMETER: "" 147 | run: | 148 | mkdir -p .work && echo "${{ secrets.UPTEST_DATASOURCE }}" > .work/uptest-datasource.yaml 149 | make e2e 150 | 151 | 152 | - name: Create Successful Status Check 153 | env: 154 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 155 | EXAMPLE_HASH: ${{ needs.get-example-list.outputs.example_hash }} 156 | run: | 157 | gh api \ 158 | --method POST \ 159 | -H "Accept: application/vnd.github+json" \ 160 | /repos/${{ github.repository }}/statuses/${{ steps.checkout-pr.outputs.commit-sha }} \ 161 | -f state='success' \ 162 | -f target_url='https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' \ 163 | -f description='Passed' \ 164 | -f context="Uptest-${EXAMPLE_HASH}" 165 | 166 | 167 | - name: Collect Cluster Dump 168 | if: always() 169 | run: | 170 | make controlplane.dump 171 | 172 | 173 | - name: Upload Cluster Dump 174 | if: always() 175 | uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 176 | with: 177 | name: controlplane-dump 178 | path: ./_output/controlplane-dump 179 | 180 | - name: Cleanup 181 | if: always() 182 | run: | 183 | eval $(make --no-print-directory build.vars) 184 | ${KUBECTL} delete managed --all || true 185 | 186 | 187 | - name: Create Unsuccessful Status Check 188 | if: failure() 189 | env: 190 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 191 | EXAMPLE_HASH: ${{ needs.get-example-list.outputs.example_hash }} 192 | run: | 193 | gh api \ 194 | --method POST \ 195 | -H "Accept: application/vnd.github+json" \ 196 | /repos/${{ github.repository }}/statuses/${{ steps.checkout-pr.outputs.commit-sha }} \ 197 | -f state='failure' \ 198 | -f target_url='https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' \ 199 | -f description='Failed' \ 200 | -f context="Uptest-${EXAMPLE_HASH}" 201 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:base"], 4 | // The maximum number of PRs to be created in parallel 5 | "prConcurrentLimit": 5, 6 | // The branches renovate should target 7 | "baseBranches": ["main"], 8 | "ignorePaths": ["design/**"], 9 | "postUpdateOptions": ["gomodTidy"], 10 | // By default renovate will auto detect whether semantic commits have been used 11 | // in the recent history and comply with that, we explicitly disable it 12 | "semanticCommits": "disabled", 13 | // All PRs should have a label 14 | "labels": ["automated"], 15 | "customManagers": [ 16 | { 17 | // We want a PR to bump Go versions used through env variables in any Github 18 | // Actions, taking it from the official Github repository. 19 | "customType": "regex", 20 | "description": "Bump Go version in workflows", 21 | "fileMatch": ["^\\.github\\/workflows\\/[^/]+\\.ya?ml$"], 22 | "matchStrings": [ 23 | "GO_VERSION: '(?.*?)'\\n" 24 | ], 25 | "datasourceTemplate": "golang-version", 26 | "depNameTemplate": "golang" 27 | }, 28 | { 29 | // We want a PR to bump golangci-lint versions used through env variables in 30 | // any Github Actions, taking it from the official Github repository tags. 31 | "customType": "regex", 32 | "description": "Bump golangci-lint version in workflows", 33 | "fileMatch": ["^\\.github\\/workflows\\/[^/]+\\.ya?ml$"], 34 | "matchStrings": [ 35 | "GOLANGCI_VERSION: '(?.*?)'\\n" 36 | ], 37 | "datasourceTemplate": "github-releases", 38 | "depNameTemplate": "golangci/golangci-lint" 39 | }, 40 | { 41 | // We want a PR to bump docker buildx versions used through env variables in 42 | // any Github Actions, taking it from the official Github repository releases. 43 | "customType": "regex", 44 | "description": "Bump Docker Buildx version in workflows", 45 | "fileMatch": ["^\\.github\\/workflows\\/[^/]+\\.ya?ml$"], 46 | "matchStrings": [ 47 | "DOCKER_BUILDX_VERSION: '(?.*?)'\\n" 48 | ], 49 | "datasourceTemplate": "github-releases", 50 | "depNameTemplate": "docker/buildx" 51 | }, 52 | { 53 | // We want a PR to bump golangci-lint versions used through make variables in 54 | // the Makefile, taking it from the official Github repository releases. 55 | "customType": "regex", 56 | "description": "Bump golangci-lint version in the Makefile", 57 | "fileMatch": ["^Makefile$", "^\\.github\\/workflows\\/[^/]+\\.ya?ml$"], 58 | "matchStrings": ["GOLANGCILINT_VERSION \\??= (?.*?)\\n"], 59 | "datasourceTemplate": "github-releases", 60 | "depNameTemplate": "golangci/golangci-lint", 61 | "extractVersionTemplate": "^(?.*)$" 62 | }, 63 | { 64 | // We want a PR to bump up CLI versions used through make variables in 65 | // the Makefile, taking it from the official Github repository releases. 66 | "customType": "regex", 67 | "description": "Bump up CLI version in the Makefile", 68 | "fileMatch": ["^Makefile$"], 69 | "matchStrings": ["UP_VERSION \\??= (?.*?)\\n"], 70 | "datasourceTemplate": "github-releases", 71 | "depNameTemplate": "upbound/up" 72 | }, 73 | { 74 | // We want a PR to bump uptest versions used through make variables in 75 | // the Makefile, taking it from the official Github repository releases. 76 | "customType": "regex", 77 | "description": "Bump Uptest version in the Makefile", 78 | "fileMatch": ["^Makefile$"], 79 | "matchStrings": ["UPTEST_VERSION \\??= (?.*?)\\n"], 80 | "datasourceTemplate": "github-releases", 81 | "depNameTemplate": "crossplane/uptest" 82 | }, 83 | { 84 | // We want a PR to bump kind versions used through make variables in 85 | // the Makefile, taking it from the official Github repository releases. 86 | "customType": "regex", 87 | "description": "Bump kind version in the Makefile", 88 | "fileMatch": ["^Makefile$"], 89 | "matchStrings": ["KIND_VERSION \\??= (?.*?)\\n"], 90 | "datasourceTemplate": "github-tags", 91 | "depNameTemplate": "kubernetes-sigs/kind" 92 | }, 93 | { 94 | // We want a PR to bump Crossplane versions used through make variables in 95 | // the Makefile, taking it from the official Github repository releases. 96 | "customType": "regex", 97 | "description": "Bump Crossplane version in the Makefile", 98 | "fileMatch": ["^Makefile$"], 99 | "matchStrings": ["CROSSPLANE_VERSION \\??= (?.*?)\\n"], 100 | "datasourceTemplate": "github-releases", 101 | "depNameTemplate": "crossplane/crossplane", 102 | "extractVersionTemplate": "^(?.*)$" 103 | }, 104 | { 105 | // We want a PR to bump Crossplane CLI versions used through make variables in 106 | // the Makefile, taking it from the official Github repository releases. 107 | "customType": "regex", 108 | "description": "Bump Crossplane CLI version in the Makefile", 109 | "fileMatch": ["^Makefile$"], 110 | "matchStrings": ["CROSSPLANE_CLI_VERSION ??= (?.*?)\\n"], 111 | "datasourceTemplate": "github-releases", 112 | "depNameTemplate": "crossplane/crossplane" 113 | } 114 | ], 115 | // PackageRules disabled below should be enabled in case of vulnerabilities 116 | "vulnerabilityAlerts": {"enabled": true}, 117 | "packageRules": [ 118 | { 119 | // We need to ignore k8s.io/client-go older versions as they switched to 120 | // semantic version and old tags are still available in the repo. 121 | "matchDatasources": ["go"], 122 | "matchDepNames": ["k8s.io/client-go"], 123 | "allowedVersions": "<1.0" 124 | }, 125 | { 126 | // We want a single PR for all the patches bumps of kubernetes related 127 | // dependencies, as most of the times these are all strictly related. 128 | "matchDatasources": ["go"], 129 | "groupName": "kubernetes patches", 130 | "matchUpdateTypes": ["patch", "digest"], 131 | "matchPackagePrefixes": ["k8s.io", "sigs.k8s.io"] 132 | }, 133 | { 134 | // We want dedicated PRs for each minor and major bumps to kubernetes related 135 | // dependencies. 136 | "matchDatasources": ["go"], 137 | "matchUpdateTypes": ["major", "minor"], 138 | "matchPackagePrefixes": ["k8s.io", "sigs.k8s.io"] 139 | }, 140 | { 141 | // We want dedicated PRs for each bump to non-kubernetes Go dependencies, but 142 | // only if there are known vulnerabilities in the current version. 143 | "matchDatasources": ["go"], 144 | "matchPackagePatterns": ["*"], 145 | "enabled": false, 146 | "excludePackagePrefixes": ["k8s.io", "sigs.k8s.io"], 147 | "matchUpdateTypes": ["major"] 148 | }, 149 | { 150 | // We want a single PR for all minor and patch bumps to non-kubernetes Go 151 | // dependencies, but only if there are known vulnerabilities in the current 152 | // version. 153 | "matchDatasources": ["go"], 154 | "matchPackagePatterns": ["*"], 155 | "enabled": false, 156 | "excludePackagePrefixes": ["k8s.io", "sigs.k8s.io"], 157 | "matchUpdateTypes": ["minor", "patch", "digest"], 158 | "groupName": "all non-major go dependencies" 159 | }, 160 | { 161 | // We want a single PR for all minor and patch bumps of Github Actions 162 | "matchDepTypes": ["action"], 163 | "matchUpdateTypes": ["minor", "patch"], 164 | "groupName": "all non-major github action", 165 | "pinDigests": true 166 | }, 167 | { 168 | // We want a single PR for bumping Crossplane and Crossplane CLI versions in CI 169 | "matchDepNames": ["crossplane/crossplane"], 170 | "groupName": "crossplane versions in CI", 171 | "groupSlug": "crossplane-in-ci" 172 | }, 173 | { 174 | // We want a single PR for bumping golangci-lint versions 175 | "matchDepNames": ["golangci/golangci-lint"], 176 | "groupName": "golangci-lint versions in CI", 177 | "groupSlug": "golangci-lint-in-ci" 178 | }, 179 | { 180 | // We want dedicated PRs for each major bump to Github Actions 181 | "matchDepTypes": ["action"], 182 | "pinDigests": true 183 | } 184 | ] 185 | } -------------------------------------------------------------------------------- /apis/namespaced/v1beta1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | 3 | // SPDX-FileCopyrightText: 2024 The Crossplane Authors 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | 7 | // Code generated by controller-gen. DO NOT EDIT. 8 | 9 | package v1beta1 10 | 11 | import ( 12 | runtime "k8s.io/apimachinery/pkg/runtime" 13 | ) 14 | 15 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 16 | func (in *ClusterProviderConfig) DeepCopyInto(out *ClusterProviderConfig) { 17 | *out = *in 18 | out.TypeMeta = in.TypeMeta 19 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 20 | in.Spec.DeepCopyInto(&out.Spec) 21 | in.Status.DeepCopyInto(&out.Status) 22 | } 23 | 24 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderConfig. 25 | func (in *ClusterProviderConfig) DeepCopy() *ClusterProviderConfig { 26 | if in == nil { 27 | return nil 28 | } 29 | out := new(ClusterProviderConfig) 30 | in.DeepCopyInto(out) 31 | return out 32 | } 33 | 34 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 35 | func (in *ClusterProviderConfig) DeepCopyObject() runtime.Object { 36 | if c := in.DeepCopy(); c != nil { 37 | return c 38 | } 39 | return nil 40 | } 41 | 42 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 43 | func (in *ClusterProviderConfigList) DeepCopyInto(out *ClusterProviderConfigList) { 44 | *out = *in 45 | out.TypeMeta = in.TypeMeta 46 | in.ListMeta.DeepCopyInto(&out.ListMeta) 47 | if in.Items != nil { 48 | in, out := &in.Items, &out.Items 49 | *out = make([]ClusterProviderConfig, len(*in)) 50 | for i := range *in { 51 | (*in)[i].DeepCopyInto(&(*out)[i]) 52 | } 53 | } 54 | } 55 | 56 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderConfigList. 57 | func (in *ClusterProviderConfigList) DeepCopy() *ClusterProviderConfigList { 58 | if in == nil { 59 | return nil 60 | } 61 | out := new(ClusterProviderConfigList) 62 | in.DeepCopyInto(out) 63 | return out 64 | } 65 | 66 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 67 | func (in *ClusterProviderConfigList) DeepCopyObject() runtime.Object { 68 | if c := in.DeepCopy(); c != nil { 69 | return c 70 | } 71 | return nil 72 | } 73 | 74 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 75 | func (in *ProviderConfig) DeepCopyInto(out *ProviderConfig) { 76 | *out = *in 77 | out.TypeMeta = in.TypeMeta 78 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 79 | in.Spec.DeepCopyInto(&out.Spec) 80 | in.Status.DeepCopyInto(&out.Status) 81 | } 82 | 83 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfig. 84 | func (in *ProviderConfig) DeepCopy() *ProviderConfig { 85 | if in == nil { 86 | return nil 87 | } 88 | out := new(ProviderConfig) 89 | in.DeepCopyInto(out) 90 | return out 91 | } 92 | 93 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 94 | func (in *ProviderConfig) DeepCopyObject() runtime.Object { 95 | if c := in.DeepCopy(); c != nil { 96 | return c 97 | } 98 | return nil 99 | } 100 | 101 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 102 | func (in *ProviderConfigList) DeepCopyInto(out *ProviderConfigList) { 103 | *out = *in 104 | out.TypeMeta = in.TypeMeta 105 | in.ListMeta.DeepCopyInto(&out.ListMeta) 106 | if in.Items != nil { 107 | in, out := &in.Items, &out.Items 108 | *out = make([]ProviderConfig, len(*in)) 109 | for i := range *in { 110 | (*in)[i].DeepCopyInto(&(*out)[i]) 111 | } 112 | } 113 | } 114 | 115 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigList. 116 | func (in *ProviderConfigList) DeepCopy() *ProviderConfigList { 117 | if in == nil { 118 | return nil 119 | } 120 | out := new(ProviderConfigList) 121 | in.DeepCopyInto(out) 122 | return out 123 | } 124 | 125 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 126 | func (in *ProviderConfigList) DeepCopyObject() runtime.Object { 127 | if c := in.DeepCopy(); c != nil { 128 | return c 129 | } 130 | return nil 131 | } 132 | 133 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 134 | func (in *ProviderConfigSpec) DeepCopyInto(out *ProviderConfigSpec) { 135 | *out = *in 136 | in.Credentials.DeepCopyInto(&out.Credentials) 137 | } 138 | 139 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigSpec. 140 | func (in *ProviderConfigSpec) DeepCopy() *ProviderConfigSpec { 141 | if in == nil { 142 | return nil 143 | } 144 | out := new(ProviderConfigSpec) 145 | in.DeepCopyInto(out) 146 | return out 147 | } 148 | 149 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 150 | func (in *ProviderConfigStatus) DeepCopyInto(out *ProviderConfigStatus) { 151 | *out = *in 152 | in.ProviderConfigStatus.DeepCopyInto(&out.ProviderConfigStatus) 153 | } 154 | 155 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigStatus. 156 | func (in *ProviderConfigStatus) DeepCopy() *ProviderConfigStatus { 157 | if in == nil { 158 | return nil 159 | } 160 | out := new(ProviderConfigStatus) 161 | in.DeepCopyInto(out) 162 | return out 163 | } 164 | 165 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 166 | func (in *ProviderConfigUsage) DeepCopyInto(out *ProviderConfigUsage) { 167 | *out = *in 168 | out.TypeMeta = in.TypeMeta 169 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 170 | in.TypedProviderConfigUsage.DeepCopyInto(&out.TypedProviderConfigUsage) 171 | } 172 | 173 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigUsage. 174 | func (in *ProviderConfigUsage) DeepCopy() *ProviderConfigUsage { 175 | if in == nil { 176 | return nil 177 | } 178 | out := new(ProviderConfigUsage) 179 | in.DeepCopyInto(out) 180 | return out 181 | } 182 | 183 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 184 | func (in *ProviderConfigUsage) DeepCopyObject() runtime.Object { 185 | if c := in.DeepCopy(); c != nil { 186 | return c 187 | } 188 | return nil 189 | } 190 | 191 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 192 | func (in *ProviderConfigUsageList) DeepCopyInto(out *ProviderConfigUsageList) { 193 | *out = *in 194 | out.TypeMeta = in.TypeMeta 195 | in.ListMeta.DeepCopyInto(&out.ListMeta) 196 | if in.Items != nil { 197 | in, out := &in.Items, &out.Items 198 | *out = make([]ProviderConfigUsage, len(*in)) 199 | for i := range *in { 200 | (*in)[i].DeepCopyInto(&(*out)[i]) 201 | } 202 | } 203 | } 204 | 205 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigUsageList. 206 | func (in *ProviderConfigUsageList) DeepCopy() *ProviderConfigUsageList { 207 | if in == nil { 208 | return nil 209 | } 210 | out := new(ProviderConfigUsageList) 211 | in.DeepCopyInto(out) 212 | return out 213 | } 214 | 215 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 216 | func (in *ProviderConfigUsageList) DeepCopyObject() runtime.Object { 217 | if c := in.DeepCopy(); c != nil { 218 | return c 219 | } 220 | return nil 221 | } 222 | 223 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 224 | func (in *ProviderCredentials) DeepCopyInto(out *ProviderCredentials) { 225 | *out = *in 226 | in.CommonCredentialSelectors.DeepCopyInto(&out.CommonCredentialSelectors) 227 | } 228 | 229 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderCredentials. 230 | func (in *ProviderCredentials) DeepCopy() *ProviderCredentials { 231 | if in == nil { 232 | return nil 233 | } 234 | out := new(ProviderCredentials) 235 | in.DeepCopyInto(out) 236 | return out 237 | } 238 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - release-* 8 | pull_request: {} 9 | workflow_dispatch: {} 10 | 11 | env: 12 | # Common versions 13 | GO_VERSION: '1.24' 14 | GOLANGCI_VERSION: 'v2.6.1' 15 | DOCKER_BUILDX_VERSION: 'v0.28.0' 16 | 17 | jobs: 18 | detect-noop: 19 | runs-on: ubuntu-24.04 20 | outputs: 21 | noop: ${{ steps.noop.outputs.should_skip }} 22 | steps: 23 | - name: Detect No-op Changes 24 | id: noop 25 | uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1 26 | with: 27 | github_token: ${{ secrets.GITHUB_TOKEN }} 28 | paths_ignore: '["**.md", "**.png", "**.jpg"]' 29 | do_not_skip: '["workflow_dispatch", "schedule", "push"]' 30 | 31 | report-breaking-changes: 32 | runs-on: ubuntu-24.04 33 | needs: detect-noop 34 | if: needs.detect-noop.outputs.noop != 'true' 35 | steps: 36 | - name: Checkout 37 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 38 | with: 39 | submodules: true 40 | 41 | - name: Get modified CRDs 42 | id: modified-crds 43 | uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # v47.0.1 44 | with: 45 | files: | 46 | package/crds/** 47 | - name: Report breaking CRD OpenAPI v3 schema changes 48 | if: steps.modified-crds.outputs.any_changed == 'true' 49 | env: 50 | MODIFIED_CRD_LIST: ${{ steps.modified-crds.outputs.all_changed_files }} 51 | run: | 52 | make crddiff 53 | - name: Report native schema version changes 54 | if: ${{ inputs.upjet-based-provider }} 55 | run: | 56 | make schema-version-diff 57 | 58 | 59 | lint: 60 | runs-on: ubuntu-24.04 61 | needs: detect-noop 62 | if: needs.detect-noop.outputs.noop != 'true' 63 | 64 | steps: 65 | - name: Checkout 66 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 67 | with: 68 | submodules: true 69 | 70 | - name: Setup Go 71 | uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 72 | with: 73 | go-version: ${{ env.GO_VERSION }} 74 | 75 | - name: Find the Go Build Cache 76 | id: go 77 | run: echo "cache=$(make go.cachedir)" >> $GITHUB_OUTPUT 78 | 79 | - name: Cache the Go Build Cache 80 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 81 | with: 82 | path: ${{ steps.go.outputs.cache }} 83 | key: ${{ runner.os }}-build-lint-${{ hashFiles('**/go.sum') }} 84 | restore-keys: ${{ runner.os }}-build-lint- 85 | 86 | - name: Cache Go Dependencies 87 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 88 | with: 89 | path: .work/pkg 90 | key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} 91 | restore-keys: ${{ runner.os }}-pkg- 92 | 93 | - name: Vendor Dependencies 94 | run: make vendor vendor.check 95 | 96 | # We could run 'make lint' but we prefer this action because it leaves 97 | # 'annotations' (i.e. it comments on PRs to point out linter violations). 98 | - name: Lint 99 | uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 100 | with: 101 | version: ${{ env.GOLANGCI_VERSION }} 102 | 103 | check-diff: 104 | runs-on: ubuntu-24.04 105 | needs: detect-noop 106 | if: needs.detect-noop.outputs.noop != 'true' 107 | 108 | steps: 109 | - name: Checkout 110 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 111 | with: 112 | submodules: true 113 | 114 | - name: Setup Go 115 | uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 116 | with: 117 | go-version: ${{ env.GO_VERSION }} 118 | 119 | - name: Install goimports 120 | run: go install golang.org/x/tools/cmd/goimports 121 | 122 | - name: Find the Go Build Cache 123 | id: go 124 | run: echo "cache=$(make go.cachedir)" >> $GITHUB_OUTPUT 125 | 126 | - name: Cache the Go Build Cache 127 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 128 | with: 129 | path: ${{ steps.go.outputs.cache }} 130 | key: ${{ runner.os }}-build-check-diff-${{ hashFiles('**/go.sum') }} 131 | restore-keys: ${{ runner.os }}-build-check-diff- 132 | 133 | - name: Cache Go Dependencies 134 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 135 | with: 136 | path: .work/pkg 137 | key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} 138 | restore-keys: ${{ runner.os }}-pkg- 139 | 140 | - name: Vendor Dependencies 141 | run: make vendor vendor.check 142 | 143 | - name: Check Diff 144 | run: make check-diff 145 | 146 | unit-tests: 147 | runs-on: ubuntu-24.04 148 | needs: detect-noop 149 | if: needs.detect-noop.outputs.noop != 'true' 150 | 151 | steps: 152 | - name: Checkout 153 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 154 | with: 155 | submodules: true 156 | 157 | - name: Fetch History 158 | run: git fetch --prune --unshallow 159 | 160 | - name: Setup Go 161 | uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 162 | with: 163 | go-version: ${{ env.GO_VERSION }} 164 | 165 | - name: Find the Go Build Cache 166 | id: go 167 | run: echo "cache=$(make go.cachedir)" >> $GITHUB_OUTPUT 168 | 169 | - name: Cache the Go Build Cache 170 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 171 | with: 172 | path: ${{ steps.go.outputs.cache }} 173 | key: ${{ runner.os }}-build-unit-tests-${{ hashFiles('**/go.sum') }} 174 | restore-keys: ${{ runner.os }}-build-unit-tests- 175 | 176 | - name: Cache Go Dependencies 177 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 178 | with: 179 | path: .work/pkg 180 | key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} 181 | restore-keys: ${{ runner.os }}-pkg- 182 | 183 | - name: Vendor Dependencies 184 | run: make vendor vendor.check 185 | 186 | - name: Run Unit Tests 187 | run: make -j2 test 188 | 189 | - name: Publish Unit Test Coverage 190 | uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 191 | with: 192 | flags: unittests 193 | files: _output/tests/linux_amd64/coverage.txt 194 | 195 | local-deploy: 196 | runs-on: ubuntu-24.04 197 | needs: detect-noop 198 | if: needs.detect-noop.outputs.noop != 'true' 199 | 200 | steps: 201 | - name: Checkout 202 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 203 | with: 204 | submodules: true 205 | 206 | - name: Fetch History 207 | run: git fetch --prune --unshallow 208 | 209 | - name: Setup Go 210 | uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 211 | with: 212 | go-version: ${{ env.GO_VERSION }} 213 | 214 | - name: Find the Go Build Cache 215 | id: go 216 | run: echo "cache=$(make go.cachedir)" >> $GITHUB_OUTPUT 217 | 218 | - name: Cache the Go Build Cache 219 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 220 | with: 221 | path: ${{ steps.go.outputs.cache }} 222 | key: ${{ runner.os }}-build-unit-tests-${{ hashFiles('**/go.sum') }} 223 | restore-keys: ${{ runner.os }}-build-unit-tests- 224 | 225 | - name: Cache Go Dependencies 226 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 227 | with: 228 | path: .work/pkg 229 | key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} 230 | restore-keys: ${{ runner.os }}-pkg- 231 | 232 | - name: Vendor Dependencies 233 | run: make vendor vendor.check 234 | 235 | - name: Deploying locally built provider package 236 | run: make local-deploy 237 | 238 | publish-artifacts: 239 | runs-on: ubuntu-24.04 240 | needs: 241 | - detect-noop 242 | - report-breaking-changes 243 | - lint 244 | - check-diff 245 | - unit-tests 246 | - local-deploy 247 | if: needs.detect-noop.outputs.noop != 'true' 248 | 249 | steps: 250 | - name: Setup QEMU 251 | uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 252 | with: 253 | platforms: all 254 | 255 | - name: Setup Docker Buildx 256 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 257 | with: 258 | version: ${{ env.DOCKER_BUILDX_VERSION }} 259 | install: true 260 | 261 | - name: Checkout 262 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 263 | with: 264 | submodules: true 265 | 266 | - name: Fetch History 267 | run: git fetch --prune --unshallow 268 | 269 | - name: Setup Go 270 | uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 271 | with: 272 | go-version: ${{ env.GO_VERSION }} 273 | 274 | - name: Find the Go Build Cache 275 | id: go 276 | run: echo "cache=$(make go.cachedir)" >> $GITHUB_OUTPUT 277 | 278 | - name: Cache the Go Build Cache 279 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 280 | with: 281 | path: ${{ steps.go.outputs.cache }} 282 | key: ${{ runner.os }}-build-publish-artifacts-${{ hashFiles('**/go.sum') }} 283 | restore-keys: ${{ runner.os }}-build-publish-artifacts- 284 | 285 | - name: Cache Go Dependencies 286 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 287 | with: 288 | path: .work/pkg 289 | key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} 290 | restore-keys: ${{ runner.os }}-pkg- 291 | 292 | - name: Vendor Dependencies 293 | run: make vendor vendor.check 294 | 295 | - name: Build Artifacts 296 | run: make -j2 build.all 297 | env: 298 | # We're using docker buildx, which doesn't actually load the images it 299 | # builds by default. Specifying --load does so. 300 | BUILD_ARGS: "--load" 301 | 302 | - name: Upload Artifacts to GitHub 303 | uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 304 | with: 305 | name: output 306 | path: _output/** 307 | -------------------------------------------------------------------------------- /package/crds/null.template.m.crossplane.io_resources.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.19.0 7 | name: resources.null.template.m.crossplane.io 8 | spec: 9 | group: null.template.m.crossplane.io 10 | names: 11 | categories: 12 | - crossplane 13 | - managed 14 | - template 15 | kind: Resource 16 | listKind: ResourceList 17 | plural: resources 18 | singular: resource 19 | scope: Namespaced 20 | versions: 21 | - additionalPrinterColumns: 22 | - jsonPath: .status.conditions[?(@.type=='Synced')].status 23 | name: SYNCED 24 | type: string 25 | - jsonPath: .status.conditions[?(@.type=='Ready')].status 26 | name: READY 27 | type: string 28 | - jsonPath: .metadata.annotations.crossplane\.io/external-name 29 | name: EXTERNAL-NAME 30 | type: string 31 | - jsonPath: .metadata.creationTimestamp 32 | name: AGE 33 | type: date 34 | name: v1alpha1 35 | schema: 36 | openAPIV3Schema: 37 | description: Resource is the Schema for the Resources API. The null_resource 38 | resource implements the standard resource lifecycle but takes no further 39 | action.hashicorp. The triggers argument allows specifying an arbitrary set 40 | of values that, when changed, will cause the resource to be replaced. 41 | properties: 42 | apiVersion: 43 | description: |- 44 | APIVersion defines the versioned schema of this representation of an object. 45 | Servers should convert recognized schemas to the latest internal value, and 46 | may reject unrecognized values. 47 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 48 | type: string 49 | kind: 50 | description: |- 51 | Kind is a string value representing the REST resource this object represents. 52 | Servers may infer this from the endpoint the client submits requests to. 53 | Cannot be updated. 54 | In CamelCase. 55 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 56 | type: string 57 | metadata: 58 | type: object 59 | spec: 60 | description: ResourceSpec defines the desired state of Resource 61 | properties: 62 | forProvider: 63 | properties: 64 | triggers: 65 | additionalProperties: 66 | type: string 67 | description: |- 68 | running any associated provisioners. 69 | A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners. 70 | type: object 71 | x-kubernetes-map-type: granular 72 | type: object 73 | initProvider: 74 | description: |- 75 | THIS IS A BETA FIELD. It will be honored 76 | unless the Management Policies feature flag is disabled. 77 | InitProvider holds the same fields as ForProvider, with the exception 78 | of Identifier and other resource reference fields. The fields that are 79 | in InitProvider are merged into ForProvider when the resource is created. 80 | The same fields are also added to the terraform ignore_changes hook, to 81 | avoid updating them after creation. This is useful for fields that are 82 | required on creation, but we do not desire to update them after creation, 83 | for example because of an external controller is managing them, like an 84 | autoscaler. 85 | properties: 86 | triggers: 87 | additionalProperties: 88 | type: string 89 | description: |- 90 | running any associated provisioners. 91 | A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners. 92 | type: object 93 | x-kubernetes-map-type: granular 94 | type: object 95 | managementPolicies: 96 | default: 97 | - '*' 98 | description: |- 99 | THIS IS A BETA FIELD. It is on by default but can be opted out 100 | through a Crossplane feature flag. 101 | ManagementPolicies specify the array of actions Crossplane is allowed to 102 | take on the managed and external resources. 103 | See the design doc for more information: https://github.com/crossplane/crossplane/blob/499895a25d1a1a0ba1604944ef98ac7a1a71f197/design/design-doc-observe-only-resources.md?plain=1#L223 104 | and this one: https://github.com/crossplane/crossplane/blob/444267e84783136daa93568b364a5f01228cacbe/design/one-pager-ignore-changes.md 105 | items: 106 | description: |- 107 | A ManagementAction represents an action that the Crossplane controllers 108 | can take on an external resource. 109 | enum: 110 | - Observe 111 | - Create 112 | - Update 113 | - Delete 114 | - LateInitialize 115 | - '*' 116 | type: string 117 | type: array 118 | providerConfigRef: 119 | default: 120 | kind: ClusterProviderConfig 121 | name: default 122 | description: |- 123 | ProviderConfigReference specifies how the provider that will be used to 124 | create, observe, update, and delete this managed resource should be 125 | configured. 126 | properties: 127 | kind: 128 | description: Kind of the referenced object. 129 | type: string 130 | name: 131 | description: Name of the referenced object. 132 | type: string 133 | required: 134 | - kind 135 | - name 136 | type: object 137 | writeConnectionSecretToRef: 138 | description: |- 139 | WriteConnectionSecretToReference specifies the namespace and name of a 140 | Secret to which any connection details for this managed resource should 141 | be written. Connection details frequently include the endpoint, username, 142 | and password required to connect to the managed resource. 143 | properties: 144 | name: 145 | description: Name of the secret. 146 | type: string 147 | required: 148 | - name 149 | type: object 150 | required: 151 | - forProvider 152 | type: object 153 | status: 154 | description: ResourceStatus defines the observed state of Resource. 155 | properties: 156 | atProvider: 157 | properties: 158 | id: 159 | description: (String) This is set to a random value at create 160 | time. 161 | type: string 162 | triggers: 163 | additionalProperties: 164 | type: string 165 | description: |- 166 | running any associated provisioners. 167 | A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners. 168 | type: object 169 | x-kubernetes-map-type: granular 170 | type: object 171 | conditions: 172 | description: Conditions of the resource. 173 | items: 174 | description: A Condition that may apply to a resource. 175 | properties: 176 | lastTransitionTime: 177 | description: |- 178 | LastTransitionTime is the last time this condition transitioned from one 179 | status to another. 180 | format: date-time 181 | type: string 182 | message: 183 | description: |- 184 | A Message containing details about this condition's last transition from 185 | one status to another, if any. 186 | type: string 187 | observedGeneration: 188 | description: |- 189 | ObservedGeneration represents the .metadata.generation that the condition was set based upon. 190 | For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date 191 | with respect to the current state of the instance. 192 | format: int64 193 | type: integer 194 | reason: 195 | description: A Reason for this condition's last transition from 196 | one status to another. 197 | type: string 198 | status: 199 | description: Status of this condition; is it currently True, 200 | False, or Unknown? 201 | type: string 202 | type: 203 | description: |- 204 | Type of this condition. At most one of each condition type may apply to 205 | a resource at any point in time. 206 | type: string 207 | required: 208 | - lastTransitionTime 209 | - reason 210 | - status 211 | - type 212 | type: object 213 | type: array 214 | x-kubernetes-list-map-keys: 215 | - type 216 | x-kubernetes-list-type: map 217 | observedGeneration: 218 | description: |- 219 | ObservedGeneration is the latest metadata.generation 220 | which resulted in either a ready state, or stalled due to error 221 | it can not recover from without human intervention. 222 | format: int64 223 | type: integer 224 | type: object 225 | required: 226 | - spec 227 | type: object 228 | served: true 229 | storage: true 230 | subresources: 231 | status: {} 232 | --------------------------------------------------------------------------------