Skip to content

Commit

Permalink
converter for istio in-cluster operator config to sail operator config
Browse files Browse the repository at this point in the history
Signed-off-by: ctartici <[email protected]>
Signed-off-by: ctartici <[email protected]>
  • Loading branch information
ctartici committed Feb 9, 2025
1 parent 2a9e854 commit 427c845
Show file tree
Hide file tree
Showing 5 changed files with 327 additions and 3 deletions.
18 changes: 17 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ spec:
pilot:
env:
PILOT_ENABLE_STATUS: "true"
version: v1.23.0
version: v1.24.0
namespace: istio-system
```

Expand All @@ -303,6 +303,22 @@ Note the quotes around the value of `spec.values.pilot.env.PILOT_ENABLE_STATUS`.

Sail Operator's Istio resource does not have a `spec.components` field. Instead, you can enable and disable components directly by setting `spec.values.<component>.enabled: true/false`. Other functionality exposed through `spec.components` like the k8s overlays is not currently available.

### Converter Script
This script is used to convert an Istio in-cluster operator configuration to a Sail Operator configuration. Upon execution, a new YAML file will be created in the same directory which ISTIO-OPERATOR-CONFIG-YAML is present. The new file will be named: sail-operator-config.yaml

#### Usage
It is necessary to set ISTIO_VERSION and ISTIO_NAMESPACE as environment variables to be able to run the script.

```bash
export ISTIO_VERSION=v1.24.0
export ISTIO_NAMESPACE=istio-system
./tools/configuration-converter.sh <ISTIO_OPERATOR_CONFIG_YAML_WITH_PATH>
```

> [!WARNING]
> This script is still under development.
> Please verify the resulting configuration carefully after conversion to ensure it meets your expectations and requirements.

### CNI

The CNI plugin's lifecycle is managed separately from the control plane. You will have to create a [IstioCNI resource](#istiocni-resource) to use CNI.
Expand Down
93 changes: 91 additions & 2 deletions tests/e2e/controlplane/control_plane_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
. "github.com/istio-ecosystem/sail-operator/pkg/test/util/ginkgo"
"github.com/istio-ecosystem/sail-operator/pkg/test/util/supportedversion"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/common"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/configconverter"
. "github.com/istio-ecosystem/sail-operator/tests/e2e/util/gomega"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -111,6 +112,8 @@ metadata:
})

Describe("given Istio version", func() {
var istioYamlFileWithPath string
var err error
for _, version := range supportedversion.List {
Context(version.Name, func() {
BeforeAll(func() {
Expand Down Expand Up @@ -168,17 +171,97 @@ spec:
})
})

When("Sail Operator configuration", func() {
BeforeAll(func() {
Expect(configconverter.SetEnvVariables("ISTIO_VERSION", version.Name)).To(Succeed(), "error adding env variable: ISTIO_VERSION")
Expect(configconverter.SetEnvVariables("ISTIO_NAMESPACE", controlPlaneNamespace)).To(Succeed(), "error adding env variable: ISTIO_NAMESPACE")
istioYamlText := `
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: default
spec:
components:
pilot:
enabled: true
k8s:
resources:
requests:
cpu: 1000m # override from default 500m
memory: 4096Mi # ... default 2048Mi
hpaSpec:
maxReplicas: 10 # ... default 5
minReplicas: 2 # ... default 1
nodeSelector: # ... default empty
master: "true"
tolerations: # ... default empty
- key: dedicated
operator: Exists
effect: NoSchedule
- key: CriticalAddonsOnly
operator: Exists
values:
global:
istiod:
enableAnalysis: true
pilot:
env:
PILOT_ENABLE_STATUS: true`
Log("Istio in-cluster Operator Config YAML:", indent(2, istioYamlText))
istioYamlFileWithPath, err = configconverter.SaveYamlToFile(istioYamlText)
Expect(err).To(Succeed(), "failed to write YAML file")
Success("Provided istio config saved to file")
})

It("is created", func() {
Expect(configconverter.ExecuteConfigConverter(istioYamlFileWithPath)).To(Succeed(), "error in execution of ./configuration-converter.sh")
Success("Sail Operator Yaml Created")
})

It("is validated", func() {
sailYamlText := `
apiVersion: sailoperator.io/v1
kind: Istio
metadata:
name: default
spec:
values:
global:
istiod:
enableAnalysis: true
pilot:
env:
PILOT_ENABLE_STATUS: "true"
enabled: true
version: %s
namespace: %s`
sailYamlText = fmt.Sprintf(sailYamlText, version.Name, controlPlaneNamespace)
isConversionValidated, err := configconverter.ValidateYamlContent(sailYamlText)
Expect(err).To(Succeed(), "failed to read file")
Expect(isConversionValidated).To(BeTrue(), "YAML content is not as wanted")
Success("Conversion completed")
})
})

When("the Istio CR is created", func() {
BeforeAll(func() {
istioYAML := `
sailYAML := `
apiVersion: sailoperator.io/v1
kind: Istio
metadata:
name: default
spec:
values:
global:
istiod:
enableAnalysis: true
pilot:
env:
PILOT_ENABLE_STATUS: "true"
enabled: true
version: %s
namespace: %s`
istioYAML = fmt.Sprintf(istioYAML, version.Name, controlPlaneNamespace)
istioYAML := fmt.Sprintf(sailYAML, version.Name, controlPlaneNamespace)
Log("Istio YAML:", indent(2, istioYAML))
Expect(k.CreateFromString(istioYAML)).
To(Succeed(), "Istio CR failed to be created")
Expand Down Expand Up @@ -308,6 +391,11 @@ spec:
By("Deleting any left-over Istio and IstioRevision resources")
Expect(forceDeleteIstioResources()).To(Succeed())
Success("Resources deleted")

