diff --git a/.github/workflows/cts.yaml b/.github/workflows/cts.yaml index c9f2081ef..8ed49160d 100644 --- a/.github/workflows/cts.yaml +++ b/.github/workflows/cts.yaml @@ -143,5 +143,7 @@ jobs: run: kubectl get ${{ matrix.emqx[0] }} ${{ matrix.emqx[1] }} -o json - if: failure() run: kubectl get events --sort-by='.lastTimestamp' + - if: failure() + run: kubectl get pods -l "apps.emqx.io/managed-by=emqx-operator" -o json - if: failure() run: kubectl logs -l "apps.emqx.io/managed-by=emqx-operator" -c emqx diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 25aa789d2..5f291d6e0 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -85,5 +85,9 @@ jobs: run: kubectl get ${{ matrix.emqx[0] }} ${{ matrix.emqx[1] }} -o json - if: failure() run: kubectl get events --sort-by='.lastTimestamp' + - if: failure() + run: kubectl get sts -l "apps.emqx.io/managed-by=emqx-operator" -o json + - if: failure() + run: kubectl get pods -l "apps.emqx.io/managed-by=emqx-operator" -o json - if: failure() run: kubectl logs -l "apps.emqx.io/managed-by=emqx-operator" -c emqx diff --git a/apis/apps/v2beta1/util.go b/apis/apps/v2beta1/util.go index 780291115..f6f8d9b0f 100644 --- a/apis/apps/v2beta1/util.go +++ b/apis/apps/v2beta1/util.go @@ -19,6 +19,7 @@ package v2beta1 import ( "fmt" "net" + "strconv" "strings" emperror "emperror.dev/errors" @@ -172,31 +173,65 @@ func AddLabel(labels map[string]string, labelKey, labelValue string) map[string] return labels } -func GetDashboardServicePort(hoconString string) (*corev1.ServicePort, error) { +func GetDashboardPortMap(hoconString string) (map[string]int32, error) { + portMap := make(map[string]int32) + portMap["dashboard"] = 18083 // default port + hoconConfig, err := hocon.ParseString(hoconString) if err != nil { return nil, emperror.Wrapf(err, "failed to parse %s", hoconString) } - dashboardPort := strings.Trim(hoconConfig.GetString("dashboard.listeners.http.bind"), `"`) - if dashboardPort == "" { - return nil, emperror.Errorf("failed to get dashboard.listeners.http.bind in %s", hoconConfig.String()) + + if dashboardPort := strings.Trim(hoconConfig.GetString("dashboard.listeners.http.bind"), `"`); dashboardPort != "" { + if !strings.Contains(dashboardPort, ":") { + // example: ":18083" + dashboardPort = fmt.Sprintf(":%s", dashboardPort) + } + _, strPort, _ := net.SplitHostPort(dashboardPort) + if port, _ := strconv.Atoi(strPort); port != 0 { + portMap["dashboard"] = int32(port) + } else { + // port = 0 means disable dashboard + // delete default port + delete(portMap, "dashboard") + } } - if !strings.Contains(dashboardPort, ":") { - // example: ":18083" - dashboardPort = fmt.Sprintf(":%s", dashboardPort) + + if dashboardHttpsPort := strings.Trim(hoconConfig.GetString("dashboard.listeners.https.bind"), `"`); dashboardHttpsPort != "" { + if !strings.Contains(dashboardHttpsPort, ":") { + // example: ":18084" + dashboardHttpsPort = fmt.Sprintf(":%s", dashboardHttpsPort) + } + _, strPort, _ := net.SplitHostPort(dashboardHttpsPort) + if port, _ := strconv.Atoi(strPort); port != 0 { + portMap["dashboard-https"] = int32(port) + } else { + // port = 0 means disable dashboard + // delete default port + delete(portMap, "dashboard-https") + } } - _, strPort, err := net.SplitHostPort(dashboardPort) + + return portMap, nil +} + +func GetDashboardServicePort(hoconString string) ([]corev1.ServicePort, error) { + dashboardSvcPortList := []corev1.ServicePort{} + portMap, err := GetDashboardPortMap(hoconString) if err != nil { - return nil, emperror.Wrapf(err, "failed to split %s", dashboardPort) + return nil, emperror.Wrapf(err, "failed to get dashboard port map") } - intStrValue := intstr.Parse(strPort) - - return &corev1.ServicePort{ - Name: "dashboard", - Protocol: corev1.ProtocolTCP, - Port: int32(intStrValue.IntValue()), - TargetPort: intStrValue, - }, nil + + for name, port := range portMap { + dashboardSvcPortList = append(dashboardSvcPortList, corev1.ServicePort{ + Name: name, + Protocol: corev1.ProtocolTCP, + Port: port, + TargetPort: intstr.FromInt(int(port)), + }) + } + + return dashboardSvcPortList, nil } func GetListenersServicePorts(hoconString string) ([]corev1.ServicePort, error) { @@ -365,6 +400,18 @@ func MergeContainerPorts(ports1, ports2 []corev1.ContainerPort) []corev1.Contain return result } +func TransServicePortsToContainerPorts(ports []corev1.ServicePort) []corev1.ContainerPort { + result := make([]corev1.ContainerPort, 0, len(ports)) + for _, item := range ports { + result = append(result, corev1.ContainerPort{ + Name: item.Name, + ContainerPort: item.Port, + Protocol: item.Protocol, + }) + } + return result +} + func mergeMap(dst, src map[string]string) map[string]string { if dst == nil { dst = make(map[string]string) diff --git a/apis/apps/v2beta1/util_test.go b/apis/apps/v2beta1/util_test.go index 3dc44257f..e59a05a14 100644 --- a/apis/apps/v2beta1/util_test.go +++ b/apis/apps/v2beta1/util_test.go @@ -24,12 +24,98 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" ) +func TestGetDashboardPortMap(t *testing.T) { + t.Run("empty config", func(t *testing.T) { + instance := &EMQX{} + got, err := GetDashboardPortMap(instance.Spec.Config.Data) + assert.Nil(t, err) + assert.Equal(t, map[string]int32{ + "dashboard": 18083, + }, got) + }) + + t.Run("wrong config", func(t *testing.T) { + instance := &EMQX{} + instance.Spec.Config.Data = `hello world` + got, err := GetDashboardPortMap(instance.Spec.Config.Data) + assert.ErrorContains(t, err, "failed to parse") + assert.Nil(t, got) + }) + + t.Run("a single http port", func(t *testing.T) { + instance := &EMQX{} + instance.Spec.Config.Data = `dashboard.listeners.http.bind = 18083` + got, err := GetDashboardPortMap(instance.Spec.Config.Data) + assert.Nil(t, err) + assert.Equal(t, map[string]int32{ + "dashboard": 18083, + }, got) + }) + + t.Run("a single IPV4 http port", func(t *testing.T) { + instance := &EMQX{} + instance.Spec.Config.Data = `dashboard.listeners.http.bind = "0.0.0.0:18083"` + got, err := GetDashboardPortMap(instance.Spec.Config.Data) + assert.Nil(t, err) + assert.Equal(t, map[string]int32{ + "dashboard": 18083, + }, got) + }) + + t.Run("a single IPV6 http port", func(t *testing.T) { + instance := &EMQX{} + instance.Spec.Config.Data = `dashboard.listeners.http.bind = "[::]:18083"` + got, err := GetDashboardPortMap(instance.Spec.Config.Data) + assert.Nil(t, err) + assert.Equal(t, map[string]int32{ + "dashboard": 18083, + }, got) + }) + + t.Run("a single https port", func(t *testing.T) { + instance := &EMQX{} + instance.Spec.Config.Data = `dashboard.listeners.https.bind = 18084` + got, err := GetDashboardPortMap(instance.Spec.Config.Data) + assert.Nil(t, err) + assert.Equal(t, map[string]int32{ + "dashboard": 18083, // default http port + "dashboard-https": 18084, + }, got) + }) + + t.Run("disable http port and a single https port", func(t *testing.T) { + instance := &EMQX{} + instance.Spec.Config.Data = ` + dashboard.listeners.http.bind = 0 + dashboard.listeners.https.bind = 18084 + ` + got, err := GetDashboardPortMap(instance.Spec.Config.Data) + assert.Nil(t, err) + assert.Equal(t, map[string]int32{ + "dashboard-https": 18084, + }, got) + }) + + t.Run("disable all port", func(t *testing.T) { + instance := &EMQX{} + instance.Spec.Config.Data = ` + dashboard.listeners.http.bind = 0 + dashboard.listeners.https.bind = 0 + ` + got, err := GetDashboardPortMap(instance.Spec.Config.Data) + assert.Nil(t, err) + assert.Empty(t, got) + }) +} + func TestGetDashboardServicePort(t *testing.T) { - expect := &corev1.ServicePort{ - Name: "dashboard", - Protocol: corev1.ProtocolTCP, - Port: int32(18083), - TargetPort: intstr.Parse("18083"), + expect := []corev1.ServicePort{ + { + Name: "dashboard", + Protocol: corev1.ProtocolTCP, + Port: int32(18083), + TargetPort: intstr.Parse("18083"), + }, } t.Run("a single port", func(t *testing.T) { @@ -56,26 +142,18 @@ func TestGetDashboardServicePort(t *testing.T) { assert.Equal(t, expect, got) }) - t.Run("wrong config", func(t *testing.T) { - instance := &EMQX{} - instance.Spec.Config.Data = `hello world` - got, err := GetDashboardServicePort(instance.Spec.Config.Data) - assert.ErrorContains(t, err, "failed to parse") - assert.Nil(t, got) - }) - t.Run("empty config", func(t *testing.T) { instance := &EMQX{} got, err := GetDashboardServicePort(instance.Spec.Config.Data) - assert.ErrorContains(t, err, "failed to get dashboard.listeners.http.bind") - assert.Nil(t, got) + assert.Nil(t, err) + assert.Equal(t, expect, got) }) - t.Run("empty dashboard listeners config", func(t *testing.T) { + t.Run("wrong config", func(t *testing.T) { instance := &EMQX{} - instance.Spec.Config.Data = `foo = bar` + instance.Spec.Config.Data = `hello world` got, err := GetDashboardServicePort(instance.Spec.Config.Data) - assert.ErrorContains(t, err, "failed to get dashboard.listeners.http.bind") + assert.ErrorContains(t, err, "failed to parse") assert.Nil(t, got) }) } diff --git a/controllers/apps/v2beta1/add_emqx_core.go b/controllers/apps/v2beta1/add_emqx_core.go index ba5ee7e1f..673c6826d 100644 --- a/controllers/apps/v2beta1/add_emqx_core.go +++ b/controllers/apps/v2beta1/add_emqx_core.go @@ -114,20 +114,7 @@ func (a *addCore) reconcile(ctx context.Context, instance *appsv2beta1.EMQX, _ i } func getNewStatefulSet(instance *appsv2beta1.EMQX) *appsv1.StatefulSet { - var containerPort corev1.ContainerPort - if svcPort, err := appsv2beta1.GetDashboardServicePort(instance.Spec.Config.Data); err != nil { - containerPort = corev1.ContainerPort{ - Name: "dashboard", - Protocol: corev1.ProtocolTCP, - ContainerPort: 18083, - } - } else { - containerPort = corev1.ContainerPort{ - Name: "dashboard", - Protocol: corev1.ProtocolTCP, - ContainerPort: svcPort.Port, - } - } + svcPorts, _ := appsv2beta1.GetDashboardServicePort(instance.Spec.Config.Data) preSts := generateStatefulSet(instance) podTemplateSpecHash := computeHash(preSts.Spec.Template.DeepCopy(), instance.Status.CoreNodesStatus.CollisionCount) @@ -137,14 +124,20 @@ func getNewStatefulSet(instance *appsv2beta1.EMQX) *appsv1.StatefulSet { preSts.Spec.Template.Labels = appsv2beta1.CloneAndAddLabel(preSts.Spec.Template.Labels, appsv2beta1.LabelsPodTemplateHashKey, podTemplateSpecHash) preSts.Spec.Template.Spec.Containers[0].Ports = appsv2beta1.MergeContainerPorts( preSts.Spec.Template.Spec.Containers[0].Ports, - []corev1.ContainerPort{ - containerPort, - }, + appsv2beta1.TransServicePortsToContainerPorts(svcPorts), ) - preSts.Spec.Template.Spec.Containers[0].Env = append([]corev1.EnvVar{ - {Name: "EMQX_DASHBOARD__LISTENERS__HTTP__BIND", Value: strconv.Itoa(int(containerPort.ContainerPort))}, - }, preSts.Spec.Template.Spec.Containers[0].Env...) - + for _, p := range preSts.Spec.Template.Spec.Containers[0].Ports { + var name string + if p.Name == "dashboard" { + name = "EMQX_DASHBOARD__LISTENERS__HTTP__BIND" + } + if p.Name == "dashboard-https" { + name = "EMQX_DASHBOARD__LISTENERS__HTTPS__BIND" + } + preSts.Spec.Template.Spec.Containers[0].Env = append([]corev1.EnvVar{ + {Name: name, Value: strconv.Itoa(int(p.ContainerPort))}, + }, preSts.Spec.Template.Spec.Containers[0].Env...) + } return preSts } diff --git a/controllers/apps/v2beta1/add_emqx_core_test.go b/controllers/apps/v2beta1/add_emqx_core_test.go index 48c1279fa..3c2c41b95 100644 --- a/controllers/apps/v2beta1/add_emqx_core_test.go +++ b/controllers/apps/v2beta1/add_emqx_core_test.go @@ -5,266 +5,152 @@ import ( appsv2beta1 "github.com/emqx/emqx-operator/apis/apps/v2beta1" "github.com/stretchr/testify/assert" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/pointer" ) -func TestGenerateStatefulSet(t *testing.T) { +func TestGetNewStatefulSet(t *testing.T) { instance := &appsv2beta1.EMQX{ ObjectMeta: metav1.ObjectMeta{ Name: "emqx", Namespace: "emqx", + Labels: map[string]string{ + "emqx-label-key": "emqx-label-value", + }, + Annotations: map[string]string{ + "emqx-annotation-key": "emqx-annotation-value", + }, }, Spec: appsv2beta1.EMQXSpec{ Image: "emqx/emqx:5.1", ClusterDomain: "cluster.local", }, } + instance.Spec.CoreTemplate.ObjectMeta = metav1.ObjectMeta{ + Labels: map[string]string{ + "core-label-key": "core-label-value", + }, + Annotations: map[string]string{ + "core-annotation-key": "core-annotation-value", + }, + } instance.Spec.CoreTemplate.Spec.Replicas = pointer.Int32(3) + instance.Status.CoreNodesStatus = appsv2beta1.EMQXNodesStatus{ + CollisionCount: pointer.Int32(0), + } t.Run("check metadata", func(t *testing.T) { emqx := instance.DeepCopy() - emqx.Annotations = map[string]string{ - "kubectl.kubernetes.io/last-applied-config": "fake", - } - - got := generateStatefulSet(emqx) - assert.Equal(t, appsv2beta1.DefaultCoreLabels(emqx), got.Labels) - assert.NotContains(t, "kubectl.kubernetes.io/last-applied-config", got.Annotations) + got := getNewStatefulSet(emqx) + + assert.Equal(t, emqx.Spec.CoreTemplate.Annotations, got.Annotations) + assert.Equal(t, "core-label-value", got.Labels["core-label-key"]) + assert.Equal(t, "emqx", got.Labels[appsv2beta1.LabelsInstanceKey]) + assert.Equal(t, "emqx-operator", got.Labels[appsv2beta1.LabelsManagedByKey]) + assert.Equal(t, "core", got.Labels[appsv2beta1.LabelsDBRoleKey]) + assert.Equal(t, "emqx-core-"+got.Labels[appsv2beta1.LabelsPodTemplateHashKey], got.Name) + assert.Equal(t, emqx.Namespace, got.Namespace) }) - t.Run("check sts spec", func(t *testing.T) { + t.Run("check selector and pod metadata", func(t *testing.T) { emqx := instance.DeepCopy() - - got := generateStatefulSet(emqx) - assert.Equal(t, int32(3), *got.Spec.Replicas) - assert.Equal(t, "emqx-headless", got.Spec.ServiceName) - assert.Equal(t, appsv2beta1.DefaultCoreLabels(emqx), got.Spec.Selector.MatchLabels) - assert.Equal(t, appsv1.ParallelPodManagement, got.Spec.PodManagementPolicy) + got := getNewStatefulSet(emqx) + assert.Equal(t, emqx.Spec.CoreTemplate.ObjectMeta.Annotations, got.Spec.Template.Annotations) + assert.EqualValues(t, map[string]string{ + appsv2beta1.LabelsInstanceKey: "emqx", + appsv2beta1.LabelsManagedByKey: "emqx-operator", + appsv2beta1.LabelsDBRoleKey: "core", + appsv2beta1.LabelsPodTemplateHashKey: got.Labels[appsv2beta1.LabelsPodTemplateHashKey], + "core-label-key": "core-label-value", + }, got.Spec.Template.Labels) + + assert.EqualValues(t, map[string]string{ + appsv2beta1.LabelsInstanceKey: "emqx", + appsv2beta1.LabelsManagedByKey: "emqx-operator", + appsv2beta1.LabelsDBRoleKey: "core", + appsv2beta1.LabelsPodTemplateHashKey: got.Labels[appsv2beta1.LabelsPodTemplateHashKey], + "core-label-key": "core-label-value", + }, got.Spec.Selector.MatchLabels) }) - t.Run("check sts template spec", func(t *testing.T) { + t.Run("check http port", func(t *testing.T) { emqx := instance.DeepCopy() + emqx.Spec.Config.Data = "dashboard.listeners.http.bind = 18083" + got := getNewStatefulSet(emqx) - emqx.Spec.CoreTemplate.Spec.Affinity = &corev1.Affinity{} - emqx.Spec.CoreTemplate.Spec.Tolerations = []corev1.Toleration{{Key: "fake"}} - emqx.Spec.CoreTemplate.Spec.NodeSelector = map[string]string{"fake": "fake"} - emqx.Spec.CoreTemplate.Spec.NodeName = "fake" - got := generateStatefulSet(emqx) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.Affinity, got.Spec.Template.Spec.Affinity) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.Tolerations, got.Spec.Template.Spec.Tolerations) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.NodeSelector, got.Spec.Template.Spec.NodeSelector) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.NodeName, got.Spec.Template.Spec.NodeName) - - emqx.Spec.ImagePullSecrets = []corev1.LocalObjectReference{{Name: "fake-secret"}} - got = generateStatefulSet(emqx) - assert.Equal(t, emqx.Spec.ImagePullSecrets, got.Spec.Template.Spec.ImagePullSecrets) - - emqx.Spec.CoreTemplate.Spec.PodSecurityContext = &corev1.PodSecurityContext{ - RunAsUser: pointer.Int64(1000), - RunAsGroup: pointer.Int64(1000), - FSGroup: pointer.Int64(1000), - } - got = generateStatefulSet(emqx) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.PodSecurityContext, got.Spec.Template.Spec.SecurityContext) + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Ports, + corev1.ContainerPort{ + Name: "dashboard", + Protocol: corev1.ProtocolTCP, + ContainerPort: 18083, + }, + ) - emqx.Spec.CoreTemplate.Spec.InitContainers = []corev1.Container{{Name: "fake-init-container"}} - got = generateStatefulSet(emqx) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.InitContainers, got.Spec.Template.Spec.InitContainers) + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{ + Name: "EMQX_DASHBOARD__LISTENERS__HTTP__BIND", + Value: "18083", + }, + ) }) - t.Run("check sts template spec containers", func(t *testing.T) { + t.Run("check https port", func(t *testing.T) { emqx := instance.DeepCopy() + emqx.Spec.Config.Data = "dashboard.listeners.http.bind = 0 \n dashboard.listeners.https.bind = 18084" + got := getNewStatefulSet(emqx) - emqx.Spec.CoreTemplate.Spec.ExtraContainers = []corev1.Container{{Name: "fake-container"}} - got := generateStatefulSet(emqx) - assert.Len(t, got.Spec.Template.Spec.Containers, 2) - - emqx.Spec.Image = "emqx/emqx:5.1" - emqx.Spec.ImagePullPolicy = corev1.PullIfNotPresent - emqx.Spec.CoreTemplate.Spec.Command = []string{"fake"} - emqx.Spec.CoreTemplate.Spec.Args = []string{"fake"} - emqx.Spec.CoreTemplate.Spec.Ports = []corev1.ContainerPort{{Name: "fake"}} - emqx.Spec.CoreTemplate.Spec.Env = []corev1.EnvVar{{Name: "foo", Value: "bar"}} - emqx.Spec.CoreTemplate.Spec.EnvFrom = []corev1.EnvFromSource{ - { - ConfigMapRef: &corev1.ConfigMapEnvSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: "fake-config", - }, - }, + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Ports, + corev1.ContainerPort{ + Name: "dashboard-https", + Protocol: corev1.ProtocolTCP, + ContainerPort: 18084, }, - } - emqx.Spec.CoreTemplate.Spec.Resources = corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("100Mi"), - }, - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("100Mi"), - }, - } - emqx.Spec.CoreTemplate.Spec.ContainerSecurityContext = &corev1.SecurityContext{ - RunAsUser: pointer.Int64(1000), - RunAsGroup: pointer.Int64(1000), - RunAsNonRoot: pointer.Bool(true), - } - emqx.Spec.CoreTemplate.Spec.ReadinessProbe = &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: "/status", - Port: intstr.FromInt(18083), - }, - }, - InitialDelaySeconds: int32(10), - PeriodSeconds: int32(5), - FailureThreshold: int32(30), - } - emqx.Spec.CoreTemplate.Spec.Lifecycle = &corev1.Lifecycle{ - PreStop: &corev1.LifecycleHandler{ - Exec: &corev1.ExecAction{ - Command: []string{"emqx", "ctl", "cluster", "leave"}, - }, - }, - } - emqx.Spec.CoreTemplate.Spec.ExtraVolumeMounts = []corev1.VolumeMount{{Name: "fake-volume-mount"}} + ) - got = generateStatefulSet(emqx) - assert.Equal(t, emqx.Spec.Image, got.Spec.Template.Spec.Containers[0].Image) - assert.Equal(t, emqx.Spec.ImagePullPolicy, got.Spec.Template.Spec.Containers[0].ImagePullPolicy) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.Command, got.Spec.Template.Spec.Containers[0].Command) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.Args, got.Spec.Template.Spec.Containers[0].Args) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.Ports, got.Spec.Template.Spec.Containers[0].Ports) - assert.ElementsMatch(t, []corev1.EnvVar{ - { - Name: "POD_NAME", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.name", - }, - }, - }, - { - Name: "EMQX_CLUSTER__DISCOVERY_STRATEGY", - Value: "dns", + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{ + Name: "EMQX_DASHBOARD__LISTENERS__HTTPS__BIND", + Value: "18084", }, - { - Name: "EMQX_CLUSTER__DNS__RECORD_TYPE", - Value: "srv", - }, - { - Name: "EMQX_CLUSTER__DNS__NAME", - Value: "emqx-headless.emqx.svc.cluster.local", - }, - { - Name: "EMQX_NODE__DATA_DIR", - Value: "data", - }, - { - Name: "EMQX_NODE__ROLE", - Value: "core", - }, - { - Name: "EMQX_HOST", - Value: "$(POD_NAME).$(EMQX_CLUSTER__DNS__NAME)", - }, - { - Name: "EMQX_NODE__COOKIE", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: emqx.NodeCookieNamespacedName().Name, - }, - Key: "node_cookie", - }, - }, - }, - { - Name: "EMQX_API_KEY__BOOTSTRAP_FILE", - Value: `"/opt/emqx/data/bootstrap_api_key"`, - }, - { - Name: "foo", - Value: "bar", - }, - }, got.Spec.Template.Spec.Containers[0].Env) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.EnvFrom, got.Spec.Template.Spec.Containers[0].EnvFrom) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.Resources, got.Spec.Template.Spec.Containers[0].Resources) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.ContainerSecurityContext, got.Spec.Template.Spec.Containers[0].SecurityContext) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.ReadinessProbe, got.Spec.Template.Spec.Containers[0].ReadinessProbe) - assert.Equal(t, emqx.Spec.CoreTemplate.Spec.Lifecycle, got.Spec.Template.Spec.Containers[0].Lifecycle) - assert.Equal(t, []corev1.VolumeMount{ - { - Name: "bootstrap-api-key", - MountPath: "/opt/emqx/data/bootstrap_api_key", - SubPath: "bootstrap_api_key", - ReadOnly: true, - }, - { - Name: "bootstrap-config", - MountPath: "/opt/emqx/etc/emqx.conf", - SubPath: "emqx.conf", - ReadOnly: true, - }, - { - Name: "emqx-core-log", - MountPath: "/opt/emqx/log", - }, - { - Name: "emqx-core-data", - MountPath: "/opt/emqx/data", - }, - { - Name: "fake-volume-mount", - }, - }, got.Spec.Template.Spec.Containers[0].VolumeMounts) + ) }) - t.Run("check sts spec volume", func(t *testing.T) { + t.Run("check http and https port", func(t *testing.T) { emqx := instance.DeepCopy() - emqx.Spec.CoreTemplate.Spec.ExtraVolumes = []corev1.Volume{{Name: "fake-volume"}} + emqx.Spec.Config.Data = "dashboard.listeners.http.bind = 18083 \n dashboard.listeners.https.bind = 18084" + got := getNewStatefulSet(emqx) - got := generateStatefulSet(emqx) - assert.Equal(t, []corev1.Volume{ - { - Name: "emqx-core-data", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Ports, + corev1.ContainerPort{ + Name: "dashboard", + Protocol: corev1.ProtocolTCP, + ContainerPort: 18083, }, - { - Name: "bootstrap-api-key", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: emqx.BootstrapAPIKeyNamespacedName().Name, - }, - }, - }, - { - Name: "bootstrap-config", - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: emqx.ConfigsNamespacedName().Name, - }, - }, - }, + ) + + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Ports, + corev1.ContainerPort{ + Name: "dashboard-https", + Protocol: corev1.ProtocolTCP, + ContainerPort: 18084, }, - { - Name: "emqx-core-log", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, + ) + + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{ + Name: "EMQX_DASHBOARD__LISTENERS__HTTP__BIND", + Value: "18083", }, - { - Name: "fake-volume", + ) + + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{ + Name: "EMQX_DASHBOARD__LISTENERS__HTTPS__BIND", + Value: "18084", }, - }, got.Spec.Template.Spec.Volumes) + ) }) t.Run("check sts volume claim templates", func(t *testing.T) { @@ -287,7 +173,12 @@ func TestGenerateStatefulSet(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "emqx-core-data", Namespace: "emqx", - Labels: appsv2beta1.DefaultCoreLabels(emqx), + Labels: map[string]string{ + appsv2beta1.LabelsDBRoleKey: "core", + appsv2beta1.LabelsInstanceKey: "emqx", + appsv2beta1.LabelsManagedByKey: "emqx-operator", + "core-label-key": "core-label-value", + }, }, Spec: corev1.PersistentVolumeClaimSpec{ AccessModes: []corev1.PersistentVolumeAccessMode{ diff --git a/controllers/apps/v2beta1/add_emqx_repl.go b/controllers/apps/v2beta1/add_emqx_repl.go index 445eb0e92..bc0cfad59 100644 --- a/controllers/apps/v2beta1/add_emqx_repl.go +++ b/controllers/apps/v2beta1/add_emqx_repl.go @@ -122,20 +122,7 @@ func (a *addRepl) reconcile(ctx context.Context, instance *appsv2beta1.EMQX, _ i } func getNewReplicaSet(instance *appsv2beta1.EMQX) *appsv1.ReplicaSet { - var containerPort corev1.ContainerPort - if svcPort, err := appsv2beta1.GetDashboardServicePort(instance.Spec.Config.Data); err != nil { - containerPort = corev1.ContainerPort{ - Name: "dashboard", - Protocol: corev1.ProtocolTCP, - ContainerPort: 18083, - } - } else { - containerPort = corev1.ContainerPort{ - Name: "dashboard", - Protocol: corev1.ProtocolTCP, - ContainerPort: svcPort.Port, - } - } + svcPorts, _ := appsv2beta1.GetDashboardServicePort(instance.Spec.Config.Data) preRs := generateReplicaSet(instance) podTemplateSpecHash := computeHash(preRs.Spec.Template.DeepCopy(), instance.Status.ReplicantNodesStatus.CollisionCount) @@ -145,13 +132,20 @@ func getNewReplicaSet(instance *appsv2beta1.EMQX) *appsv1.ReplicaSet { preRs.Spec.Template.Labels = appsv2beta1.CloneAndAddLabel(preRs.Spec.Template.Labels, appsv2beta1.LabelsPodTemplateHashKey, podTemplateSpecHash) preRs.Spec.Template.Spec.Containers[0].Ports = appsv2beta1.MergeContainerPorts( preRs.Spec.Template.Spec.Containers[0].Ports, - []corev1.ContainerPort{ - containerPort, - }, + appsv2beta1.TransServicePortsToContainerPorts(svcPorts), ) - preRs.Spec.Template.Spec.Containers[0].Env = append([]corev1.EnvVar{ - {Name: "EMQX_DASHBOARD__LISTENERS__HTTP__BIND", Value: strconv.Itoa(int(containerPort.ContainerPort))}, - }, preRs.Spec.Template.Spec.Containers[0].Env...) + for _, p := range preRs.Spec.Template.Spec.Containers[0].Ports { + var name string + if p.Name == "dashboard" { + name = "EMQX_DASHBOARD__LISTENERS__HTTP__BIND" + } + if p.Name == "dashboard-https" { + name = "EMQX_DASHBOARD__LISTENERS__HTTPS__BIND" + } + preRs.Spec.Template.Spec.Containers[0].Env = append([]corev1.EnvVar{ + {Name: name, Value: strconv.Itoa(int(p.ContainerPort))}, + }, preRs.Spec.Template.Spec.Containers[0].Env...) + } return preRs } diff --git a/controllers/apps/v2beta1/add_emqx_repl_test.go b/controllers/apps/v2beta1/add_emqx_repl_test.go new file mode 100644 index 000000000..0a807715d --- /dev/null +++ b/controllers/apps/v2beta1/add_emqx_repl_test.go @@ -0,0 +1,158 @@ +package v2beta1 + +import ( + "testing" + + appsv2beta1 "github.com/emqx/emqx-operator/apis/apps/v2beta1" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" +) + +func TestGetNewReplicaSet(t *testing.T) { + instance := &appsv2beta1.EMQX{ + ObjectMeta: metav1.ObjectMeta{ + Name: "emqx", + Namespace: "emqx", + Labels: map[string]string{ + "emqx-label-key": "emqx-label-value", + }, + Annotations: map[string]string{ + "emqx-annotation-key": "emqx-annotation-value", + }, + }, + Spec: appsv2beta1.EMQXSpec{ + Image: "emqx/emqx:5.1", + ClusterDomain: "cluster.local", + }, + } + instance.Spec.ReplicantTemplate = &appsv2beta1.EMQXReplicantTemplate{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "repl-label-key": "repl-label-value", + }, + Annotations: map[string]string{ + "repl-annotation-key": "repl-annotation-value", + }, + }, + Spec: appsv2beta1.EMQXReplicantTemplateSpec{ + Replicas: pointer.Int32(3), + }, + } + instance.Status.ReplicantNodesStatus = &appsv2beta1.EMQXNodesStatus{ + CollisionCount: pointer.Int32(0), + } + + t.Run("check metadata", func(t *testing.T) { + emqx := instance.DeepCopy() + got := getNewReplicaSet(emqx) + + assert.Equal(t, emqx.Spec.ReplicantTemplate.Annotations, got.Annotations) + assert.Equal(t, "repl-label-value", got.Labels["repl-label-key"]) + assert.Equal(t, "emqx", got.Labels[appsv2beta1.LabelsInstanceKey]) + assert.Equal(t, "emqx-operator", got.Labels[appsv2beta1.LabelsManagedByKey]) + assert.Equal(t, "replicant", got.Labels[appsv2beta1.LabelsDBRoleKey]) + assert.Equal(t, "emqx-replicant-"+got.Labels[appsv2beta1.LabelsPodTemplateHashKey], got.Name) + assert.Equal(t, emqx.Namespace, got.Namespace) + }) + + t.Run("check selector and pod metadata", func(t *testing.T) { + emqx := instance.DeepCopy() + got := getNewReplicaSet(emqx) + assert.Equal(t, emqx.Spec.ReplicantTemplate.ObjectMeta.Annotations, got.Spec.Template.Annotations) + assert.EqualValues(t, map[string]string{ + appsv2beta1.LabelsInstanceKey: "emqx", + appsv2beta1.LabelsManagedByKey: "emqx-operator", + appsv2beta1.LabelsDBRoleKey: "replicant", + appsv2beta1.LabelsPodTemplateHashKey: got.Labels[appsv2beta1.LabelsPodTemplateHashKey], + "repl-label-key": "repl-label-value", + }, got.Spec.Template.Labels) + + assert.EqualValues(t, map[string]string{ + appsv2beta1.LabelsInstanceKey: "emqx", + appsv2beta1.LabelsManagedByKey: "emqx-operator", + appsv2beta1.LabelsDBRoleKey: "replicant", + appsv2beta1.LabelsPodTemplateHashKey: got.Labels[appsv2beta1.LabelsPodTemplateHashKey], + "repl-label-key": "repl-label-value", + }, got.Spec.Selector.MatchLabels) + }) + + t.Run("check http port", func(t *testing.T) { + emqx := instance.DeepCopy() + emqx.Spec.Config.Data = "dashboard.listeners.http.bind = 18083" + got := getNewReplicaSet(emqx) + + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Ports, + corev1.ContainerPort{ + Name: "dashboard", + Protocol: corev1.ProtocolTCP, + ContainerPort: 18083, + }, + ) + + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{ + Name: "EMQX_DASHBOARD__LISTENERS__HTTP__BIND", + Value: "18083", + }, + ) + }) + + t.Run("check https port", func(t *testing.T) { + emqx := instance.DeepCopy() + emqx.Spec.Config.Data = "dashboard.listeners.http.bind = 0 \n dashboard.listeners.https.bind = 18084" + got := getNewReplicaSet(emqx) + + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Ports, + corev1.ContainerPort{ + Name: "dashboard-https", + Protocol: corev1.ProtocolTCP, + ContainerPort: 18084, + }, + ) + + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{ + Name: "EMQX_DASHBOARD__LISTENERS__HTTPS__BIND", + Value: "18084", + }, + ) + }) + + t.Run("check http and https port", func(t *testing.T) { + emqx := instance.DeepCopy() + emqx.Spec.Config.Data = "dashboard.listeners.http.bind = 18083 \n dashboard.listeners.https.bind = 18084" + got := getNewReplicaSet(emqx) + + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Ports, + corev1.ContainerPort{ + Name: "dashboard", + Protocol: corev1.ProtocolTCP, + ContainerPort: 18083, + }, + ) + + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Ports, + corev1.ContainerPort{ + Name: "dashboard-https", + Protocol: corev1.ProtocolTCP, + ContainerPort: 18084, + }, + ) + + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{ + Name: "EMQX_DASHBOARD__LISTENERS__HTTP__BIND", + Value: "18083", + }, + ) + + assert.Contains(t, got.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{ + Name: "EMQX_DASHBOARD__LISTENERS__HTTPS__BIND", + Value: "18084", + }, + ) + }) +} diff --git a/controllers/apps/v2beta1/add_svc.go b/controllers/apps/v2beta1/add_svc.go index 4d873464b..8ec0d49ac 100644 --- a/controllers/apps/v2beta1/add_svc.go +++ b/controllers/apps/v2beta1/add_svc.go @@ -83,22 +83,12 @@ func generateDashboardService(instance *appsv2beta1.EMQX, configStr string) *cor svc.Spec = *instance.Spec.DashboardServiceTemplate.Spec.DeepCopy() } - port, err := appsv2beta1.GetDashboardServicePort(configStr) - if err != nil { - port = &corev1.ServicePort{ - Name: "dashboard", - Protocol: corev1.ProtocolTCP, - Port: 18083, - TargetPort: intstr.Parse("18083"), - } + ports, _ := appsv2beta1.GetDashboardServicePort(configStr) + if len(ports) == 0 { + return nil } - svc.Spec.Ports = appsv2beta1.MergeServicePorts( - svc.Spec.Ports, - []corev1.ServicePort{ - *port, - }, - ) + svc.Spec.Ports = appsv2beta1.MergeServicePorts(svc.Spec.Ports, ports) svc.Spec.Selector = appsv2beta1.DefaultCoreLabels(instance) return &corev1.Service{ diff --git a/controllers/apps/v2beta1/add_svc_test.go b/controllers/apps/v2beta1/add_svc_test.go index 9199ebf15..0169f1bf2 100644 --- a/controllers/apps/v2beta1/add_svc_test.go +++ b/controllers/apps/v2beta1/add_svc_test.go @@ -63,68 +63,120 @@ func TestGenerateHeadlessSVC(t *testing.T) { } func TestGenerateDashboardService(t *testing.T) { - instance := &appsv2beta1.EMQX{ - ObjectMeta: metav1.ObjectMeta{ - Name: "emqx", - Namespace: "emqx", - }, - Spec: appsv2beta1.EMQXSpec{ - CoreTemplate: appsv2beta1.EMQXCoreTemplate{ - ObjectMeta: metav1.ObjectMeta{ - Labels: appsv2beta1.DefaultCoreLabels(emqx), + t.Run("check metadata", func(t *testing.T) { + emqx := &appsv2beta1.EMQX{ + ObjectMeta: metav1.ObjectMeta{ + Name: "emqx", + Namespace: "emqx", + Labels: map[string]string{ + "emqx-label-key": "emqx", }, - }, - DashboardServiceTemplate: &appsv2beta1.ServiceTemplate{ - Enabled: pointer.Bool(true), - ObjectMeta: metav1.ObjectMeta{ - Name: "emqx-dashboard", - Labels: map[string]string{ - appsv2beta1.LabelsInstanceKey: "emqx", - }, - Annotations: map[string]string{ - "foo": "bar", - }, + Annotations: map[string]string{ + "emqx-annotation-key": "emqx", }, - Spec: corev1.ServiceSpec{ - Selector: appsv2beta1.DefaultCoreLabels(emqx), - Ports: []corev1.ServicePort{ - { - Name: "dashboard", - Protocol: corev1.ProtocolTCP, - Port: 18083, - TargetPort: intstr.FromInt(18083), + }, + Spec: appsv2beta1.EMQXSpec{ + DashboardServiceTemplate: &appsv2beta1.ServiceTemplate{ + Enabled: pointer.Bool(true), + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "dashboard-label-key": "dashboard", + }, + Annotations: map[string]string{ + "dashboard-annotation-key": "dashboard", }, }, }, }, - }, - } - - expect := &corev1.Service{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Service", - }, - ObjectMeta: metav1.ObjectMeta{ + } + got := generateDashboardService(emqx, "") + assert.Equal(t, metav1.ObjectMeta{ Name: "emqx-dashboard", Namespace: "emqx", - Labels: appsv2beta1.DefaultLabels(emqx), + Labels: map[string]string{ + "apps.emqx.io/instance": "emqx", + "apps.emqx.io/managed-by": "emqx-operator", + "dashboard-label-key": "dashboard", + // "emqx-label-key": "emqx", + }, Annotations: map[string]string{ - "foo": "bar", + "dashboard-annotation-key": "dashboard", + // "emqx-annotation-key": "emqx", }, - }, - Spec: corev1.ServiceSpec{ - Selector: appsv2beta1.DefaultCoreLabels(emqx), - Ports: []corev1.ServicePort{ - { - Name: "dashboard", - Protocol: corev1.ProtocolTCP, - Port: 18083, - TargetPort: intstr.FromInt(18083), - }, + }, got.ObjectMeta) + }) + + t.Run("check disabled", func(t *testing.T) { + emqx := &appsv2beta1.EMQX{} + emqx.Spec.DashboardServiceTemplate = &appsv2beta1.ServiceTemplate{ + Enabled: pointer.Bool(false), + } + got := generateDashboardService(emqx, "") + assert.Nil(t, got) + }) + + t.Run("check selector", func(t *testing.T) { + emqx := &appsv2beta1.EMQX{ + ObjectMeta: metav1.ObjectMeta{ + Name: "emqx", }, - }, - } + } + got := generateDashboardService(emqx, "") + assert.Equal(t, map[string]string{ + appsv2beta1.LabelsInstanceKey: "emqx", + appsv2beta1.LabelsManagedByKey: "emqx-operator", + appsv2beta1.LabelsDBRoleKey: "core", + }, got.Spec.Selector) + }) + + t.Run("check http ports", func(t *testing.T) { + emqx := &appsv2beta1.EMQX{} + got := generateDashboardService(emqx, "dashboard.listeners.http.bind = 18083") + assert.Equal(t, []corev1.ServicePort{ + { + Name: "dashboard", + Protocol: corev1.ProtocolTCP, + Port: 18083, + TargetPort: intstr.FromInt(18083), + }, + }, got.Spec.Ports) + }) + + t.Run("check https ports", func(t *testing.T) { + emqx := &appsv2beta1.EMQX{} + got := generateDashboardService(emqx, "dashboard.listeners.http.bind = 0\ndashboard.listeners.https.bind= 18084") + assert.Equal(t, []corev1.ServicePort{ + { + Name: "dashboard-https", + Protocol: corev1.ProtocolTCP, + Port: 18084, + TargetPort: intstr.FromInt(18084), + }, + }, got.Spec.Ports) + }) + + t.Run("check http and https ports", func(t *testing.T) { + emqx := &appsv2beta1.EMQX{} + got := generateDashboardService(emqx, "dashboard.listeners.http.bind = 18083\ndashboard.listeners.https.bind= 18084") + assert.ElementsMatch(t, []corev1.ServicePort{ + { + Name: "dashboard", + Protocol: corev1.ProtocolTCP, + Port: 18083, + TargetPort: intstr.FromInt(18083), + }, + { + Name: "dashboard-https", + Protocol: corev1.ProtocolTCP, + Port: 18084, + TargetPort: intstr.FromInt(18084), + }, + }, got.Spec.Ports) + }) - assert.Equal(t, expect, generateDashboardService(instance, "")) + t.Run("check empty ports", func(t *testing.T) { + emqx := &appsv2beta1.EMQX{} + got := generateDashboardService(emqx, "dashboard.listeners.http.bind = 0\ndashboard.listeners.https.bind= 0") + assert.Nil(t, got) + }) } diff --git a/controllers/apps/v2beta1/emqx_controller.go b/controllers/apps/v2beta1/emqx_controller.go index f540e62b1..7b58e213f 100644 --- a/controllers/apps/v2beta1/emqx_controller.go +++ b/controllers/apps/v2beta1/emqx_controller.go @@ -18,8 +18,9 @@ package v2beta1 import ( "context" - "fmt" + "net" "sort" + "strconv" "strings" "time" @@ -161,14 +162,19 @@ func newRequester(k8sClient client.Client, instance *appsv2beta1.EMQX) (innerReq return nil, err } - var port string - dashboardPort, err := appsv2beta1.GetDashboardServicePort(instance.Spec.Config.Data) - if err != nil || dashboardPort == nil { - port = "18083" + portMap, err := appsv2beta1.GetDashboardPortMap(instance.Spec.Config.Data) + if err != nil { + return nil, err } - if dashboardPort != nil { - port = dashboardPort.TargetPort.String() + var schema, port string + if dashboardHttps, ok := portMap["dashboard-https"]; ok { + schema = "https" + port = strconv.FormatInt(int64(dashboardHttps), 10) + } + if dashboard, ok := portMap["dashboard"]; ok { + schema = "http" + port = strconv.FormatInt(int64(dashboard), 10) } podList := &corev1.PodList{} @@ -185,7 +191,8 @@ func newRequester(k8sClient client.Client, instance *appsv2beta1.EMQX) (innerReq for _, pod := range podList.Items { if pod.Status.Phase == corev1.PodRunning && pod.Status.PodIP != "" { return &innerReq.Requester{ - Host: fmt.Sprintf("%s:%s", pod.Status.PodIP, port), + Schema: schema, + Host: net.JoinHostPort(pod.Status.PodIP, port), Username: username, Password: password, }, nil diff --git a/controllers/apps/v2beta1/update_pod_conditions.go b/controllers/apps/v2beta1/update_pod_conditions.go index 76c568ab8..836f89e32 100644 --- a/controllers/apps/v2beta1/update_pod_conditions.go +++ b/controllers/apps/v2beta1/update_pod_conditions.go @@ -3,7 +3,8 @@ package v2beta1 import ( "context" "encoding/json" - "fmt" + "net" + "strconv" semver "github.com/Masterminds/semver/v3" appsv2beta1 "github.com/emqx/emqx-operator/apis/apps/v2beta1" @@ -99,20 +100,24 @@ func (u *updatePodConditions) checkRebalanceStatus(instance *appsv2beta1.EMQX, r if r == nil { return corev1.ConditionFalse } - var port string - dashboardPort, err := appsv2beta1.GetDashboardServicePort(instance.Spec.Config.Data) - if err != nil || dashboardPort == nil { - port = "18083" - } - if dashboardPort != nil { - port = dashboardPort.TargetPort.String() + portMap, _ := appsv2beta1.GetDashboardPortMap(instance.Spec.Config.Data) + + var schema, port string + if dashboardHttps, ok := portMap["dashboard-https"]; ok { + schema = "https" + port = strconv.FormatInt(int64(dashboardHttps), 10) + } + if dashboard, ok := portMap["dashboard"]; ok { + schema = "http" + port = strconv.FormatInt(int64(dashboard), 10) } requester := &innerReq.Requester{ + Schema: schema, + Host: net.JoinHostPort(pod.Status.PodIP, port), Username: r.GetUsername(), Password: r.GetPassword(), - Host: fmt.Sprintf("%s:%s", pod.Status.PodIP, port), } url := requester.GetURL("api/v5/load_rebalance/availability_check") diff --git a/internal/requester/requester.go b/internal/requester/requester.go index c1fc225e6..af8569b65 100644 --- a/internal/requester/requester.go +++ b/internal/requester/requester.go @@ -23,6 +23,7 @@ type RequesterInterface interface { } type Requester struct { + Schema string Host string Username string Password string @@ -40,9 +41,16 @@ func (requester *Requester) GetHost() string { return requester.Host } +func (requester *Requester) GetSchema() string { + if requester.Schema == "" { + return "http" + } + return requester.Schema +} + func (requester *Requester) GetURL(path string, query ...string) url.URL { url := url.URL{ - Scheme: "http", + Scheme: requester.GetSchema(), Host: requester.GetHost(), Path: path, } @@ -58,10 +66,10 @@ func (requester *Requester) GetURL(path string, query ...string) url.URL { func (requester *Requester) Request(method string, url url.URL, body []byte, header http.Header) (resp *http.Response, respBody []byte, err error) { if url.Scheme == "" { - url.Scheme = "http" + url.Scheme = requester.GetSchema() } if url.Host == "" { - url.Host = requester.Host + url.Host = requester.GetHost() } req, err := http.NewRequest(method, url.String(), bytes.NewReader(body)) @@ -83,7 +91,9 @@ func (requester *Requester) Request(method string, url url.URL, body []byte, hea } req.Close = true - httpClient := http.Client{} + tr := http.DefaultTransport.(*http.Transport).Clone() + tr.TLSClientConfig.InsecureSkipVerify = true + httpClient := http.Client{Transport: tr} resp, err = httpClient.Do(req) if err != nil { return nil, nil, emperror.Wrap(err, "failed to request API") @@ -103,6 +113,7 @@ type FakeRequester struct { } func (f *FakeRequester) GetURL(path string, query ...string) url.URL { return url.URL{Path: path} } +func (f *FakeRequester) GetSchema() string { return "http" } func (f *FakeRequester) GetHost() string { return "" } func (f *FakeRequester) GetUsername() string { return "" } func (f *FakeRequester) GetPassword() string { return "" }