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
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ metadata:
name: example
spec:
namespace: istio-system
version: v1.22.0
```

**Note:** You can explicitly specify the version using the `spec.version` field. If not specified, the default version supported by the Operator will be used.

When you create an `Istio` resource, the sail operator then creates an `IstioRevision` that represents a control plane deployment.

```yaml
Expand All @@ -53,7 +54,6 @@ metadata:
...
spec:
namespace: istio-system
version: v1.22.0
status:
...
state: Healthy
Expand All @@ -67,13 +67,12 @@ kind: Istio
metadata:
name: example
spec:
version: v1.20.0
namespace: istio-system
values:
global:
mtls:
enabled: true
trustDomainAliases:
- example.net
variant: debug
logging:
level: "all:debug"
meshConfig:
trustDomain: example.com
trustDomainAliases:
Expand Down
68 changes: 49 additions & 19 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ spec:
values:
pilot:
traceSampling: 0.1
version: v1.23.2
version: v1.24.3
```

Note that the only field that was added is the `spec.version` field. There are a few situations however where the APIs are different and require different approaches to achieve the same outcome.
Expand Down Expand Up @@ -294,7 +294,7 @@ spec:
pilot:
env:
PILOT_ENABLE_STATUS: "true"
version: v1.23.0
version: v1.24.3
namespace: istio-system
```

Expand All @@ -304,6 +304,37 @@ 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, the script takes an input YAML file and istio version and generates a sail operator configuration file.

#### Usage
To run the configuration-converter.sh script, you need to provide four arguments, only input file is required other arguments are optional:

1. Input file path (<input>): The path to your Istio operator configuration YAML file (required).
2. Output file path (<output>): The path where the converted Sail configuration will be saved. If not provided, the script will save the output with -sail.yaml appended to the input file name.
3. Namespace (-n <namespace>): The Kubernetes namespace for the Istio deployment. Defaults to istio-system if not provided.
4. Version (-v <version>): The version of Istio to be used. If not provided, the `spec.version` field will be omitted from the output file and the operator will deploy the latest version when the YAML manifest is applied.

```bash
./tools/configuration-converter.sh </path/to/input.yaml> [/path/to/output.yaml] [-n namespace] [-v version]
```

##### Sample command only with input file:

```bash
./tools/configuration-converter.sh /home/user/istio_config.yaml
```

##### Sample command with custom output, namespace, and version:

```bash
./tools/configuration-converter.sh /home/user/input/istio_config.yaml /home/user/output/output.yaml -n custom-namespace -v v1.24.3
```

