1
0
mirror of https://github.com/rancher/steve.git synced 2025-06-27 07:17:13 +00:00
steve/pkg/resources/clusters/clusters.go
2020-07-19 13:55:34 -07:00

175 lines
4.0 KiB
Go

package clusters
import (
"context"
"net/http"
"time"
"github.com/rancher/apiserver/pkg/store/empty"
"github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/clustercache"
"github.com/rancher/steve/pkg/podimpersonation"
"github.com/rancher/steve/pkg/stores/proxy"
"github.com/rancher/steve/pkg/stores/switchschema"
"github.com/rancher/steve/pkg/stores/switchstore"
"github.com/rancher/wrangler/pkg/data"
"github.com/rancher/wrangler/pkg/schemas/validation"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/discovery"
)
const (
rancherCluster = "management.cattle.io.cluster"
localID = "local"
)
var (
local = types.APIObject{
Type: "cluster",
ID: localID,
Object: &Cluster{},
}
localList = types.APIObjectList{
Objects: []types.APIObject{
local,
},
}
)
func Register(ctx context.Context, schemas *types.APISchemas, cg proxy.ClientGetter, cluster clustercache.ClusterCache) error {
k8s, err := cg.AdminK8sInterface()
if err != nil {
return err
}
shell := &shell{
cg: cg,
namespace: "dashboard-shells",
impersonator: podimpersonation.New("shell", cg, time.Hour),
}
picker := &picker{
start: time.Now(),
discovery: k8s.Discovery(),
}
cluster.OnAdd(ctx, shell.impersonator.PurgeOldRoles)
cluster.OnChange(ctx, func(gvr schema.GroupVersionResource, key string, obj, oldObj runtime.Object) error {
return shell.impersonator.PurgeOldRoles(gvr, key, obj)
})
schemas.MustImportAndCustomize(Cluster{}, func(schema *types.APISchema) {
schema.CollectionMethods = []string{http.MethodGet}
schema.ResourceMethods = []string{http.MethodGet}
schema.Formatter = Format
schema.Store = &switchstore.Store{
Picker: picker.Picker,
}
schema.LinkHandlers = map[string]http.Handler{
"shell": shell,
}
})
return nil
}
type Cluster struct {
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ClusterSpec `json:"spec"`
Status ClusterStatus `json:"status"`
}
type ClusterSpec struct {
DisplayName string `json:"displayName"`
}
type ClusterStatus struct {
Driver string `json:"driver"`
Version *version.Info `json:"version,omitempty"`
}
func Format(request *types.APIRequest, resource *types.RawResource) {
copy := [][]string{
{"spec", "displayName"},
{"metadata", "creationTimestamp"},
{"status", "driver"},
{"status", "version"},
}
from := resource.APIObject.Data()
to := data.New()
for _, keys := range copy {
to.SetNested(data.GetValueN(from, keys...), keys...)
}
resource.APIObject.Object = to
resource.Links["api"] = request.URLBuilder.RelativeToRoot("/k8s/clusters/" + resource.ID)
}
type Store struct {
empty.Store
start time.Time
discovery discovery.DiscoveryInterface
}
type picker struct {
start time.Time
discovery discovery.DiscoveryInterface
}
func (p *picker) Picker(apiOp *types.APIRequest, schema *types.APISchema, verb, id string) (types.Store, error) {
clusters := apiOp.Schemas.LookupSchema(rancherCluster)
if clusters == nil {
return &Store{
start: p.start,
discovery: p.discovery,
}, nil
}
return &switchschema.Store{
Schema: clusters,
}, nil
}
func (s *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
if id == localID {
return s.newLocal(), nil
}
return types.APIObject{}, validation.NotFound
}
func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
return types.APIObjectList{
Objects: []types.APIObject{
s.newLocal(),
},
}, nil
}
func (s *Store) newLocal() types.APIObject {
cluster := &Cluster{
ObjectMeta: metav1.ObjectMeta{
CreationTimestamp: metav1.NewTime(s.start),
},
Spec: ClusterSpec{
DisplayName: "Remote",
},
Status: ClusterStatus{
Driver: "remote",
},
}
version, err := s.discovery.ServerVersion()
if err == nil {
cluster.Status.Version = version
}
return types.APIObject{
Type: "cluster",
ID: localID,
Object: cluster,
}
}