Skip to content
Merged
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
1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ ARG TARGETOS TARGETARCH
COPY --from=packager /output /

ADD out/${TARGETOS:-linux}_${TARGETARCH:-amd64}/sail-operator /sail-operator
ADD resources /var/lib/sail-operator/resources

USER 65532:65532
WORKDIR /
Expand Down
2 changes: 1 addition & 1 deletion Makefile.core.mk
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ build: build-$(TARGET_ARCH) ## Build the sail-operator binary.

.PHONY: run
run: gen ## Run a controller from your host.
POD_NAMESPACE=${NAMESPACE} go run ./cmd/main.go --config-file=./hack/config.properties --resource-directory=./resources
POD_NAMESPACE=${NAMESPACE} go run ./cmd/main.go --config-file=./hack/config.properties

# docker build -t ${IMAGE} --build-arg GIT_TAG=${GIT_TAG} --build-arg GIT_REVISION=${GIT_REVISION} --build-arg GIT_STATUS=${GIT_STATUS} .
.PHONY: docker-build
Expand Down
11 changes: 10 additions & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/istio-ecosystem/sail-operator/pkg/helm"
"github.com/istio-ecosystem/sail-operator/pkg/scheme"
"github.com/istio-ecosystem/sail-operator/pkg/version"
"github.com/istio-ecosystem/sail-operator/resources"
_ "k8s.io/client-go/plugin/pkg/client/auth"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
Expand All @@ -47,6 +48,7 @@ func main() {
var metricsAddr string
var probeAddr string
var configFile string
var resourceDirectory string
var logAPIRequests bool
var printVersion bool
var leaderElectionEnabled bool
Expand All @@ -55,7 +57,7 @@ func main() {
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8443", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
flag.StringVar(&configFile, "config-file", "/etc/sail-operator/config.properties", "Location of the config file, propagated by k8s downward APIs")
flag.StringVar(&reconcilerCfg.ResourceDirectory, "resource-directory", "/var/lib/sail-operator/resources", "Where to find resources (e.g. charts)")
flag.StringVar(&resourceDirectory, "resource-directory", "", "Where to find resources (e.g. charts). If empty, uses embedded resources.")
flag.IntVar(&reconcilerCfg.MaxConcurrentReconciles, "max-concurrent-reconciles", 1,
"MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run.")
flag.BoolVar(&logAPIRequests, "log-api-requests", false, "Whether to log each request sent to the Kubernetes API server")
Expand All @@ -78,6 +80,13 @@ func main() {

ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

if resourceDirectory != "" {
setupLog.Info("using filesystem resources", "directory", resourceDirectory)
reconcilerCfg.ResourceFS = os.DirFS(resourceDirectory)
} else {
setupLog.Info("using embedded resources")
reconcilerCfg.ResourceFS = resources.FS
}
reconcilerCfg.OperatorNamespace = os.Getenv("POD_NAMESPACE")
if reconcilerCfg.OperatorNamespace == "" {
contents, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
Expand Down
2 changes: 1 addition & 1 deletion controllers/istio/istio_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (r *Reconciler) reconcileActiveRevision(ctx context.Context, istio *v1.Isti
values, err := revision.ComputeValues(
istio.Spec.Values, istio.Spec.Namespace, version,
r.Config.Platform, r.Config.DefaultProfile, istio.Spec.Profile,
r.Config.ResourceDirectory, getActiveRevisionName(istio))
r.Config.ResourceFS, getActiveRevisionName(istio))
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion controllers/istio/istio_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package istio
import (
"context"
"fmt"
"os"
"runtime/debug"
"strings"
"testing"
Expand Down Expand Up @@ -1091,7 +1092,7 @@ func noWrites(t *testing.T) interceptor.Funcs {

func newReconcilerTestConfig(t *testing.T) config.ReconcilerConfig {
return config.ReconcilerConfig{
ResourceDirectory: t.TempDir(),
ResourceFS: os.DirFS(t.TempDir()),
Platform: config.PlatformKubernetes,
DefaultProfile: "",
MaxConcurrentReconciles: 1,
Expand Down
9 changes: 5 additions & 4 deletions controllers/istiocni/istiocni_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,20 +162,21 @@ func (r *Reconciler) installHelmChart(ctx context.Context, cni *v1.IstioCNI) err

// apply userValues on top of defaultValues from profiles
mergedHelmValues, err := istiovalues.ApplyProfilesAndPlatform(
r.Config.ResourceDirectory, version, r.Config.Platform, r.Config.DefaultProfile, cni.Spec.Profile, helm.FromValues(userValues))
r.Config.ResourceFS, version, r.Config.Platform, r.Config.DefaultProfile, cni.Spec.Profile, helm.FromValues(userValues))
if err != nil {
return fmt.Errorf("failed to apply profile: %w", err)
}

_, err = r.ChartManager.UpgradeOrInstallChart(ctx, r.getChartDir(version), mergedHelmValues, cni.Spec.Namespace, cniReleaseName, &ownerReference)
_, err = r.ChartManager.UpgradeOrInstallChart(
ctx, r.Config.ResourceFS, r.getChartPath(version), mergedHelmValues, cni.Spec.Namespace, cniReleaseName, &ownerReference)
if err != nil {
return fmt.Errorf("failed to install/update Helm chart %q: %w", cniChartName, err)
}
return nil
}

func (r *Reconciler) getChartDir(version string) string {
return path.Join(r.Config.ResourceDirectory, version, "charts", cniChartName)
func (r *Reconciler) getChartPath(version string) string {
return path.Join(version, "charts", cniChartName)
}

func applyImageDigests(version string, values *v1.CNIValues, config config.OperatorConfig) *v1.CNIValues {
Expand Down
3 changes: 2 additions & 1 deletion controllers/istiocni/istiocni_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package istiocni
import (
"context"
"fmt"
"os"
"testing"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -705,7 +706,7 @@ func normalize(condition v1.IstioCNICondition) v1.IstioCNICondition {

func newReconcilerTestConfig(t *testing.T) config.ReconcilerConfig {
return config.ReconcilerConfig{
ResourceDirectory: t.TempDir(),
ResourceFS: os.DirFS(t.TempDir()),
Platform: config.PlatformKubernetes,
DefaultProfile: "",
MaxConcurrentReconciles: 1,
Expand Down
8 changes: 4 additions & 4 deletions controllers/istiorevision/istiorevision_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,13 @@ func (r *Reconciler) installHelmCharts(ctx context.Context, rev *v1.IstioRevisio
}

values := helm.FromValues(rev.Spec.Values)
_, err := r.ChartManager.UpgradeOrInstallChart(ctx, r.getChartDir(rev, constants.IstiodChartName),
_, err := r.ChartManager.UpgradeOrInstallChart(ctx, r.Config.ResourceFS, r.getChartPath(rev, constants.IstiodChartName),
values, rev.Spec.Namespace, getReleaseName(rev, constants.IstiodChartName), &ownerReference)
if err != nil {
return fmt.Errorf("failed to install/update Helm chart %q: %w", constants.IstiodChartName, err)
}
if rev.Name == v1.DefaultRevision {
_, err := r.ChartManager.UpgradeOrInstallChart(ctx, r.getChartDir(rev, constants.BaseChartName),
_, err := r.ChartManager.UpgradeOrInstallChart(ctx, r.Config.ResourceFS, r.getChartPath(rev, constants.BaseChartName),
values, r.Config.OperatorNamespace, getReleaseName(rev, constants.BaseChartName), &ownerReference)
if err != nil {
return fmt.Errorf("failed to install/update Helm chart %q: %w", constants.BaseChartName, err)
Expand All @@ -195,8 +195,8 @@ func getReleaseName(rev *v1.IstioRevision, chartName string) string {
return fmt.Sprintf("%s-%s", rev.Name, chartName)
}

func (r *Reconciler) getChartDir(rev *v1.IstioRevision, chartName string) string {
return path.Join(r.Config.ResourceDirectory, rev.Spec.Version, "charts", chartName)
func (r *Reconciler) getChartPath(rev *v1.IstioRevision, chartName string) string {
return path.Join(rev.Spec.Version, "charts", chartName)
}

func (r *Reconciler) uninstallHelmCharts(ctx context.Context, rev *v1.IstioRevision) error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package istiorevision
import (
"context"
"fmt"
"os"
"strings"
"testing"

Expand Down Expand Up @@ -1053,7 +1054,7 @@ func TestIgnoreStatusChangePredicate(t *testing.T) {

func newReconcilerTestConfig(t *testing.T) config.ReconcilerConfig {
return config.ReconcilerConfig{
ResourceDirectory: t.TempDir(),
ResourceFS: os.DirFS(t.TempDir()),
Platform: config.PlatformKubernetes,
DefaultProfile: "",
MaxConcurrentReconciles: 1,
Expand Down
8 changes: 4 additions & 4 deletions controllers/istiorevisiontag/istiorevisiontag_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,13 @@ func (r *Reconciler) installHelmCharts(ctx context.Context, tag *v1.IstioRevisio
return err
}

_, err := r.ChartManager.UpgradeOrInstallChart(ctx, r.getChartDir(rev, revisionTagsChartName),
_, err := r.ChartManager.UpgradeOrInstallChart(ctx, r.Config.ResourceFS, r.getChartPath(rev, revisionTagsChartName),
values, rev.Spec.Namespace, getReleaseName(tag, revisionTagsChartName), &ownerReference)
if err != nil {
return fmt.Errorf("failed to install/update Helm chart %q: %w", revisionTagsChartName, err)
}
if tag.Name == v1.DefaultRevision {
_, err := r.ChartManager.UpgradeOrInstallChart(ctx, r.getChartDir(rev, constants.BaseChartName),
_, err := r.ChartManager.UpgradeOrInstallChart(ctx, r.Config.ResourceFS, r.getChartPath(rev, constants.BaseChartName),
values, r.Config.OperatorNamespace, getReleaseName(tag, constants.BaseChartName), &ownerReference)
if err != nil {
return fmt.Errorf("failed to install/update Helm chart %q: %w", constants.BaseChartName, err)
Expand All @@ -217,8 +217,8 @@ func getReleaseName(tag *v1.IstioRevisionTag, chartName string) string {
return fmt.Sprintf("%s-%s", tag.Name, chartName)
}

func (r *Reconciler) getChartDir(tag *v1.IstioRevision, chartName string) string {
return path.Join(r.Config.ResourceDirectory, tag.Spec.Version, "charts", chartName)
func (r *Reconciler) getChartPath(rev *v1.IstioRevision, chartName string) string {
return path.Join(rev.Spec.Version, "charts", chartName)
}

func (r *Reconciler) uninstallHelmCharts(ctx context.Context, tag *v1.IstioRevisionTag) error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package istiorevisiontag
import (
"context"
"fmt"
"os"
"strings"
"testing"

Expand Down Expand Up @@ -277,7 +278,7 @@ func TestDetermineInUseCondition(t *testing.T) {

func newReconcilerTestConfig(t *testing.T) config.ReconcilerConfig {
return config.ReconcilerConfig{
ResourceDirectory: t.TempDir(),
ResourceFS: os.DirFS(t.TempDir()),
Platform: config.PlatformKubernetes,
DefaultProfile: "",
MaxConcurrentReconciles: 1,
Expand Down
3 changes: 2 additions & 1 deletion controllers/webhook/webhook_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"net"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"

Expand Down Expand Up @@ -615,7 +616,7 @@ func generateSelfSignedCert(dnsNames ...string) (certPEM []byte, keyPEM []byte,

func newReconcilerTestConfig(t *testing.T) config.ReconcilerConfig {
return config.ReconcilerConfig{
ResourceDirectory: t.TempDir(),
ResourceFS: os.DirFS(t.TempDir()),
Platform: config.PlatformKubernetes,
DefaultProfile: "",
MaxConcurrentReconciles: 1,
Expand Down
9 changes: 5 additions & 4 deletions controllers/ztunnel/ztunnel_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func (r *Reconciler) installHelmChart(ctx context.Context, ztunnel *v1.ZTunnel)

// apply userValues on top of defaultValues from profiles
mergedHelmValues, err := istiovalues.ApplyProfilesAndPlatform(
r.Config.ResourceDirectory, version, r.Config.Platform, r.Config.DefaultProfile, defaultProfile, helm.FromValues(userValues))
r.Config.ResourceFS, version, r.Config.Platform, r.Config.DefaultProfile, defaultProfile, helm.FromValues(userValues))
if err != nil {
return fmt.Errorf("failed to apply profile: %w", err)
}
Expand All @@ -166,15 +166,16 @@ func (r *Reconciler) installHelmChart(ctx context.Context, ztunnel *v1.ZTunnel)
return fmt.Errorf("failed to apply user overrides: %w", err)
}

_, err = r.ChartManager.UpgradeOrInstallChart(ctx, r.getChartDir(version), finalHelmValues, ztunnel.Spec.Namespace, ztunnelChart, &ownerReference)
_, err = r.ChartManager.UpgradeOrInstallChart(
ctx, r.Config.ResourceFS, r.getChartPath(version), finalHelmValues, ztunnel.Spec.Namespace, ztunnelChart, &ownerReference)
if err != nil {
return fmt.Errorf("failed to install/update Helm chart %q: %w", ztunnelChart, err)
}
return nil
}

func (r *Reconciler) getChartDir(version string) string {
return path.Join(r.Config.ResourceDirectory, version, "charts", ztunnelChart)
func (r *Reconciler) getChartPath(version string) string {
return path.Join(version, "charts", ztunnelChart)
}

func applyImageDigests(version string, values *v1.ZTunnelValues, config config.OperatorConfig) *v1.ZTunnelValues {
Expand Down
7 changes: 4 additions & 3 deletions controllers/ztunnel/ztunnel_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package ztunnel
import (
"context"
"fmt"
"os"
"testing"
"time"

Expand Down Expand Up @@ -581,8 +582,8 @@ func normalize(condition v1.ZTunnelCondition) v1.ZTunnelCondition {

func newReconcilerTestConfig(t *testing.T) config.ReconcilerConfig {
return config.ReconcilerConfig{
ResourceDirectory: t.TempDir(),
Platform: config.PlatformKubernetes,
DefaultProfile: "",
ResourceFS: os.DirFS(t.TempDir()),
Platform: config.PlatformKubernetes,
DefaultProfile: "",
}
}
3 changes: 2 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package config

import (
"io/fs"
"strings"

"github.com/magiconair/properties"
Expand All @@ -34,7 +35,7 @@ type IstioImageConfig struct {
}

type ReconcilerConfig struct {
ResourceDirectory string
ResourceFS fs.FS
Platform Platform
DefaultProfile string
OperatorNamespace string
Expand Down
26 changes: 18 additions & 8 deletions pkg/helm/chartmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ import (
"context"
"errors"
"fmt"
"io/fs"

"helm.sh/helm/v3/pkg/action"
chartLoader "helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/release"
"helm.sh/helm/v3/pkg/storage/driver"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -60,19 +61,28 @@ func (h *ChartManager) newActionConfig(ctx context.Context, namespace string) (*
return actionConfig, err
}

// UpgradeOrInstallChart upgrades a chart in cluster or installs it new if it does not already exist
// UpgradeOrInstallChart upgrades a chart in cluster or installs it new if it does not already exist.
// It loads the chart from an fs.FS (e.g., embed.FS or os.DirFS).
func (h *ChartManager) UpgradeOrInstallChart(
ctx context.Context, chartDir string, values Values,
ctx context.Context, resourceFS fs.FS, chartPath string, values Values,
namespace, releaseName string, ownerReference *metav1.OwnerReference,
) (*release.Release, error) {
log := logf.FromContext(ctx)

cfg, err := h.newActionConfig(ctx, namespace)
loadedChart, err := LoadChart(resourceFS, chartPath)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to load chart from fs: %w", err)
}

chart, err := chartLoader.Load(chartDir)
return h.upgradeOrInstallChart(ctx, loadedChart, values, namespace, releaseName, ownerReference)
}

// upgradeOrInstallChart is the internal implementation that works with an already-loaded chart
func (h *ChartManager) upgradeOrInstallChart(
ctx context.Context, chart *chart.Chart, values Values,
namespace, releaseName string, ownerReference *metav1.OwnerReference,
) (*release.Release, error) {
log := logf.FromContext(ctx)

cfg, err := h.newActionConfig(ctx, namespace)
if err != nil {
return nil, err
}
Expand Down
Loading
Loading