Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
cd403bc
feat(install): add GetWatchSpecs for drift detection
aslakknutsen Feb 2, 2026
9e63b66
feat(install): add Gateway API value helpers
aslakknutsen Feb 3, 2026
c80b95d
feat(crds): embed CRD YAML files for programmatic access
aslakknutsen Feb 3, 2026
6c9bb4b
feat(install): add CRD management for Gateway API mode
aslakknutsen Feb 3, 2026
6ac7ba6
refactor(install): use shared value computation pipeline
aslakknutsen Feb 4, 2026
2a5efea
feat(install): add DriftReconciler for automatic drift detection
aslakknutsen Feb 4, 2026
017d629
feat(install): add LibraryRBACRules for consumer RBAC aggregation
aslakknutsen Feb 5, 2026
50e93f7
feat(install): auto-populate downstream image refs from embedded FS
aslakknutsen Feb 6, 2026
0263fb4
feat(install): derive version from resource FS instead of versions.yaml
aslakknutsen Feb 6, 2026
bd2833b
refactor(install): replace manual MergeValues with generic map merge
aslakknutsen Feb 10, 2026
2bd25cb
feat(install): add batch CRD ownership management and Status type
aslakknutsen Feb 11, 2026
5821c6e
refactor(install)!: replace Installer+DriftReconciler with Library actor
aslakknutsen Feb 11, 2026
ff5c63c
feat(install): watch CRDs for ownership changes and lifecycle events
aslakknutsen Feb 11, 2026
bd13a1a
ix(install): resolve default version in getWatchSpecs
aslakknutsen Feb 12, 2026
0e200c2
feat(install): add Status.String() for human-readable status output
aslakknutsen Feb 12, 2026
733e978
feat(install): add structured logging to Library internals
aslakknutsen Feb 12, 2026
fdd3cc9
fix(install): reclaim CRDs with lost labels and reinstall deleted ones
aslakknutsen Feb 12, 2026
80e4e90
fix(install): remove error retry loop from workqueue
aslakknutsen Feb 12, 2026
45b94d2
refactor(install): extract CRDManager type and split filtering utilities
aslakknutsen Feb 12, 2026
5de427d
fix(install): strip "v" prefix from image tags and normalize version …
aslakknutsen Feb 12, 2026
cb80b57
fix(install): deep-copy Values to prevent infinite reconcile loop
aslakknutsen Feb 13, 2026
2ddbe94
refactor(install)!: remove OwnerRef and support Apply/Uninstall lifec…
aslakknutsen Feb 13, 2026
dd2ec6f
refactor(install): restructure package for clarity and fix race condi…
aslakknutsen Feb 14, 2026
942be7f
test(install): add fake-client tests for crdManager
aslakknutsen Feb 14, 2026
e83768d
feat(install): use configurable managed-by label for Library resources
aslakknutsen Feb 16, 2026
e538d1a
fix(install)!: accept namespace/revision params in Uninstall for cras…
aslakknutsen Feb 16, 2026
d8bcbce
feat(install): allow consumer to adopt orphaned OLM-managed CRDs
aslakknutsen Feb 19, 2026
72bf038
feat(install): add Enqueue() to force reconciliation on external stat…
aslakknutsen Feb 23, 2026
bd10b40
fix(install): prevent panic on double Uninstall by niling closed chan…
aslakknutsen Mar 3, 2026
2cefc40
fix(install): add exponential backoff on failed reconciliations
aslakknutsen Mar 3, 2026
50152cb
fix(install): fix Uninstall deadlock caused by niled processingDone c…
aslakknutsen Mar 5, 2026
f1067e9
docs(install): add README and fix source.Channel usage in USAGE.md
aslakknutsen Mar 6, 2026
ebc5039
feat(install): load image digests from embedded CSV annotations
aslakknutsen Mar 9, 2026
1efbbf7
fix(install): clear status after successful Uninstall
aslakknutsen Mar 16, 2026
b3c6688
fix(embed): update embed csv ref to match downstream
aslakknutsen Mar 16, 2026
57c3abf
fix: remove unused default values and deprecated api refs
aslakknutsen Mar 16, 2026
e70288b
refactor(bundle): move CSV embed out of bundle/manifests to avoid ope…
aslakknutsen Mar 16, 2026
2e8a2d0
fix: lint stuff
aslakknutsen Mar 16, 2026
385d509
fix: lint stuff
aslakknutsen Mar 16, 2026
fcd3fe5
fix: make gen go.mod updates
aslakknutsen Mar 16, 2026
4159c7d
fix(install): align clearIgnoredFields with upstream webhook predicate
aslakknutsen Mar 18, 2026
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
20 changes: 20 additions & 0 deletions bundle/bundle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package bundle