> [!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 Expand Up @@ -1224,26 +1255,26 @@ These installation instructions are adapted from: https://istio.io/latest/docs/s

```sh
kubectl apply --context="${CTX_CLUSTER1}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml \
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml" \
-l service=helloworld -n sample
kubectl apply --context="${CTX_CLUSTER1}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml \
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml" \
-l version=v1 -n sample
kubectl apply --context="${CTX_CLUSTER1}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/sleep/sleep.yaml -n sample
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/sleep/sleep.yaml" -n sample
```

13. Deploy sample applications in `cluster2`.

```sh
kubectl apply --context="${CTX_CLUSTER2}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml \
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml" \
-l service=helloworld -n sample
kubectl apply --context="${CTX_CLUSTER2}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml \
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml" \
-l version=v2 -n sample
kubectl apply --context="${CTX_CLUSTER2}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/sleep/sleep.yaml -n sample
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/sleep/sleep.yaml" -n sample
```

14. Wait for the sample applications to be ready.
Expand Down Expand Up @@ -1396,13 +1427,13 @@ In this setup there is a Primary cluster (`cluster1`) and a Remote cluster (`clu
kubectl get ns sample --context "${CTX_CLUSTER1}" || kubectl create --context="${CTX_CLUSTER1}" namespace sample
kubectl label --context="${CTX_CLUSTER1}" namespace sample istio-injection=enabled
kubectl apply --context="${CTX_CLUSTER1}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml \
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml" \
-l service=helloworld -n sample
kubectl apply --context="${CTX_CLUSTER1}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml \
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml" \
-l version=v1 -n sample
kubectl apply --context="${CTX_CLUSTER1}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/sleep/sleep.yaml -n sample
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/sleep/sleep.yaml" -n sample
```

10. Deploy sample applications to `cluster2`.
Expand All @@ -1411,13 +1442,13 @@ In this setup there is a Primary cluster (`cluster1`) and a Remote cluster (`clu
kubectl get ns sample --context "${CTX_CLUSTER2}" || kubectl create --context="${CTX_CLUSTER2}" namespace sample
kubectl label --context="${CTX_CLUSTER2}" namespace sample istio-injection=enabled
kubectl apply --context="${CTX_CLUSTER2}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml \
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml" \
-l service=helloworld -n sample
kubectl apply --context="${CTX_CLUSTER2}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml \
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml" \
-l version=v2 -n sample
kubectl apply --context="${CTX_CLUSTER2}" \
-f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/sleep/sleep.yaml -n sample
-f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/sleep/sleep.yaml" -n sample
```

11. Verify that you see a response from both v1 and v2 on `cluster1`.
Expand Down Expand Up @@ -1665,10 +1696,9 @@ In this setup there is an external control plane cluster (`cluster1`) and a remo
11. Deploy the `sleep` and `helloworld` applications to the `sample` namespace.

```sh
kubectl apply -f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml -l service=helloworld -n sample --context="${CTX_CLUSTER2}"
kubectl apply -f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml -l version=v1 -n sample --context="${CTX_CLUSTER2}"
kubectl apply -f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/sleep/sleep.yaml -n sample --context="${CTX_CLUSTER2}"

kubectl apply -f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml" -l service=helloworld -n sample --context="${CTX_CLUSTER2}"
kubectl apply -f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/helloworld.yaml" -l version=v1 -n sample --context="${CTX_CLUSTER2}"
kubectl apply -f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/sleep/sleep.yaml" -n sample --context="${CTX_CLUSTER2}"
```

12. Verify the pods in the `sample` namespace have a sidecar injected.
Expand Down Expand Up @@ -1703,7 +1733,7 @@ In this setup there is an external control plane cluster (`cluster1`) and a remo

Expose `helloworld` through the ingress gateway.
```sh
kubectl apply -f https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/gateway-api/helloworld-gateway.yaml -n sample --context="${CTX_CLUSTER2}"
kubectl apply -f "https://raw.githubusercontent.com/istio/istio/${ISTIO_VERSION}/samples/helloworld/gateway-api/helloworld-gateway.yaml" -n sample --context="${CTX_CLUSTER2}"
kubectl -n sample --context="${CTX_CLUSTER2}" wait --for=condition=programmed gtw helloworld-gateway
```

Expand Down
150 changes: 150 additions & 0 deletions pkg/converter/converter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// 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 converter

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

"github.com/google/go-cmp/cmp"
"github.com/istio-ecosystem/sail-operator/pkg/test/project"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/shell"
. "github.com/onsi/gomega"
"gopkg.in/yaml.v3"
)

var (
converter = filepath.Join(project.RootDir, "tools", "configuration-converter.sh")
istioFile = filepath.Join(project.RootDir, "tools", "istioConfig.yaml")
sailFile = filepath.Join(project.RootDir, "tools", "istioConfig-sail.yaml")
)

func TestConversion(t *testing.T) {
testcases := []struct {
name string
input string
args string
expectedOutput string
}{
{
name: "simple",
input: `apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: default
spec:`,
args: fmt.Sprintf("%s %s -n istio-system -v v1.24.3", istioFile, sailFile),
expectedOutput: `apiVersion: sailoperator.io/v1
kind: Istio
metadata:
name: default
spec:
namespace: istio-system
version: v1.24.3`,
},
{
name: "complex",
input: `apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: default
spec:
components:
base:
enabled: true
pilot:
enabled: false
values:
global:
externalIstiod: true
operatorManageWebhooks: true
configValidation: false
base:
enableCRDTemplates: true
pilot:
env:
PILOT_ENABLE_STATUS: true`,
args: fmt.Sprintf("-v v1.24.3 %s -n istio-system %s", istioFile, sailFile),
expectedOutput: `apiVersion: sailoperator.io/v1
kind: Istio
metadata:
name: default
spec:
values:
global:
externalIstiod: true
operatorManageWebhooks: true
configValidation: false
base:
enableCRDTemplates: true
enabled: true
pilot:
env:
PILOT_ENABLE_STATUS: "true"
enabled: false
namespace: istio-system
version: v1.24.3`,
},
{
name: "mandatory-arguments-only",
input: `apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: default
spec:`,
args: istioFile,
expectedOutput: `apiVersion: sailoperator.io/v1
kind: Istio
metadata:
name: default
spec:
namespace: istio-system`,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
g := NewWithT(t)
t.Cleanup(func() {
g.Expect(os.Remove(istioFile)).To(Succeed())
g.Expect(os.Remove(sailFile)).To(Succeed())
})

g.Expect(os.WriteFile(istioFile, []byte(tc.input), 0o644)).To(Succeed(), "failed to write YAML file")

_, err := shell.ExecuteCommand(converter + " " + tc.args)
g.Expect(err).NotTo(HaveOccurred(), "error in execution of ./configuration-converter.sh")

actualOutput, err := os.ReadFile(sailFile)
g.Expect(err).NotTo(HaveOccurred(), "Cannot read %s", sailFile)

actualData, err := parseYaml(actualOutput)
g.Expect(err).NotTo(HaveOccurred(), "Failed to parse sailFile")

expectedData, err := parseYaml([]byte(tc.expectedOutput))
g.Expect(err).NotTo(HaveOccurred(), "Failed to parse expected output")

g.Expect(cmp.Diff(actualData, expectedData)).To(Equal(""), "Conversion is not as expected")
})
}
}

// parseYaml takes a YAML string and unmarshals it into a map
func parseYaml(yamlContent []byte) (map[string]interface{}, error) {
var config map[string]interface{}
err := yaml.Unmarshal(yamlContent, &config)
return config, err
}
35 changes: 35 additions & 0 deletions tests/e2e/controlplane/control_plane_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ import (
"testing"

"github.com/istio-ecosystem/sail-operator/pkg/env"
"github.com/istio-ecosystem/sail-operator/pkg/kube"
. "github.com/istio-ecosystem/sail-operator/pkg/test/util/ginkgo"
k8sclient "github.com/istio-ecosystem/sail-operator/tests/e2e/util/client"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/common"
. "github.com/istio-ecosystem/sail-operator/tests/e2e/util/gomega"
"github.com/istio-ecosystem/sail-operator/tests/e2e/util/kubectl"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

Expand Down Expand Up @@ -64,3 +69,33 @@ func setup() {

k = kubectl.New()
}

var _ = BeforeSuite(func(ctx SpecContext) {
Expect(k.CreateNamespace(namespace)).To(Succeed(), "Namespace failed to be created")

if skipDeploy {
Success("Skipping operator installation because it was deployed externally")
} else {
Expect(common.InstallOperatorViaHelm()).
To(Succeed(), "Operator failed to be deployed")
}

Eventually(common.GetObject).WithArguments(ctx, cl, kube.Key(deploymentName, namespace), &appsv1.Deployment{}).
Should(HaveCondition(appsv1.DeploymentAvailable, metav1.ConditionTrue), "Error getting Istio CRD")
Success("Operator is deployed in the namespace and Running")
})

var _ = AfterSuite(func(ctx SpecContext) {
if skipDeploy {
Success("Skipping operator undeploy because it was deployed externally")
return
}

By("Deleting operator deployment")
Expect(common.UninstallOperator()).
To(Succeed(), "Operator failed to be deleted")
GinkgoWriter.Println("Operator uninstalled")

Expect(k.DeleteNamespace(namespace)).To(Succeed(), "Namespace failed to be deleted")
Success("Namespace deleted")
})
Loading