mirror of
https://github.com/hanzo-ml/spark-operator.git
synced 2026-10-30 20:39:07 +00:00
2352 lines
61 KiB
Go
2352 lines
61 KiB
Go
/*
|
|
Copyright 2018 Google LLC
|
|
|
|
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
|
|
|
|
https://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 webhook
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"github.com/kubeflow/spark-operator/v2/api/v1beta2"
|
|
"github.com/kubeflow/spark-operator/v2/pkg/common"
|
|
)
|
|
|
|
func TestPatchSparkPod_OwnerReference(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
}
|
|
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Test patching a pod without existing OwnerReference and Volume.
|
|
modifiedPod, err := getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedPod.OwnerReferences, 1)
|
|
|
|
// Test patching a pod with existing OwnerReference and Volume.
|
|
pod.OwnerReferences = append(pod.OwnerReferences, metav1.OwnerReference{Name: "owner-reference1"})
|
|
|
|
modifiedPod, err = getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedPod.OwnerReferences, 2)
|
|
|
|
// Test patching OwnerReference be idempotent.
|
|
oldOwnerReferences := modifiedPod.DeepCopy().OwnerReferences
|
|
pod.OwnerReferences = modifiedPod.DeepCopy().OwnerReferences
|
|
modifiedPod, err = getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Equal(t, modifiedPod.OwnerReferences, oldOwnerReferences)
|
|
}
|
|
|
|
func TestPatchSparkPod_Local_Volumes(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Volumes: []corev1.Volume{
|
|
{
|
|
Name: "spark-local-dir-1",
|
|
VolumeSource: corev1.VolumeSource{
|
|
HostPath: &corev1.HostPathVolumeSource{
|
|
Path: "/tmp/mnt-1",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "spark-local-dir-2",
|
|
VolumeSource: corev1.VolumeSource{
|
|
HostPath: &corev1.HostPathVolumeSource{
|
|
Path: "/tmp/mnt-2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
VolumeMounts: []corev1.VolumeMount{
|
|
{
|
|
Name: "spark-local-dir-1",
|
|
MountPath: "/tmp/mnt-1",
|
|
},
|
|
{
|
|
Name: "spark-local-dir-2",
|
|
MountPath: "/tmp/mnt-2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedPod, err := getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// local volume will not be added by webhook
|
|
assert.Empty(t, modifiedPod.Spec.Volumes)
|
|
}
|
|
|
|
func TestPatchSparkPod_Volumes_Subpath(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Volumes: []corev1.Volume{
|
|
{
|
|
Name: "spark-pvc",
|
|
VolumeSource: corev1.VolumeSource{
|
|
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
|
|
ClaimName: "claim-test",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
VolumeMounts: []corev1.VolumeMount{
|
|
{
|
|
Name: "spark-pvc",
|
|
MountPath: "/mnt/spark",
|
|
SubPath: "/foo/test",
|
|
},
|
|
{
|
|
Name: "spark-pvc",
|
|
MountPath: "/mnt/foo",
|
|
SubPath: "/bar/test",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Test patching a pod without existing OwnerReference and Volume.
|
|
modifiedPod, err := getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.Len(t, modifiedPod.Spec.Volumes, 1)
|
|
assert.Equal(t, app.Spec.Volumes[0], modifiedPod.Spec.Volumes[0])
|
|
assert.Len(t, modifiedPod.Spec.Containers[0].VolumeMounts, 2)
|
|
assert.Equal(t, app.Spec.Driver.VolumeMounts[0], modifiedPod.Spec.Containers[0].VolumeMounts[0])
|
|
assert.Equal(t, app.Spec.Driver.VolumeMounts[1], modifiedPod.Spec.Containers[0].VolumeMounts[1])
|
|
}
|
|
|
|
func TestPatchSparkPod_Volumes(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Volumes: []corev1.Volume{
|
|
{
|
|
Name: "spark",
|
|
VolumeSource: corev1.VolumeSource{
|
|
HostPath: &corev1.HostPathVolumeSource{
|
|
Path: "/spark",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "foo",
|
|
VolumeSource: corev1.VolumeSource{
|
|
EmptyDir: &corev1.EmptyDirVolumeSource{},
|
|
},
|
|
},
|
|
},
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
VolumeMounts: []corev1.VolumeMount{
|
|
{
|
|
Name: "spark",
|
|
MountPath: "/mnt/spark",
|
|
},
|
|
{
|
|
Name: "foo",
|
|
MountPath: "/mnt/foo",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Test patching a pod without existing OwnerReference and Volume.
|
|
modifiedPod, err := getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.Len(t, modifiedPod.Spec.Volumes, 2)
|
|
assert.Equal(t, app.Spec.Volumes[0], modifiedPod.Spec.Volumes[0])
|
|
assert.Equal(t, app.Spec.Volumes[1], modifiedPod.Spec.Volumes[1])
|
|
assert.Len(t, modifiedPod.Spec.Containers[0].VolumeMounts, 2)
|
|
assert.Equal(t, app.Spec.Driver.VolumeMounts[0], modifiedPod.Spec.Containers[0].VolumeMounts[0])
|
|
assert.Equal(t, app.Spec.Driver.VolumeMounts[1], modifiedPod.Spec.Containers[0].VolumeMounts[1])
|
|
|
|
// Test patching a pod with existing OwnerReference and Volume.
|
|
pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{Name: "volume1"})
|
|
pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
|
|
Name: "volume1",
|
|
})
|
|
|
|
modifiedPod, err = getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.Len(t, modifiedPod.Spec.Volumes, 3)
|
|
assert.Equal(t, app.Spec.Volumes[0], modifiedPod.Spec.Volumes[1])
|
|
assert.Equal(t, app.Spec.Volumes[1], modifiedPod.Spec.Volumes[2])
|
|
assert.Len(t, modifiedPod.Spec.Containers[0].VolumeMounts, 3)
|
|
assert.Equal(t, app.Spec.Driver.VolumeMounts[0], modifiedPod.Spec.Containers[0].VolumeMounts[1])
|
|
assert.Equal(t, app.Spec.Driver.VolumeMounts[1], modifiedPod.Spec.Containers[0].VolumeMounts[2])
|
|
}
|
|
|
|
func TestPatchSparkPod_Affinity(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
Affinity: &corev1.Affinity{
|
|
PodAffinity: &corev1.PodAffinity{
|
|
RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{
|
|
{
|
|
LabelSelector: &metav1.LabelSelector{
|
|
MatchLabels: map[string]string{common.LabelSparkRole: common.SparkRoleDriver},
|
|
},
|
|
TopologyKey: "kubernetes.io/hostname",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Test patching a pod with a pod Affinity.
|
|
modifiedPod, err := getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.NotNil(t, modifiedPod.Spec.Affinity)
|
|
assert.Len(t, modifiedPod.Spec.Affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution, 1)
|
|
assert.Equal(t, "kubernetes.io/hostname",
|
|
modifiedPod.Spec.Affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].TopologyKey)
|
|
}
|
|
|
|
func TestPatchSparkPod_ConfigMaps(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
ConfigMaps: []v1beta2.NamePath{
|
|
{Name: "foo", Path: "/path/to/foo"},
|
|
{Name: "bar", Path: "/path/to/bar"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedPod, err := getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.Len(t, modifiedPod.Spec.Volumes, 2)
|
|
assert.Equal(t, "foo-vol", modifiedPod.Spec.Volumes[0].Name)
|
|
assert.NotNil(t, modifiedPod.Spec.Volumes[0].ConfigMap)
|
|
assert.Equal(t, "bar-vol", modifiedPod.Spec.Volumes[1].Name)
|
|
assert.NotNil(t, modifiedPod.Spec.Volumes[1].ConfigMap)
|
|
assert.Len(t, modifiedPod.Spec.Containers[0].VolumeMounts, 2)
|
|
assert.Equal(t, "/path/to/foo", modifiedPod.Spec.Containers[0].VolumeMounts[0].MountPath)
|
|
assert.Equal(t, "/path/to/bar", modifiedPod.Spec.Containers[0].VolumeMounts[1].MountPath)
|
|
}
|
|
|
|
func TestPatchSparkPod_SparkConfigMap(t *testing.T) {
|
|
sparkConfMapName := "spark-conf"
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
SparkConfigMap: &sparkConfMapName,
|
|
},
|
|
}
|
|
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedPod, err := getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.Len(t, modifiedPod.Spec.Volumes, 1)
|
|
assert.Equal(t, common.SparkConfigMapVolumeName, modifiedPod.Spec.Volumes[0].Name)
|
|
assert.NotNil(t, modifiedPod.Spec.Volumes[0].ConfigMap)
|
|
assert.Len(t, modifiedPod.Spec.Containers[0].VolumeMounts, 1)
|
|
assert.Equal(t, common.DefaultSparkConfDir, modifiedPod.Spec.Containers[0].VolumeMounts[0].MountPath)
|
|
assert.Len(t, modifiedPod.Spec.Containers[0].Env, 1)
|
|
assert.Equal(t, common.DefaultSparkConfDir, modifiedPod.Spec.Containers[0].Env[0].Value)
|
|
}
|
|
|
|
func TestPatchSparkPod_HadoopConfigMap(t *testing.T) {
|
|
hadoopConfMapName := "hadoop-conf"
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
HadoopConfigMap: &hadoopConfMapName,
|
|
},
|
|
}
|
|
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedPod, err := getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.Len(t, modifiedPod.Spec.Volumes, 1)
|
|
assert.Equal(t, common.HadoopConfigMapVolumeName, modifiedPod.Spec.Volumes[0].Name)
|
|
assert.NotNil(t, modifiedPod.Spec.Volumes[0].ConfigMap)
|
|
assert.Len(t, modifiedPod.Spec.Containers[0].VolumeMounts, 1)
|
|
assert.Equal(t, common.DefaultHadoopConfDir, modifiedPod.Spec.Containers[0].VolumeMounts[0].MountPath)
|
|
assert.Len(t, modifiedPod.Spec.Containers[0].Env, 1)
|
|
assert.Equal(t, common.DefaultHadoopConfDir, modifiedPod.Spec.Containers[0].Env[0].Value)
|
|
}
|
|
|
|
// func TestPatchSparkPod_PrometheusConfigMaps(t *testing.T) {
|
|
// var appPort int32 = 9999
|
|
// appPortName := "jmx-exporter"
|
|
// app := &v1beta2.SparkApplication{
|
|
// ObjectMeta: metav1.ObjectMeta{
|
|
// Name: "spark-test",
|
|
// UID: "spark-test-1",
|
|
// },
|
|
// Spec: v1beta2.SparkApplicationSpec{
|
|
// Monitoring: &v1beta2.MonitoringSpec{
|
|
// Prometheus: &v1beta2.PrometheusSpec{
|
|
// JmxExporterJar: "",
|
|
// Port: &appPort,
|
|
// PortName: &appPortName,
|
|
// ConfigFile: nil,
|
|
// Configuration: nil,
|
|
// },
|
|
// ExposeDriverMetrics: true,
|
|
// },
|
|
// },
|
|
// }
|
|
|
|
// pod := &corev1.Pod{
|
|
// ObjectMeta: metav1.ObjectMeta{
|
|
// Name: "spark-driver",
|
|
// Labels: map[string]string{
|
|
// common.LabelSparkRole: common.SparkRoleDriver,
|
|
// common.LabelLaunchedBySparkOperator: "true",
|
|
// },
|
|
// },
|
|
// Spec: corev1.PodSpec{
|
|
// Containers: []corev1.Container{
|
|
// {
|
|
// Name: common.SparkDriverContainerName,
|
|
// Image: "spark-driver:latest",
|
|
// },
|
|
// },
|
|
// },
|
|
// }
|
|
|
|
// modifiedPod, err := getModifiedPod(pod, app)
|
|
// if err != nil {
|
|
// t.Fatal(err)
|
|
// }
|
|
|
|
// expectedConfigMapName := GetPrometheusConfigMapName(app)
|
|
// expectedVolumeName := expectedConfigMapName + "-vol"
|
|
// expectedContainerPort := *app.Spec.Monitoring.Prometheus.Port
|
|
// expectedContainerPortName := *app.Spec.Monitoring.Prometheus.PortName
|
|
// assert.Len(t, modifiedPod.Spec.Volumes, 1)
|
|
// assert.Equal(t, expectedVolumeName, modifiedPod.Spec.Volumes[0].Name)
|
|
// assert.NotNil(t, modifiedPod.Spec.Volumes[0].ConfigMap)
|
|
// assert.Equal(t, expectedConfigMapName, modifiedPod.Spec.Volumes[0].ConfigMap.Name)
|
|
// assert.Len(t, modifiedPod.Spec.Containers[0].VolumeMounts, 1)
|
|
// assert.Equal(t, expectedVolumeName, modifiedPod.Spec.Containers[0].VolumeMounts[0].Name)
|
|
// assert.Equal(t, common.PrometheusConfigMapMountPath, modifiedPod.Spec.Containers[0].VolumeMounts[0].MountPath)
|
|
// assert.Equal(t, expectedContainerPort, modifiedPod.Spec.Containers[0].Ports[0].ContainerPort)
|
|
// assert.Equal(t, expectedContainerPortName, modifiedPod.Spec.Containers[0].Ports[0].Name)
|
|
// assert.Equal(t, corev1.Protocol(common.DefaultPrometheusPortProtocol), modifiedPod.Spec.Containers[0].Ports[0].Protocol)
|
|
// }
|
|
|
|
func TestPatchSparkPod_Tolerations(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
Tolerations: []corev1.Toleration{
|
|
{
|
|
Key: "Key1",
|
|
Operator: "Equal",
|
|
Value: "Value1",
|
|
Effect: "NoEffect",
|
|
},
|
|
{
|
|
Key: "Key2",
|
|
Operator: "Equal",
|
|
Value: "Value2",
|
|
Effect: "NoEffect",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Test patching a pod with a Toleration.
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedPod, err := getModifiedPod(pod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.Len(t, modifiedPod.Spec.Tolerations, 2)
|
|
assert.Equal(t, app.Spec.Driver.Tolerations[0], modifiedPod.Spec.Tolerations[0])
|
|
assert.Equal(t, app.Spec.Driver.Tolerations[1], modifiedPod.Spec.Tolerations[1])
|
|
}
|
|
|
|
func TestPatchSparkPod_SecurityContext(t *testing.T) {
|
|
var user int64 = 1000
|
|
var user2 int64 = 2000
|
|
var AllowPrivilegeEscalation = false
|
|
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
PodSecurityContext: &corev1.PodSecurityContext{
|
|
RunAsUser: &user,
|
|
},
|
|
SecurityContext: &corev1.SecurityContext{
|
|
AllowPrivilegeEscalation: &AllowPrivilegeEscalation,
|
|
RunAsUser: &user2,
|
|
},
|
|
},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
PodSecurityContext: &corev1.PodSecurityContext{
|
|
RunAsUser: &user,
|
|
},
|
|
SecurityContext: &corev1.SecurityContext{
|
|
AllowPrivilegeEscalation: &AllowPrivilegeEscalation,
|
|
RunAsUser: &user2,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Equal(t, app.Spec.Driver.PodSecurityContext, modifiedDriverPod.Spec.SecurityContext)
|
|
assert.Equal(t, app.Spec.Driver.SecurityContext, modifiedDriverPod.Spec.Containers[0].SecurityContext)
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Equal(t, app.Spec.Executor.PodSecurityContext, modifiedExecutorPod.Spec.SecurityContext)
|
|
assert.Equal(t, app.Spec.Executor.SecurityContext, modifiedExecutorPod.Spec.Containers[0].SecurityContext)
|
|
}
|
|
|
|
func TestPatchSparkPod_SchedulerName(t *testing.T) {
|
|
var schedulerName = "another_scheduler"
|
|
var defaultScheduler = "default-scheduler"
|
|
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test-patch-schedulername",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
SchedulerName: &schedulerName,
|
|
},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
SchedulerName: defaultScheduler,
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
//Driver scheduler name should be updated when specified.
|
|
assert.Equal(t, schedulerName, modifiedDriverPod.Spec.SchedulerName)
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
SchedulerName: defaultScheduler,
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
//Executor scheduler name should remain the same as before when not specified in SparkApplicationSpec
|
|
assert.Equal(t, defaultScheduler, modifiedExecutorPod.Spec.SchedulerName)
|
|
}
|
|
|
|
func TestPatchSparkPod_PriorityClassName(t *testing.T) {
|
|
var priorityClassName = "critical"
|
|
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test-patch-priorityclassname",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{},
|
|
PriorityClassName: &priorityClassName,
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{},
|
|
PriorityClassName: &priorityClassName,
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
//Driver priorityClassName should be populated when specified
|
|
assert.Equal(t, priorityClassName, modifiedDriverPod.Spec.PriorityClassName)
|
|
|
|
var defaultPriority int32
|
|
var defaultPolicy = corev1.PreemptLowerPriority
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
Priority: &defaultPriority,
|
|
PreemptionPolicy: &defaultPolicy,
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
//Executor priorityClassName should also be populated when specified in SparkApplicationSpec
|
|
assert.Equal(t, priorityClassName, modifiedExecutorPod.Spec.PriorityClassName)
|
|
assert.Nil(t, modifiedExecutorPod.Spec.Priority)
|
|
assert.Nil(t, modifiedExecutorPod.Spec.PreemptionPolicy)
|
|
}
|
|
|
|
func TestPatchSparkPod_Sidecars(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
Sidecars: []corev1.Container{
|
|
{
|
|
Name: "sidecar1",
|
|
Image: "sidecar1:latest",
|
|
},
|
|
{
|
|
Name: "sidecar2",
|
|
Image: "sidecar2:latest",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
Sidecars: []corev1.Container{
|
|
{
|
|
Name: "sidecar1",
|
|
Image: "sidecar1:latest",
|
|
},
|
|
{
|
|
Name: "sidecar2",
|
|
Image: "sidecar2:latest",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedDriverPod.Spec.Containers, 3)
|
|
assert.Equal(t, "sidecar1", modifiedDriverPod.Spec.Containers[1].Name)
|
|
assert.Equal(t, "sidecar2", modifiedDriverPod.Spec.Containers[2].Name)
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedExecutorPod.Spec.Containers, 3)
|
|
assert.Equal(t, "sidecar1", modifiedExecutorPod.Spec.Containers[1].Name)
|
|
assert.Equal(t, "sidecar2", modifiedExecutorPod.Spec.Containers[2].Name)
|
|
}
|
|
|
|
func TestPatchSparkPod_InitContainers(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
InitContainers: []corev1.Container{
|
|
{
|
|
Name: "init-container1",
|
|
Image: "init-container1:latest",
|
|
},
|
|
{
|
|
Name: "init-container2",
|
|
Image: "init-container2:latest",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
InitContainers: []corev1.Container{
|
|
{
|
|
Name: "init-container1",
|
|
Image: "init-container1:latest",
|
|
},
|
|
{
|
|
Name: "init-container2",
|
|
Image: "init-container2:latest",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedDriverPod.Spec.InitContainers, 2)
|
|
assert.Equal(t, "init-container1", modifiedDriverPod.Spec.InitContainers[0].Name)
|
|
assert.Equal(t, "init-container2", modifiedDriverPod.Spec.InitContainers[1].Name)
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedExecutorPod.Spec.InitContainers, 2)
|
|
assert.Equal(t, "init-container1", modifiedExecutorPod.Spec.InitContainers[0].Name)
|
|
assert.Equal(t, "init-container2", modifiedExecutorPod.Spec.InitContainers[1].Name)
|
|
}
|
|
|
|
func TestPatchSparkPod_DNSConfig(t *testing.T) {
|
|
aVal := "5"
|
|
sampleDNSConfig := &corev1.PodDNSConfig{
|
|
Nameservers: []string{"8.8.8.8", "4.4.4.4"},
|
|
Searches: []string{"svc.cluster.local", "cluster.local"},
|
|
Options: []corev1.PodDNSConfigOption{
|
|
{Name: "ndots", Value: &aVal},
|
|
},
|
|
}
|
|
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{DNSConfig: sampleDNSConfig},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{DNSConfig: sampleDNSConfig},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.NotNil(t, modifiedDriverPod.Spec.DNSConfig)
|
|
assert.Equal(t, sampleDNSConfig, modifiedDriverPod.Spec.DNSConfig)
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.NotNil(t, modifiedExecutorPod.Spec.DNSConfig)
|
|
assert.Equal(t, sampleDNSConfig, modifiedExecutorPod.Spec.DNSConfig)
|
|
}
|
|
|
|
func TestPatchSparkPod_NodeSector(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
NodeSelector: map[string]string{"disk": "ssd", "secondkey": "secondvalue"},
|
|
},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
NodeSelector: map[string]string{"nodeType": "gpu", "secondkey": "secondvalue"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedDriverPod.Spec.NodeSelector, 2)
|
|
assert.Equal(t, "ssd", modifiedDriverPod.Spec.NodeSelector["disk"])
|
|
assert.Equal(t, "secondvalue", modifiedDriverPod.Spec.NodeSelector["secondkey"])
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedExecutorPod.Spec.NodeSelector, 2)
|
|
assert.Equal(t, "gpu", modifiedExecutorPod.Spec.NodeSelector["nodeType"])
|
|
assert.Equal(t, "secondvalue", modifiedExecutorPod.Spec.NodeSelector["secondkey"])
|
|
}
|
|
|
|
func TestPatchSparkPod_GPU(t *testing.T) {
|
|
cpuLimit := int64(10)
|
|
cpuRequest := int64(5)
|
|
|
|
type testcase struct {
|
|
gpuSpec *v1beta2.GPUSpec
|
|
cpuLimits *int64
|
|
cpuRequests *int64
|
|
}
|
|
|
|
getResourceRequirements := func(test testcase) *corev1.ResourceRequirements {
|
|
if test.cpuLimits == nil && test.cpuRequests == nil {
|
|
return nil
|
|
}
|
|
ret := corev1.ResourceRequirements{}
|
|
if test.cpuLimits != nil {
|
|
ret.Limits = corev1.ResourceList{}
|
|
ret.Limits[corev1.ResourceCPU] = *resource.NewQuantity(*test.cpuLimits, resource.DecimalSI)
|
|
}
|
|
if test.cpuRequests != nil {
|
|
ret.Requests = corev1.ResourceList{}
|
|
ret.Requests[corev1.ResourceCPU] = *resource.NewQuantity(*test.cpuRequests, resource.DecimalSI)
|
|
}
|
|
return &ret
|
|
}
|
|
|
|
assertFn := func(t *testing.T, modifiedPod *corev1.Pod, test testcase) {
|
|
// check GPU Limits
|
|
if test.gpuSpec != nil && test.gpuSpec.Name != "" && test.gpuSpec.Quantity > 0 {
|
|
quantity := modifiedPod.Spec.Containers[0].Resources.Limits[corev1.ResourceName(test.gpuSpec.Name)]
|
|
count, succeed := (&quantity).AsInt64()
|
|
if succeed != true {
|
|
t.Fatal(fmt.Errorf("value cannot be represented in an int64 OR would result in a loss of precision"))
|
|
}
|
|
assert.Equal(t, test.gpuSpec.Quantity, count)
|
|
}
|
|
|
|
// check CPU Requests
|
|
if test.cpuRequests != nil {
|
|
quantity := modifiedPod.Spec.Containers[0].Resources.Requests[corev1.ResourceCPU]
|
|
count, succeed := (&quantity).AsInt64()
|
|
if succeed != true {
|
|
t.Fatal(fmt.Errorf("value cannot be represented in an int64 OR would result in a loss of precision"))
|
|
}
|
|
assert.Equal(t, *test.cpuRequests, count)
|
|
}
|
|
|
|
// check CPU Limits
|
|
if test.cpuLimits != nil {
|
|
quantity := modifiedPod.Spec.Containers[0].Resources.Limits[corev1.ResourceCPU]
|
|
count, succeed := (&quantity).AsInt64()
|
|
if succeed != true {
|
|
t.Fatal(fmt.Errorf("value cannot be represented in an int64 OR would result in a loss of precision"))
|
|
}
|
|
assert.Equal(t, *test.cpuLimits, count)
|
|
}
|
|
}
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{},
|
|
},
|
|
},
|
|
}
|
|
tests := []testcase{
|
|
{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
nil,
|
|
&cpuLimit,
|
|
nil,
|
|
},
|
|
{
|
|
nil,
|
|
nil,
|
|
&cpuRequest,
|
|
},
|
|
{
|
|
nil,
|
|
&cpuLimit,
|
|
&cpuRequest,
|
|
},
|
|
{
|
|
&v1beta2.GPUSpec{},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
&v1beta2.GPUSpec{},
|
|
&cpuLimit,
|
|
nil,
|
|
},
|
|
{
|
|
&v1beta2.GPUSpec{},
|
|
nil,
|
|
&cpuRequest,
|
|
},
|
|
{
|
|
&v1beta2.GPUSpec{},
|
|
&cpuLimit,
|
|
&cpuRequest,
|
|
},
|
|
{
|
|
&v1beta2.GPUSpec{Name: "example.com/gpu", Quantity: 1},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
&v1beta2.GPUSpec{Name: "example.com/gpu", Quantity: 1},
|
|
&cpuLimit,
|
|
nil,
|
|
},
|
|
{
|
|
&v1beta2.GPUSpec{Name: "example.com/gpu", Quantity: 1},
|
|
nil,
|
|
&cpuRequest,
|
|
},
|
|
{
|
|
&v1beta2.GPUSpec{Name: "example.com/gpu", Quantity: 1},
|
|
&cpuLimit,
|
|
&cpuRequest,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
app.Spec.Driver.GPU = test.gpuSpec
|
|
app.Spec.Executor.GPU = test.gpuSpec
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
if getResourceRequirements(test) != nil {
|
|
driverPod.Spec.Containers[0].Resources = *getResourceRequirements(test)
|
|
}
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assertFn(t, modifiedDriverPod, test)
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
if getResourceRequirements(test) != nil {
|
|
executorPod.Spec.Containers[0].Resources = *getResourceRequirements(test)
|
|
}
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assertFn(t, modifiedExecutorPod, test)
|
|
}
|
|
}
|
|
|
|
func TestPatchSparkPod_HostNetwork(t *testing.T) {
|
|
var hostNetwork = true
|
|
var defaultNetwork = false
|
|
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test-hostNetwork",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{},
|
|
},
|
|
},
|
|
}
|
|
|
|
tests := []*bool{
|
|
nil,
|
|
&defaultNetwork,
|
|
&hostNetwork,
|
|
}
|
|
|
|
for _, test := range tests {
|
|
app.Spec.Driver.HostNetwork = test
|
|
app.Spec.Executor.HostNetwork = test
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if test == nil || *test == false {
|
|
assert.False(t, modifiedDriverPod.Spec.HostNetwork)
|
|
} else {
|
|
assert.True(t, true, modifiedDriverPod.Spec.HostNetwork)
|
|
assert.Equal(t, corev1.DNSClusterFirstWithHostNet, modifiedDriverPod.Spec.DNSPolicy)
|
|
}
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if test == nil || *test == false {
|
|
assert.False(t, modifiedExecutorPod.Spec.HostNetwork)
|
|
} else {
|
|
assert.True(t, true, modifiedExecutorPod.Spec.HostNetwork)
|
|
assert.Equal(t, corev1.DNSClusterFirstWithHostNet, modifiedExecutorPod.Spec.DNSPolicy)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPatchSparkPod_Env(t *testing.T) {
|
|
drvEnvKey := "TEST_DRV_ENV_VAR_KEY"
|
|
drvEnvVal := "test_drv_env_var_val"
|
|
exeEnvKey := "TEST_EXE_ENV_VAR_KEY"
|
|
exeEnvVal := "test_exe_env_var_val"
|
|
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
Env: []corev1.EnvVar{
|
|
{
|
|
Name: exeEnvKey,
|
|
Value: exeEnvVal,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
Env: []corev1.EnvVar{
|
|
{
|
|
Name: drvEnvKey,
|
|
Value: drvEnvVal,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.Len(t, modifiedExecutorPod.Spec.Containers[0].Env, 1)
|
|
assert.Equal(t, exeEnvKey, modifiedExecutorPod.Spec.Containers[0].Env[0].Name)
|
|
assert.Equal(t, exeEnvVal, modifiedExecutorPod.Spec.Containers[0].Env[0].Value)
|
|
assert.Nil(t, modifiedExecutorPod.Spec.Containers[0].Env[0].ValueFrom)
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.Len(t, modifiedDriverPod.Spec.Containers[0].Env, 1)
|
|
assert.Equal(t, drvEnvKey, modifiedDriverPod.Spec.Containers[0].Env[0].Name)
|
|
assert.Equal(t, drvEnvVal, modifiedDriverPod.Spec.Containers[0].Env[0].Value)
|
|
assert.Nil(t, modifiedDriverPod.Spec.Containers[0].Env[0].ValueFrom)
|
|
}
|
|
|
|
var _ = Describe("addEnvVars", func() {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "test-app",
|
|
Namespace: "test-namespace",
|
|
},
|
|
}
|
|
|
|
driver := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "test-app-driver",
|
|
Namespace: "test-namespace",
|
|
Labels: map[string]string{
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
executor := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "test-app-executor",
|
|
Namespace: "test-namespace",
|
|
Labels: map[string]string{
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.Spark3DefaultExecutorContainerName,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
Context("SparkApplication with both driver and executor env set", func() {
|
|
BeforeEach(func() {
|
|
app.Spec.Driver.Env = []corev1.EnvVar{
|
|
{
|
|
Name: "KEY1",
|
|
Value: "VALUE1",
|
|
},
|
|
{
|
|
Name: "KEY2",
|
|
Value: "VALUE2",
|
|
},
|
|
}
|
|
app.Spec.Executor.Env = []corev1.EnvVar{
|
|
{
|
|
Name: "KEY3",
|
|
Value: "VALUE3",
|
|
},
|
|
{
|
|
Name: "KEY4",
|
|
Value: "VALUE4",
|
|
},
|
|
}
|
|
})
|
|
|
|
AfterEach(func() {
|
|
driver.Spec.Containers[0].Env = nil
|
|
executor.Spec.Containers[0].Env = nil
|
|
})
|
|
|
|
It("Should add environment variables to driver pod", func() {
|
|
Expect(addEnvVars(driver, app)).NotTo(HaveOccurred())
|
|
Expect(driver.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "KEY1", Value: "VALUE1"}))
|
|
Expect(driver.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "KEY2", Value: "VALUE2"}))
|
|
})
|
|
|
|
It("Should add environment variables to executor pods", func() {
|
|
Expect(addEnvVars(executor, app)).NotTo(HaveOccurred())
|
|
Expect(executor.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "KEY3", Value: "VALUE3"}))
|
|
Expect(executor.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "KEY4", Value: "VALUE4"}))
|
|
})
|
|
})
|
|
|
|
Context("SparkApplication with only driver env set", func() {
|
|
BeforeEach(func() {
|
|
app.Spec.Driver.Env = []corev1.EnvVar{
|
|
{
|
|
Name: "KEY1",
|
|
Value: "VALUE1",
|
|
},
|
|
{
|
|
Name: "KEY2",
|
|
Value: "VALUE2",
|
|
},
|
|
}
|
|
app.Spec.Executor.Env = nil
|
|
})
|
|
|
|
AfterEach(func() {
|
|
driver.Spec.Containers[0].Env = nil
|
|
executor.Spec.Containers[0].Env = nil
|
|
})
|
|
|
|
It("Should add environment variables to driver pod", func() {
|
|
Expect(addEnvVars(driver, app)).NotTo(HaveOccurred())
|
|
Expect(driver.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "KEY1", Value: "VALUE1"}))
|
|
Expect(driver.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "KEY2", Value: "VALUE2"}))
|
|
})
|
|
|
|
It("Should not add environment variables to executor pods", func() {
|
|
Expect(addEnvVars(executor, app)).NotTo(HaveOccurred())
|
|
Expect(executor.Spec.Containers[0].Env).To(HaveLen(0))
|
|
})
|
|
|
|
})
|
|
|
|
Context("SparkApplication with only executor env set", func() {
|
|
BeforeEach(func() {
|
|
app.Spec.Driver.Env = nil
|
|
app.Spec.Executor.Env = []corev1.EnvVar{
|
|
{
|
|
Name: "KEY3",
|
|
Value: "VALUE3",
|
|
},
|
|
{
|
|
Name: "KEY4",
|
|
Value: "VALUE4",
|
|
},
|
|
}
|
|
})
|
|
|
|
AfterEach(func() {
|
|
driver.Spec.Containers[0].Env = nil
|
|
executor.Spec.Containers[0].Env = nil
|
|
})
|
|
|
|
It("Should add environment variables to driver pod", func() {
|
|
Expect(addEnvVars(driver, app)).NotTo(HaveOccurred())
|
|
Expect(driver.Spec.Containers[0].Env).To(HaveLen(0))
|
|
})
|
|
|
|
It("Should add environment variables to executor pods", func() {
|
|
Expect(addEnvVars(executor, app)).NotTo(HaveOccurred())
|
|
Expect(executor.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "KEY3", Value: "VALUE3"}))
|
|
Expect(executor.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "KEY4", Value: "VALUE4"}))
|
|
})
|
|
})
|
|
})
|
|
|
|
func TestPatchSparkPod_EnvFrom(t *testing.T) {
|
|
configMapName := "test-config-map"
|
|
secretName := "test-secret"
|
|
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
EnvFrom: []corev1.EnvFromSource{
|
|
{
|
|
ConfigMapRef: &corev1.ConfigMapEnvSource{
|
|
LocalObjectReference: corev1.LocalObjectReference{
|
|
Name: configMapName,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
SecretRef: &corev1.SecretEnvSource{
|
|
LocalObjectReference: corev1.LocalObjectReference{
|
|
Name: secretName,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
EnvFrom: []corev1.EnvFromSource{
|
|
{
|
|
ConfigMapRef: &corev1.ConfigMapEnvSource{
|
|
LocalObjectReference: corev1.LocalObjectReference{
|
|
Name: configMapName,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
SecretRef: &corev1.SecretEnvSource{
|
|
LocalObjectReference: corev1.LocalObjectReference{
|
|
Name: secretName,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedDriverPod.Spec.Containers[0].EnvFrom, 2)
|
|
assert.Equal(t, configMapName, modifiedDriverPod.Spec.Containers[0].EnvFrom[0].ConfigMapRef.Name)
|
|
assert.Equal(t, secretName, modifiedDriverPod.Spec.Containers[0].EnvFrom[1].SecretRef.Name)
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedExecutorPod.Spec.Containers[0].EnvFrom, 2)
|
|
assert.Equal(t, configMapName, modifiedExecutorPod.Spec.Containers[0].EnvFrom[0].ConfigMapRef.Name)
|
|
assert.Equal(t, secretName, modifiedExecutorPod.Spec.Containers[0].EnvFrom[1].SecretRef.Name)
|
|
}
|
|
|
|
func TestPatchSparkPod_GracePeriodSeconds(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test-hostNetwork",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{},
|
|
},
|
|
},
|
|
}
|
|
|
|
test1 := int64(60)
|
|
tests := []*int64{
|
|
&test1,
|
|
nil,
|
|
}
|
|
|
|
for _, test := range tests {
|
|
app.Spec.Driver.TerminationGracePeriodSeconds = test
|
|
app.Spec.Executor.TerminationGracePeriodSeconds = test
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if test == nil {
|
|
assert.Nil(t, modifiedDriverPod.Spec.TerminationGracePeriodSeconds)
|
|
} else {
|
|
assert.Equal(t, int64(60), *modifiedDriverPod.Spec.TerminationGracePeriodSeconds)
|
|
}
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if test == nil {
|
|
assert.Nil(t, modifiedDriverPod.Spec.TerminationGracePeriodSeconds)
|
|
} else {
|
|
assert.Equal(t, int64(60), *modifiedExecPod.Spec.TerminationGracePeriodSeconds)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPatchSparkPod_Lifecycle(t *testing.T) {
|
|
testcases := []struct {
|
|
ExecutorContainerName string
|
|
}{
|
|
{
|
|
ExecutorContainerName: common.SparkExecutorContainerName,
|
|
},
|
|
{
|
|
ExecutorContainerName: common.Spark3DefaultExecutorContainerName,
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testcases {
|
|
preStopTest := &corev1.ExecAction{
|
|
Command: []string{"/bin/sh", "-c", "echo Hello from the pre stop handler > /usr/share/message"},
|
|
}
|
|
postStartTest := &corev1.ExecAction{
|
|
Command: []string{"/bin/sh", "-c", "echo Hello from the post start handler > /usr/share/message"},
|
|
}
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
Lifecycle: &corev1.Lifecycle{
|
|
PreStop: &corev1.LifecycleHandler{Exec: preStopTest},
|
|
},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
Lifecycle: &corev1.Lifecycle{
|
|
PostStart: &corev1.LifecycleHandler{Exec: postStartTest},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: testCase.ExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Equal(t, preStopTest, modifiedDriverPod.Spec.Containers[0].Lifecycle.PreStop.Exec)
|
|
assert.Equal(t, postStartTest, modifiedExecutorPod.Spec.Containers[0].Lifecycle.PostStart.Exec)
|
|
}
|
|
}
|
|
|
|
func getModifiedPod(old *corev1.Pod, app *v1beta2.SparkApplication) (*corev1.Pod, error) {
|
|
newPod := old.DeepCopy()
|
|
if err := mutateSparkPod(newPod, app); err != nil {
|
|
return nil, err
|
|
}
|
|
return newPod, nil
|
|
}
|
|
|
|
func TestPatchSparkPod_HostAliases(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
HostAliases: []corev1.HostAlias{
|
|
{
|
|
IP: "127.0.0.1",
|
|
Hostnames: []string{"localhost"},
|
|
},
|
|
{
|
|
IP: "192.168.0.1",
|
|
Hostnames: []string{"test.com", "test2.com"},
|
|
},
|
|
{
|
|
IP: "192.168.0.2",
|
|
Hostnames: []string{"test3.com"},
|
|
},
|
|
{
|
|
IP: "192.168.0.3",
|
|
Hostnames: []string{"test4.com"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
HostAliases: []corev1.HostAlias{
|
|
{
|
|
IP: "127.0.0.1",
|
|
Hostnames: []string{"localhost"},
|
|
},
|
|
{
|
|
IP: "192.168.0.1",
|
|
Hostnames: []string{"test.com", "test2.com"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedDriverPod.Spec.HostAliases, 4)
|
|
assert.Equal(t, "127.0.0.1", modifiedDriverPod.Spec.HostAliases[0].IP)
|
|
assert.Equal(t, "192.168.0.1", modifiedDriverPod.Spec.HostAliases[1].IP)
|
|
assert.Equal(t, "192.168.0.2", modifiedDriverPod.Spec.HostAliases[2].IP)
|
|
assert.Equal(t, "192.168.0.3", modifiedDriverPod.Spec.HostAliases[3].IP)
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedExecutorPod.Spec.HostAliases, 2)
|
|
assert.Equal(t, "127.0.0.1", modifiedExecutorPod.Spec.HostAliases[0].IP)
|
|
assert.Equal(t, "192.168.0.1", modifiedExecutorPod.Spec.HostAliases[1].IP)
|
|
}
|
|
|
|
func TestPatchSparkPod_Ports(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
Ports: []v1beta2.Port{
|
|
{Name: "driverPort1", ContainerPort: 8080, Protocol: "TCP"},
|
|
{Name: "driverPort2", ContainerPort: 8081, Protocol: "TCP"},
|
|
},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
Ports: []v1beta2.Port{
|
|
{Name: "executorPort1", ContainerPort: 8082, Protocol: "TCP"},
|
|
{Name: "executorPort2", ContainerPort: 8083, Protocol: "TCP"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.Len(t, modifiedDriverPod.Spec.Containers[0].Ports, 2)
|
|
assert.Equal(t, "driverPort1", modifiedDriverPod.Spec.Containers[0].Ports[0].Name)
|
|
assert.Equal(t, "driverPort2", modifiedDriverPod.Spec.Containers[0].Ports[1].Name)
|
|
assert.Equal(t, int32(8080), modifiedDriverPod.Spec.Containers[0].Ports[0].ContainerPort)
|
|
assert.Equal(t, int32(8081), modifiedDriverPod.Spec.Containers[0].Ports[1].ContainerPort)
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assert.Len(t, modifiedExecutorPod.Spec.Containers[0].Ports, 2)
|
|
assert.Equal(t, "executorPort1", modifiedExecutorPod.Spec.Containers[0].Ports[0].Name)
|
|
assert.Equal(t, "executorPort2", modifiedExecutorPod.Spec.Containers[0].Ports[1].Name)
|
|
assert.Equal(t, int32(8082), modifiedExecutorPod.Spec.Containers[0].Ports[0].ContainerPort)
|
|
assert.Equal(t, int32(8083), modifiedExecutorPod.Spec.Containers[0].Ports[1].ContainerPort)
|
|
}
|
|
|
|
func TestPatchSparkPod_ShareProcessNamespace(t *testing.T) {
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{},
|
|
},
|
|
},
|
|
}
|
|
|
|
shareProcessNamespaceTrue := true
|
|
shareProcessNamespaceFalse := false
|
|
tests := []*bool{
|
|
nil,
|
|
&shareProcessNamespaceTrue,
|
|
&shareProcessNamespaceFalse,
|
|
}
|
|
|
|
for _, test := range tests {
|
|
app.Spec.Driver.ShareProcessNamespace = test
|
|
app.Spec.Executor.ShareProcessNamespace = test
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-driver",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-executor",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if test == nil || *test == false {
|
|
assert.Nil(t, modifiedDriverPod.Spec.ShareProcessNamespace)
|
|
assert.Nil(t, modifiedExecutorPod.Spec.ShareProcessNamespace)
|
|
} else {
|
|
assert.True(t, *modifiedDriverPod.Spec.ShareProcessNamespace)
|
|
assert.True(t, *modifiedExecutorPod.Spec.ShareProcessNamespace)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPatchSparkPod_MemoryLimit(t *testing.T) {
|
|
|
|
var memory = "1Gi"
|
|
var memoryLimit = "10Gi"
|
|
|
|
app := &v1beta2.SparkApplication{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test-memory",
|
|
UID: "spark-test-1",
|
|
},
|
|
Spec: v1beta2.SparkApplicationSpec{
|
|
Driver: v1beta2.DriverSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
Memory: &memory,
|
|
MemoryLimit: &memoryLimit,
|
|
},
|
|
},
|
|
Executor: v1beta2.ExecutorSpec{
|
|
SparkPodSpec: v1beta2.SparkPodSpec{
|
|
Memory: &memory,
|
|
MemoryLimit: &memoryLimit,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
driverPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test-memory",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleDriver,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkDriverContainerName,
|
|
Image: "spark-driver:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedDriverPod, err := getModifiedPod(driverPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expectedDriverMemoryRequest := modifiedDriverPod.Spec.Containers[0].Resources.Requests[corev1.ResourceMemory]
|
|
expectedDriverMemoryLimit := modifiedDriverPod.Spec.Containers[0].Resources.Limits[corev1.ResourceMemory]
|
|
|
|
assert.Equal(t, "10Gi", expectedDriverMemoryLimit.String())
|
|
assert.NotEqual(t, expectedDriverMemoryRequest.String(), expectedDriverMemoryLimit.String())
|
|
|
|
executorPod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "spark-test-memory",
|
|
Labels: map[string]string{
|
|
common.LabelSparkRole: common.SparkRoleExecutor,
|
|
common.LabelLaunchedBySparkOperator: "true",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: common.SparkExecutorContainerName,
|
|
Image: "spark-executor:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
modifiedExecutorPod, err := getModifiedPod(executorPod, app)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expectedExecutorMemoryRequest := modifiedExecutorPod.Spec.Containers[0].Resources.Requests[corev1.ResourceMemory]
|
|
expectedExecutorMemoryLimit := modifiedExecutorPod.Spec.Containers[0].Resources.Limits[corev1.ResourceMemory]
|
|
|
|
assert.Equal(t, "10Gi", expectedExecutorMemoryLimit.String())
|
|
assert.NotEqual(t, expectedExecutorMemoryRequest.String(), expectedExecutorMemoryLimit.String())
|
|
|
|
}
|