The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/aggregator/registry/dataplaneservice/storage/storage.go

151 lines
5.8 KiB

package storage
import (
"context"
"fmt"
"k8s.io/apimachinery/pkg/api/meta"
metatable "k8s.io/apimachinery/pkg/api/meta/table"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/generic"
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
"k8s.io/apiserver/pkg/registry/rest"
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
"github.com/grafana/grafana/pkg/aggregator/apis/aggregation"
"github.com/grafana/grafana/pkg/aggregator/registry/dataplaneservice"
)
// REST implements a RESTStorage for Data Plane services.
type REST struct {
*genericregistry.Store
}
// NewREST returns a RESTStorage object that will work against Data Plane services.
func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *REST {
strategy := dataplaneservice.NewStrategy(scheme)
store := &genericregistry.Store{
NewFunc: func() runtime.Object { return &aggregation.DataPlaneService{} },
NewListFunc: func() runtime.Object { return &aggregation.DataPlaneServiceList{} },
PredicateFunc: dataplaneservice.MatchDataPlaneService,
DefaultQualifiedResource: aggregation.Resource("dataplaneservices"),
SingularQualifiedResource: aggregation.Resource("dataplaneservice"),
CreateStrategy: strategy,
UpdateStrategy: strategy,
DeleteStrategy: strategy,
ResetFieldsStrategy: strategy,
TableConvertor: rest.NewDefaultTableConvertor(aggregation.Resource("dataplaneservices")),
}
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: dataplaneservice.GetAttrs}
if err := store.CompleteWithOptions(options); err != nil {
panic(err) // TODO: Propagate error up
}
return &REST{store}
}
// Implement CategoriesProvider
var _ rest.CategoriesProvider = &REST{}
// Categories implements the CategoriesProvider interface. Returns a list of categories a resource is part of.
func (c *REST) Categories() []string {
return []string{"dataplane"}
}
var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc()
// ConvertToTable implements the TableConvertor interface for REST.
func (c *REST) ConvertToTable(ctx context.Context, obj runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
table := &metav1.Table{
ColumnDefinitions: []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: swaggerMetadataDescriptions["name"]},
{Name: "Available", Type: "string", Description: "Whether this service is available."},
{Name: "Age", Type: "string", Description: swaggerMetadataDescriptions["creationTimestamp"]},
},
}
if m, err := meta.ListAccessor(obj); err == nil {
table.ResourceVersion = m.GetResourceVersion()
table.Continue = m.GetContinue()
table.RemainingItemCount = m.GetRemainingItemCount()
} else {
if m, err := meta.CommonAccessor(obj); err == nil {
table.ResourceVersion = m.GetResourceVersion()
}
}
var err error
table.Rows, err = metatable.MetaToTableRow(obj, func(obj runtime.Object, m metav1.Object, name, age string) ([]interface{}, error) {
svc := obj.(*aggregation.DataPlaneService)
status := string(aggregation.ConditionUnknown)
if condition := getCondition(svc.Status.Conditions, "Available"); condition != nil {
switch {
case condition.Status == aggregation.ConditionTrue:
status = string(condition.Status)
case len(condition.Reason) > 0:
status = fmt.Sprintf("%s (%s)", condition.Status, condition.Reason)
default:
status = string(condition.Status)
}
}
return []interface{}{name, status, age}, nil
})
return table, err
}
func getCondition(conditions []aggregation.DataPlaneServiceCondition, conditionType aggregation.DataPlaneServiceConditionType) *aggregation.DataPlaneServiceCondition {
for i, condition := range conditions {
if condition.Type == conditionType {
return &conditions[i]
}
}
return nil
}
// NewStatusREST makes a RESTStorage for status that has more limited options.
// It is based on the original REST so that we can share the same underlying store
func NewStatusREST(scheme *runtime.Scheme, rest *REST) *StatusREST {
strategy := dataplaneservice.NewStatusStrategy(scheme)
statusStore := *rest.Store
statusStore.CreateStrategy = nil
statusStore.DeleteStrategy = nil
statusStore.UpdateStrategy = strategy
statusStore.ResetFieldsStrategy = strategy
return &StatusREST{store: &statusStore}
}
// StatusREST implements the REST endpoint for changing the status of an DataPlaneService.
type StatusREST struct {
store *genericregistry.Store
}
var _ = rest.Patcher(&StatusREST{})
// New creates a new DataPlaneService object.
func (r *StatusREST) New() runtime.Object {
return &aggregation.DataPlaneService{}
}
// Destroy cleans up resources on shutdown.
func (r *StatusREST) Destroy() {
// Given that underlying store is shared with REST,
// we don't destroy it here explicitly.
}
// Get retrieves the object from the storage. It is required to support Patch.
func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
return r.store.Get(ctx, name, options)
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
// We are explicitly setting forceAllowCreate to false in the call to the underlying storage because
// subresources should never allow create on update.
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
}
// GetResetFields implements rest.ResetFieldsStrategy
func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
return r.store.GetResetFields()
}