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
Enable ambient for experimental
  • Loading branch information
kolodziejczak committed Nov 21, 2025
commit ac7e7ee2e2009c0f04d383e309d299b101e3836e
1 change: 1 addition & 0 deletions api/v1alpha2/experimental.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type Experimental struct {
// Enables the Dual Stack support
// +kubebuilder:validation:Optional
EnableDualStack *bool `json:"enableDualStack,omitempty"`
EnableAmbient *bool `json:"enableAmbient,omitempty"`
}

type PilotFeatures struct {
Expand Down
76 changes: 71 additions & 5 deletions api/v1alpha2/istio_merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ package v1alpha2

import (
"encoding/json"

"github.com/golang/protobuf/ptypes/duration"
"google.golang.org/protobuf/types/known/structpb"
meshv1alpha1 "istio.io/api/mesh/v1alpha1"
iopv1alpha1 "istio.io/istio/operator/pkg/apis"
"istio.io/istio/operator/pkg/values"
"istio.io/istio/pkg/util/protomarshal"
appsv1 "k8s.io/api/apps/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/intstr"

"google.golang.org/protobuf/types/known/structpb"
meshv1alpha1 "istio.io/api/mesh/v1alpha1"
iopv1alpha1 "istio.io/istio/operator/pkg/apis"
)

func (i *Istio) MergeInto(op iopv1alpha1.IstioOperator) (iopv1alpha1.IstioOperator, error) {
Expand Down Expand Up @@ -87,6 +87,17 @@ func (m *meshConfigBuilder) BuildDualStackConfig(enableDualStack bool) *meshConf
return m
}

func (m *meshConfigBuilder) BuildAmbientConfig(ambientEnabled bool) *meshConfigBuilder {
if ambientEnabled {
err := m.c.SetPath("defaultConfig.proxyMetadata.ISTIO_META_ENABLE_HBONE", "true")
if err != nil {
return nil
}
}

return m
}

func (m *meshConfigBuilder) AddProxyMetadata(key, value string) (*meshConfigBuilder, error) {
err := m.c.SetPath("defaultConfig.proxyMetadata."+key, value)
if err != nil {
Expand Down Expand Up @@ -194,23 +205,30 @@ func (i *Istio) mergeConfig(op iopv1alpha1.IstioOperator) (iopv1alpha1.IstioOper
}

dualStackEnabled := i.Spec.Experimental != nil && i.Spec.Experimental.EnableDualStack != nil && *i.Spec.Experimental.EnableDualStack
ambientEnabled := i.Spec.Experimental != nil && i.Spec.Experimental.EnableAmbient != nil && *i.Spec.Experimental.EnableAmbient == true

newMeshConfig := mcb.
BuildNumTrustedProxies(i.Spec.Config.NumTrustedProxies).
BuildExternalAuthorizerConfiguration(i.Spec.Config.Authorizers).
BuildPrometheusMergeConfig(i.Spec.Config.Telemetry.Metrics.PrometheusMerge).
BuildDualStackConfig(dualStackEnabled).
BuildAmbientConfig(ambientEnabled).
Build()

op.Spec.MeshConfig = newMeshConfig

op = applyGatewayExternalTrafficPolicy(op, i)

op, err = applyDualStack(op, i)
if err != nil {
return op, err
}

op, err = enableAmbient(op, ambientEnabled)
if err != nil {
return op, err
}

return op, nil
}

Expand Down Expand Up @@ -288,6 +306,54 @@ func enableDualStack(op iopv1alpha1.IstioOperator, i *Istio) (iopv1alpha1.IstioO
return op, nil
}

func enableAmbient(op iopv1alpha1.IstioOperator, ambientEnabled bool) (iopv1alpha1.IstioOperator, error) {
// if ambient is not enabled in the spec.Experimental, then we exit early without changes
if !ambientEnabled {
return op, nil
}

// enable ztunnel component
boolValue := iopv1alpha1.BoolValue{}
err := boolValue.UnmarshalJSON([]byte("true"))
if err != nil {
return iopv1alpha1.IstioOperator{}, err
}
if op.Spec.Components == nil {
op.Spec.Components = &iopv1alpha1.IstioComponentSpec{}
}

op.Spec.Components.Ztunnel = &iopv1alpha1.ComponentSpec{
Enabled: &boolValue,
}

// set values
valuesMap, err := values.MapFromObject(op.Spec.Values)
if err != nil {
return iopv1alpha1.IstioOperator{}, err
}

if valuesMap == nil {
valuesMap = make(values.Map)
}

err = valuesMap.SetPath("pilot.env.PILOT_ENABLE_AMBIENT", "true")
if err != nil {
return iopv1alpha1.IstioOperator{}, err
}

err = valuesMap.SetPath("cni.ambient.enabled", true)
if err != nil {
return iopv1alpha1.IstioOperator{}, err
}

op.Spec.Values, err = values.ConvertMap[json.RawMessage](valuesMap)
if err != nil {
return op, err
}

return op, nil
}

//nolint:gocognit,gocyclo,cyclop,funlen // cognitive complexity 189 of func `(*Istio).mergeResources` is high (> 20), cyclomatic complexity 70 of func `(*Istio).mergeResources` is high (> 30), Function 'mergeResources' has too many statements (129 > 50) TODO: refactor this function
func (i *Istio) mergeResources(op iopv1alpha1.IstioOperator) (iopv1alpha1.IstioOperator, error) {
if i.Spec.Components == nil {
Expand Down
101 changes: 101 additions & 0 deletions api/v1alpha2/merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,30 @@ var _ = Describe("Merge", func() {
Expect(dualStack).To(Equal("true"))
})

It("should set ISTIO_META_ENABLE_HBONE in the mesh Config if ambient is enabled in the Istio CR", func() {
// given
enableAmbient := true
iop := iopv1alpha1.IstioOperator{
Spec: iopv1alpha1.IstioOperatorSpec{},
}
istioCR := istiov1alpha2.Istio{Spec: istiov1alpha2.IstioSpec{
Config: istiov1alpha2.Config{},
Experimental: &istiov1alpha2.Experimental{
EnableAmbient: &enableAmbient,
},
}}

// when
out, err := istioCR.MergeInto(iop)

meshConfig, err := values.MapFromObject(out.Spec.MeshConfig)
Expect(err).ShouldNot(HaveOccurred())

dualStack, exists := meshConfig.GetPath("defaultConfig.proxyMetadata.ISTIO_META_ENABLE_HBONE")
Expect(exists).To(BeTrue())
Expect(dualStack).To(Equal("true"))
})

Context("Pilot", func() {
Context("When Istio CR has 500m configured for CPU limits", func() {
It("should set CPU limits to 500m in IOP", func() {
Expand Down Expand Up @@ -865,6 +889,83 @@ var _ = Describe("Merge", func() {
})
})

Context("Ztunnel", func() {
It("should set dual stack env for Istio pilot if dualStack is enabled in the Istio CR", func() {
iop := iopv1alpha1.IstioOperator{
Spec: iopv1alpha1.IstioOperatorSpec{},
}

enabled := true

istioCR := istiov1alpha2.Istio{
Spec: istiov1alpha2.IstioSpec{
Experimental: &istiov1alpha2.Experimental{
EnableAmbient: &enabled,
},
},
}

// when
out, err := istioCR.MergeInto(iop)

valuesMap, err := values.MapFromObject(out.Spec.Values)
Expect(err).ShouldNot(HaveOccurred())

Expect(values.TryGetPathAs[string](valuesMap, "pilot.env.PILOT_ENABLE_AMBIENT")).To(Equal("true"))
})

It("should set dual stack env for Istio pilot if dualStack is enabled in the Istio CR", func() {
iop := iopv1alpha1.IstioOperator{
Spec: iopv1alpha1.IstioOperatorSpec{},
}

enabled := true

istioCR := istiov1alpha2.Istio{
Spec: istiov1alpha2.IstioSpec{
Experimental: &istiov1alpha2.Experimental{
EnableAmbient: &enabled,
},
},
}

// when
out, err := istioCR.MergeInto(iop)

valuesMap, err := values.MapFromObject(out.Spec.Values)
Expect(err).ShouldNot(HaveOccurred())

gp, good := valuesMap.GetPath("cni.ambient.enabled")
Expect(good).To(BeTrue())
Expect(gp).To(BeTrue())

})

It("should set Ztunnel component to enabled if experimental enableAmbient is set to true", func() {
iop := iopv1alpha1.IstioOperator{
Spec: iopv1alpha1.IstioOperatorSpec{},
}

enabled := true

istioCR := istiov1alpha2.Istio{
Spec: istiov1alpha2.IstioSpec{
Experimental: &istiov1alpha2.Experimental{
EnableAmbient: &enabled,
},
},
}

// when
out, err := istioCR.MergeInto(iop)

// then
Expect(err).ShouldNot(HaveOccurred())
ztunnelEnabled := out.Spec.Components.Ztunnel.Enabled.GetValueOrFalse()
Expect(ztunnelEnabled).To(BeTrue())
})
})

Context("EgressGateway", func() {
Context("When Istio CR has 500m configured for CPU and 500Mi for memory limits", func() {
It("should set CPU limits to 500m and 500Mi for memory in IOP", func() {
Expand Down
5 changes: 5 additions & 0 deletions api/v1alpha2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading