This commit is contained in:
Darren Shepherd
2020-01-30 22:37:59 -07:00
parent 19c6732de0
commit 8b42d0aff8
71 changed files with 4024 additions and 507 deletions

View File

@@ -3,20 +3,19 @@ package apigroups
import (
"net/http"
"github.com/rancher/norman/v2/pkg/data"
"github.com/rancher/norman/v2/pkg/store/empty"
"github.com/rancher/norman/v2/pkg/types"
"github.com/rancher/steve/pkg/schemaserver/store/empty"
"github.com/rancher/steve/pkg/schemaserver/types"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/discovery"
)
func Register(schemas *types.Schemas, discovery discovery.DiscoveryInterface) {
schemas.MustImportAndCustomize(v1.APIGroup{}, func(schema *types.Schema) {
func Register(schemas *types.APISchemas, discovery discovery.DiscoveryInterface) {
schemas.MustImportAndCustomize(v1.APIGroup{}, func(schema *types.APISchema) {
schema.CollectionMethods = []string{http.MethodGet}
schema.ResourceMethods = []string{http.MethodGet}
schema.Store = NewStore(discovery)
schema.Formatter = func(request *types.APIRequest, resource *types.RawResource) {
resource.ID = data.Object(resource.Values).String("name")
resource.ID = resource.APIObject.Data().String("name")
}
})
}
@@ -34,38 +33,32 @@ func NewStore(discovery discovery.DiscoveryInterface) types.Store {
}
}
func (e *Store) ByID(apiOp *types.APIRequest, schema *types.Schema, id string) (types.APIObject, error) {
groupList, err := e.discovery.ServerGroups()
if err != nil {
return types.APIObject{}, err
}
if id == "core" {
id = ""
}
for _, group := range groupList.Groups {
if group.Name == id {
return types.ToAPI(group), nil
}
}
return types.APIObject{}, nil
func (e *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
return types.DefaultByID(e, apiOp, schema, id)
}
func (e *Store) List(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (types.APIObject, error) {
groupList, err := e.discovery.ServerGroups()
if err != nil {
return types.APIObject{}, err
func toAPIObject(schema *types.APISchema, group v1.APIGroup) types.APIObject {
if group.Name == "" {
group.Name = "core"
}
return types.APIObject{
Type: schema.ID,
ID: group.Name,
Object: group,
}
var result []interface{}
}
func (e *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
groupList, err := e.discovery.ServerGroups()
if err != nil {
return types.APIObjectList{}, err
}
var result types.APIObjectList
for _, item := range groupList.Groups {
if item.Name == "" {
item.Name = "core"
}
result = append(result, item)
result.Objects = append(result.Objects, toAPIObject(schema, item))
}
return types.ToAPI(result), nil
return result, nil
}

View File

@@ -1,9 +1,11 @@
package common
import (
"github.com/rancher/norman/v2/pkg/types"
"github.com/rancher/steve/pkg/attributes"
"github.com/rancher/steve/pkg/table"
"github.com/rancher/steve/pkg/schema/table"
"github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/wrangler/pkg/schemas"
"github.com/rancher/wrangler/pkg/schemas/mappers"
)
var (
@@ -22,12 +24,15 @@ var (
)
type DefaultColumns struct {
types.EmptyMapper
mappers.EmptyMapper
}
func (d *DefaultColumns) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
if attributes.Columns(schema) == nil {
attributes.SetColumns(schema, []table.Column{
func (d *DefaultColumns) ModifySchema(schema *schemas.Schema, schemas *schemas.Schemas) error {
as := &types.APISchema{
Schema: schema,
}
if attributes.Columns(as) == nil {
attributes.SetColumns(as, []table.Column{
NameColumn,
CreatedColumn,
})

View File

@@ -0,0 +1,111 @@
package common
import (
"net/http"
"github.com/rancher/steve/pkg/attributes"
"github.com/rancher/steve/pkg/schema/table"
"github.com/rancher/steve/pkg/schemaserver/types"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/rest"
)
type DynamicColumns struct {
client *rest.RESTClient
}
func NewDynamicColumns(config *rest.Config) (*DynamicColumns, error) {
c, err := newClient(config)
if err != nil {
return nil, err
}
return &DynamicColumns{
client: c,
}, nil
}
func hasGet(methods []string) bool {
for _, method := range methods {
if method == http.MethodGet {
return true
}
}
return false
}
func (d *DynamicColumns) SetColumns(schema *types.APISchema) error {
if attributes.Columns(schema) != nil {
return nil
}
gvr := attributes.GVR(schema)
if gvr.Resource == "" {
return nil
}
nsed := attributes.Namespaced(schema)
if !hasGet(schema.CollectionMethods) {
return nil
}
r := d.client.Get()
if gvr.Group == "" {
r.Prefix("api")
} else {
r.Prefix("apis", gvr.Group)
}
r.Prefix(gvr.Version)
if nsed {
r.Prefix("namespaces", "default")
}
r.Prefix(gvr.Resource)
obj, err := r.Do().Get()
if err != nil {
return err
}
t, ok := obj.(*metav1.Table)
if !ok {
return nil
}
var cols []table.Column
for _, cd := range t.ColumnDefinitions {
cols = append(cols, table.Column{
Name: cd.Name,
Field: "metadata.computed.fields." + cd.Name,
Type: cd.Type,
Format: cd.Format,
})
}
if len(cols) > 0 {
attributes.SetColumns(schema, cols)
schema.Attributes["server-side-column"] = "true"
}
return nil
}
func newClient(config *rest.Config) (*rest.RESTClient, error) {
scheme := runtime.NewScheme()
if err := metav1.AddMetaToScheme(scheme); err != nil {
return nil, err
}
if err := metav1beta1.AddMetaToScheme(scheme); err != nil {
return nil, err
}
config = rest.CopyConfig(config)
config.UserAgent = rest.DefaultKubernetesUserAgent()
config.AcceptContentTypes = "application/json;as=Table;v=v1beta1;g=meta.k8s.io"
config.ContentType = "application/json;as=Table;v=v1beta1;g=meta.k8s.io"
config.GroupVersion = &schema.GroupVersion{}
config.NegotiatedSerializer = serializer.NewCodecFactory(scheme)
config.APIPath = "/"
return rest.RESTClientFor(config)
}

View File

@@ -1,25 +1,27 @@
package common
import (
"github.com/rancher/norman/v2/pkg/store/proxy"
"github.com/rancher/norman/v2/pkg/types"
"github.com/rancher/norman/v2/pkg/types/convert"
"github.com/rancher/norman/v2/pkg/types/values"
"github.com/rancher/steve/pkg/resources/schema"
"github.com/rancher/steve/pkg/schema"
"github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/steve/pkg/server/store/proxy"
"k8s.io/apimachinery/pkg/api/meta"
)
func Register(collection *schema.Collection, clientGetter proxy.ClientGetter) error {
collection.AddTemplate(&schema.Template{
func DefaultTemplate(clientGetter proxy.ClientGetter) schema.Template {
return schema.Template{
Store: proxy.NewProxyStore(clientGetter),
Formatter: Formatter,
Mapper: &DefaultColumns{},
})
return nil
}
}
func Formatter(request *types.APIRequest, resource *types.RawResource) {
selfLink := convert.ToString(values.GetValueN(resource.Values, "metadata", "selfLink"))
meta, err := meta.Accessor(resource.APIObject.Object)
if err != nil {
return
}
selfLink := meta.GetSelfLink()
if selfLink == "" {
return
}

View File

@@ -5,15 +5,14 @@ import (
"strconv"
"sync"
schema2 "k8s.io/apimachinery/pkg/runtime/schema"
"github.com/rancher/norman/v2/pkg/store/empty"
"github.com/rancher/norman/v2/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/attributes"
"github.com/rancher/steve/pkg/clustercache"
"github.com/rancher/steve/pkg/schemaserver/store/empty"
"github.com/rancher/steve/pkg/schemaserver/types"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
schema2 "k8s.io/apimachinery/pkg/runtime/schema"
)
var (
@@ -24,11 +23,11 @@ var (
}
)
func Register(schemas *types.Schemas, ccache clustercache.ClusterCache) {
schemas.MustImportAndCustomize(Count{}, func(schema *types.Schema) {
func Register(schemas *types.APISchemas, ccache clustercache.ClusterCache) {
schemas.MustImportAndCustomize(Count{}, func(schema *types.APISchema) {
schema.CollectionMethods = []string{http.MethodGet}
schema.ResourceMethods = []string{http.MethodGet}
schema.Attributes["access"] = accesscontrol.AccessListMap{
schema.Attributes["access"] = accesscontrol.AccessListByVerb{
"watch": accesscontrol.AccessList{
{
Namespace: "*",
@@ -58,27 +57,39 @@ type Store struct {
ccache clustercache.ClusterCache
}
func (s *Store) ByID(apiOp *types.APIRequest, schema *types.Schema, id string) (types.APIObject, error) {
c := s.getCount(apiOp)
return types.ToAPI(c), nil
func toAPIObject(c Count) types.APIObject {
return types.APIObject{
Type: "count",
ID: c.ID,
Object: c,
}
}
func (s *Store) List(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (types.APIObject, error) {
func (s *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
c := s.getCount(apiOp)
return types.ToAPI([]interface{}{c}), nil
return toAPIObject(c), nil
}
func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, w types.WatchRequest) (chan types.APIEvent, error) {
func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
c := s.getCount(apiOp)
return types.APIObjectList{
Objects: []types.APIObject{
toAPIObject(c),
},
}, nil
}
func (s *Store) Watch(apiOp *types.APIRequest, schema *types.APISchema, w types.WatchRequest) (chan types.APIEvent, error) {
var (
result = make(chan types.APIEvent, 100)
counts map[string]ItemCount
gvrToSchema = map[schema2.GroupVersionResource]*types.Schema{}
gvrToSchema = map[schema2.GroupVersionResource]*types.APISchema{}
countLock sync.Mutex
)
counts = s.getCount(apiOp).Counts
for id := range counts {
schema := apiOp.Schemas.Schema(id)
schema := apiOp.Schemas.LookupSchema(id)
if schema == nil {
continue
}
@@ -107,11 +118,6 @@ func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, w types.Wat
return nil
}
apiObj := apiOp.Filter(nil, schema, types.ToAPI(obj))
if apiObj.IsNil() {
return nil
}
_, namespace, revision, ok := getInfo(obj)
if !ok {
return nil
@@ -151,7 +157,7 @@ func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, w types.Wat
result <- types.APIEvent{
Name: "resource.change",
ResourceType: "counts",
Object: types.ToAPI(Count{
Object: toAPIObject(Count{
ID: "count",
Counts: countsCopy,
}),
@@ -170,8 +176,8 @@ func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, w types.Wat
return result, nil
}
func (s *Store) schemasToWatch(apiOp *types.APIRequest) (result []*types.Schema) {
for _, schema := range apiOp.Schemas.Schemas() {
func (s *Store) schemasToWatch(apiOp *types.APIRequest) (result []*types.APISchema) {
for _, schema := range apiOp.Schemas.Schemas {
if ignore[schema.ID] {
continue
}

View File

@@ -1,38 +1,28 @@
package resources
import (
"github.com/rancher/norman/v2/pkg/store/apiroot"
"github.com/rancher/norman/v2/pkg/subscribe"
"github.com/rancher/norman/v2/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/client"
"github.com/rancher/steve/pkg/clustercache"
"github.com/rancher/steve/pkg/resources/apigroups"
"github.com/rancher/steve/pkg/resources/common"
"github.com/rancher/steve/pkg/resources/core"
"github.com/rancher/steve/pkg/resources/counts"
"github.com/rancher/steve/pkg/resources/schema"
"k8s.io/client-go/kubernetes"
"github.com/rancher/steve/pkg/schema"
"github.com/rancher/steve/pkg/schemaserver/store/apiroot"
"github.com/rancher/steve/pkg/schemaserver/subscribe"
"github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/steve/pkg/server/resources/apigroups"
"github.com/rancher/steve/pkg/server/resources/common"
"github.com/rancher/steve/pkg/server/resources/counts"
"k8s.io/client-go/discovery"
)
func SchemaFactory(
cf *client.Factory,
as *accesscontrol.AccessStore,
k8s kubernetes.Interface,
ccache clustercache.ClusterCache,
) (*schema.Collection, error) {
baseSchema := types.EmptySchemas()
collection := schema.NewCollection(baseSchema, as)
core.Register(collection)
func DefaultSchemas(baseSchema *types.APISchemas, discovery discovery.DiscoveryInterface, ccache clustercache.ClusterCache) *types.APISchemas {
counts.Register(baseSchema, ccache)
subscribe.Register(baseSchema)
apigroups.Register(baseSchema, k8s.Discovery())
apigroups.Register(baseSchema, discovery)
apiroot.Register(baseSchema, []string{"v1"}, []string{"proxy:/apis"})
if err := common.Register(collection, cf); err != nil {
return nil, err
}
return collection, nil
return baseSchema
}
func DefaultSchemaTemplates(cf *client.Factory) []schema.Template {
return []schema.Template{
common.DefaultTemplate(cf),
}
}