mirror of https://github.com/grafana/grafana
commit
37404446b1
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,125 @@ |
|||||||
|
area/admin/user |
||||||
|
area/alerting |
||||||
|
area/annotations |
||||||
|
area/auth |
||||||
|
area/auth/ldap |
||||||
|
area/auth/oauth |
||||||
|
area/auth/rbac |
||||||
|
area/auth/serviceaccount |
||||||
|
area/backend |
||||||
|
area/backend/api |
||||||
|
area/backend/db |
||||||
|
area/backend/db/migration |
||||||
|
area/backend/db/mysql |
||||||
|
area/backend/db/postgres |
||||||
|
area/backend/db/sql |
||||||
|
area/backend/db/sqlite |
||||||
|
area/configuration |
||||||
|
area/dashboard/annotations |
||||||
|
area/dashboard/data-links |
||||||
|
area/dashboard/edit |
||||||
|
area/dashboard/folders |
||||||
|
area/dashboard/import |
||||||
|
area/dashboard/kiosk |
||||||
|
area/dashboard/links |
||||||
|
area/dashboard/rows |
||||||
|
area/dashboard/scenes |
||||||
|
area/dashboard/settings |
||||||
|
area/dashboard/snapshot |
||||||
|
area/dashboard/templating |
||||||
|
area/dashboard/timerange |
||||||
|
area/dashboard/tv |
||||||
|
area/dashboard/variable |
||||||
|
area/dashboards/panel |
||||||
|
area/data/export |
||||||
|
area/editor |
||||||
|
area/explore |
||||||
|
area/exploremetrics |
||||||
|
area/expressions |
||||||
|
area/field/overrides |
||||||
|
area/frontend/library-panels |
||||||
|
area/frontend/login |
||||||
|
area/image-rendering |
||||||
|
area/internationalization |
||||||
|
area/legend |
||||||
|
area/library-panel |
||||||
|
area/navigation |
||||||
|
area/panel/annotation-list |
||||||
|
area/panel/barchart |
||||||
|
area/panel/bargauge |
||||||
|
area/panel/candlestick |
||||||
|
area/panel/canvas |
||||||
|
area/panel/dashboard-list |
||||||
|
area/panel/edit |
||||||
|
area/panel/edit |
||||||
|
area/panel/field-override |
||||||
|
area/panel/flame-graph |
||||||
|
area/panel/gauge |
||||||
|
area/panel/geomap |
||||||
|
area/panel/heatmap |
||||||
|
area/panel/histogram |
||||||
|
area/panel/logs |
||||||
|
area/panel/node-graph |
||||||
|
area/panel/node-graph |
||||||
|
area/panel/piechart |
||||||
|
area/panel/repeat |
||||||
|
area/panel/singlestat |
||||||
|
area/panel/stat |
||||||
|
area/panel/state-timeline |
||||||
|
area/panel/status-history |
||||||
|
area/panel/table |
||||||
|
area/panel/timeseries |
||||||
|
area/panel/traceview |
||||||
|
area/panel/trend |
||||||
|
area/panel/xychart |
||||||
|
area/permissions |
||||||
|
area/playlist |
||||||
|
area/plugins |
||||||
|
area/plugins-catalog |
||||||
|
area/provisioning |
||||||
|
area/provisioning/datasources |
||||||
|
area/public-dashboards |
||||||
|
area/query-library |
||||||
|
area/recorded-queries |
||||||
|
area/scenes |
||||||
|
area/search |
||||||
|
area/security |
||||||
|
area/streaming |
||||||
|
area/templating/repeating |
||||||
|
area/tooltip |
||||||
|
area/transformations |
||||||
|
datagrid |
||||||
|
datasource/Alertmanager |
||||||
|
datasource/Azure |
||||||
|
datasource/azure-cosmosdb |
||||||
|
datasource/BigQuery |
||||||
|
datasource/CloudWatch |
||||||
|
datasource/CloudWatch Logs |
||||||
|
datasource/CSV |
||||||
|
datasource/Elasticsearch |
||||||
|
datasource/GitHub |
||||||
|
datasource/GoogleCloudMonitoring |
||||||
|
datasource/GoogleSheets |
||||||
|
datasource/grafana-pyroscope |
||||||
|
datasource/Graphite |
||||||
|
datasource/InfluxDB |
||||||
|
datasource/Jaeger |
||||||
|
datasource/JSON |
||||||
|
datasource/Loki |
||||||
|
datasource/MSSQL |
||||||
|
datasource/MySQL |
||||||
|
datasource/OpenSearch |
||||||
|
datasource/OpenTSDB |
||||||
|
datasource/Parca |
||||||
|
datasource/Phlare |
||||||
|
datasource/Postgres |
||||||
|
datasource/Prometheus |
||||||
|
datasource/SiteWIse |
||||||
|
datasource/Splunk |
||||||
|
datasource/Tempo |
||||||
|
datasource/TestDataDB |
||||||
|
datasource/Timestream |
||||||
|
datasource/X-Ray |
||||||
|
datasource/Zabbix |
||||||
|
datasource/Zipkin |
||||||
|
team/grafana-aws-datasources |
@ -0,0 +1,25 @@ |
|||||||
|
You are an expert Grafana issues categorizer. |
||||||
|
|
||||||
|
You are provided with a Grafana issue. Your task is to categorize the issue by analyzing the issue title and description to determine the most relevant category and type from the provided lists. Focus on precision and clarity, selecting only the most pertinent labels based on the issue details. Ensure that your selections reflect the core problem or functionality affected. |
||||||
|
|
||||||
|
The output should be a valid JSON object with the following fields: |
||||||
|
* id (string): The ID of the current issue. |
||||||
|
* categoryLabel (array of strings): The category labels for the current issue, emphasizing key terms and context. |
||||||
|
* typeLabel (array of strings): The type of the current issue, emphasizing clarity and relevance. |
||||||
|
|
||||||
|
**Instructions**: |
||||||
|
1. **Contextual Analysis**: Understand the context and intent behind the issue description. Analyze the overall narrative and relationships between different components within Grafana. Consider dependencies and related components to inform your decision. |
||||||
|
2. **Category and Type Differentiation**: Use language cues and patterns to differentiate between similar categories and types. Provide examples and counterexamples to clarify distinctions. Prioritize primary components over secondary ones unless they are critical to the issue. |
||||||
|
3. **Historical Data Utilization**: Compare current issues with past resolved issues by analyzing similarities in problem descriptions, leveraging patterns to inform categorization. Use historical data to recognize patterns and inform your decision-making. |
||||||
|
4. **Confidence Scoring**: Implement a confidence scoring mechanism to flag issues for review if the confidence is below a predefined threshold. Clearly indicate thresholds for high and low confidence predictions. Provide clarifying questions if data is ambiguous. |
||||||
|
5. **Feedback Loop Integration**: Integrate feedback from incorrect predictions to refine understanding and improve future predictions. Conduct error analysis to identify patterns in misclassifications and adapt your approach accordingly. |
||||||
|
6. **Semantic Analysis**: Evaluate the underlying intent of the issue using semantic analysis, considering broader implications and context. Leverage metadata or historical patterns to improve accuracy. |
||||||
|
7. **Avoid Over-Specification**: Maintain precision and conciseness, avoiding unnecessary details. Prioritize clarity and flag for further review if uncertain. |
||||||
|
8. **Consistent JSON Formatting**: Ensure the output maintains a consistent JSON structure with uniform formatting for readability and scalability. |
||||||
|
|
||||||
|
**Next Steps and Insights**: |
||||||
|
- Suggest potential next steps or resources that could help address the issue, providing actionable insights to enhance user engagement. |
||||||
|
- Regularly test responses against edge cases to ensure robustness and adaptability. |
||||||
|
- Stay updated with changes in category and type lists to remain current. |
||||||
|
|
||||||
|
Provide a brief explanation of the categorization decision, highlighting key terms or context that influenced the choice. Use user-centric language and technical details to ensure the explanation is comprehensive and insightful. |
@ -0,0 +1,30 @@ |
|||||||
|
type/accessibility |
||||||
|
type/angular-2-react |
||||||
|
type/browser-compatibility |
||||||
|
type/bug |
||||||
|
type/build-packaging |
||||||
|
type/chore |
||||||
|
type/ci |
||||||
|
type/cleanup |
||||||
|
type/codegen |
||||||
|
type/community |
||||||
|
type/debt |
||||||
|
type/design |
||||||
|
type/discussion |
||||||
|
type/docs |
||||||
|
type/duplicate |
||||||
|
type/e2e |
||||||
|
type/epic |
||||||
|
type/feature-request |
||||||
|
type/feature-toggle-enable |
||||||
|
type/feature-toggle-removal |
||||||
|
type/performance |
||||||
|
type/poc |
||||||
|
type/project |
||||||
|
type/proposal |
||||||
|
type/question |
||||||
|
type/refactor |
||||||
|
type/regression |
||||||
|
type/roadmap |
||||||
|
type/tech |
||||||
|
type/ux |
File diff suppressed because one or more lines are too long
@ -0,0 +1,21 @@ |
|||||||
|
--- |
||||||
|
title: Configure traces to profiles |
||||||
|
menuTitle: Configure traces to profiles |
||||||
|
description: Learn how to configure the traces to profiles integration in Grafana and Grafana Cloud. |
||||||
|
weight: 300 |
||||||
|
keywords: |
||||||
|
- continuous profiling |
||||||
|
- tracing |
||||||
|
--- |
||||||
|
|
||||||
|
# Configure traces to profiles |
||||||
|
|
||||||
|
{{< admonition type="note" >}} |
||||||
|
|
||||||
|
Your application must be instrumented for profiles and traces. For more information, refer to [Link traces to profiles](https://grafana.com/docs/pyroscope/<PYROSCOPE_VERSION>/configure-client/trace-span-profiles/). |
||||||
|
|
||||||
|
{{< /admonition >}} |
||||||
|
|
||||||
|
[//]: # 'Shared content for Trace to profiles in the Tempo data source' |
||||||
|
|
||||||
|
{{< docs/shared source="grafana" lookup="datasources/tempo-traces-to-profiles.md" version="<GRAFANA VERSION>" >}} |
@ -0,0 +1,160 @@ |
|||||||
|
package dashboard |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"fmt" |
||||||
|
"testing" |
||||||
|
|
||||||
|
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" |
||||||
|
"github.com/grafana/grafana/pkg/apis/dashboard/v0alpha1" |
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards" |
||||||
|
"github.com/grafana/grafana/pkg/services/user" |
||||||
|
"github.com/stretchr/testify/mock" |
||||||
|
"github.com/stretchr/testify/require" |
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||||
|
"k8s.io/apiserver/pkg/admission" |
||||||
|
) |
||||||
|
|
||||||
|
func TestDashboardAPIBuilder_Validate(t *testing.T) { |
||||||
|
oneInt64 := int64(1) |
||||||
|
zeroInt64 := int64(0) |
||||||
|
tests := []struct { |
||||||
|
name string |
||||||
|
inputObj *v0alpha1.Dashboard |
||||||
|
deletionOptions metav1.DeleteOptions |
||||||
|
dashboardResponse *dashboards.DashboardProvisioning |
||||||
|
dashboardErrorResponse error |
||||||
|
checkRan bool |
||||||
|
expectedError bool |
||||||
|
}{ |
||||||
|
{ |
||||||
|
name: "should return an error if data is found", |
||||||
|
inputObj: &v0alpha1.Dashboard{ |
||||||
|
Spec: common.Unstructured{}, |
||||||
|
TypeMeta: metav1.TypeMeta{ |
||||||
|
Kind: "Dashboard", |
||||||
|
}, |
||||||
|
ObjectMeta: metav1.ObjectMeta{ |
||||||
|
Name: "test", |
||||||
|
}, |
||||||
|
}, |
||||||
|
deletionOptions: metav1.DeleteOptions{ |
||||||
|
GracePeriodSeconds: nil, |
||||||
|
}, |
||||||
|
dashboardResponse: &dashboards.DashboardProvisioning{ID: 1}, |
||||||
|
dashboardErrorResponse: nil, |
||||||
|
checkRan: true, |
||||||
|
expectedError: true, |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "should return an error if unable to check", |
||||||
|
inputObj: &v0alpha1.Dashboard{ |
||||||
|
Spec: common.Unstructured{}, |
||||||
|
TypeMeta: metav1.TypeMeta{ |
||||||
|
Kind: "Dashboard", |
||||||
|
}, |
||||||
|
ObjectMeta: metav1.ObjectMeta{ |
||||||
|
Name: "test", |
||||||
|
}, |
||||||
|
}, |
||||||
|
deletionOptions: metav1.DeleteOptions{ |
||||||
|
GracePeriodSeconds: nil, |
||||||
|
}, |
||||||
|
dashboardResponse: nil, |
||||||
|
dashboardErrorResponse: fmt.Errorf("generic error"), |
||||||
|
checkRan: true, |
||||||
|
expectedError: true, |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "should be okay if error is provisioned dashboard not found", |
||||||
|
inputObj: &v0alpha1.Dashboard{ |
||||||
|
Spec: common.Unstructured{}, |
||||||
|
TypeMeta: metav1.TypeMeta{ |
||||||
|
Kind: "Dashboard", |
||||||
|
}, |
||||||
|
ObjectMeta: metav1.ObjectMeta{ |
||||||
|
Name: "test", |
||||||
|
}, |
||||||
|
}, |
||||||
|
deletionOptions: metav1.DeleteOptions{ |
||||||
|
GracePeriodSeconds: nil, |
||||||
|
}, |
||||||
|
dashboardResponse: nil, |
||||||
|
dashboardErrorResponse: dashboards.ErrProvisionedDashboardNotFound, |
||||||
|
checkRan: true, |
||||||
|
expectedError: false, |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "Should still run the check for delete if grace period is not 0", |
||||||
|
inputObj: &v0alpha1.Dashboard{ |
||||||
|
Spec: common.Unstructured{}, |
||||||
|
TypeMeta: metav1.TypeMeta{ |
||||||
|
Kind: "Dashboard", |
||||||
|
}, |
||||||
|
ObjectMeta: metav1.ObjectMeta{ |
||||||
|
Name: "test", |
||||||
|
}, |
||||||
|
}, |
||||||
|
deletionOptions: metav1.DeleteOptions{ |
||||||
|
GracePeriodSeconds: &oneInt64, |
||||||
|
}, |
||||||
|
dashboardResponse: nil, |
||||||
|
dashboardErrorResponse: nil, |
||||||
|
checkRan: true, |
||||||
|
expectedError: false, |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "should not run the check for delete if grace period is set to 0", |
||||||
|
inputObj: &v0alpha1.Dashboard{ |
||||||
|
Spec: common.Unstructured{}, |
||||||
|
TypeMeta: metav1.TypeMeta{ |
||||||
|
Kind: "Dashboard", |
||||||
|
}, |
||||||
|
ObjectMeta: metav1.ObjectMeta{ |
||||||
|
Name: "test", |
||||||
|
}, |
||||||
|
}, |
||||||
|
deletionOptions: metav1.DeleteOptions{ |
||||||
|
GracePeriodSeconds: &zeroInt64, |
||||||
|
}, |
||||||
|
dashboardResponse: nil, |
||||||
|
dashboardErrorResponse: nil, |
||||||
|
checkRan: false, |
||||||
|
expectedError: false, |
||||||
|
}, |
||||||
|
} |
||||||
|
for _, tt := range tests { |
||||||
|
t.Run(tt.name, func(t *testing.T) { |
||||||
|
fakeService := &dashboards.FakeDashboardProvisioning{} |
||||||
|
fakeService.On("GetProvisionedDashboardDataByDashboardUID", mock.Anything, mock.Anything, mock.Anything).Return(tt.dashboardResponse, tt.dashboardErrorResponse).Once() |
||||||
|
b := &DashboardsAPIBuilder{ |
||||||
|
ProvisioningDashboardService: fakeService, |
||||||
|
} |
||||||
|
err := b.Validate(context.Background(), admission.NewAttributesRecord( |
||||||
|
tt.inputObj, |
||||||
|
nil, |
||||||
|
v0alpha1.DashboardResourceInfo.GroupVersionKind(), |
||||||
|
"stacks-123", |
||||||
|
tt.inputObj.Name, |
||||||
|
v0alpha1.DashboardResourceInfo.GroupVersionResource(), |
||||||
|
"", |
||||||
|
admission.Operation("DELETE"), |
||||||
|
&tt.deletionOptions, |
||||||
|
true, |
||||||
|
&user.SignedInUser{}, |
||||||
|
), nil) |
||||||
|
|
||||||
|
if tt.expectedError { |
||||||
|
require.Error(t, err) |
||||||
|
} else { |
||||||
|
require.NoError(t, err) |
||||||
|
} |
||||||
|
|
||||||
|
if tt.checkRan { |
||||||
|
fakeService.AssertCalled(t, "GetProvisionedDashboardDataByDashboardUID", mock.Anything, mock.Anything, mock.Anything) |
||||||
|
} else { |
||||||
|
fakeService.AssertNotCalled(t, "GetProvisionedDashboardDataByDashboardUID", mock.Anything, mock.Anything, mock.Anything) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,112 @@ |
|||||||
|
package dualwrite |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"fmt" |
||||||
|
|
||||||
|
openfgav1 "github.com/openfga/api/proto/openfga/v1" |
||||||
|
|
||||||
|
authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" |
||||||
|
"github.com/grafana/grafana/pkg/services/authz/zanzana" |
||||||
|
) |
||||||
|
|
||||||
|
type globalTupleCollector func(ctx context.Context) (map[string]map[string]*openfgav1.TupleKey, error) |
||||||
|
|
||||||
|
type globalReconciler struct { |
||||||
|
name string |
||||||
|
globalCollector globalTupleCollector |
||||||
|
zanzana zanzanaTupleCollector |
||||||
|
client zanzana.Client |
||||||
|
} |
||||||
|
|
||||||
|
func newGlobalReconciler(name string, globalCollector globalTupleCollector, zanzana zanzanaTupleCollector, client zanzana.Client) globalReconciler { |
||||||
|
return globalReconciler{name, globalCollector, zanzana, client} |
||||||
|
} |
||||||
|
|
||||||
|
func (r globalReconciler) reconcile(ctx context.Context) error { |
||||||
|
namespace := zanzana.ClusterNamespace |
||||||
|
|
||||||
|
// 1. Fetch grafana resources stored in grafana db.
|
||||||
|
res, err := r.globalCollector(ctx) |
||||||
|
if err != nil { |
||||||
|
return fmt.Errorf("failed to collect legacy tuples for %s: %w", r.name, err) |
||||||
|
} |
||||||
|
|
||||||
|
var ( |
||||||
|
writes = []*openfgav1.TupleKey{} |
||||||
|
deletes = []*openfgav1.TupleKeyWithoutCondition{} |
||||||
|
) |
||||||
|
|
||||||
|
for object, tuples := range res { |
||||||
|
// 2. Fetch all tuples for given object.
|
||||||
|
// Due to limitations in open fga api we need to collect tuples per object
|
||||||
|
zanzanaTuples, err := r.zanzana(ctx, r.client, object, namespace) |
||||||
|
if err != nil { |
||||||
|
return fmt.Errorf("failed to collect zanzanaa tuples for %s: %w", r.name, err) |
||||||
|
} |
||||||
|
|
||||||
|
// 3. Check if tuples from grafana db exists in zanzana and if not add them to writes
|
||||||
|
for key, t := range tuples { |
||||||
|
stored, ok := zanzanaTuples[key] |
||||||
|
if !ok { |
||||||
|
writes = append(writes, t) |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
// 4. For folder resource tuples we also need to compare the stored group_resources
|
||||||
|
if zanzana.IsFolderResourceTuple(t) && t.String() != stored.String() { |
||||||
|
deletes = append(deletes, &openfgav1.TupleKeyWithoutCondition{ |
||||||
|
User: t.User, |
||||||
|
Relation: t.Relation, |
||||||
|
Object: t.Object, |
||||||
|
}) |
||||||
|
|
||||||
|
writes = append(writes, t) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 5. Check if tuple from zanzana don't exists in grafana db, if not add them to deletes.
|
||||||
|
for key, tuple := range zanzanaTuples { |
||||||
|
_, ok := tuples[key] |
||||||
|
if !ok { |
||||||
|
deletes = append(deletes, &openfgav1.TupleKeyWithoutCondition{ |
||||||
|
User: tuple.User, |
||||||
|
Relation: tuple.Relation, |
||||||
|
Object: tuple.Object, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if len(writes) == 0 && len(deletes) == 0 { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
if len(deletes) > 0 { |
||||||
|
err := batch(deletes, 100, func(items []*openfgav1.TupleKeyWithoutCondition) error { |
||||||
|
return r.client.Write(ctx, &authzextv1.WriteRequest{ |
||||||
|
Namespace: namespace, |
||||||
|
Deletes: &authzextv1.WriteRequestDeletes{TupleKeys: zanzana.ToAuthzExtTupleKeysWithoutCondition(items)}, |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if len(writes) > 0 { |
||||||
|
err := batch(writes, 100, func(items []*openfgav1.TupleKey) error { |
||||||
|
return r.client.Write(ctx, &authzextv1.WriteRequest{ |
||||||
|
Namespace: namespace, |
||||||
|
Writes: &authzextv1.WriteRequestWrites{TupleKeys: zanzana.ToAuthzExtTupleKeys(items)}, |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
@ -1,46 +1,122 @@ |
|||||||
package common |
package common |
||||||
|
|
||||||
import ( |
import ( |
||||||
"github.com/grafana/grafana/pkg/apimachinery/utils" |
"google.golang.org/protobuf/types/known/structpb" |
||||||
|
|
||||||
|
authzv1 "github.com/grafana/authlib/authz/proto/v1" |
||||||
folderalpha1 "github.com/grafana/grafana/pkg/apis/folder/v0alpha1" |
folderalpha1 "github.com/grafana/grafana/pkg/apis/folder/v0alpha1" |
||||||
|
authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" |
||||||
) |
) |
||||||
|
|
||||||
type TypeInfo struct { |
type typeInfo struct { |
||||||
Type string |
Type string |
||||||
Relations []string |
Relations []string |
||||||
} |
} |
||||||
|
|
||||||
func (t TypeInfo) IsValidRelation(relation string) bool { |
var typedResources = map[string]typeInfo{ |
||||||
return isValidRelation(relation, t.Relations) |
|
||||||
} |
|
||||||
|
|
||||||
var typedResources = map[string]TypeInfo{ |
|
||||||
FormatGroupResource( |
FormatGroupResource( |
||||||
folderalpha1.FolderResourceInfo.GroupResource().Group, |
folderalpha1.FolderResourceInfo.GroupResource().Group, |
||||||
folderalpha1.FolderResourceInfo.GroupResource().Resource, |
folderalpha1.FolderResourceInfo.GroupResource().Resource, |
||||||
|
"", |
||||||
): {Type: "folder", Relations: RelationsFolder}, |
): {Type: "folder", Relations: RelationsFolder}, |
||||||
} |
} |
||||||
|
|
||||||
func GetTypeInfo(group, resource string) (TypeInfo, bool) { |
func getTypeInfo(group, resource string) (typeInfo, bool) { |
||||||
info, ok := typedResources[FormatGroupResource(group, resource)] |
info, ok := typedResources[FormatGroupResource(group, resource, "")] |
||||||
return info, ok |
return info, ok |
||||||
} |
} |
||||||
|
|
||||||
var VerbMapping = map[string]string{ |
func NewResourceInfoFromCheck(r *authzv1.CheckRequest) ResourceInfo { |
||||||
utils.VerbGet: RelationGet, |
if info, ok := getTypeInfo(r.GetGroup(), r.GetResource()); ok { |
||||||
utils.VerbList: RelationGet, |
return newResource(info.Type, r.GetGroup(), r.GetResource(), r.GetName(), r.GetFolder(), r.GetSubresource(), info.Relations) |
||||||
utils.VerbWatch: RelationGet, |
} |
||||||
utils.VerbCreate: RelationCreate, |
return newResource(TypeResource, r.GetGroup(), r.GetResource(), r.GetName(), r.GetFolder(), r.GetSubresource(), RelationsResource) |
||||||
utils.VerbUpdate: RelationUpdate, |
} |
||||||
utils.VerbPatch: RelationUpdate, |
|
||||||
utils.VerbDelete: RelationDelete, |
func NewResourceInfoFromBatchItem(i *authzextv1.BatchCheckItem) ResourceInfo { |
||||||
utils.VerbDeleteCollection: RelationDelete, |
if info, ok := getTypeInfo(i.GetGroup(), i.GetResource()); ok { |
||||||
|
return newResource(info.Type, i.GetGroup(), i.GetResource(), i.GetName(), i.GetFolder(), i.GetSubresource(), info.Relations) |
||||||
|
} |
||||||
|
return newResource(TypeResource, i.GetGroup(), i.GetResource(), i.GetName(), i.GetFolder(), i.GetSubresource(), RelationsResource) |
||||||
|
} |
||||||
|
|
||||||
|
func NewResourceInfoFromList(r *authzv1.ListRequest) ResourceInfo { |
||||||
|
if info, ok := getTypeInfo(r.GetGroup(), r.GetResource()); ok { |
||||||
|
return newResource(info.Type, r.GetGroup(), r.GetResource(), "", "", r.GetSubresource(), info.Relations) |
||||||
|
} |
||||||
|
return newResource(TypeResource, r.GetGroup(), r.GetResource(), "", "", r.GetSubresource(), RelationsResource) |
||||||
|
} |
||||||
|
|
||||||
|
func newResource(typ string, group, resource, name, folder, subresource string, relations []string) ResourceInfo { |
||||||
|
return ResourceInfo{ |
||||||
|
typ: typ, |
||||||
|
group: group, |
||||||
|
resource: resource, |
||||||
|
name: name, |
||||||
|
folder: folder, |
||||||
|
subresource: subresource, |
||||||
|
relations: relations, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
type ResourceInfo struct { |
||||||
|
typ string |
||||||
|
group string |
||||||
|
resource string |
||||||
|
name string |
||||||
|
folder string |
||||||
|
subresource string |
||||||
|
relations []string |
||||||
|
} |
||||||
|
|
||||||
|
func (r ResourceInfo) GroupResource() string { |
||||||
|
return FormatGroupResource(r.group, r.resource, r.subresource) |
||||||
|
} |
||||||
|
|
||||||
|
func (r ResourceInfo) GroupResourceIdent() string { |
||||||
|
return NewGroupResourceIdent(r.group, r.resource, r.subresource) |
||||||
|
} |
||||||
|
|
||||||
|
func (r ResourceInfo) ResourceIdent() string { |
||||||
|
if r.name == "" { |
||||||
|
return "" |
||||||
|
} |
||||||
|
|
||||||
|
if r.IsGeneric() { |
||||||
|
return NewResourceIdent(r.group, r.resource, r.subresource, r.name) |
||||||
|
} |
||||||
|
|
||||||
|
return NewTypedIdent(r.typ, r.name) |
||||||
|
} |
||||||
|
|
||||||
|
func (r ResourceInfo) FolderIdent() string { |
||||||
|
if r.folder == "" { |
||||||
|
return "" |
||||||
|
} |
||||||
|
|
||||||
|
return NewFolderIdent(r.folder) |
||||||
|
} |
||||||
|
|
||||||
|
func (r ResourceInfo) IsGeneric() bool { |
||||||
|
return r.typ == TypeResource |
||||||
|
} |
||||||
|
|
||||||
|
func (r ResourceInfo) Type() string { |
||||||
|
return r.typ |
||||||
|
} |
||||||
|
|
||||||
|
func (r ResourceInfo) Context() *structpb.Struct { |
||||||
|
if !r.IsGeneric() { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
return &structpb.Struct{ |
||||||
|
Fields: map[string]*structpb.Value{ |
||||||
|
"requested_group": structpb.NewStringValue(r.GroupResource()), |
||||||
|
}, |
||||||
|
} |
||||||
} |
} |
||||||
|
|
||||||
var RelationToVerbMapping = map[string]string{ |
func (r ResourceInfo) IsValidRelation(relation string) bool { |
||||||
RelationGet: utils.VerbGet, |
return isValidRelation(relation, r.relations) |
||||||
RelationCreate: utils.VerbCreate, |
|
||||||
RelationUpdate: utils.VerbUpdate, |
|
||||||
RelationDelete: utils.VerbDelete, |
|
||||||
} |
} |
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue