Files
kubesphere/pkg/kapis/resources/v1alpha2/handler.go

383 lines
12 KiB
Go

package v1alpha2
import (
"fmt"
"github.com/emicklei/go-restful"
v1 "k8s.io/api/core/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/kubernetes"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/components"
"kubesphere.io/kubesphere/pkg/models/git"
"kubesphere.io/kubesphere/pkg/models/kubeconfig"
"kubesphere.io/kubesphere/pkg/models/kubectl"
"kubesphere.io/kubesphere/pkg/models/quotas"
"kubesphere.io/kubesphere/pkg/models/registries"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/resource"
"kubesphere.io/kubesphere/pkg/models/revisions"
"kubesphere.io/kubesphere/pkg/models/routers"
"kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/server/params"
"net/http"
"strconv"
"strings"
)
type resourceHandler struct {
resourcesGetter *resource.ResourceGetter
componentsGetter components.ComponentsGetter
resourceQuotaGetter quotas.ResourceQuotaGetter
revisionGetter revisions.RevisionGetter
routerOperator routers.RouterOperator
gitVerifier git.GitVerifier
registryGetter registries.RegistryGetter
kubeconfigOperator kubeconfig.Interface
kubectlOperator kubectl.Interface
}
func newResourceHandler(k8sClient kubernetes.Interface, factory informers.InformerFactory, masterURL string) *resourceHandler {
return &resourceHandler{
resourcesGetter: resource.NewResourceGetter(factory),
componentsGetter: components.NewComponentsGetter(factory.KubernetesSharedInformerFactory()),
resourceQuotaGetter: quotas.NewResourceQuotaGetter(factory.KubernetesSharedInformerFactory()),
revisionGetter: revisions.NewRevisionGetter(factory.KubernetesSharedInformerFactory()),
routerOperator: routers.NewRouterOperator(k8sClient, factory.KubernetesSharedInformerFactory()),
gitVerifier: git.NewGitVerifier(factory.KubernetesSharedInformerFactory()),
registryGetter: registries.NewRegistryGetter(factory.KubernetesSharedInformerFactory()),
kubeconfigOperator: kubeconfig.NewOperator(k8sClient, nil, masterURL),
kubectlOperator: kubectl.NewOperator(k8sClient, factory.KubernetesSharedInformerFactory(),
factory.KubeSphereSharedInformerFactory()),
}
}
func (r *resourceHandler) handleGetNamespacedResources(request *restful.Request, response *restful.Response) {
r.handleListNamespaceResources(request, response)
}
func (r *resourceHandler) handleListNamespaceResources(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
resource := request.PathParameter("resources")
orderBy := params.GetStringValueWithDefault(request, params.OrderByParam, v1alpha2.CreateTime)
limit, offset := params.ParsePaging(request)
reverse := params.GetBoolValueWithDefault(request, params.ReverseParam, false)
conditions, err := params.ParseConditions(request)
if err != nil {
klog.Error(err)
api.HandleBadRequest(response, request, err)
return
}
result, err := r.resourcesGetter.ListResources(namespace, resource, conditions, orderBy, reverse, limit, offset)
if err != nil {
klog.Error(err)
api.HandleInternalError(response, nil, err)
return
}
response.WriteEntity(result)
}
func (r *resourceHandler) handleGetSystemHealthStatus(_ *restful.Request, response *restful.Response) {
result, err := r.componentsGetter.GetSystemHealthStatus()
if err != nil {
api.HandleInternalError(response, nil, err)
return
}
response.WriteAsJson(result)
}
func (r *resourceHandler) handleGetComponentStatus(request *restful.Request, response *restful.Response) {
component := request.PathParameter("component")
result, err := r.componentsGetter.GetComponentStatus(component)
if err != nil {
api.HandleInternalError(response, nil, err)
return
}
response.WriteAsJson(result)
}
func (r *resourceHandler) handleGetComponents(_ *restful.Request, response *restful.Response) {
result, err := r.componentsGetter.GetAllComponentsStatus()
if err != nil {
api.HandleInternalError(response, nil, err)
return
}
response.WriteAsJson(result)
}
func (r *resourceHandler) handleGetClusterQuotas(_ *restful.Request, response *restful.Response) {
result, err := r.resourceQuotaGetter.GetClusterQuota()
if err != nil {
api.HandleInternalError(response, nil, err)
return
}
response.WriteAsJson(result)
}
func (r *resourceHandler) handleGetNamespaceQuotas(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
quota, err := r.resourceQuotaGetter.GetNamespaceQuota(namespace)
if err != nil {
api.HandleInternalError(response, nil, err)
return
}
response.WriteAsJson(quota)
}
func (r *resourceHandler) handleGetDaemonSetRevision(request *restful.Request, response *restful.Response) {
daemonset := request.PathParameter("daemonset")
namespace := request.PathParameter("namespace")
revision, err := strconv.Atoi(request.PathParameter("revision"))
if err != nil {
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
result, err := r.revisionGetter.GetDaemonSetRevision(namespace, daemonset, revision)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
response.WriteAsJson(result)
}
func (r *resourceHandler) handleGetDeploymentRevision(request *restful.Request, response *restful.Response) {
deploy := request.PathParameter("deployment")
namespace := request.PathParameter("namespace")
revision := request.PathParameter("revision")
result, err := r.revisionGetter.GetDeploymentRevision(namespace, deploy, revision)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
response.WriteAsJson(result)
}
func (r *resourceHandler) handleGetStatefulSetRevision(request *restful.Request, response *restful.Response) {
statefulset := request.PathParameter("statefulset")
namespace := request.PathParameter("namespace")
revision, err := strconv.Atoi(request.PathParameter("revision"))
if err != nil {
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
result, err := r.revisionGetter.GetStatefulSetRevision(namespace, statefulset, revision)
if err != nil {
api.HandleInternalError(response, nil, err)
return
}
response.WriteAsJson(result)
}
// Get ingress controller service for specified namespace
func (r *resourceHandler) handleGetRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
router, err := r.routerOperator.GetRouter(namespace)
if err != nil {
if k8serr.IsNotFound(err) {
response.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
} else {
api.HandleInternalError(response, nil, err)
}
return
}
response.WriteAsJson(router)
}
// Create ingress controller and related services
func (r *resourceHandler) handleCreateRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
newRouter := api.Router{}
err := request.ReadEntity(&newRouter)
if err != nil {
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("wrong annotations, missing key or value")))
return
}
routerType := v1.ServiceTypeNodePort
if strings.Compare(strings.ToLower(newRouter.RouterType), "loadbalancer") == 0 {
routerType = v1.ServiceTypeLoadBalancer
}
router, err := r.routerOperator.CreateRouter(namespace, routerType, newRouter.Annotations)
if err != nil {
api.HandleInternalError(response, nil, err)
return
}
response.WriteAsJson(router)
}
// Delete ingress controller and services
func (r *resourceHandler) handleDeleteRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
router, err := r.routerOperator.DeleteRouter(namespace)
if err != nil {
api.HandleInternalError(response, nil, err)
return
}
response.WriteAsJson(router)
}
func (r *resourceHandler) handleUpdateRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
newRouter := api.Router{}
err := request.ReadEntity(&newRouter)
if err != nil {
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
var routerType = v1.ServiceTypeNodePort
if strings.Compare(strings.ToLower(newRouter.RouterType), "loadbalancer") == 0 {
routerType = v1.ServiceTypeLoadBalancer
}
router, err := r.routerOperator.UpdateRouter(namespace, routerType, newRouter.Annotations)
if err != nil {
api.HandleInternalError(response, nil, err)
return
}
response.WriteAsJson(router)
}
func (r *resourceHandler) handleVerifyGitCredential(request *restful.Request, response *restful.Response) {
var credential api.GitCredential
err := request.ReadEntity(&credential)
if err != nil {
api.HandleBadRequest(response, nil, err)
return
}
err = r.gitVerifier.VerifyGitCredential(credential.RemoteUrl, credential.SecretRef.Namespace, credential.SecretRef.Name)
if err != nil {
api.HandleBadRequest(response, nil, err)
return
}
response.WriteHeader(http.StatusOK)
}
func (r *resourceHandler) handleVerifyRegistryCredential(request *restful.Request, response *restful.Response) {
var credential api.RegistryCredential
err := request.ReadEntity(&credential)
if err != nil {
api.HandleBadRequest(response, nil, err)
return
}
err = r.registryGetter.VerifyRegistryCredential(credential)
if err != nil {
api.HandleBadRequest(response, nil, err)
return
}
response.WriteHeader(http.StatusOK)
}
func (r *resourceHandler) handleGetRegistryEntry(request *restful.Request, response *restful.Response) {
imageName := request.QueryParameter("image")
namespace := request.QueryParameter("namespace")
secretName := request.QueryParameter("secret")
detail, err := r.registryGetter.GetEntry(namespace, secretName, imageName)
if err != nil {
api.HandleBadRequest(response, nil, err)
return
}
response.WriteAsJson(detail)
}
func (r *resourceHandler) handleGetNamespacedAbnormalWorkloads(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
result := api.Workloads{
Namespace: namespace,
Count: make(map[string]int),
}
for _, workloadType := range []string{api.ResourceKindDeployment, api.ResourceKindStatefulSet, api.ResourceKindDaemonSet, api.ResourceKindJob, api.ResourceKindPersistentVolumeClaim} {
var notReadyStatus string
switch workloadType {
case api.ResourceKindPersistentVolumeClaim:
notReadyStatus = strings.Join([]string{v1alpha2.StatusPending, v1alpha2.StatusLost}, "|")
case api.ResourceKindJob:
notReadyStatus = v1alpha2.StatusFailed
default:
notReadyStatus = v1alpha2.StatusUpdating
}
res, err := r.resourcesGetter.ListResources(namespace, workloadType, &params.Conditions{Match: map[string]string{v1alpha2.Status: notReadyStatus}}, "", false, -1, 0)
if err != nil {
api.HandleInternalError(response, nil, err)
}
result.Count[workloadType] = len(res.Items)
}
response.WriteAsJson(result)
}
func (r *resourceHandler) GetKubectlPod(request *restful.Request, response *restful.Response) {
user := request.PathParameter("user")
kubectlPod, err := r.kubectlOperator.GetKubectlPod(user)
if err != nil {
klog.Errorln(err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
response.WriteEntity(kubectlPod)
}
func (r *resourceHandler) GetKubeconfig(request *restful.Request, response *restful.Response) {
user := request.PathParameter("user")
kubectlConfig, err := r.kubeconfigOperator.GetKubeConfig(user)
if err != nil {
klog.Error(err)
if k8serr.IsNotFound(err) {
// recreate
response.WriteHeaderAndJson(http.StatusNotFound, errors.Wrap(err), restful.MIME_JSON)
} else {
response.WriteHeaderAndJson(http.StatusInternalServerError, errors.Wrap(err), restful.MIME_JSON)
}
return
}
response.Write([]byte(kubectlConfig))
}