* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* openFuyao is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package clustermanage
import (
"fmt"
"net/http"
"github.com/emicklei/go-restful/v3"
"github.com/gorilla/websocket"
"installer-service/pkg/constant"
"installer-service/pkg/installer"
"installer-service/pkg/utils/httputil"
"installer-service/pkg/utils/wsutil"
"installer-service/pkg/zlog"
)
type Handler struct {
installerHandler installer.Operation
}
func newHandler(handler installer.Operation) *Handler {
return &Handler{installerHandler: handler}
}
func (h *Handler) createCluster(request *restful.Request, response *restful.Response) {
req := installer.CreateClusterRequest{}
if err := request.ReadEntity(&req); err != nil {
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetParamsEmptyErrorResponseJson())
return
}
defaults, err := h.installerHandler.GetDefaultConfig()
if err != nil {
zlog.Errorf("get default config failed: %v", err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
yamlString, err := installer.BuildCreateClusterYaml(req, defaults)
if err != nil {
zlog.Errorf("build cluster yaml failed: %v", err)
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetDefaultClientFailureResponseJson())
return
}
if err := h.installerHandler.CreateCluster(yamlString); err != nil {
zlog.Errorf("create cluster err: %v", err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
response.WriteHeaderAndEntity(http.StatusOK, httputil.GetDefaultSuccessResponseJson())
}
func (h *Handler) judgeClusterNode(request *restful.Request, response *restful.Response) {
req := installer.ClusterNodeInfo{}
if err := request.ReadEntity(&req); err != nil {
zlog.Errorf("req: %v, err: %v", req, err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
if err := h.installerHandler.JudgeClusterNode(&req); err != nil {
zlog.Errorf("req: %v, err: %v", req, err)
response.WriteHeaderAndEntity(http.StatusBadRequest, &httputil.ResponseJson{
Code: constant.ClientError,
Message: fmt.Sprintf("%v", err),
Data: nil,
})
return
}
response.WriteHeaderAndEntity(http.StatusOK, httputil.GetDefaultSuccessResponseJson())
}
var upgrade = websocket.Upgrader{
CheckOrigin: wsutil.CheckOrigin,
}
func (h *Handler) getClusterLog(request *restful.Request, response *restful.Response) {
clusterName := request.PathParameter("cluster-name")
zlog.Info(clusterName)
conn, err := upgrade.Upgrade(response.ResponseWriter, request.Request, nil)
if err != nil {
zlog.Warn("Failed to upgrade connection:", err)
response.WriteHeader(http.StatusInternalServerError)
response.Write([]byte("Internal Server Error - Failed to upgrade connection."))
return
}
defer func(conn *websocket.Conn) {
err := conn.Close()
if err != nil {
zlog.Warn("Failed to close the conn")
}
}(conn)
zlog.Info("1")
result, status := h.installerHandler.GetClusterLog(clusterName, conn)
zlog.Info("2")
_ = response.WriteHeaderAndEntity(status, result)
}
func (h *Handler) listNode(request *restful.Request, response *restful.Response) {
clusterName := request.PathParameter("cluster-name")
if clusterName == "" {
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetParamsEmptyErrorResponseJson())
return
}
nodeName := request.QueryParameter("nodeName")
req := installer.NodeRequest{
ClusterName: clusterName,
NodeName: nodeName,
}
zlog.Info("req data: %v", req)
data, err := h.installerHandler.GetNodesByQuery(req)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
res := httputil.GetDefaultSuccessResponseJson()
res.Data = data
response.WriteHeaderAndEntity(http.StatusOK, res)
}
func (h *Handler) listClusterGet(request *restful.Request, response *restful.Response) {
data, err := h.installerHandler.GetAllClusters()
if err != nil {
zlog.Errorf("failed to get clusters: %v", err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
res := httputil.GetDefaultSuccessResponseJson()
res.Data = data
response.WriteHeaderAndEntity(http.StatusOK, res)
}
func (h *Handler) getClusterFull(request *restful.Request, response *restful.Response) {
clusterName := request.PathParameter("cluster-name")
if clusterName == "" {
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetParamsEmptyErrorResponseJson())
return
}
data, err := h.installerHandler.GetClusterFull(clusterName)
if err != nil {
zlog.Errorf("failed to get cluster full info: %v", err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
res := httputil.GetDefaultSuccessResponseJson()
res.Data = data
response.WriteHeaderAndEntity(http.StatusOK, res)
}
func (h *Handler) deleteCluster(request *restful.Request, response *restful.Response) {
clusterName := request.PathParameter("cluster-name")
zlog.Info(clusterName)
result, status := h.installerHandler.DeleteCluster(clusterName)
_ = response.WriteHeaderAndEntity(status, result)
}
func (h *Handler) getDefaultConfig(request *restful.Request, response *restful.Response) {
data, err := h.installerHandler.GetDefaultConfig()
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
res := httputil.GetDefaultSuccessResponseJson()
res.Data = data
response.WriteHeaderAndEntity(http.StatusOK, res)
}
func (h *Handler) scaleUpCluster(request *restful.Request, response *restful.Response) {
req := installer.ScaleUpRequest{}
if err := request.ReadEntity(&req); err != nil {
zlog.Errorf("read req failed: %v", err)
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetParamsEmptyErrorResponseJson())
return
}
if len(req.Nodes) == 0 {
zlog.Errorf("req nodes is empty")
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetParamsEmptyErrorResponseJson())
return
}
clusterName := request.PathParameter("cluster-name")
if clusterName != "" {
zlog.Infof("scale up cluster: %s, nodes: %v", clusterName, req.Nodes)
}
if err := h.installerHandler.CreateBKENodes(clusterName, req.Nodes); err != nil {
zlog.Errorf("CreateBKENodes failed: %v", err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
response.WriteHeaderAndEntity(http.StatusOK, httputil.GetDefaultSuccessResponseJson())
}
func (h *Handler) scaleDownCluster(request *restful.Request, response *restful.Response) {
req := installer.ScaleDownRequest{}
if err := request.ReadEntity(&req); err != nil {
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetParamsEmptyErrorResponseJson())
return
}
if len(req.Nodes) == 0 {
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetParamsEmptyErrorResponseJson())
return
}
clusterName := request.PathParameter("cluster-name")
if clusterName != "" {
zlog.Infof("scale down cluster: %s, nodes: %v", clusterName, req.Nodes)
}
if err := h.installerHandler.DeleteBKENodes(clusterName, req.Nodes); err != nil {
zlog.Errorf("DeleteBKENodes failed: %v", err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
response.WriteHeaderAndEntity(http.StatusOK, httputil.GetDefaultSuccessResponseJson())
}
func (h *Handler) upgradeCluster(request *restful.Request, response *restful.Response) {
req := installer.UpgradeRequest{}
if err := request.ReadEntity(&req); err != nil {
zlog.Errorf("Read upgrade entity failed: %v", err)
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetParamsEmptyErrorResponseJson())
return
}
if req.Version == "" {
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetParamsEmptyErrorResponseJson())
return
}
clusterName := request.PathParameter("cluster-name")
if clusterName != "" {
zlog.Infof("upgrade cluster: %s to version %s", clusterName, req.Version)
}
if err := h.installerHandler.UpgradeClusterVersion(clusterName, req.Version); err != nil {
zlog.Errorf("upgrade cluster failed: %v", err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
response.WriteHeaderAndEntity(http.StatusOK, httputil.GetDefaultSuccessResponseJson())
}
func (h *Handler) uploadPatchFile(request *restful.Request, response *restful.Response) {
req := installer.PatchFileData{}
if err := request.ReadEntity(&req); err != nil {
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetParamsEmptyErrorResponseJson())
return
}
err := h.installerHandler.UploadPatchFile(req.FileName, req.FileContent)
if err != nil {
zlog.Errorf("upload patch file err: %v", err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
response.WriteHeaderAndEntity(http.StatusOK, httputil.GetDefaultSuccessResponseJson())
}
func (h *Handler) getOpenFuyaoVersions(request *restful.Request, response *restful.Response) {
data, err := h.installerHandler.GetOpenFuyaoVersions()
if err != nil {
zlog.Errorf("get openFuyao versions err: %v", err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
res := httputil.GetDefaultSuccessResponseJson()
res.Data = map[string][]string{"versions": data}
response.WriteHeaderAndEntity(http.StatusOK, res)
}
func (h *Handler) getInstallableVersions(request *restful.Request, response *restful.Response) {
data, err := h.installerHandler.GetInstallableVersions()
if err != nil {
zlog.Errorf("get installable versions err: %v", err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
res := httputil.GetDefaultSuccessResponseJson()
res.Data = map[string][]string{"versions": data}
response.WriteHeaderAndEntity(http.StatusOK, res)
}
func (h *Handler) getUpgradeOpenFuyaoVersions(request *restful.Request, response *restful.Response) {
currentVersion := request.QueryParameter("currentVersion")
clusterName := request.PathParameter("cluster-name")
if clusterName != "" {
if cluster, err := h.installerHandler.GetClustersByName(clusterName); err == nil && cluster != nil {
if cluster.Spec.ClusterConfig.Cluster.OpenFuyaoVersion != "" {
currentVersion = cluster.Spec.ClusterConfig.Cluster.OpenFuyaoVersion
}
} else if currentVersion == "" {
zlog.Errorf("failed to get cluster %s info: %v", clusterName, err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
zlog.Infof("get upgrade versions for cluster %s, currentVersion=%s", clusterName, currentVersion)
} else {
if currentVersion == "" {
req := installer.ClusterPatchInfo{}
if err := request.ReadEntity(&req); err == nil {
currentVersion = req.ClusterVersion
}
}
}
data, err := h.installerHandler.GetUpgradeableVersions(currentVersion)
if err != nil {
zlog.Errorf("get upgradeable versions err: %v", err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, httputil.GetDefaultServerFailureResponseJson())
return
}
res := httputil.GetDefaultSuccessResponseJson()
res.Data = map[string][]string{"versions": data}
response.WriteHeaderAndEntity(http.StatusOK, res)
}
func (h *Handler) autoUpgrade(request *restful.Request, response *restful.Response) {
req := installer.AutoUpgradeRequest{}
if err := request.ReadEntity(&req); err != nil {
zlog.Errorf("Read autoUpgrade entity failed: %v", err)
response.WriteHeaderAndEntity(http.StatusBadRequest, httputil.GetParamsEmptyErrorResponseJson())
return
}
clusterName := request.PathParameter("cluster-name")
if clusterName != "" {
zlog.Infof("auto-upgrade for cluster: %s", clusterName)
}
if err := h.installerHandler.AutoUpgradePatchPrepare(clusterName, req); err != nil {
zlog.Errorf("Auto upgrade preparation failed: %v", err)
response.WriteHeaderAndEntity(
http.StatusInternalServerError,
httputil.GetResponseJson(constant.ServerError, err.Error(), nil),
)
return
}
response.WriteHeaderAndEntity(http.StatusOK, httputil.GetDefaultSuccessResponseJson())
}