From 82cb28664193c118fc64a6591585edcaa335a218 Mon Sep 17 00:00:00 2001 From: Jeroen Op 't Eynde Date: Wed, 8 Jan 2025 14:37:27 +0100 Subject: [PATCH] feat(grafanaplane): expose GroupVersionKind tuples (#21) * refactor(generator): move util functions to separate file * feat(grafanaplane): expose GroupVersionKind tuples This exposes GroupVersionKind tuples for all CRDs and XRDs covered by this library. The main goal is to configure kube-state-metrics Custom Resource State metrics. * fix(grafanaplane): update xtd dependency * fix: include plural as this is used to configure policyRules --- generator/configurations.libsonnet | 77 +++- generator/main.libsonnet | 113 +----- generator/utils.libsonnet | 89 ++++ grafanaplane/jsonnetfile.json | 2 +- grafanaplane/zz/gvks.libsonnet | 626 +++++++++++++++++++++++++++++ 5 files changed, 803 insertions(+), 104 deletions(-) create mode 100644 generator/utils.libsonnet create mode 100644 grafanaplane/zz/gvks.libsonnet diff --git a/generator/configurations.libsonnet b/generator/configurations.libsonnet index f05d79f..c702899 100644 --- a/generator/configurations.libsonnet +++ b/generator/configurations.libsonnet @@ -1,4 +1,3 @@ -local namespaced = import './namespaced.libsonnet'; local crossplane = import 'github.com/jsonnet-libs/crossplane-libsonnet/crossplane/1.17/main.libsonnet'; local configuration(key, version) = @@ -6,16 +5,78 @@ local configuration(key, version) = conf.new(key) + conf.spec.withPackage('ghcr.io/grafana/crossplane/' + key + ':' + version); -local groups = +local xrds = + std.map( + function(o) o.definition, + (import './namespaced.libsonnet'), + ); + +local crds = + std.filter( + function(crd) crd.spec.group != 'grafana.crossplane.io', + std.parseYaml(importstr './crds.yaml'), + ); + +local gvkXRDs = + std.flatMap( + function(definition) [ + { + group: definition.spec.group, + version: v.name, + kind: definition.spec.claimNames.kind, + plural: definition.spec.claimNames.plural, + } + for v in definition.spec.versions + ], + xrds + ); + +local gvkCRDs = + std.flatMap( + function(definition) [ + { + group: definition.spec.group, + version: v.name, + kind: definition.spec.names.kind, + plural: definition.spec.names.plural, + } + for v in definition.spec.versions + ], + crds + ); + +local groupSet(gvks) = std.set( std.map( - function(def) - std.splitLimit(def.definition.spec.group, '.', 1)[0], - namespaced + function(gvk) + gvk.group, + gvks, ) ); -function(configurationVersion) { - [group]: configuration('grafana-namespaced-' + group, configurationVersion) - for group in groups +local shortGroupName(group) = + std.splitLimit(group, '.', 1)[0]; + +local groupFilter(group) = + function(gvk) gvk.group == group; + +local gvkByGroup(name, gvks) = { + [shortGroupName(group)]+: { + [name]+: [ + gvk + for gvk in std.filter(groupFilter(group), gvks) + ], + } + for group in groupSet(gvks) +}; + +function(version='main') { + configurations: { + [shortGroupName(group)]: configuration('grafana-namespaced-' + shortGroupName(group), version) + for group in groupSet(gvkXRDs) + }, + + gvks: + gvkByGroup('xrd', gvkXRDs) + + gvkByGroup('crd', gvkCRDs), } diff --git a/generator/main.libsonnet b/generator/main.libsonnet index fa42850..504bc46 100644 --- a/generator/main.libsonnet +++ b/generator/main.libsonnet @@ -1,75 +1,35 @@ -local parser = import 'github.com/Duologic/jsonnet-parser/parser.libsonnet'; local a = import 'github.com/crdsonnet/astsonnet/main.libsonnet'; local autils = import 'github.com/crdsonnet/astsonnet/utils.libsonnet'; + local helpers = import 'github.com/crdsonnet/crdsonnet/crdsonnet/helpers.libsonnet'; local crdsonnet = import 'github.com/crdsonnet/crdsonnet/crdsonnet/main.libsonnet'; -local d = import 'github.com/jsonnet-libs/docsonnet/doc-util/main.libsonnet'; - local processor = crdsonnet.processor.new('ast'); -local definitions = import './namespaced.libsonnet'; +local utils = import './utils.libsonnet'; local configurations = import './configurations.libsonnet'; +local definitions = + std.map( + function(o) o.definition, + (import './namespaced.libsonnet'), + ); + local globalDefinitions = std.filter( function(crd) crd.spec.group == 'grafana.crossplane.io', std.parseYaml(importstr './crds.yaml'), ); - -local subPackageDocstring(name, help='') = - a.object.new([ - a.field.new( - a.string.new('#'), - a.literal.new( - std.manifestJsonEx( - d.package.newSub(name, help) - , ' ', '' - ), - ), - ), - ]); - -local mergeDocstring(group, version, name, obj, help='') = - autils.deepMergeObjects([ - a.object.new([ - a.field.new( - a.id.new(group), - a.object.new([ - a.field.new( - a.string.new('#'), - a.literal.new( - std.manifestJsonEx( - d.package.newSub(group, '') - , ' ', '' - ), - ), - ), - a.field.new( - a.id.new(version), - a.object.new([ - a.field.new( - a.id.new(name), - subPackageDocstring(name, help) - ), - ]), - ), - ]), - ), - ]), - obj, - ]); - local compositions = std.foldl( - function(acc, def) - local render = crdsonnet.xrd.render(def.definition, 'grafana.net', processor); + function(acc, definition) + local render = crdsonnet.xrd.render(definition, 'grafana.net', processor); - local group = helpers.getGroupKey(def.definition.spec.group, 'grafana.net'); + local group = helpers.getGroupKey(definition.spec.group, 'grafana.net'); local version = 'v1alpha1'; - local kind = helpers.camelCaseKind(crdsonnet.xrd.getKind(def.definition)); + local kind = helpers.camelCaseKind(crdsonnet.xrd.getKind(definition)); - local renderWithDocs = mergeDocstring(group, version, kind, render); + local renderWithDocs = utils.mergeDocstring(group, version, kind, render); autils.deepMergeObjects([acc, renderWithDocs]), definitions, @@ -85,7 +45,7 @@ local global = local version = definition.spec.versions[0].name; local kind = helpers.camelCaseKind(crdsonnet.crd.getKind(definition)); - local renderWithDocs = mergeDocstring(group, version, kind, render); + local renderWithDocs = utils.mergeDocstring(group, version, kind, render); autils.deepMergeObjects([acc, renderWithDocs]), globalDefinitions, @@ -94,52 +54,15 @@ local global = local ast = autils.deepMergeObjects([compositions, global]); -local splitIntoFiles(objast, sub='', depth=1, maxDepth=5) = - local subdir = if sub != '' then sub + '/' else ''; - std.foldl( - function(acc, member) - if member.type == 'field' - && member.expr.type == 'object' - && !std.startsWith(member.fieldname.string, '#') - then - acc - + { - [subdir + 'main.libsonnet']+: - a.object.withMembersMixin([ - member - + a.field.withExpr( - if depth != maxDepth - then a.import_statement.new('./' + member.fieldname.string + '/main.libsonnet') - else a.import_statement.new('./' + member.fieldname.string + '.libsonnet') - ), - ]), - } - + (if depth != maxDepth && member.fieldname.string != 'global' - then splitIntoFiles(member.expr, subdir + member.fieldname.string, depth + 1) - else { - [subdir + member.fieldname.string + '.libsonnet']: member.expr, - }) - else - acc - + { - [subdir + 'main.libsonnet']+: - a.object.withMembersMixin([member]), - } - , - objast.members, - { - [subdir + 'main.libsonnet']: - a.object.new([]), - } - ); - function(version='main') - local files = splitIntoFiles(ast, 'zz'); + local files = utils.splitIntoFiles(ast, 'zz'); { [file.key]: file.value.toString() for file in std.objectKeysValues(files) } + { - 'zz/configurations.libsonnet': std.manifestJson(configurations(version)), + local conf = configurations(version), + 'zz/configurations.libsonnet': std.manifestJson(conf.configurations), 'zz/version.libsonnet': std.manifestJson(version), + 'zz/gvks.libsonnet': std.manifestJson(conf.gvks), } diff --git a/generator/utils.libsonnet b/generator/utils.libsonnet new file mode 100644 index 0000000..5effa2e --- /dev/null +++ b/generator/utils.libsonnet @@ -0,0 +1,89 @@ +local a = import 'github.com/crdsonnet/astsonnet/main.libsonnet'; +local autils = import 'github.com/crdsonnet/astsonnet/utils.libsonnet'; +local d = import 'github.com/jsonnet-libs/docsonnet/doc-util/main.libsonnet'; + +{ + local root = self, + + subPackageDocstring(name, help=''): + a.object.new([ + a.field.new( + a.string.new('#'), + a.literal.new( + std.manifestJsonEx( + d.package.newSub(name, help) + , ' ', '' + ), + ), + ), + ]), + + mergeDocstring(group, version, name, obj, help=''): + autils.deepMergeObjects([ + a.object.new([ + a.field.new( + a.id.new(group), + a.object.new([ + a.field.new( + a.string.new('#'), + a.literal.new( + std.manifestJsonEx( + d.package.newSub(group, '') + , ' ', '' + ), + ), + ), + a.field.new( + a.id.new(version), + a.object.new([ + a.field.new( + a.id.new(name), + root.subPackageDocstring(name, help) + ), + ]), + ), + ]), + ), + ]), + obj, + ]), + + splitIntoFiles(objast, sub='', depth=1, maxDepth=5): + local subdir = if sub != '' then sub + '/' else ''; + std.foldl( + function(acc, member) + if member.type == 'field' + && member.expr.type == 'object' + && !std.startsWith(member.fieldname.string, '#') + then + acc + + { + [subdir + 'main.libsonnet']+: + a.object.withMembersMixin([ + member + + a.field.withExpr( + if depth != maxDepth + then a.import_statement.new('./' + member.fieldname.string + '/main.libsonnet') + else a.import_statement.new('./' + member.fieldname.string + '.libsonnet') + ), + ]), + } + + (if depth != maxDepth && member.fieldname.string != 'global' + then root.splitIntoFiles(member.expr, subdir + member.fieldname.string, depth + 1) + else { + [subdir + member.fieldname.string + '.libsonnet']: member.expr, + }) + else + acc + + { + [subdir + 'main.libsonnet']+: + a.object.withMembersMixin([member]), + } + , + objast.members, + { + [subdir + 'main.libsonnet']: + a.object.new([]), + } + ), +} diff --git a/grafanaplane/jsonnetfile.json b/grafanaplane/jsonnetfile.json index 07b9e06..f54e861 100644 --- a/grafanaplane/jsonnetfile.json +++ b/grafanaplane/jsonnetfile.json @@ -17,7 +17,7 @@ "subdir": "" } }, - "version": "duologic/rfc1123" + "version": "master" } ], "legacyImports": true diff --git a/grafanaplane/zz/gvks.libsonnet b/grafanaplane/zz/gvks.libsonnet new file mode 100644 index 0000000..03efe80 --- /dev/null +++ b/grafanaplane/zz/gvks.libsonnet @@ -0,0 +1,626 @@ +{ + alerting: { + crd: [ + { + group: 'alerting.grafana.crossplane.io', + kind: 'ContactPoint', + plural: 'contactpoints', + version: 'v1alpha1', + }, + { + group: 'alerting.grafana.crossplane.io', + kind: 'MessageTemplate', + plural: 'messagetemplates', + version: 'v1alpha1', + }, + { + group: 'alerting.grafana.crossplane.io', + kind: 'MuteTiming', + plural: 'mutetimings', + version: 'v1alpha1', + }, + { + group: 'alerting.grafana.crossplane.io', + kind: 'NotificationPolicy', + plural: 'notificationpolicies', + version: 'v1alpha1', + }, + { + group: 'alerting.grafana.crossplane.io', + kind: 'RuleGroup', + plural: 'rulegroups', + version: 'v1alpha1', + }, + ], + xrd: [ + { + group: 'alerting.grafana.net.namespaced', + kind: 'ContactPoint', + plural: 'contactpoints', + version: 'v1alpha1', + }, + { + group: 'alerting.grafana.net.namespaced', + kind: 'MessageTemplate', + plural: 'messagetemplates', + version: 'v1alpha1', + }, + { + group: 'alerting.grafana.net.namespaced', + kind: 'MuteTiming', + plural: 'mutetimings', + version: 'v1alpha1', + }, + { + group: 'alerting.grafana.net.namespaced', + kind: 'NotificationPolicy', + plural: 'notificationpolicies', + version: 'v1alpha1', + }, + { + group: 'alerting.grafana.net.namespaced', + kind: 'RuleGroup', + plural: 'rulegroups', + version: 'v1alpha1', + }, + ], + }, + cloud: { + crd: [ + { + group: 'cloud.grafana.crossplane.io', + kind: 'AccessPolicy', + plural: 'accesspolicies', + version: 'v1alpha1', + }, + { + group: 'cloud.grafana.crossplane.io', + kind: 'AccessPolicyToken', + plural: 'accesspolicytokens', + version: 'v1alpha1', + }, + { + group: 'cloud.grafana.crossplane.io', + kind: 'PluginInstallation', + plural: 'plugininstallations', + version: 'v1alpha1', + }, + { + group: 'cloud.grafana.crossplane.io', + kind: 'Stack', + plural: 'stacks', + version: 'v1alpha1', + }, + { + group: 'cloud.grafana.crossplane.io', + kind: 'StackServiceAccount', + plural: 'stackserviceaccounts', + version: 'v1alpha1', + }, + { + group: 'cloud.grafana.crossplane.io', + kind: 'StackServiceAccountToken', + plural: 'stackserviceaccounttokens', + version: 'v1alpha1', + }, + ], + xrd: [ + { + group: 'cloud.grafana.net.namespaced', + kind: 'AccessPolicy', + plural: 'accesspolicies', + version: 'v1alpha1', + }, + { + group: 'cloud.grafana.net.namespaced', + kind: 'AccessPolicyToken', + plural: 'accesspolicytokens', + version: 'v1alpha1', + }, + { + group: 'cloud.grafana.net.namespaced', + kind: 'PluginInstallation', + plural: 'plugininstallations', + version: 'v1alpha1', + }, + { + group: 'cloud.grafana.net.namespaced', + kind: 'Stack', + plural: 'stacks', + version: 'v1alpha1', + }, + { + group: 'cloud.grafana.net.namespaced', + kind: 'StackServiceAccount', + plural: 'stackserviceaccounts', + version: 'v1alpha1', + }, + { + group: 'cloud.grafana.net.namespaced', + kind: 'StackServiceAccountToken', + plural: 'stackserviceaccounttokens', + version: 'v1alpha1', + }, + ], + }, + enterprise: { + crd: [ + { + group: 'enterprise.grafana.crossplane.io', + kind: 'DataSourcePermission', + plural: 'datasourcepermissions', + version: 'v1alpha1', + }, + { + group: 'enterprise.grafana.crossplane.io', + kind: 'Report', + plural: 'reports', + version: 'v1alpha1', + }, + { + group: 'enterprise.grafana.crossplane.io', + kind: 'RoleAssignment', + plural: 'roleassignments', + version: 'v1alpha1', + }, + { + group: 'enterprise.grafana.crossplane.io', + kind: 'Role', + plural: 'roles', + version: 'v1alpha1', + }, + { + group: 'enterprise.grafana.crossplane.io', + kind: 'TeamExternalGroup', + plural: 'teamexternalgroups', + version: 'v1alpha1', + }, + ], + xrd: [ + { + group: 'enterprise.grafana.net.namespaced', + kind: 'DataSourcePermission', + plural: 'datasourcepermissions', + version: 'v1alpha1', + }, + { + group: 'enterprise.grafana.net.namespaced', + kind: 'Report', + plural: 'reports', + version: 'v1alpha1', + }, + { + group: 'enterprise.grafana.net.namespaced', + kind: 'RoleAssignment', + plural: 'roleassignments', + version: 'v1alpha1', + }, + { + group: 'enterprise.grafana.net.namespaced', + kind: 'Role', + plural: 'roles', + version: 'v1alpha1', + }, + { + group: 'enterprise.grafana.net.namespaced', + kind: 'TeamExternalGroup', + plural: 'teamexternalgroups', + version: 'v1alpha1', + }, + ], + }, + ml: { + crd: [ + { + group: 'ml.grafana.crossplane.io', + kind: 'Holiday', + plural: 'holidays', + version: 'v1alpha1', + }, + { + group: 'ml.grafana.crossplane.io', + kind: 'Job', + plural: 'jobs', + version: 'v1alpha1', + }, + { + group: 'ml.grafana.crossplane.io', + kind: 'OutlierDetector', + plural: 'outlierdetectors', + version: 'v1alpha1', + }, + ], + xrd: [ + { + group: 'ml.grafana.net.namespaced', + kind: 'Holiday', + plural: 'holidays', + version: 'v1alpha1', + }, + { + group: 'ml.grafana.net.namespaced', + kind: 'Job', + plural: 'jobs', + version: 'v1alpha1', + }, + { + group: 'ml.grafana.net.namespaced', + kind: 'OutlierDetector', + plural: 'outlierdetectors', + version: 'v1alpha1', + }, + ], + }, + oncall: { + crd: [ + { + group: 'oncall.grafana.crossplane.io', + kind: 'EscalationChain', + plural: 'escalationchains', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.crossplane.io', + kind: 'Escalation', + plural: 'escalations', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.crossplane.io', + kind: 'Integration', + plural: 'integrations', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.crossplane.io', + kind: 'OnCallShift', + plural: 'oncallshifts', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.crossplane.io', + kind: 'OutgoingWebhook', + plural: 'outgoingwebhooks', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.crossplane.io', + kind: 'Route', + plural: 'routes', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.crossplane.io', + kind: 'Schedule', + plural: 'schedules', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.crossplane.io', + kind: 'UserNotificationRule', + plural: 'usernotificationrules', + version: 'v1alpha1', + }, + ], + xrd: [ + { + group: 'oncall.grafana.net.namespaced', + kind: 'EscalationChain', + plural: 'escalationchains', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.net.namespaced', + kind: 'Escalation', + plural: 'escalations', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.net.namespaced', + kind: 'Integration', + plural: 'integrations', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.net.namespaced', + kind: 'OnCallShift', + plural: 'oncallshifts', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.net.namespaced', + kind: 'OutgoingWebhook', + plural: 'outgoingwebhooks', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.net.namespaced', + kind: 'Route', + plural: 'routes', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.net.namespaced', + kind: 'Schedule', + plural: 'schedules', + version: 'v1alpha1', + }, + { + group: 'oncall.grafana.net.namespaced', + kind: 'UserNotificationRule', + plural: 'usernotificationrules', + version: 'v1alpha1', + }, + ], + }, + oss: { + crd: [ + { + group: 'oss.grafana.crossplane.io', + kind: 'Annotation', + plural: 'annotations', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'DashboardPermission', + plural: 'dashboardpermissions', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'DashboardPublic', + plural: 'dashboardpublics', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'Dashboard', + plural: 'dashboards', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'DataSource', + plural: 'datasources', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'FolderPermission', + plural: 'folderpermissions', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'Folder', + plural: 'folders', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'LibraryPanel', + plural: 'librarypanels', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'OrganizationPreferences', + plural: 'organizationpreferences', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'Organization', + plural: 'organizations', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'Playlist', + plural: 'playlists', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'ServiceAccountPermission', + plural: 'serviceaccountpermissions', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'ServiceAccount', + plural: 'serviceaccounts', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'ServiceAccountToken', + plural: 'serviceaccounttokens', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'SsoSettings', + plural: 'ssosettings', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'Team', + plural: 'teams', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.crossplane.io', + kind: 'User', + plural: 'users', + version: 'v1alpha1', + }, + ], + xrd: [ + { + group: 'oss.grafana.net.namespaced', + kind: 'Annotation', + plural: 'annotations', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'DashboardPermission', + plural: 'dashboardpermissions', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'DashboardPublic', + plural: 'dashboardpublics', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'Dashboard', + plural: 'dashboards', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'DataSource', + plural: 'datasources', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'FolderPermission', + plural: 'folderpermissions', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'Folder', + plural: 'folders', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'LibraryPanel', + plural: 'librarypanels', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'OrganizationPreferences', + plural: 'organizationpreferences', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'Organization', + plural: 'organizations', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'Playlist', + plural: 'playlists', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'ServiceAccountPermission', + plural: 'serviceaccountpermissions', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'ServiceAccount', + plural: 'serviceaccounts', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'ServiceAccountToken', + plural: 'serviceaccounttokens', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'SsoSettings', + plural: 'ssosettings', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'Team', + plural: 'teams', + version: 'v1alpha1', + }, + { + group: 'oss.grafana.net.namespaced', + kind: 'User', + plural: 'users', + version: 'v1alpha1', + }, + ], + }, + slo: { + crd: [ + { + group: 'slo.grafana.crossplane.io', + kind: 'SLO', + plural: 'slos', + version: 'v1alpha1', + }, + ], + xrd: [ + { + group: 'slo.grafana.net.namespaced', + kind: 'SLO', + plural: 'slos', + version: 'v1alpha1', + }, + ], + }, + sm: { + crd: [ + { + group: 'sm.grafana.crossplane.io', + kind: 'Check', + plural: 'checks', + version: 'v1alpha1', + }, + { + group: 'sm.grafana.crossplane.io', + kind: 'Installation', + plural: 'installations', + version: 'v1alpha1', + }, + { + group: 'sm.grafana.crossplane.io', + kind: 'Probe', + plural: 'probes', + version: 'v1alpha1', + }, + ], + xrd: [ + { + group: 'sm.grafana.net.namespaced', + kind: 'Check', + plural: 'checks', + version: 'v1alpha1', + }, + { + group: 'sm.grafana.net.namespaced', + kind: 'Installation', + plural: 'installations', + version: 'v1alpha1', + }, + { + group: 'sm.grafana.net.namespaced', + kind: 'Probe', + plural: 'probes', + version: 'v1alpha1', + }, + ], + }, +}