Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ sdk/java/.gradle
sdk/java/build/
sdk/java/build.gradle
sdk/python/venv

**/.claude/settings.local.json
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,33 @@ This component supports all of the configuration options of the [official Helm c
https://github.com/jetstack/cert-manager/tree/master/deploy/charts/cert-manager), except that these
are strongly typed so you will get IDE support and static error checking.

### CRDs Configuration

The component handles Custom Resource Definitions (CRDs) for cert-manager in two ways:

1. **Modern approach (recommended)**: Use the structured `crds` object:
```typescript
const manager = new certmanager.CertManager("cert-manager", {
crds: {
enabled: true, // Whether to install CRDs (default: false)
keep: false, // Whether to keep CRDs after uninstall (default: false)
},
// Other configuration...
});
```

2. **Legacy approach (deprecated)**: Use the boolean `installCRDs` parameter:
```typescript
const manager = new certmanager.CertManager("cert-manager", {
installCRDs: true,
// Other configuration...
});
```

The component handles both approaches correctly, but the structured `crds` object is preferred for new deployments as it offers more fine-grained control.

### Other Configuration

The Helm deployment uses reasonable defaults, including the chart name and repo URL, however,
if you need to override them, you may do so using the `helmOptions` parameter. Refer to
[the API docs for the `kubernetes:helm/v3:Release` Pulumi type](
Expand Down
14 changes: 14 additions & 0 deletions examples/examples_ts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,17 @@ func TestTsCertManagerPreview(t *testing.T) {
p.Preview(t)
})
}

// This tests the Output being passed to repository to fix #133
func TestTsCertManagerCrdsNotKept(t *testing.T) {
t.Run("TestSimpleCertManagerTsCrdsNotKept", func(t *testing.T) {
p := pulumitest.NewPulumiTest(t, "simple-cert-manager-ts",
opttest.LocalProviderPath("pulumi-kubernetes-cert-manager", filepath.Join(getCwd(t), "..", "bin")),
opttest.YarnLink("@pulumi/kubernetes-cert-manager"),
)
p.SetConfig(t, "repository", "public.ecr.aws/eks-anywhere-dev/cert-manager/cert-manager-controller")
p.Up(t)
p.Destroy(t)
p.Up(t)
})
}
89 changes: 47 additions & 42 deletions examples/simple-cert-manager-ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,56 @@ import * as random from "@pulumi/random";
import * as pulumi from "@pulumi/pulumi"

const randomString = new random.RandomString("random", {
length: 16,
special: false,
length: 16,
special: false,
})

const conf = new pulumi.Config()
const confRepo = conf.get("repository")
let repository = randomString.result
if (confRepo) {
repository = pulumi.output(confRepo)
repository = pulumi.output(confRepo)
}

// Create a sandbox namespace.
const ns = new k8s.core.v1.Namespace("sandbox-ns");

