diff --git a/pkg/server/apis/v1alpha1/descriptors/tenant.go b/pkg/server/apis/v1alpha1/descriptors/tenant.go index 29762e911..dd9aba0db 100644 --- a/pkg/server/apis/v1alpha1/descriptors/tenant.go +++ b/pkg/server/apis/v1alpha1/descriptors/tenant.go @@ -89,24 +89,18 @@ var tenant = []definition.Descriptor{ }, }, { - Path: "/tenants/{tenant}/precheck", - Description: "Checks worker clusters' status before running workflows", + Path: "/tenants/{tenant}/executioncontexts", + Description: "List execution contexts of a tenant, an execution context describes context of workflow execution, including information about cluster, namespace, pvc, etc.", Definitions: []definition.Definition{ { - Method: definition.Get, + Method: definition.List, Parameters: []definition.Parameter{ { Source: definition.Path, Name: httputil.TenantNamePathParameterName, }, - { - Source: definition.Query, - Name: "checklist", - Description: "Items to check", - Default: "ReservedResources", - }, }, - Function: handler.Precheck, + Function: handler.ListExecutionContexts, Results: definition.DataErrorResults("worker cluster status"), }, }, diff --git a/pkg/server/apis/v1alpha1/types.go b/pkg/server/apis/v1alpha1/types.go index cf1a73e34..ceeca97cf 100644 --- a/pkg/server/apis/v1alpha1/types.go +++ b/pkg/server/apis/v1alpha1/types.go @@ -248,3 +248,40 @@ type StorageUsage struct { type StorageCleanup struct { Paths []string `json:"paths"` } + +// ExecutionContextSpec describes the execution context +type ExecutionContextSpec struct { + Cluster string `json:"cluster"` + Namespace string `json:"namespace"` + Integration string `json:"integration"` + PVC string `json:"pvc"` +} + +// ExecutionContextStatus describe the status of execution context, it contains information that affects +// pipeline execution, like reserved resources, pvc status. +type ExecutionContextStatus struct { + // Phase of the execution context, could be 'Ready', 'NotReady' or 'Unknown' + Phase ExecutionContextPhase `json:"phase"` + ReservedResources map[core_v1.ResourceName]string `json:"reservedResources"` + PVC *core_v1.PersistentVolumeClaimStatus `json:"pvc"` +} + +// ExecutionContext represtents a context used to execute workflows. +type ExecutionContext struct { + // Metadata for the particular object, including name, namespace, labels, etc + meta_v1.ObjectMeta `json:"metadata,omitempty"` + Spec ExecutionContextSpec `json:"spec"` + Status ExecutionContextStatus `json:"status"` +} + +// ExecutionContextPhase represents the phase of ExecutionContext. +type ExecutionContextPhase string + +const ( + // ExecutionContextReady is ready phase + ExecutionContextReady ExecutionContextPhase = "Ready" + // ExecutionContextNotReady is not ready phase + ExecutionContextNotReady ExecutionContextPhase = "NotReady" + // ExecutionContextNotUnknown is unknown phase + ExecutionContextNotUnknown ExecutionContextPhase = "Unknown" +) diff --git a/pkg/server/handler/v1alpha1/executioncontext.go b/pkg/server/handler/v1alpha1/executioncontext.go new file mode 100644 index 000000000..951a61deb --- /dev/null +++ b/pkg/server/handler/v1alpha1/executioncontext.go @@ -0,0 +1,83 @@ +package v1alpha1 + +import ( + "context" + + "github.com/caicloud/nirvana/log" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/caicloud/cyclone/pkg/common" + api "github.com/caicloud/cyclone/pkg/server/apis/v1alpha1" + "github.com/caicloud/cyclone/pkg/server/biz/integration/cluster" + svrcommon "github.com/caicloud/cyclone/pkg/server/common" + "github.com/caicloud/cyclone/pkg/server/config" + "github.com/caicloud/cyclone/pkg/server/handler" + "github.com/caicloud/cyclone/pkg/server/types" +) + +// ListExecutionContexts list execution contexts of a tenant +func ListExecutionContexts(ctx context.Context, tenant string) (*types.ListResponse, error) { + var executionContexts []api.ExecutionContext + + integrations, err := cluster.GetSchedulableClusters(handler.K8sClient, tenant) + if err != nil { + return nil, err + } + + for _, integration := range integrations { + cluster := integration.Spec.Cluster + if cluster == nil { + log.Warningf("Cluster of integration %s is nil", integration.Name) + continue + } + + pvcName := cluster.PVC + if pvcName == "" { + pvcName = svrcommon.TenantPVC(tenant) + } + + executionContext := api.ExecutionContext{ + Spec: api.ExecutionContextSpec{ + Integration: integration.Name, + Cluster: cluster.ClusterName, + Namespace: cluster.Namespace, + PVC: pvcName, + }, + Status: api.ExecutionContextStatus{ + Phase: api.ExecutionContextNotUnknown, + ReservedResources: config.Config.StorageUsageWatcher.ResourceRequirements, + }, + } + + pvcStatus, err := getPVCStatus(tenant, pvcName, cluster) + if err != nil { + log.Warningf("Get PVC status in %s/%s", cluster.ClusterName, cluster.Namespace) + } else { + executionContext.Status.PVC = pvcStatus + if pvcStatus.Phase == "Bound" { + executionContext.Status.Phase = api.ExecutionContextReady + } else { + executionContext.Status.Phase = api.ExecutionContextNotReady + } + } + + executionContexts = append(executionContexts, executionContext) + } + + return types.NewListResponse(len(executionContexts), executionContexts), nil +} + +func getPVCStatus(tenant, pvcName string, cluster *api.ClusterSource) (*corev1.PersistentVolumeClaimStatus, error) { + client, err := common.NewClusterClient(&cluster.Credential, cluster.IsControlCluster) + if err != nil { + return nil, err + } + + pvc, err := client.CoreV1().PersistentVolumeClaims(cluster.Namespace).Get(pvcName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + + return &pvc.Status, nil +} diff --git a/pkg/server/handler/v1alpha1/precheck.go b/pkg/server/handler/v1alpha1/precheck.go deleted file mode 100644 index 00d1717c8..000000000 --- a/pkg/server/handler/v1alpha1/precheck.go +++ /dev/null @@ -1,99 +0,0 @@ -package v1alpha1 - -import ( - "context" - "strings" - - "github.com/caicloud/nirvana/log" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - - "github.com/caicloud/cyclone/pkg/common" - "github.com/caicloud/cyclone/pkg/server/biz/integration/cluster" - svrcommon "github.com/caicloud/cyclone/pkg/server/common" - "github.com/caicloud/cyclone/pkg/server/config" - "github.com/caicloud/cyclone/pkg/server/handler" -) - -// Precheck checks worker cluster status -func Precheck(ctx context.Context, tenant string, checklist string) (*WorkersContextStatus, error) { - lists := strings.Split(checklist, ",") - workersContext := &WorkersContextStatus{ - Workers: []*WorkerContextStatus{}, - } - - integrations, err := cluster.GetSchedulableClusters(handler.K8sClient, tenant) - if err != nil { - return nil, err - } - - for _, integration := range integrations { - cluster := integration.Spec.Cluster - if cluster == nil { - log.Warningf("Cluster of integration %s is nil", integration.Name) - continue - } - - workerContext := &WorkerContextStatus{ - Integration: integration.Name, - Cluster: cluster.ClusterName, - Namespace: cluster.Namespace, - Opened: cluster.IsWorkerCluster, - } - workersContext.Workers = append(workersContext.Workers, workerContext) - - if !cluster.IsWorkerCluster { - log.Infof("Cluster %s is not a worker cluster, skip", integration.Name) - continue - } - - var client *kubernetes.Clientset - var err error - check: - for _, item := range lists { - switch item { - case "ReservedResources": - workerContext.ReservedResources = config.Config.StorageUsageWatcher.ResourceRequirements - case "PVC": - if client == nil { - client, err = common.NewClusterClient(&cluster.Credential, cluster.IsControlCluster) - if err != nil { - log.Warningf("New cluster client for integration %s error %v", integration.Name, err) - continue check - } - } - - pvcName := cluster.PVC - if pvcName == "" { - pvcName = svrcommon.TenantPVC(tenant) - } - pvc, err := client.CoreV1().PersistentVolumeClaims(cluster.Namespace).Get(pvcName, metav1.GetOptions{}) - if err != nil { - log.Warningf("Get PVC %s in namespace %s", pvcName, cluster.Namespace) - continue check - } - workerContext.PVC = &pvc.Status - - } - } - } - - return workersContext, nil -} - -// WorkerContextStatus describes the status of worker clusters, it contains information that affects -// pipeline execution, like reserved resources, pvc status. -type WorkerContextStatus struct { - Cluster string `json:"cluster"` - Namespace string `json:"namespace"` - Integration string `json:"integration"` - Opened bool `json:"opened"` - ReservedResources map[corev1.ResourceName]string `json:"reservedResources"` - PVC *corev1.PersistentVolumeClaimStatus `json:"pvc"` -} - -// WorkersContextStatus contains a set of WorkerContextStatus– -type WorkersContextStatus struct { - Workers []*WorkerContextStatus `json:"workers"` -}