Expect(configconverter.DeleteFile("istioConfig.yaml")).To(Succeed(), "Created file for converter failed to be deleted")
Expect(configconverter.DeleteFile("sail-operator-config.yaml")).To(Succeed(), "Created file for converter failed to be deleted")
Success("Configuration Converter files deleted")

Success("Cleanup done")
})
})
Expand Down Expand Up @@ -341,6 +429,7 @@ func ImageFromRegistry(regexp string) types.GomegaMatcher {
return HaveField("Image", MatchRegexp(regexp))
}

//nolint:unparam
func indent(level int, str string) string {
indent := strings.Repeat(" ", level)
return indent + strings.ReplaceAll(str, "\n", "\n"+indent)
Expand Down
96 changes: 96 additions & 0 deletions tests/e2e/util/configconverter/configconverter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//go:build e2e

// 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 configconverter

import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/istio-ecosystem/sail-operator/pkg/test/project"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/shell"
)

func SetEnvVariables(envKey, envValue string) error {
err := os.Setenv(envKey, envValue)
if err != nil {
return fmt.Errorf("failed to set env variable: %w", err)
}
return nil
}

// saveYamlToFile writes the given YAML content to IstioConfig.yaml
func SaveYamlToFile(yamlText string) (string, error) {
// Create file in the same directory with the converter
istioYamlFile := "istioConfig.yaml"
istioYamlFileWithPath := filepath.Join(project.RootDir, "tools", istioYamlFile)

// Write to file
if err := os.WriteFile(istioYamlFileWithPath, []byte(yamlText), 0o644); err != nil {
return "", fmt.Errorf("failed to write YAML file: %w", err)
}

return istioYamlFileWithPath, nil
}

func ExecuteConfigConverter(istioYamlFilePath string) error {
// Define file path
configConverterPath := filepath.Join(project.RootDir, "tools", "configuration-converter.sh")

_, err := shell.ExecuteBashScript(configConverterPath, istioYamlFilePath)
if err != nil {
return fmt.Errorf("error in execution of %s %s: %w", configConverterPath, istioYamlFilePath, err)
}

return nil
}

// compareYamlContent checks if the provided YAML string matches the content of converted config
func ValidateYamlContent(yamlString string) (bool, error) {
sailYamlWithPath := filepath.Join(project.RootDir, "tools", "sail-operator-config.yaml")

// Write the input YAML string to a temporary file
tmpFile := filepath.Join(project.RootDir, "tools", "temp.yaml")
err := os.WriteFile(tmpFile, []byte(yamlString), 0o644)
if err != nil {
return false, fmt.Errorf("failed to write temporary YAML file: %w", err)
}
defer os.Remove(tmpFile)

// The command will check if the files are equal, ignoring order
cmd := fmt.Sprintf("yq eval 'diff %s %s' > /dev/null 2>&1", sailYamlWithPath, tmpFile)
output, err := shell.ExecuteCommand(cmd)
if err != nil {
if strings.Contains(output, "diff") {
return false, nil
}
return false, fmt.Errorf("error executing yq comparison: %w", err)
}

// If no output from yq, the files are considered equal
return true, nil
}

func DeleteFile(fileName string) error {
fileWithPath := filepath.Join(project.RootDir, "tools", fileName)
err := os.Remove(fileWithPath)
if err != nil {
return fmt.Errorf("failed to delete file %s: %w", fileWithPath, err)
}
return nil
}
32 changes: 32 additions & 0 deletions tests/e2e/util/shell/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)

Expand Down Expand Up @@ -53,3 +54,34 @@ func ExecuteShell(command string, input string) (string, error) {

return stdout.String(), nil
}

// Execute bash script with optional arguments
func ExecuteBashScript(scriptPath string, args ...string) (string, error) {
absScriptPath, err := filepath.Abs(scriptPath)
if err != nil {
return "", fmt.Errorf("error getting absolute path: %w", err)
}

if _, err := os.Stat(absScriptPath); os.IsNotExist(err) {
return "", fmt.Errorf("script file does not exist: %s", absScriptPath)
}

scriptDir := filepath.Dir(absScriptPath)
cmdArgs := append([]string{absScriptPath}, args...)
cmd := exec.Command("bash", cmdArgs...)

var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr

// set dir to dir of the script before execution
cmd.Dir = scriptDir

// Run the script
err = cmd.Run()
if err != nil {
return "", fmt.Errorf("error executing script: %s, stderr: %s", err, stderr.String())
}

return stdout.String(), nil
}
Loading

0 comments on commit 427c845

Please sign in to comment.