// Install a cert manager into our cluster.
const manager = new certmanager.CertManager("cert-manager", {
installCRDs: true,
helmOptions: {
namespace: ns.metadata.name,
version: "v1.15.3",
},
image: pulumi.all([repository, "v1.15.3-eks-a-v0.21.3-dev-build.0"]).apply(([repository, tag]) => {
return {
repository,
tag: tag,
}
}),
cainjector: {
"image": {
repository: "public.ecr.aws/eks-anywhere-dev/cert-manager/cert-manager-cainjector",
tag: "v1.15.3-eks-a-v0.21.3-dev-build.0",
// Using the new crds field instead of installCRDs
crds: {
enabled: true,
keep: false,
},
},
startupapicheck: {
"image": {
repository: "public.ecr.aws/eks-anywhere-dev/cert-manager/cert-manager-startupapicheck",
tag: "v1.15.3-eks-a-v0.21.3-dev-build.0",
}
},
webhook: {
image: {
repository: "public.ecr.aws/eks-anywhere-dev/cert-manager/cert-manager-webhook",
tag: "v1.15.3-eks-a-v0.21.3-dev-build.0"
helmOptions: {
namespace: ns.metadata.name,
version: "v1.15.3",
timeout: 600, // 10 minute timeout for CI environments
},
image: pulumi.all([repository, "v1.15.3-eks-a-v0.21.3-dev-build.0"]).apply(([repository, tag]) => {
return {
repository,
tag: tag,
}
}),
cainjector: {
"image": {
repository: "public.ecr.aws/eks-anywhere-dev/cert-manager/cert-manager-cainjector",
tag: "v1.15.3-eks-a-v0.21.3-dev-build.0",
},
},
startupapicheck: {
"image": {
repository: "public.ecr.aws/eks-anywhere-dev/cert-manager/cert-manager-startupapicheck",
tag: "v1.15.3-eks-a-v0.21.3-dev-build.0",
}
},
webhook: {
image: {
repository: "public.ecr.aws/eks-anywhere-dev/cert-manager/cert-manager-webhook",
tag: "v1.15.3-eks-a-v0.21.3-dev-build.0"
}
}
}
});

// Create a cluster issuer that uses self-signed certificates.
Expand All @@ -57,19 +62,19 @@ const manager = new certmanager.CertManager("cert-manager", {
// https://cert-manager.io/docs/configuration/selfsigned/
// for additional details on other signing providers.
const issuer = new k8s.apiextensions.CustomResource(
"issuer",
{
apiVersion: "cert-manager.io/v1",
kind: "Issuer",
metadata: {
name: "selfsigned-issuer",
namespace: ns.metadata.name,
},
spec: {
selfSigned: {},
"issuer",
{
apiVersion: "cert-manager.io/v1",
kind: "Issuer",
metadata: {
name: "selfsigned-issuer",
namespace: ns.metadata.name,
},
spec: {
selfSigned: {},
},
},
},
{ dependsOn: manager }
{ dependsOn: manager }
);

export const certManagerStatus = manager.status;
17 changes: 17 additions & 0 deletions provider/cmd/pulumi-resource-kubernetes-cert-manager/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@
"installCRDs": {
"type": "boolean"
},
"crds": {
"$ref": "#/types/kubernetes-cert-manager:index:CertManagerCrds"
},
"no_proxy": {
"items": {
"type": "string"
Expand Down Expand Up @@ -880,6 +883,20 @@
}
},
"type": "object"
},
"kubernetes-cert-manager:index:CertManagerCrds": {
"properties": {
"enabled": {
"description": "Enable customization of the installation of CRDs. Cannot be enabled with installCRDs.",
"type": "boolean"
},
"keep": {
"description": "Keep CRDs on chart uninstall. Setting to false will remove CRDs when the chart is removed.",
"type": "boolean",
"default": false
}
},
"type": "object"
}
},
"language": {
Expand Down
4 changes: 3 additions & 1 deletion provider/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/pulumi/pulumi-kubernetes/sdk/v4 v4.23.0
github.com/pulumi/pulumi/pkg/v3 v3.193.0
github.com/pulumi/pulumi/sdk/v3 v3.193.0
github.com/stretchr/testify v1.10.0
)

replace github.com/pulumi/pulumi-kubernetes-cert-manager/sdk => ../sdk
Expand All @@ -31,6 +32,7 @@ require (
github.com/cloudflare/circl v1.6.1 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/djherbis/times v1.5.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
Expand Down Expand Up @@ -64,6 +66,7 @@ require (
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/term v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231 // indirect
github.com/pulumi/esc v0.17.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
Expand All @@ -74,7 +77,6 @@ require (
github.com/skeema/knownhosts v1.3.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/texttheater/golang-levenshtein v1.0.1 // indirect
github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
Expand Down
7 changes: 2 additions & 5 deletions provider/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -187,16 +187,13 @@ github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyh
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/texttheater/golang-levenshtein v1.0.1 h1:+cRNoVrfiwufQPhoMzB6N0Yf/Mqajr6t1lOv8GyGE2U=
Expand Down
61 changes: 60 additions & 1 deletion provider/pkg/provider/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func (c *CertManager) DefaultRepoURL() string { return "https
type CertManagerArgs struct {
Global kcm.CertManagerGlobalPtrInput `pulumi:"global"`
InstallCRDs *bool `pulumi:"installCRDs"`
Crds *CertManagerCrds `pulumi:"crds"`
ReplicaCount *int `pulumi:"replicaCount"`
Strategy *appsv1.DeploymentStrategy `pulumi:"strategy" pschema:"ref=/kubernetes/v4.21.0/schema.json#/types/kubernetes:apps/v1:DeploymentStrategy"`
// Comma separated list of feature gates that should be enabled on the controller pod.
Expand Down Expand Up @@ -92,7 +93,51 @@ type CertManagerArgs struct {
HelmOptions *helmbase.ReleaseType `pulumi:"helmOptions" pschema:"ref=#/types/chart-cert-manager:index:Release" json:"-"`
}

func (args *CertManagerArgs) R() **helmbase.ReleaseType { return &args.HelmOptions }
func (args *CertManagerArgs) R() **helmbase.ReleaseType {
// This function prepares the HelmOptions for the cert-manager release
// by ensuring proper handling of CRDs configuration.

// Initialize default values for CRDs configuration
// The cert-manager Helm chart provides two mechanisms for managing CRDs:
// 1. Legacy: installCRDs boolean flag (deprecated)
// 2. Modern: structured crds object with enabled and keep properties
keepFalse := false
enabledFalse := false

// Ensure Crds object exists with proper defaults
// This guarantees that we always have a valid crds configuration
// to pass to the Helm chart, preventing potential nil pointer issues
if args.Crds == nil {
args.Crds = &CertManagerCrds{
Enabled: &enabledFalse, // Default: don't install CRDs
Keep: &keepFalse, // Default: don't keep CRDs after uninstall
}
} else {
// Set defaults for any unspecified fields within the crds object
// This handles cases where users specify a partial crds configuration
if args.Crds.Enabled == nil {
args.Crds.Enabled = &enabledFalse
}
if args.Crds.Keep == nil {
args.Crds.Keep = &keepFalse
}
}

// Handle the legacy installCRDs parameter
// Note: Setting both installCRDs=true AND crds.enabled=true in the Helm chart
// will cause an error, so we need to convert installCRDs to the modern format
if args.InstallCRDs != nil && *args.InstallCRDs {
// Convert legacy format to modern format:
// 1. Set crds.enabled=true to enable CRD installation
// 2. Clear installCRDs to avoid conflict with the Helm chart
enabledTrue := true
args.Crds.Enabled = &enabledTrue
args.InstallCRDs = nil
}

// Return the prepared HelmOptions
return &args.HelmOptions
}

type CertManagerGlobal struct {
// Reference to one or more secrets to be used when pulling images.
Expand Down Expand Up @@ -246,6 +291,20 @@ type CertManagerWebhookURL struct {
Host *string `pulumi:"host"`
}

type CertManagerCrds struct {
// Enable customization of the installation of CRDs. Cannot be enabled with installCRDs.
// Default: false - CRDs are not installed by default
Enabled *bool `pulumi:"enabled"`

// Keep CRDs on chart uninstall. Setting to false will remove CRDs when the chart is removed.
// Default: false - CRDs are removed when the chart is uninstalled
//
// IMPORTANT: Setting this to false can cause data loss if CRDs are removed while custom
// resources still exist. Only set this to false if you're certain there are no cert-manager
// resources in your cluster or if you intend to delete them before uninstalling.
Keep *bool `pulumi:"keep"`
}

type CertManagerCaInjector struct {
ReplicaCount *int `pulumi:"replicaCount"`
TimeoutSeconds *int `pulumi:"timeoutSeconds"`
Expand Down
45 changes: 44 additions & 1 deletion provider/pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,48 @@ func Serve(version string, schema []byte) {
// creates, registers, and returns the resulting object.
func Construct(ctx *pulumi.Context, typ, name string, inputs pp.ConstructInputs,
opts pulumi.ResourceOption) (*pp.ConstructResult, error) {
return helmbase.Construct(ctx, &CertManager{}, typ, name, &CertManagerArgs{}, inputs, opts)
args := &CertManagerArgs{}
if err := inputs.CopyTo(args); err != nil {
return nil, err
}

// Set default values for the Crds configuration
// The cert-manager Helm chart is transitioning from using installCRDs (boolean)
// to a structured object crds: { enabled: boolean, keep: boolean }
//
// This section handles both formats and ensures proper defaults are set.
// For the structured format:
// - crds.enabled (default: false) - Whether to install CRDs
// - crds.keep (default: false) - Whether to keep CRDs after chart uninstall
keepFalse := false
enabledFalse := false

// Initialize the Crds object if it doesn't exist
if args.Crds == nil {
args.Crds = &CertManagerCrds{
Keep: &keepFalse, // Default: don't keep CRDs after uninstall
Enabled: &enabledFalse, // Default: don't install CRDs
}
} else {
// Ensure all fields have proper defaults set
if args.Crds.Keep == nil {
args.Crds.Keep = &keepFalse
}
if args.Crds.Enabled == nil {
args.Crds.Enabled = &enabledFalse
}
}

// Handle legacy installCRDs parameter for backward compatibility
// For background: In the Helm chart, setting both installCRDs=true and crds.enabled=true
// causes a conflict, so we need to handle this case specifically.
if args.InstallCRDs != nil && *args.InstallCRDs {
// If installCRDs is true, we set crds.enabled=true and clear installCRDs
// to avoid sending conflicting configuration to the Helm chart
enabledTrue := true
args.Crds.Enabled = &enabledTrue
args.InstallCRDs = nil
}

return helmbase.Construct(ctx, &CertManager{}, typ, name, args, inputs, opts)
}
Loading