import _ "embed"

//go:embed manifests/servicemeshoperator3.clusterserviceversion.yaml
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is generated after compilation so it might embed outdated version IIUC. This looks quite dangerous.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For context, it broke our upstream sync job which is removing generated files in the bundle dir before running make gen

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FilipB The Library that reads this is imported via Source, not as a binary. We'll tag the "source release" after the CSV has been updated with the latest SHAs from the binary builds.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FilipB Sorry for breaking the job. If you can make an exception to the delete that would be great. Else I can technically move that file up one level, but that require some code changes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries. Just to be clear, there is no need to move bundle/bundle.go file, it fails on:
ERROR: exit status 1: bundle/bundle.go:19:12: pattern manifests/servicemeshoperator3.clusterserviceversion.yaml: no matching files found as we do rm -rf bundle/**/*.yaml before running make gen

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it's actually failing on make mirror-licenses which is part of gen target. I thought it fails during compilation.

var CSV []byte
27 changes: 27 additions & 0 deletions chart/crds/crds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package crds provides embedded CRD YAML files for Istio and Sail resources.
package crds

import "embed"

// FS contains all CRD YAML files from the chart/crds directory.
// This allows programmatic access to CRDs for installation.
//
// CRD files follow the naming convention: {group}_{plural}.yaml
// Example: extensions.istio.io_wasmplugins.yaml
//
//go:embed *.yaml
var FS embed.FS
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ require (
k8s.io/apimachinery v0.35.1
k8s.io/cli-runtime v0.35.0
k8s.io/client-go v0.35.1
k8s.io/utils v0.0.0-20260108192941-914a6e750570
sigs.k8s.io/controller-runtime v0.23.3
sigs.k8s.io/yaml v1.6.0
)

