Skip to content

Commit

Permalink
Add config option to set maximum Istio version
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Grimm <[email protected]>
  • Loading branch information
dgn committed Dec 4, 2024
1 parent 5af33d3 commit e74df6c
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 1 deletion.
8 changes: 8 additions & 0 deletions controllers/istio/istio_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"strings"
"time"

"github.com/Masterminds/semver/v3"
"github.com/go-logr/logr"
"github.com/istio-ecosystem/sail-operator/api/v1alpha1"
"github.com/istio-ecosystem/sail-operator/pkg/config"
Expand Down Expand Up @@ -98,6 +99,13 @@ func validate(istio *v1alpha1.Istio) error {
if istio.Spec.Version == "" {
return reconciler.NewValidationError("spec.version not set")
}
istioVersion, err := semver.NewVersion(istio.Spec.Version)
if err != nil {
return reconciler.NewValidationError("spec.version is not a valid semver: " + err.Error())
}
if config.Config.MaximumIstioVersion != nil && istioVersion.GreaterThan(config.Config.MaximumIstioVersion) {
return reconciler.NewValidationError("spec.version is not supported")
}
if istio.Spec.Namespace == "" {
return reconciler.NewValidationError("spec.namespace not set")
}
Expand Down
30 changes: 30 additions & 0 deletions controllers/istio/istio_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"testing"
"time"

"github.com/Masterminds/semver/v3"
"github.com/google/go-cmp/cmp"
"github.com/istio-ecosystem/sail-operator/api/v1alpha1"
"github.com/istio-ecosystem/sail-operator/pkg/config"
Expand Down Expand Up @@ -169,6 +170,7 @@ func TestValidate(t *testing.T) {
name string
istio *v1alpha1.Istio
expectErr string
config config.OperatorConfig
}{
{
name: "success",
Expand Down Expand Up @@ -207,8 +209,36 @@ func TestValidate(t *testing.T) {
},
expectErr: "spec.namespace not set",
},
{
name: "invalid version",
istio: &v1alpha1.Istio{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
},
Spec: v1alpha1.IstioSpec{
Version: "v.-1.0",
},
},
expectErr: "spec.version is not a valid semver",
},
{
name: "version higher than maximum istio version",
istio: &v1alpha1.Istio{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
},
Spec: v1alpha1.IstioSpec{
Version: "v2.1.0",
},
},
expectErr: "spec.version is not supported",
config: config.OperatorConfig{
MaximumIstioVersion: semver.MustParse("v2.0.0"),
},
},
}
for _, tc := range testCases {
config.Config = tc.config
t.Run(tc.name, func(t *testing.T) {
g := NewWithT(t)

Expand Down
8 changes: 8 additions & 0 deletions controllers/istiorevision/istiorevision_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"reflect"
"regexp"

"github.com/Masterminds/semver/v3"
"github.com/go-logr/logr"
"github.com/istio-ecosystem/sail-operator/api/v1alpha1"
"github.com/istio-ecosystem/sail-operator/pkg/config"
Expand Down Expand Up @@ -123,6 +124,13 @@ func (r *Reconciler) validate(ctx context.Context, rev *v1alpha1.IstioRevision)
if rev.Spec.Version == "" {
return reconciler.NewValidationError("spec.version not set")
}
istioVersion, err := semver.NewVersion(rev.Spec.Version)
if err != nil {
return reconciler.NewValidationError("spec.version is not a valid semver: " + err.Error())
}
if config.Config.MaximumIstioVersion != nil && istioVersion.GreaterThan(config.Config.MaximumIstioVersion) {
return reconciler.NewValidationError("spec.version is not supported")
}
if rev.Spec.Namespace == "" {
return reconciler.NewValidationError("spec.namespace not set")
}
Expand Down
46 changes: 46 additions & 0 deletions controllers/istiorevision/istiorevision_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"strings"
"testing"

"github.com/Masterminds/semver/v3"
"github.com/istio-ecosystem/sail-operator/api/v1alpha1"
"github.com/istio-ecosystem/sail-operator/pkg/config"
"github.com/istio-ecosystem/sail-operator/pkg/constants"
Expand Down Expand Up @@ -52,6 +53,7 @@ func TestValidate(t *testing.T) {
rev *v1alpha1.IstioRevision
objects []client.Object
expectErr string
config config.OperatorConfig
}{
{
name: "success",
Expand Down Expand Up @@ -185,9 +187,53 @@ func TestValidate(t *testing.T) {
objects: []client.Object{ns},
expectErr: `spec.values.revision does not match IstioRevision name`,
},
{
name: "invalid version",
rev: &v1alpha1.IstioRevision{
ObjectMeta: metav1.ObjectMeta{
Name: "my-revision",
},
Spec: v1alpha1.IstioRevisionSpec{
Version: "v.-1.0",
Namespace: "istio-system",
Values: &v1alpha1.Values{
Revision: ptr.Of("other-revision"),
Global: &v1alpha1.GlobalConfig{
IstioNamespace: ptr.Of("other-namespace"),
},
},
},
},
objects: []client.Object{ns},
expectErr: "spec.version is not a valid semver",
},
{
name: "version higher than maximum istio version",
rev: &v1alpha1.IstioRevision{
ObjectMeta: metav1.ObjectMeta{
Name: "my-revision",
},
Spec: v1alpha1.IstioRevisionSpec{
Version: "v2.1.0",
Namespace: "istio-system",
Values: &v1alpha1.Values{
Revision: ptr.Of("other-revision"),
Global: &v1alpha1.GlobalConfig{
IstioNamespace: ptr.Of("other-namespace"),
},
},
},
},
objects: []client.Object{ns},
expectErr: "spec.version is not supported",
config: config.OperatorConfig{
MaximumIstioVersion: semver.MustParse("v2.0.0"),
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
config.Config = tc.config
g := NewWithT(t)
cl := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(tc.objects...).Build()
r := NewReconciler(cfg, cl, scheme.Scheme, nil)
Expand Down
12 changes: 11 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ package config
import (
"strings"

"github.com/Masterminds/semver/v3"
"github.com/magiconair/properties"
)

var Config = OperatorConfig{}

type OperatorConfig struct {
ImageDigests map[string]IstioImageConfig `properties:"images"`
ImageDigests map[string]IstioImageConfig `properties:"images"`
MaximumIstioVersion *semver.Version `properties:"-"` // property name is 'maxIstioVersion'
}

type IstioImageConfig struct {
Expand Down Expand Up @@ -59,5 +61,13 @@ func Read(configFile string) error {
newImageDigests[strings.Replace(k, "_", ".", -1)] = v
}
Config.ImageDigests = newImageDigests
// special handling to decode maxIstioVersion field
maxIstioVersion := p.GetString("maxIstioVersion", "")
if maxIstioVersion != "" {
Config.MaximumIstioVersion, err = semver.NewVersion(maxIstioVersion)
if err != nil {
return err
}
}
return nil
}
19 changes: 19 additions & 0 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"os"
"testing"

"github.com/Masterminds/semver/v3"
"github.com/google/go-cmp/cmp"
)

Expand Down Expand Up @@ -84,6 +85,24 @@ images.v1_20_0.ztunnel=ztunnel-test
`,
success: false,
},
{
name: "invalid-maxIstioVersion",
configFile: `
maxIstioVersion=v-2.31
`,
success: false,
},
{
name: "maxIstioVersion",
configFile: `
maxIstioVersion=v1.24.0
`,
expectedConfig: OperatorConfig{
ImageDigests: map[string]IstioImageConfig{},
MaximumIstioVersion: semver.MustParse("v1.24.0"),
},
success: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
Expand Down

0 comments on commit e74df6c

Please sign in to comment.