require (
Expand Down Expand Up @@ -175,7 +177,6 @@ require (
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e // indirect
k8s.io/kubectl v0.35.0 // indirect
k8s.io/utils v0.0.0-20260108192941-914a6e750570 // indirect
oras.land/oras-go/v2 v2.6.0 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.1 // indirect
sigs.k8s.io/controller-tools v0.14.0 // indirect
Expand All @@ -184,5 +185,4 @@ require (
sigs.k8s.io/kustomize/kyaml v0.20.1 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
)
109 changes: 109 additions & 0 deletions pkg/install/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# pkg/install

Library for managing istiod installations without running the Sail Operator.
Designed for embedding in other operators (e.g. OpenShift Ingress) that need
to install and maintain Istio as an internal dependency.

## Usage

```go
lib, err := install.New(kubeConfig, resourceFS)
notifyCh := lib.Start(ctx)

// In controller reconcile:
lib.Apply(install.Options{
Namespace: "istio-system",
Values: install.GatewayAPIDefaults(),
})

// Read result after notification:
for range notifyCh {
status := lib.Status()
// update conditions from status
}

// Teardown:
lib.Uninstall(ctx, "istio-system", "default")
```

## How it works

The Library runs as an independent actor with a simple state model:

1. **Apply** -- consumer sends desired state (version, namespace, values)
2. **Reconcile** -- Library installs/upgrades CRDs and istiod via Helm
3. **Drift detection** -- dynamic informers watch owned resources and CRDs, re-enqueuing reconciliation on changes
4. **Status** -- consumer reads the reconciliation result

The reconciliation loop sits idle until the first `Apply()` call. After that,
it stays active with informers running until `Uninstall()` clears the desired
state and stops the loop.

## Public API

### Constructor

- `New(kubeConfig, resourceFS)` -- creates a Library with Kubernetes clients, Helm chart manager, and CRD manager
- `FromDirectory(path)` -- creates an `fs.FS` from a filesystem path (alternative to embedded resources)

### Library methods

| Method | Description |
|---|---|
| `Start(ctx)` | Starts the reconciliation loop; returns a notification channel |
| `Apply(opts)` | Sets desired state; enqueues reconciliation if changed |
| `Enqueue()` | Forces re-reconciliation without changing desired state |
| `Status()` | Returns the latest reconciliation result |
| `Uninstall(ctx, ns, rev)` | Stops informers, waits for processing, then Helm-uninstalls |

### Types

- **Options** -- install options: `Namespace`, `Version`, `Revision`, `Values`, `ManageCRDs`, `IncludeAllCRDs`, `OverwriteOLMManagedCRD`
- **Status** -- reconciliation result: `CRDState`, `CRDMessage`, `CRDs`, `Installed`, `Version`, `Error`
- **CRDManagementState** -- aggregate CRD ownership: `ManagedByCIO`, `ManagedByOLM`, `UnknownManagement`, `MixedOwnership`, `NoneExist`
- **CRDInfo** -- per-CRD state: `Name`, `State`, `Found`
- **ImageNames** -- image names for each component: `Istiod`, `Proxy`, `CNI`, `ZTunnel`

### Helper functions

- `GatewayAPIDefaults()` -- pre-configured values for Gateway API mode on OpenShift
- `MergeValues(base, overlay)` -- deep-merge two Values structs (overlay wins)
- `DefaultVersion(resourceFS)` -- highest stable semver version from the resource FS
- `NormalizeVersion(version)` -- ensures a `v` prefix
- `ValidateVersion(resourceFS, version)` -- checks that a version directory exists
- `SetImageDefaults(resourceFS, registry, images)` -- populates image refs from version directories
- `LibraryRBACRules()` -- returns RBAC PolicyRules for a consumer's ClusterRole

## CRD management

The Library classifies existing CRDs by ownership labels before deciding what to do:

| State | Meaning | Action |
|---|---|---|
| `NoneExist` | No target CRDs on cluster | Install with CIO labels |
| `ManagedByCIO` | All owned by Cluster Ingress Operator | Update as needed |
| `ManagedByOLM` | All owned by OLM (OSSM subscription) | Leave alone; Helm install proceeds |
| `UnknownManagement` | CRDs exist without recognized labels | Leave alone; set Status.Error |
| `MixedOwnership` | Inconsistent labels across CRDs | Leave alone; set Status.Error |

The `OverwriteOLMManagedCRD` callback in Options lets the consumer decide
whether to take over OLM-managed CRDs (e.g. after an OSSM subscription is deleted).

Which CRDs are targeted depends on `IncludeAllCRDs`: when false (default), only
CRDs matching `PILOT_INCLUDE_RESOURCES` / `PILOT_IGNORE_RESOURCES` are managed.

## Files

| File | Purpose |
|---|---|
| `library.go` | Public API, types (`Library`, `Status`, `Options`), constructor |
| `lifecycle.go` | Reconciliation loop, workqueue, `Start`/`Apply`/`Uninstall` |
| `installer.go` | Core install/uninstall logic, Helm values resolution, watch spec extraction |
| `crds.go` | CRD ownership classification, install, update |
| `crds_filter.go` | CRD selection based on `PILOT_INCLUDE_RESOURCES` / `PILOT_IGNORE_RESOURCES` |
| `values.go` | `GatewayAPIDefaults()`, `MergeValues()` |
| `predicates.go` | Event filtering for informers (ownership checks, status-only changes) |
| `informers.go` | Dynamic informer setup for drift detection |
| `version.go` | Version resolution and validation |
| `images.go` | Image configuration from resource FS |
| `rbac.go` | RBAC rules for library consumers |
Loading