From de2bff1d0721b35af04fbce31f558eb17cf6abc1 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Fri, 13 Dec 2024 13:45:22 +0300 Subject: [PATCH] POC/Provisioning: Add informer (with healthcheck) (#97806) Co-authored-by: Todd Treece <360020+toddtreece@users.noreply.github.com> --- pkg/apis/provisioning/v0alpha1/register.go | 7 +- pkg/apis/provisioning/v0alpha1/types.go | 45 +++- .../v0alpha1/zz_generated.deepcopy.go | 46 +++- .../v0alpha1/zz_generated.openapi.go | 138 +++++++++- ...enerated.openapi_violation_exceptions.list | 3 + pkg/apiserver/registry/generic/storage.go | 4 +- .../provisioning/v0alpha1/editingoptions.go | 43 ++++ .../v0alpha1/githubrepositoryconfig.go | 97 +++++++ .../provisioning/v0alpha1/healthstatus.go | 45 ++++ .../v0alpha1/localrepositoryconfig.go | 25 ++ .../provisioning/v0alpha1/repository.go | 211 ++++++++++++++++ .../provisioning/v0alpha1/repositoryspec.go | 110 ++++++++ .../provisioning/v0alpha1/repositorystatus.go | 34 +++ .../v0alpha1/s3repositoryconfig.go | 34 +++ .../provisioning/v0alpha1/syncstatus.go | 85 +++++++ pkg/generated/applyconfiguration/utils.go | 36 ++- .../clientset/versioned/clientset.go | 15 +- .../versioned/fake/clientset_generated.go | 7 + .../clientset/versioned/fake/register.go | 2 + .../clientset/versioned/scheme/register.go | 2 + .../typed/provisioning/v0alpha1/doc.go | 6 + .../typed/provisioning/v0alpha1/fake/doc.go | 6 + .../v0alpha1/fake/fake_provisioning_client.go | 26 ++ .../v0alpha1/fake/fake_repository.go | 183 ++++++++++++++ .../v0alpha1/generated_expansion.go | 7 + .../v0alpha1/provisioning_client.go | 93 +++++++ .../typed/provisioning/v0alpha1/repository.go | 59 +++++ .../informers/externalversions/factory.go | 6 + .../informers/externalversions/generic.go | 11 +- .../provisioning/interface.go | 32 +++ .../provisioning/v0alpha1/interface.go | 31 +++ .../provisioning/v0alpha1/repository.go | 76 ++++++ .../v0alpha1/expansion_generated.go | 13 + .../provisioning/v0alpha1/repository.go | 56 ++++ pkg/registry/apis/provisioning/register.go | 49 +++- .../apis/provisioning/repository/github.go | 8 +- .../provisioning/repository/repository.go | 2 +- .../provisioning/repository_controller.go | 239 ++++++++++++++++++ pkg/registry/apis/provisioning/worker.go | 10 +- pkg/tests/apis/dashboard/dashboards_test.go | 2 + .../apis/provisioning/provisioning_test.go | 11 +- .../apis/provisioning/testdata/invalid.yaml | 9 - 42 files changed, 1864 insertions(+), 60 deletions(-) create mode 100644 pkg/generated/applyconfiguration/provisioning/v0alpha1/editingoptions.go create mode 100644 pkg/generated/applyconfiguration/provisioning/v0alpha1/githubrepositoryconfig.go create mode 100644 pkg/generated/applyconfiguration/provisioning/v0alpha1/healthstatus.go create mode 100644 pkg/generated/applyconfiguration/provisioning/v0alpha1/localrepositoryconfig.go create mode 100644 pkg/generated/applyconfiguration/provisioning/v0alpha1/repository.go create mode 100644 pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go create mode 100644 pkg/generated/applyconfiguration/provisioning/v0alpha1/repositorystatus.go create mode 100644 pkg/generated/applyconfiguration/provisioning/v0alpha1/s3repositoryconfig.go create mode 100644 pkg/generated/applyconfiguration/provisioning/v0alpha1/syncstatus.go create mode 100644 pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/doc.go create mode 100644 pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/doc.go create mode 100644 pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/fake_provisioning_client.go create mode 100644 pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/fake_repository.go create mode 100644 pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/generated_expansion.go create mode 100644 pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/provisioning_client.go create mode 100644 pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/repository.go create mode 100644 pkg/generated/informers/externalversions/provisioning/interface.go create mode 100644 pkg/generated/informers/externalversions/provisioning/v0alpha1/interface.go create mode 100644 pkg/generated/informers/externalversions/provisioning/v0alpha1/repository.go create mode 100644 pkg/generated/listers/provisioning/v0alpha1/expansion_generated.go create mode 100644 pkg/generated/listers/provisioning/v0alpha1/repository.go create mode 100644 pkg/registry/apis/provisioning/repository_controller.go delete mode 100644 pkg/tests/apis/provisioning/testdata/invalid.yaml diff --git a/pkg/apis/provisioning/v0alpha1/register.go b/pkg/apis/provisioning/v0alpha1/register.go index add42f99381..c44c3a75bca 100644 --- a/pkg/apis/provisioning/v0alpha1/register.go +++ b/pkg/apis/provisioning/v0alpha1/register.go @@ -97,7 +97,12 @@ var ( func init() { localSchemeBuilder.Register(func(s *runtime.Scheme) error { - return AddKnownTypes(SchemeGroupVersion, s) + err := AddKnownTypes(SchemeGroupVersion, s) + if err != nil { + return err + } + metav1.AddToGroupVersion(s, SchemeGroupVersion) + return nil }) } diff --git a/pkg/apis/provisioning/v0alpha1/types.go b/pkg/apis/provisioning/v0alpha1/types.go index a7aff2ca618..a9a17a84f00 100644 --- a/pkg/apis/provisioning/v0alpha1/types.go +++ b/pkg/apis/provisioning/v0alpha1/types.go @@ -9,7 +9,7 @@ import ( // When this code is changed, make sure to update the code generation. // As of writing, this can be done via the hack dir in the root of the repo: ./hack/update-codegen.sh provisioning // If you've opened the generated files in this dir at some point in VSCode, you may also have to re-open them to clear errors. - +// +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type Repository struct { metav1.TypeMeta `json:",inline"` @@ -131,10 +131,45 @@ type EditingOptions struct { // This is expected never to be created by a kubectl call or similar, and is expected to rarely (if ever) be edited manually. // As such, it is also a little less well structured than the spec, such as conditional-but-ever-present fields. type RepositoryStatus struct { - // The Git commit we're currently synced to. - // A non-empty value only matters if we use a git storage backend. - // Useful for no-clone Git clients and if cloning Git clients ever lose their clones. - CurrentGitCommit string `json:"currentGitCommit,omitempty"` + // This will get updated with the current health status (and updated periodically) + Health HealthStatus `json:"health"` + + // Sync information + Sync SyncStatus `json:"sync"` +} + +type HealthStatus struct { + // When not healthy, requests will not be executed + Healthy bool `json:"healthy"` + + // When the sync job started + Checked int64 `json:"checked,omitempty"` + + // Summary messages (will be shown to users) + Message []string `json:"message,omitempty"` +} + +type SyncStatus struct { + // pending, running, success, error + State JobState `json:"state"` + + // The ID for the job that ran this sync + JobID string `json:"job,omitempty"` + + // When the sync job started + Started int64 `json:"started,omitempty"` + + // When the sync job finished + Finished int64 `json:"finished,omitempty"` + + // When the next sync check is scheduled + Scheduled int64 `json:"scheduled,omitempty"` + + // Summary messages (will be shown to users) + Message []string `json:"message,omitempty"` + + // The repository hash when the last sync ran + Hash string `json:"hash,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go b/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go index 6ea310f4d9b..aff2cd6a728 100644 --- a/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go @@ -106,6 +106,27 @@ func (in *GitHubRepositoryConfig) DeepCopy() *GitHubRepositoryConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HealthStatus) DeepCopyInto(out *HealthStatus) { + *out = *in + if in.Message != nil { + in, out := &in.Message, &out.Message + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HealthStatus. +func (in *HealthStatus) DeepCopy() *HealthStatus { + if in == nil { + return nil + } + out := new(HealthStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HelloWorld) DeepCopyInto(out *HelloWorld) { *out = *in @@ -321,7 +342,7 @@ func (in *Repository) DeepCopyInto(out *Repository) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status + in.Status.DeepCopyInto(&out.Status) return } @@ -411,6 +432,8 @@ func (in *RepositorySpec) DeepCopy() *RepositorySpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RepositoryStatus) DeepCopyInto(out *RepositoryStatus) { *out = *in + in.Health.DeepCopyInto(&out.Health) + in.Sync.DeepCopyInto(&out.Sync) return } @@ -516,6 +539,27 @@ func (in *S3RepositoryConfig) DeepCopy() *S3RepositoryConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SyncStatus) DeepCopyInto(out *SyncStatus) { + *out = *in + if in.Message != nil { + in, out := &in.Message, &out.Message + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SyncStatus. +func (in *SyncStatus) DeepCopy() *SyncStatus { + if in == nil { + return nil + } + out := new(SyncStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TestResults) DeepCopyInto(out *TestResults) { *out = *in diff --git a/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go b/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go index f3214e0ccac..204a7eccc6e 100644 --- a/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go +++ b/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go @@ -19,6 +19,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.FileItem": schema_pkg_apis_provisioning_v0alpha1_FileItem(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.FileList": schema_pkg_apis_provisioning_v0alpha1_FileList(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.GitHubRepositoryConfig": schema_pkg_apis_provisioning_v0alpha1_GitHubRepositoryConfig(ref), + "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.HealthStatus": schema_pkg_apis_provisioning_v0alpha1_HealthStatus(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.HelloWorld": schema_pkg_apis_provisioning_v0alpha1_HelloWorld(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.HistoryItem": schema_pkg_apis_provisioning_v0alpha1_HistoryItem(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.HistoryList": schema_pkg_apis_provisioning_v0alpha1_HistoryList(ref), @@ -36,6 +37,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceType": schema_pkg_apis_provisioning_v0alpha1_ResourceType(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ResourceWrapper": schema_pkg_apis_provisioning_v0alpha1_ResourceWrapper(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.S3RepositoryConfig": schema_pkg_apis_provisioning_v0alpha1_S3RepositoryConfig(ref), + "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.SyncStatus": schema_pkg_apis_provisioning_v0alpha1_SyncStatus(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.TestResults": schema_pkg_apis_provisioning_v0alpha1_TestResults(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.WebhookResponse": schema_pkg_apis_provisioning_v0alpha1_WebhookResponse(ref), } @@ -279,6 +281,49 @@ func schema_pkg_apis_provisioning_v0alpha1_GitHubRepositoryConfig(ref common.Ref } } +func schema_pkg_apis_provisioning_v0alpha1_HealthStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "healthy": { + SchemaProps: spec.SchemaProps{ + Description: "When not healthy, requests will not be executed", + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + "checked": { + SchemaProps: spec.SchemaProps{ + Description: "When the sync job started", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Description: "Summary messages (will be shown to users)", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + Required: []string{"healthy"}, + }, + }, + } +} + func schema_pkg_apis_provisioning_v0alpha1_HelloWorld(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -663,7 +708,8 @@ func schema_pkg_apis_provisioning_v0alpha1_Repository(ref common.ReferenceCallba return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "When this code is changed, make sure to update the code generation. As of writing, this can be done via the hack dir in the root of the repo: ./hack/update-codegen.sh provisioning If you've opened the generated files in this dir at some point in VSCode, you may also have to re-open them to clear errors.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { SchemaProps: spec.SchemaProps{ @@ -844,16 +890,26 @@ func schema_pkg_apis_provisioning_v0alpha1_RepositoryStatus(ref common.Reference Description: "The status of a Repository. This is expected never to be created by a kubectl call or similar, and is expected to rarely (if ever) be edited manually. As such, it is also a little less well structured than the spec, such as conditional-but-ever-present fields.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "currentGitCommit": { + "health": { SchemaProps: spec.SchemaProps{ - Description: "The Git commit we're currently synced to. A non-empty value only matters if we use a git storage backend. Useful for no-clone Git clients and if cloning Git clients ever lose their clones.", - Type: []string{"string"}, - Format: "", + Description: "This will get updated with the current health status (and updated periodically)", + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.HealthStatus"), + }, + }, + "sync": { + SchemaProps: spec.SchemaProps{ + Description: "Sync information", + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.SyncStatus"), }, }, }, + Required: []string{"health", "sync"}, }, }, + Dependencies: []string{ + "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.HealthStatus", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.SyncStatus"}, } } @@ -1066,6 +1122,78 @@ func schema_pkg_apis_provisioning_v0alpha1_S3RepositoryConfig(ref common.Referen } } +func schema_pkg_apis_provisioning_v0alpha1_SyncStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "state": { + SchemaProps: spec.SchemaProps{ + Description: "pending, running, success, error\n\nPossible enum values:\n - `\"error\"` Finished with errors\n - `\"pending\"` Job has been submitted, but not processed yet\n - `\"success\"` Finished with success\n - `\"working\"` The job is running", + Default: "", + Type: []string{"string"}, + Format: "", + Enum: []interface{}{"error", "pending", "success", "working"}, + }, + }, + "job": { + SchemaProps: spec.SchemaProps{ + Description: "The ID for the job that ran this sync", + Type: []string{"string"}, + Format: "", + }, + }, + "started": { + SchemaProps: spec.SchemaProps{ + Description: "When the sync job started", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "finished": { + SchemaProps: spec.SchemaProps{ + Description: "When the sync job finished", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "scheduled": { + SchemaProps: spec.SchemaProps{ + Description: "When the next sync check is scheduled", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Description: "Summary messages (will be shown to users)", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "hash": { + SchemaProps: spec.SchemaProps{ + Description: "The repository hash when the last sync ran", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"state"}, + }, + }, + } +} + func schema_pkg_apis_provisioning_v0alpha1_TestResults(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list b/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list index 856ce5617ef..59d96ab06e2 100644 --- a/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list +++ b/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list @@ -1,9 +1,12 @@ +API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,HealthStatus,Message API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,HistoryItem,Authors API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,JobStatus,Errors API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,ResourceWrapper,Errors API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,ResourceWrapper,Lint +API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,SyncStatus,Message API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,TestResults,Errors API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,FileList,Items API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,RepositorySpec,GitHub API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,RepositorySpec,PreferYAML +API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,SyncStatus,JobID API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,WebhookResponse,Message diff --git a/pkg/apiserver/registry/generic/storage.go b/pkg/apiserver/registry/generic/storage.go index 67b0efecb8d..a7d02fac6d0 100644 --- a/pkg/apiserver/registry/generic/storage.go +++ b/pkg/apiserver/registry/generic/storage.go @@ -9,7 +9,9 @@ import ( ) func NewRegistryStore(scheme *runtime.Scheme, resourceInfo utils.ResourceInfo, optsGetter generic.RESTOptionsGetter) (*registry.Store, error) { - strategy := NewStrategy(scheme, resourceInfo.GroupVersion()) + gv := resourceInfo.GroupVersion() + gv.Version = runtime.APIVersionInternal + strategy := NewStrategy(scheme, gv) store := ®istry.Store{ NewFunc: resourceInfo.NewFunc, NewListFunc: resourceInfo.NewListFunc, diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/editingoptions.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/editingoptions.go new file mode 100644 index 00000000000..9807b8fa4d8 --- /dev/null +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/editingoptions.go @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +// EditingOptionsApplyConfiguration represents a declarative configuration of the EditingOptions type for use +// with apply. +type EditingOptionsApplyConfiguration struct { + Create *bool `json:"create,omitempty"` + Update *bool `json:"update,omitempty"` + Delete *bool `json:"delete,omitempty"` +} + +// EditingOptionsApplyConfiguration constructs a declarative configuration of the EditingOptions type for use with +// apply. +func EditingOptions() *EditingOptionsApplyConfiguration { + return &EditingOptionsApplyConfiguration{} +} + +// WithCreate sets the Create field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Create field is set to the value of the last call. +func (b *EditingOptionsApplyConfiguration) WithCreate(value bool) *EditingOptionsApplyConfiguration { + b.Create = &value + return b +} + +// WithUpdate sets the Update field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Update field is set to the value of the last call. +func (b *EditingOptionsApplyConfiguration) WithUpdate(value bool) *EditingOptionsApplyConfiguration { + b.Update = &value + return b +} + +// WithDelete sets the Delete field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Delete field is set to the value of the last call. +func (b *EditingOptionsApplyConfiguration) WithDelete(value bool) *EditingOptionsApplyConfiguration { + b.Delete = &value + return b +} diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/githubrepositoryconfig.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/githubrepositoryconfig.go new file mode 100644 index 00000000000..c817dc77ea4 --- /dev/null +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/githubrepositoryconfig.go @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +// GitHubRepositoryConfigApplyConfiguration represents a declarative configuration of the GitHubRepositoryConfig type for use +// with apply. +type GitHubRepositoryConfigApplyConfiguration struct { + Owner *string `json:"owner,omitempty"` + Repository *string `json:"repository,omitempty"` + Branch *string `json:"branch,omitempty"` + Token *string `json:"token,omitempty"` + WebhookURL *string `json:"webhookURL,omitempty"` + WebhookSecret *string `json:"webhookSecret,omitempty"` + BranchWorkflow *bool `json:"branchWorkflow,omitempty"` + GenerateDashboardPreviews *bool `json:"generateDashboardPreviews,omitempty"` + PullRequestLinter *bool `json:"pullRequestLinter,omitempty"` +} + +// GitHubRepositoryConfigApplyConfiguration constructs a declarative configuration of the GitHubRepositoryConfig type for use with +// apply. +func GitHubRepositoryConfig() *GitHubRepositoryConfigApplyConfiguration { + return &GitHubRepositoryConfigApplyConfiguration{} +} + +// WithOwner sets the Owner field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Owner field is set to the value of the last call. +func (b *GitHubRepositoryConfigApplyConfiguration) WithOwner(value string) *GitHubRepositoryConfigApplyConfiguration { + b.Owner = &value + return b +} + +// WithRepository sets the Repository field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Repository field is set to the value of the last call. +func (b *GitHubRepositoryConfigApplyConfiguration) WithRepository(value string) *GitHubRepositoryConfigApplyConfiguration { + b.Repository = &value + return b +} + +// WithBranch sets the Branch field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Branch field is set to the value of the last call. +func (b *GitHubRepositoryConfigApplyConfiguration) WithBranch(value string) *GitHubRepositoryConfigApplyConfiguration { + b.Branch = &value + return b +} + +// WithToken sets the Token field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Token field is set to the value of the last call. +func (b *GitHubRepositoryConfigApplyConfiguration) WithToken(value string) *GitHubRepositoryConfigApplyConfiguration { + b.Token = &value + return b +} + +// WithWebhookURL sets the WebhookURL field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the WebhookURL field is set to the value of the last call. +func (b *GitHubRepositoryConfigApplyConfiguration) WithWebhookURL(value string) *GitHubRepositoryConfigApplyConfiguration { + b.WebhookURL = &value + return b +} + +// WithWebhookSecret sets the WebhookSecret field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the WebhookSecret field is set to the value of the last call. +func (b *GitHubRepositoryConfigApplyConfiguration) WithWebhookSecret(value string) *GitHubRepositoryConfigApplyConfiguration { + b.WebhookSecret = &value + return b +} + +// WithBranchWorkflow sets the BranchWorkflow field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the BranchWorkflow field is set to the value of the last call. +func (b *GitHubRepositoryConfigApplyConfiguration) WithBranchWorkflow(value bool) *GitHubRepositoryConfigApplyConfiguration { + b.BranchWorkflow = &value + return b +} + +// WithGenerateDashboardPreviews sets the GenerateDashboardPreviews field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateDashboardPreviews field is set to the value of the last call. +func (b *GitHubRepositoryConfigApplyConfiguration) WithGenerateDashboardPreviews(value bool) *GitHubRepositoryConfigApplyConfiguration { + b.GenerateDashboardPreviews = &value + return b +} + +// WithPullRequestLinter sets the PullRequestLinter field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PullRequestLinter field is set to the value of the last call. +func (b *GitHubRepositoryConfigApplyConfiguration) WithPullRequestLinter(value bool) *GitHubRepositoryConfigApplyConfiguration { + b.PullRequestLinter = &value + return b +} diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/healthstatus.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/healthstatus.go new file mode 100644 index 00000000000..6d3b33cb318 --- /dev/null +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/healthstatus.go @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +// HealthStatusApplyConfiguration represents a declarative configuration of the HealthStatus type for use +// with apply. +type HealthStatusApplyConfiguration struct { + Healthy *bool `json:"healthy,omitempty"` + Checked *int64 `json:"checked,omitempty"` + Message []string `json:"message,omitempty"` +} + +// HealthStatusApplyConfiguration constructs a declarative configuration of the HealthStatus type for use with +// apply. +func HealthStatus() *HealthStatusApplyConfiguration { + return &HealthStatusApplyConfiguration{} +} + +// WithHealthy sets the Healthy field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Healthy field is set to the value of the last call. +func (b *HealthStatusApplyConfiguration) WithHealthy(value bool) *HealthStatusApplyConfiguration { + b.Healthy = &value + return b +} + +// WithChecked sets the Checked field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Checked field is set to the value of the last call. +func (b *HealthStatusApplyConfiguration) WithChecked(value int64) *HealthStatusApplyConfiguration { + b.Checked = &value + return b +} + +// WithMessage adds the given value to the Message field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Message field. +func (b *HealthStatusApplyConfiguration) WithMessage(values ...string) *HealthStatusApplyConfiguration { + for i := range values { + b.Message = append(b.Message, values[i]) + } + return b +} diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/localrepositoryconfig.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/localrepositoryconfig.go new file mode 100644 index 00000000000..ad02843a318 --- /dev/null +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/localrepositoryconfig.go @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +// LocalRepositoryConfigApplyConfiguration represents a declarative configuration of the LocalRepositoryConfig type for use +// with apply. +type LocalRepositoryConfigApplyConfiguration struct { + Path *string `json:"path,omitempty"` +} + +// LocalRepositoryConfigApplyConfiguration constructs a declarative configuration of the LocalRepositoryConfig type for use with +// apply. +func LocalRepositoryConfig() *LocalRepositoryConfigApplyConfiguration { + return &LocalRepositoryConfigApplyConfiguration{} +} + +// WithPath sets the Path field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Path field is set to the value of the last call. +func (b *LocalRepositoryConfigApplyConfiguration) WithPath(value string) *LocalRepositoryConfigApplyConfiguration { + b.Path = &value + return b +} diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/repository.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/repository.go new file mode 100644 index 00000000000..c84cc6a99b9 --- /dev/null +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/repository.go @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// RepositoryApplyConfiguration represents a declarative configuration of the Repository type for use +// with apply. +type RepositoryApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *RepositorySpecApplyConfiguration `json:"spec,omitempty"` + Status *RepositoryStatusApplyConfiguration `json:"status,omitempty"` +} + +// Repository constructs a declarative configuration of the Repository type for use with +// apply. +func Repository(name, namespace string) *RepositoryApplyConfiguration { + b := &RepositoryApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("Repository") + b.WithAPIVersion("provisioning.grafana.app/v0alpha1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithKind(value string) *RepositoryApplyConfiguration { + b.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithAPIVersion(value string) *RepositoryApplyConfiguration { + b.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithName(value string) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithGenerateName(value string) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithNamespace(value string) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithUID(value types.UID) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithResourceVersion(value string) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithGeneration(value int64) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithCreationTimestamp(value metav1.Time) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *RepositoryApplyConfiguration) WithLabels(entries map[string]string) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Labels == nil && len(entries) > 0 { + b.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *RepositoryApplyConfiguration) WithAnnotations(entries map[string]string) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Annotations == nil && len(entries) > 0 { + b.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *RepositoryApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.OwnerReferences = append(b.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *RepositoryApplyConfiguration) WithFinalizers(values ...string) *RepositoryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.Finalizers = append(b.Finalizers, values[i]) + } + return b +} + +func (b *RepositoryApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithSpec(value *RepositorySpecApplyConfiguration) *RepositoryApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *RepositoryApplyConfiguration) WithStatus(value *RepositoryStatusApplyConfiguration) *RepositoryApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *RepositoryApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go new file mode 100644 index 00000000000..a1dd9ce6c07 --- /dev/null +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + provisioningv0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" +) + +// RepositorySpecApplyConfiguration represents a declarative configuration of the RepositorySpec type for use +// with apply. +type RepositorySpecApplyConfiguration struct { + Title *string `json:"title,omitempty"` + Description *string `json:"description,omitempty"` + Folder *string `json:"folder,omitempty"` + PreferYAML *bool `json:"preferYaml,omitempty"` + Editing *EditingOptionsApplyConfiguration `json:"editing,omitempty"` + Type *provisioningv0alpha1.RepositoryType `json:"type,omitempty"` + Linting *bool `json:"linting,omitempty"` + Local *LocalRepositoryConfigApplyConfiguration `json:"local,omitempty"` + S3 *S3RepositoryConfigApplyConfiguration `json:"s3,omitempty"` + GitHub *GitHubRepositoryConfigApplyConfiguration `json:"github,omitempty"` +} + +// RepositorySpecApplyConfiguration constructs a declarative configuration of the RepositorySpec type for use with +// apply. +func RepositorySpec() *RepositorySpecApplyConfiguration { + return &RepositorySpecApplyConfiguration{} +} + +// WithTitle sets the Title field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Title field is set to the value of the last call. +func (b *RepositorySpecApplyConfiguration) WithTitle(value string) *RepositorySpecApplyConfiguration { + b.Title = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *RepositorySpecApplyConfiguration) WithDescription(value string) *RepositorySpecApplyConfiguration { + b.Description = &value + return b +} + +// WithFolder sets the Folder field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Folder field is set to the value of the last call. +func (b *RepositorySpecApplyConfiguration) WithFolder(value string) *RepositorySpecApplyConfiguration { + b.Folder = &value + return b +} + +// WithPreferYAML sets the PreferYAML field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PreferYAML field is set to the value of the last call. +func (b *RepositorySpecApplyConfiguration) WithPreferYAML(value bool) *RepositorySpecApplyConfiguration { + b.PreferYAML = &value + return b +} + +// WithEditing sets the Editing field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Editing field is set to the value of the last call. +func (b *RepositorySpecApplyConfiguration) WithEditing(value *EditingOptionsApplyConfiguration) *RepositorySpecApplyConfiguration { + b.Editing = value + return b +} + +// WithType sets the Type field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Type field is set to the value of the last call. +func (b *RepositorySpecApplyConfiguration) WithType(value provisioningv0alpha1.RepositoryType) *RepositorySpecApplyConfiguration { + b.Type = &value + return b +} + +// WithLinting sets the Linting field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Linting field is set to the value of the last call. +func (b *RepositorySpecApplyConfiguration) WithLinting(value bool) *RepositorySpecApplyConfiguration { + b.Linting = &value + return b +} + +// WithLocal sets the Local field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Local field is set to the value of the last call. +func (b *RepositorySpecApplyConfiguration) WithLocal(value *LocalRepositoryConfigApplyConfiguration) *RepositorySpecApplyConfiguration { + b.Local = value + return b +} + +// WithS3 sets the S3 field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the S3 field is set to the value of the last call. +func (b *RepositorySpecApplyConfiguration) WithS3(value *S3RepositoryConfigApplyConfiguration) *RepositorySpecApplyConfiguration { + b.S3 = value + return b +} + +// WithGitHub sets the GitHub field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GitHub field is set to the value of the last call. +func (b *RepositorySpecApplyConfiguration) WithGitHub(value *GitHubRepositoryConfigApplyConfiguration) *RepositorySpecApplyConfiguration { + b.GitHub = value + return b +} diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositorystatus.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositorystatus.go new file mode 100644 index 00000000000..efe1ada9632 --- /dev/null +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositorystatus.go @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +// RepositoryStatusApplyConfiguration represents a declarative configuration of the RepositoryStatus type for use +// with apply. +type RepositoryStatusApplyConfiguration struct { + Health *HealthStatusApplyConfiguration `json:"health,omitempty"` + Sync *SyncStatusApplyConfiguration `json:"sync,omitempty"` +} + +// RepositoryStatusApplyConfiguration constructs a declarative configuration of the RepositoryStatus type for use with +// apply. +func RepositoryStatus() *RepositoryStatusApplyConfiguration { + return &RepositoryStatusApplyConfiguration{} +} + +// WithHealth sets the Health field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Health field is set to the value of the last call. +func (b *RepositoryStatusApplyConfiguration) WithHealth(value *HealthStatusApplyConfiguration) *RepositoryStatusApplyConfiguration { + b.Health = value + return b +} + +// WithSync sets the Sync field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Sync field is set to the value of the last call. +func (b *RepositoryStatusApplyConfiguration) WithSync(value *SyncStatusApplyConfiguration) *RepositoryStatusApplyConfiguration { + b.Sync = value + return b +} diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/s3repositoryconfig.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/s3repositoryconfig.go new file mode 100644 index 00000000000..b33e875bd91 --- /dev/null +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/s3repositoryconfig.go @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +// S3RepositoryConfigApplyConfiguration represents a declarative configuration of the S3RepositoryConfig type for use +// with apply. +type S3RepositoryConfigApplyConfiguration struct { + Region *string `json:"region,omitempty"` + Bucket *string `json:"bucket,omitempty"` +} + +// S3RepositoryConfigApplyConfiguration constructs a declarative configuration of the S3RepositoryConfig type for use with +// apply. +func S3RepositoryConfig() *S3RepositoryConfigApplyConfiguration { + return &S3RepositoryConfigApplyConfiguration{} +} + +// WithRegion sets the Region field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Region field is set to the value of the last call. +func (b *S3RepositoryConfigApplyConfiguration) WithRegion(value string) *S3RepositoryConfigApplyConfiguration { + b.Region = &value + return b +} + +// WithBucket sets the Bucket field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Bucket field is set to the value of the last call. +func (b *S3RepositoryConfigApplyConfiguration) WithBucket(value string) *S3RepositoryConfigApplyConfiguration { + b.Bucket = &value + return b +} diff --git a/pkg/generated/applyconfiguration/provisioning/v0alpha1/syncstatus.go b/pkg/generated/applyconfiguration/provisioning/v0alpha1/syncstatus.go new file mode 100644 index 00000000000..f9d9f91b9e0 --- /dev/null +++ b/pkg/generated/applyconfiguration/provisioning/v0alpha1/syncstatus.go @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" +) + +// SyncStatusApplyConfiguration represents a declarative configuration of the SyncStatus type for use +// with apply. +type SyncStatusApplyConfiguration struct { + State *v0alpha1.JobState `json:"state,omitempty"` + JobID *string `json:"job,omitempty"` + Started *int64 `json:"started,omitempty"` + Finished *int64 `json:"finished,omitempty"` + Scheduled *int64 `json:"scheduled,omitempty"` + Message []string `json:"message,omitempty"` + Hash *string `json:"hash,omitempty"` +} + +// SyncStatusApplyConfiguration constructs a declarative configuration of the SyncStatus type for use with +// apply. +func SyncStatus() *SyncStatusApplyConfiguration { + return &SyncStatusApplyConfiguration{} +} + +// WithState sets the State field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the State field is set to the value of the last call. +func (b *SyncStatusApplyConfiguration) WithState(value v0alpha1.JobState) *SyncStatusApplyConfiguration { + b.State = &value + return b +} + +// WithJobID sets the JobID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the JobID field is set to the value of the last call. +func (b *SyncStatusApplyConfiguration) WithJobID(value string) *SyncStatusApplyConfiguration { + b.JobID = &value + return b +} + +// WithStarted sets the Started field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Started field is set to the value of the last call. +func (b *SyncStatusApplyConfiguration) WithStarted(value int64) *SyncStatusApplyConfiguration { + b.Started = &value + return b +} + +// WithFinished sets the Finished field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Finished field is set to the value of the last call. +func (b *SyncStatusApplyConfiguration) WithFinished(value int64) *SyncStatusApplyConfiguration { + b.Finished = &value + return b +} + +// WithScheduled sets the Scheduled field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Scheduled field is set to the value of the last call. +func (b *SyncStatusApplyConfiguration) WithScheduled(value int64) *SyncStatusApplyConfiguration { + b.Scheduled = &value + return b +} + +// WithMessage adds the given value to the Message field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Message field. +func (b *SyncStatusApplyConfiguration) WithMessage(values ...string) *SyncStatusApplyConfiguration { + for i := range values { + b.Message = append(b.Message, values[i]) + } + return b +} + +// WithHash sets the Hash field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Hash field is set to the value of the last call. +func (b *SyncStatusApplyConfiguration) WithHash(value string) *SyncStatusApplyConfiguration { + b.Hash = &value + return b +} diff --git a/pkg/generated/applyconfiguration/utils.go b/pkg/generated/applyconfiguration/utils.go index d792c0be680..eb99862dc50 100644 --- a/pkg/generated/applyconfiguration/utils.go +++ b/pkg/generated/applyconfiguration/utils.go @@ -5,9 +5,11 @@ package applyconfiguration import ( - v0alpha1 "github.com/grafana/grafana/pkg/apis/service/v0alpha1" + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + servicev0alpha1 "github.com/grafana/grafana/pkg/apis/service/v0alpha1" internal "github.com/grafana/grafana/pkg/generated/applyconfiguration/internal" - servicev0alpha1 "github.com/grafana/grafana/pkg/generated/applyconfiguration/service/v0alpha1" + provisioningv0alpha1 "github.com/grafana/grafana/pkg/generated/applyconfiguration/provisioning/v0alpha1" + applyconfigurationservicev0alpha1 "github.com/grafana/grafana/pkg/generated/applyconfiguration/service/v0alpha1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" testing "k8s.io/client-go/testing" @@ -17,11 +19,31 @@ import ( // apply configuration type exists for the given GroupVersionKind. func ForKind(kind schema.GroupVersionKind) interface{} { switch kind { - // Group=service.grafana.app, Version=v0alpha1 - case v0alpha1.SchemeGroupVersion.WithKind("ExternalName"): - return &servicev0alpha1.ExternalNameApplyConfiguration{} - case v0alpha1.SchemeGroupVersion.WithKind("ExternalNameSpec"): - return &servicev0alpha1.ExternalNameSpecApplyConfiguration{} + // Group=provisioning.grafana.app, Version=v0alpha1 + case v0alpha1.SchemeGroupVersion.WithKind("EditingOptions"): + return &provisioningv0alpha1.EditingOptionsApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("GitHubRepositoryConfig"): + return &provisioningv0alpha1.GitHubRepositoryConfigApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("HealthStatus"): + return &provisioningv0alpha1.HealthStatusApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("LocalRepositoryConfig"): + return &provisioningv0alpha1.LocalRepositoryConfigApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("Repository"): + return &provisioningv0alpha1.RepositoryApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("RepositorySpec"): + return &provisioningv0alpha1.RepositorySpecApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("RepositoryStatus"): + return &provisioningv0alpha1.RepositoryStatusApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("S3RepositoryConfig"): + return &provisioningv0alpha1.S3RepositoryConfigApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("SyncStatus"): + return &provisioningv0alpha1.SyncStatusApplyConfiguration{} + + // Group=service.grafana.app, Version=v0alpha1 + case servicev0alpha1.SchemeGroupVersion.WithKind("ExternalName"): + return &applyconfigurationservicev0alpha1.ExternalNameApplyConfiguration{} + case servicev0alpha1.SchemeGroupVersion.WithKind("ExternalNameSpec"): + return &applyconfigurationservicev0alpha1.ExternalNameSpecApplyConfiguration{} } return nil diff --git a/pkg/generated/clientset/versioned/clientset.go b/pkg/generated/clientset/versioned/clientset.go index 55fa581701a..41a45e5ce5f 100644 --- a/pkg/generated/clientset/versioned/clientset.go +++ b/pkg/generated/clientset/versioned/clientset.go @@ -8,6 +8,7 @@ import ( "fmt" "net/http" + provisioningv0alpha1 "github.com/grafana/grafana/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1" servicev0alpha1 "github.com/grafana/grafana/pkg/generated/clientset/versioned/typed/service/v0alpha1" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" @@ -16,13 +17,20 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface + ProvisioningV0alpha1() provisioningv0alpha1.ProvisioningV0alpha1Interface ServiceV0alpha1() servicev0alpha1.ServiceV0alpha1Interface } // Clientset contains the clients for groups. type Clientset struct { *discovery.DiscoveryClient - serviceV0alpha1 *servicev0alpha1.ServiceV0alpha1Client + provisioningV0alpha1 *provisioningv0alpha1.ProvisioningV0alpha1Client + serviceV0alpha1 *servicev0alpha1.ServiceV0alpha1Client +} + +// ProvisioningV0alpha1 retrieves the ProvisioningV0alpha1Client +func (c *Clientset) ProvisioningV0alpha1() provisioningv0alpha1.ProvisioningV0alpha1Interface { + return c.provisioningV0alpha1 } // ServiceV0alpha1 retrieves the ServiceV0alpha1Client @@ -74,6 +82,10 @@ func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, var cs Clientset var err error + cs.provisioningV0alpha1, err = provisioningv0alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } cs.serviceV0alpha1, err = servicev0alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err @@ -99,6 +111,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset + cs.provisioningV0alpha1 = provisioningv0alpha1.New(c) cs.serviceV0alpha1 = servicev0alpha1.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) diff --git a/pkg/generated/clientset/versioned/fake/clientset_generated.go b/pkg/generated/clientset/versioned/fake/clientset_generated.go index 0db3aa0390a..3a8cf9c1302 100644 --- a/pkg/generated/clientset/versioned/fake/clientset_generated.go +++ b/pkg/generated/clientset/versioned/fake/clientset_generated.go @@ -7,6 +7,8 @@ package fake import ( applyconfiguration "github.com/grafana/grafana/pkg/generated/applyconfiguration" clientset "github.com/grafana/grafana/pkg/generated/clientset/versioned" + provisioningv0alpha1 "github.com/grafana/grafana/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1" + fakeprovisioningv0alpha1 "github.com/grafana/grafana/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake" servicev0alpha1 "github.com/grafana/grafana/pkg/generated/clientset/versioned/typed/service/v0alpha1" fakeservicev0alpha1 "github.com/grafana/grafana/pkg/generated/clientset/versioned/typed/service/v0alpha1/fake" "k8s.io/apimachinery/pkg/runtime" @@ -102,6 +104,11 @@ var ( _ testing.FakeClient = &Clientset{} ) +// ProvisioningV0alpha1 retrieves the ProvisioningV0alpha1Client +func (c *Clientset) ProvisioningV0alpha1() provisioningv0alpha1.ProvisioningV0alpha1Interface { + return &fakeprovisioningv0alpha1.FakeProvisioningV0alpha1{Fake: &c.Fake} +} + // ServiceV0alpha1 retrieves the ServiceV0alpha1Client func (c *Clientset) ServiceV0alpha1() servicev0alpha1.ServiceV0alpha1Interface { return &fakeservicev0alpha1.FakeServiceV0alpha1{Fake: &c.Fake} diff --git a/pkg/generated/clientset/versioned/fake/register.go b/pkg/generated/clientset/versioned/fake/register.go index bbf12658e76..d64a8572697 100644 --- a/pkg/generated/clientset/versioned/fake/register.go +++ b/pkg/generated/clientset/versioned/fake/register.go @@ -5,6 +5,7 @@ package fake import ( + provisioningv0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" servicev0alpha1 "github.com/grafana/grafana/pkg/apis/service/v0alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" @@ -17,6 +18,7 @@ var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ + provisioningv0alpha1.AddToScheme, servicev0alpha1.AddToScheme, } diff --git a/pkg/generated/clientset/versioned/scheme/register.go b/pkg/generated/clientset/versioned/scheme/register.go index dd6e9619160..0aa0fb1be43 100644 --- a/pkg/generated/clientset/versioned/scheme/register.go +++ b/pkg/generated/clientset/versioned/scheme/register.go @@ -5,6 +5,7 @@ package scheme import ( + provisioningv0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" servicev0alpha1 "github.com/grafana/grafana/pkg/apis/service/v0alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" @@ -17,6 +18,7 @@ var Scheme = runtime.NewScheme() var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ + provisioningv0alpha1.AddToScheme, servicev0alpha1.AddToScheme, } diff --git a/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/doc.go b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/doc.go new file mode 100644 index 00000000000..1c86744fecc --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/doc.go @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v0alpha1 diff --git a/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/doc.go b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/doc.go new file mode 100644 index 00000000000..d96b985b3ea --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/doc.go @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/fake_provisioning_client.go b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/fake_provisioning_client.go new file mode 100644 index 00000000000..026b4d8947d --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/fake_provisioning_client.go @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v0alpha1 "github.com/grafana/grafana/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeProvisioningV0alpha1 struct { + *testing.Fake +} + +func (c *FakeProvisioningV0alpha1) Repositories(namespace string) v0alpha1.RepositoryInterface { + return &FakeRepositories{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeProvisioningV0alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/fake_repository.go b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/fake_repository.go new file mode 100644 index 00000000000..006fa440a66 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/fake/fake_repository.go @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + provisioningv0alpha1 "github.com/grafana/grafana/pkg/generated/applyconfiguration/provisioning/v0alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeRepositories implements RepositoryInterface +type FakeRepositories struct { + Fake *FakeProvisioningV0alpha1 + ns string +} + +var repositoriesResource = v0alpha1.SchemeGroupVersion.WithResource("repositories") + +var repositoriesKind = v0alpha1.SchemeGroupVersion.WithKind("Repository") + +// Get takes name of the repository, and returns the corresponding repository object, and an error if there is any. +func (c *FakeRepositories) Get(ctx context.Context, name string, options v1.GetOptions) (result *v0alpha1.Repository, err error) { + emptyResult := &v0alpha1.Repository{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(repositoriesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v0alpha1.Repository), err +} + +// List takes label and field selectors, and returns the list of Repositories that match those selectors. +func (c *FakeRepositories) List(ctx context.Context, opts v1.ListOptions) (result *v0alpha1.RepositoryList, err error) { + emptyResult := &v0alpha1.RepositoryList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(repositoriesResource, repositoriesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v0alpha1.RepositoryList{ListMeta: obj.(*v0alpha1.RepositoryList).ListMeta} + for _, item := range obj.(*v0alpha1.RepositoryList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested repositories. +func (c *FakeRepositories) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(repositoriesResource, c.ns, opts)) + +} + +// Create takes the representation of a repository and creates it. Returns the server's representation of the repository, and an error, if there is any. +func (c *FakeRepositories) Create(ctx context.Context, repository *v0alpha1.Repository, opts v1.CreateOptions) (result *v0alpha1.Repository, err error) { + emptyResult := &v0alpha1.Repository{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(repositoriesResource, c.ns, repository, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v0alpha1.Repository), err +} + +// Update takes the representation of a repository and updates it. Returns the server's representation of the repository, and an error, if there is any. +func (c *FakeRepositories) Update(ctx context.Context, repository *v0alpha1.Repository, opts v1.UpdateOptions) (result *v0alpha1.Repository, err error) { + emptyResult := &v0alpha1.Repository{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(repositoriesResource, c.ns, repository, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v0alpha1.Repository), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeRepositories) UpdateStatus(ctx context.Context, repository *v0alpha1.Repository, opts v1.UpdateOptions) (result *v0alpha1.Repository, err error) { + emptyResult := &v0alpha1.Repository{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(repositoriesResource, "status", c.ns, repository, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v0alpha1.Repository), err +} + +// Delete takes name of the repository and deletes it. Returns an error if one occurs. +func (c *FakeRepositories) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(repositoriesResource, c.ns, name, opts), &v0alpha1.Repository{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRepositories) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(repositoriesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v0alpha1.RepositoryList{}) + return err +} + +// Patch applies the patch and returns the patched repository. +func (c *FakeRepositories) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v0alpha1.Repository, err error) { + emptyResult := &v0alpha1.Repository{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(repositoriesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v0alpha1.Repository), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied repository. +func (c *FakeRepositories) Apply(ctx context.Context, repository *provisioningv0alpha1.RepositoryApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.Repository, err error) { + if repository == nil { + return nil, fmt.Errorf("repository provided to Apply must not be nil") + } + data, err := json.Marshal(repository) + if err != nil { + return nil, err + } + name := repository.Name + if name == nil { + return nil, fmt.Errorf("repository.Name must be provided to Apply") + } + emptyResult := &v0alpha1.Repository{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(repositoriesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v0alpha1.Repository), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeRepositories) ApplyStatus(ctx context.Context, repository *provisioningv0alpha1.RepositoryApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.Repository, err error) { + if repository == nil { + return nil, fmt.Errorf("repository provided to Apply must not be nil") + } + data, err := json.Marshal(repository) + if err != nil { + return nil, err + } + name := repository.Name + if name == nil { + return nil, fmt.Errorf("repository.Name must be provided to Apply") + } + emptyResult := &v0alpha1.Repository{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(repositoriesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v0alpha1.Repository), err +} diff --git a/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/generated_expansion.go b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/generated_expansion.go new file mode 100644 index 00000000000..2e9e7e51d5b --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/generated_expansion.go @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package v0alpha1 + +type RepositoryExpansion interface{} diff --git a/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/provisioning_client.go b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/provisioning_client.go new file mode 100644 index 00000000000..ef932d139e1 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/provisioning_client.go @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + "net/http" + + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/pkg/generated/clientset/versioned/scheme" + rest "k8s.io/client-go/rest" +) + +type ProvisioningV0alpha1Interface interface { + RESTClient() rest.Interface + RepositoriesGetter +} + +// ProvisioningV0alpha1Client is used to interact with features provided by the provisioning.grafana.app group. +type ProvisioningV0alpha1Client struct { + restClient rest.Interface +} + +func (c *ProvisioningV0alpha1Client) Repositories(namespace string) RepositoryInterface { + return newRepositories(c, namespace) +} + +// NewForConfig creates a new ProvisioningV0alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*ProvisioningV0alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new ProvisioningV0alpha1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ProvisioningV0alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &ProvisioningV0alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new ProvisioningV0alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ProvisioningV0alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ProvisioningV0alpha1Client for the given RESTClient. +func New(c rest.Interface) *ProvisioningV0alpha1Client { + return &ProvisioningV0alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v0alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ProvisioningV0alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/repository.go b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/repository.go new file mode 100644 index 00000000000..472f8072900 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1/repository.go @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + "context" + + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + provisioningv0alpha1 "github.com/grafana/grafana/pkg/generated/applyconfiguration/provisioning/v0alpha1" + scheme "github.com/grafana/grafana/pkg/generated/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// RepositoriesGetter has a method to return a RepositoryInterface. +// A group's client should implement this interface. +type RepositoriesGetter interface { + Repositories(namespace string) RepositoryInterface +} + +// RepositoryInterface has methods to work with Repository resources. +type RepositoryInterface interface { + Create(ctx context.Context, repository *v0alpha1.Repository, opts v1.CreateOptions) (*v0alpha1.Repository, error) + Update(ctx context.Context, repository *v0alpha1.Repository, opts v1.UpdateOptions) (*v0alpha1.Repository, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, repository *v0alpha1.Repository, opts v1.UpdateOptions) (*v0alpha1.Repository, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v0alpha1.Repository, error) + List(ctx context.Context, opts v1.ListOptions) (*v0alpha1.RepositoryList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v0alpha1.Repository, err error) + Apply(ctx context.Context, repository *provisioningv0alpha1.RepositoryApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.Repository, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, repository *provisioningv0alpha1.RepositoryApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.Repository, err error) + RepositoryExpansion +} + +// repositories implements RepositoryInterface +type repositories struct { + *gentype.ClientWithListAndApply[*v0alpha1.Repository, *v0alpha1.RepositoryList, *provisioningv0alpha1.RepositoryApplyConfiguration] +} + +// newRepositories returns a Repositories +func newRepositories(c *ProvisioningV0alpha1Client, namespace string) *repositories { + return &repositories{ + gentype.NewClientWithListAndApply[*v0alpha1.Repository, *v0alpha1.RepositoryList, *provisioningv0alpha1.RepositoryApplyConfiguration]( + "repositories", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v0alpha1.Repository { return &v0alpha1.Repository{} }, + func() *v0alpha1.RepositoryList { return &v0alpha1.RepositoryList{} }), + } +} diff --git a/pkg/generated/informers/externalversions/factory.go b/pkg/generated/informers/externalversions/factory.go index 93a498c5d2a..86ef036dae3 100644 --- a/pkg/generated/informers/externalversions/factory.go +++ b/pkg/generated/informers/externalversions/factory.go @@ -11,6 +11,7 @@ import ( versioned "github.com/grafana/grafana/pkg/generated/clientset/versioned" internalinterfaces "github.com/grafana/grafana/pkg/generated/informers/externalversions/internalinterfaces" + provisioning "github.com/grafana/grafana/pkg/generated/informers/externalversions/provisioning" service "github.com/grafana/grafana/pkg/generated/informers/externalversions/service" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" @@ -240,9 +241,14 @@ type SharedInformerFactory interface { // client. InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + Provisioning() provisioning.Interface Service() service.Interface } +func (f *sharedInformerFactory) Provisioning() provisioning.Interface { + return provisioning.New(f, f.namespace, f.tweakListOptions) +} + func (f *sharedInformerFactory) Service() service.Interface { return service.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/generated/informers/externalversions/generic.go b/pkg/generated/informers/externalversions/generic.go index 88cc30aa0f9..82e00ef7e01 100644 --- a/pkg/generated/informers/externalversions/generic.go +++ b/pkg/generated/informers/externalversions/generic.go @@ -7,7 +7,8 @@ package externalversions import ( "fmt" - v0alpha1 "github.com/grafana/grafana/pkg/apis/service/v0alpha1" + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + servicev0alpha1 "github.com/grafana/grafana/pkg/apis/service/v0alpha1" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -38,8 +39,12 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { - // Group=service.grafana.app, Version=v0alpha1 - case v0alpha1.SchemeGroupVersion.WithResource("externalnames"): + // Group=provisioning.grafana.app, Version=v0alpha1 + case v0alpha1.SchemeGroupVersion.WithResource("repositories"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Provisioning().V0alpha1().Repositories().Informer()}, nil + + // Group=service.grafana.app, Version=v0alpha1 + case servicev0alpha1.SchemeGroupVersion.WithResource("externalnames"): return &genericInformer{resource: resource.GroupResource(), informer: f.Service().V0alpha1().ExternalNames().Informer()}, nil } diff --git a/pkg/generated/informers/externalversions/provisioning/interface.go b/pkg/generated/informers/externalversions/provisioning/interface.go new file mode 100644 index 00000000000..851568050e0 --- /dev/null +++ b/pkg/generated/informers/externalversions/provisioning/interface.go @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by informer-gen. DO NOT EDIT. + +package provisioning + +import ( + internalinterfaces "github.com/grafana/grafana/pkg/generated/informers/externalversions/internalinterfaces" + v0alpha1 "github.com/grafana/grafana/pkg/generated/informers/externalversions/provisioning/v0alpha1" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V0alpha1 provides access to shared informers for resources in V0alpha1. + V0alpha1() v0alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V0alpha1 returns a new v0alpha1.Interface. +func (g *group) V0alpha1() v0alpha1.Interface { + return v0alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/generated/informers/externalversions/provisioning/v0alpha1/interface.go b/pkg/generated/informers/externalversions/provisioning/v0alpha1/interface.go new file mode 100644 index 00000000000..51060296a02 --- /dev/null +++ b/pkg/generated/informers/externalversions/provisioning/v0alpha1/interface.go @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by informer-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + internalinterfaces "github.com/grafana/grafana/pkg/generated/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Repositories returns a RepositoryInformer. + Repositories() RepositoryInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// Repositories returns a RepositoryInformer. +func (v *version) Repositories() RepositoryInformer { + return &repositoryInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/generated/informers/externalversions/provisioning/v0alpha1/repository.go b/pkg/generated/informers/externalversions/provisioning/v0alpha1/repository.go new file mode 100644 index 00000000000..25be9d0a95a --- /dev/null +++ b/pkg/generated/informers/externalversions/provisioning/v0alpha1/repository.go @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by informer-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + "context" + time "time" + + provisioningv0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + versioned "github.com/grafana/grafana/pkg/generated/clientset/versioned" + internalinterfaces "github.com/grafana/grafana/pkg/generated/informers/externalversions/internalinterfaces" + v0alpha1 "github.com/grafana/grafana/pkg/generated/listers/provisioning/v0alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// RepositoryInformer provides access to a shared informer and lister for +// Repositories. +type RepositoryInformer interface { + Informer() cache.SharedIndexInformer + Lister() v0alpha1.RepositoryLister +} + +type repositoryInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewRepositoryInformer constructs a new informer for Repository type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewRepositoryInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredRepositoryInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredRepositoryInformer constructs a new informer for Repository type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredRepositoryInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ProvisioningV0alpha1().Repositories(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ProvisioningV0alpha1().Repositories(namespace).Watch(context.TODO(), options) + }, + }, + &provisioningv0alpha1.Repository{}, + resyncPeriod, + indexers, + ) +} + +func (f *repositoryInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredRepositoryInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *repositoryInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&provisioningv0alpha1.Repository{}, f.defaultInformer) +} + +func (f *repositoryInformer) Lister() v0alpha1.RepositoryLister { + return v0alpha1.NewRepositoryLister(f.Informer().GetIndexer()) +} diff --git a/pkg/generated/listers/provisioning/v0alpha1/expansion_generated.go b/pkg/generated/listers/provisioning/v0alpha1/expansion_generated.go new file mode 100644 index 00000000000..118fae5b629 --- /dev/null +++ b/pkg/generated/listers/provisioning/v0alpha1/expansion_generated.go @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by lister-gen. DO NOT EDIT. + +package v0alpha1 + +// RepositoryListerExpansion allows custom methods to be added to +// RepositoryLister. +type RepositoryListerExpansion interface{} + +// RepositoryNamespaceListerExpansion allows custom methods to be added to +// RepositoryNamespaceLister. +type RepositoryNamespaceListerExpansion interface{} diff --git a/pkg/generated/listers/provisioning/v0alpha1/repository.go b/pkg/generated/listers/provisioning/v0alpha1/repository.go new file mode 100644 index 00000000000..10395c928f6 --- /dev/null +++ b/pkg/generated/listers/provisioning/v0alpha1/repository.go @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by lister-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" + "k8s.io/client-go/tools/cache" +) + +// RepositoryLister helps list Repositories. +// All objects returned here must be treated as read-only. +type RepositoryLister interface { + // List lists all Repositories in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v0alpha1.Repository, err error) + // Repositories returns an object that can list and get Repositories. + Repositories(namespace string) RepositoryNamespaceLister + RepositoryListerExpansion +} + +// repositoryLister implements the RepositoryLister interface. +type repositoryLister struct { + listers.ResourceIndexer[*v0alpha1.Repository] +} + +// NewRepositoryLister returns a new RepositoryLister. +func NewRepositoryLister(indexer cache.Indexer) RepositoryLister { + return &repositoryLister{listers.New[*v0alpha1.Repository](indexer, v0alpha1.Resource("repository"))} +} + +// Repositories returns an object that can list and get Repositories. +func (s *repositoryLister) Repositories(namespace string) RepositoryNamespaceLister { + return repositoryNamespaceLister{listers.NewNamespaced[*v0alpha1.Repository](s.ResourceIndexer, namespace)} +} + +// RepositoryNamespaceLister helps list and get Repositories. +// All objects returned here must be treated as read-only. +type RepositoryNamespaceLister interface { + // List lists all Repositories in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v0alpha1.Repository, err error) + // Get retrieves the Repository from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v0alpha1.Repository, error) + RepositoryNamespaceListerExpansion +} + +// repositoryNamespaceLister implements the RepositoryNamespaceLister +// interface. +type repositoryNamespaceLister struct { + listers.ResourceIndexer[*v0alpha1.Repository] +} diff --git a/pkg/registry/apis/provisioning/register.go b/pkg/registry/apis/provisioning/register.go index a9daa59712e..24c1b25dfe2 100644 --- a/pkg/registry/apis/provisioning/register.go +++ b/pkg/registry/apis/provisioning/register.go @@ -9,6 +9,7 @@ import ( "log/slog" "net/url" "strings" + "time" "github.com/prometheus/client_golang/prometheus" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -28,6 +29,8 @@ import ( provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" + clientset "github.com/grafana/grafana/pkg/generated/clientset/versioned" + informers "github.com/grafana/grafana/pkg/generated/informers/externalversions" "github.com/grafana/grafana/pkg/registry/apis/provisioning/auth" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" "github.com/grafana/grafana/pkg/registry/apis/provisioning/lint" @@ -35,6 +38,7 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository/github" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" "github.com/grafana/grafana/pkg/registry/apis/provisioning/safepath" + "github.com/grafana/grafana/pkg/services/apiserver" "github.com/grafana/grafana/pkg/services/apiserver/builder" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/rendering" @@ -44,6 +48,7 @@ import ( const ( resourceNamePlaceholder = "$RESOURCE_NAME_PLACEHOLDER" + repoControllerWorkers = 1 ) var ( @@ -78,9 +83,10 @@ func NewProvisioningAPIBuilder( features featuremgmt.FeatureToggles, render rendering.Service, blobstore blob.PublicBlobStore, + configProvider apiserver.RestConfigProvider, ghFactory github.ClientFactory, ) *ProvisioningAPIBuilder { - return &ProvisioningAPIBuilder{ + builder := &ProvisioningAPIBuilder{ urlProvider: urlProvider, localFileResolver: local, logger: slog.Default().With("logger", "provisioning-api-builder"), @@ -96,6 +102,8 @@ func NewProvisioningAPIBuilder( }, jobs: jobs.NewJobQueue(50), // in memory for now } + + return builder } func RegisterAPIService( @@ -106,6 +114,7 @@ func RegisterAPIService( reg prometheus.Registerer, identities auth.BackgroundIdentityService, render rendering.Service, + configProvider apiserver.RestConfigProvider, ghFactory github.ClientFactory, ) (*ProvisioningAPIBuilder, error) { if !(features.IsEnabledGlobally(featuremgmt.FlagProvisioning) || @@ -125,7 +134,7 @@ func RegisterAPIService( HomePath: safepath.Clean(cfg.HomePath), }, func(namespace string) string { return cfg.AppURL - }, cfg.SecretKey, identities, features, render, store, ghFactory) + }, cfg.SecretKey, identities, features, render, store, configProvider, ghFactory) apiregistration.RegisterAPI(builder) return builder, nil } @@ -159,6 +168,7 @@ func (b *ProvisioningAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { return err } + metav1.AddToGroupVersion(scheme, provisioning.SchemeGroupVersion) // Only 1 version (for now?) return scheme.SetVersionPriority(provisioning.SchemeGroupVersion) } @@ -318,7 +328,7 @@ func (b *ProvisioningAPIBuilder) beginUpdate(ctx context.Context, obj, old runti undo, err := repo.BeginUpdate(ctx, b.logger, oldRepo) if err != nil { - return nil, err + b.logger.Warn("error in begin update", "err", err) } return func(ctx context.Context, success bool) { @@ -477,9 +487,36 @@ func (b *ProvisioningAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefini return provisioning.GetOpenAPIDefinitions } -func (b *ProvisioningAPIBuilder) GetAPIRoutes() *builder.APIRoutes { - // TODO: this is where we could inject a non-k8s managed handler... webhook maybe? - return nil +func (b *ProvisioningAPIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartHookFunc, error) { + postStartHooks := map[string]genericapiserver.PostStartHookFunc{ + "grafana-provisioning": func(postStartHookCtx genericapiserver.PostStartHookContext) error { + c, err := clientset.NewForConfig(postStartHookCtx.LoopbackClientConfig) + if err != nil { + return err + } + sharedInformerFactory := informers.NewSharedInformerFactory( + c, + 15*time.Minute, // Health check interval + ) + + repoInformer := sharedInformerFactory.Provisioning().V0alpha1().Repositories() + go repoInformer.Informer().Run(postStartHookCtx.Context.Done()) + + repoController, err := NewRepositoryController( + c.ProvisioningV0alpha1(), + repoInformer, + b, // repoGetter + b.identities, + ) + if err != nil { + return err + } + + go repoController.Run(postStartHookCtx.Context, repoControllerWorkers) + return nil + }, + } + return postStartHooks, nil } func (b *ProvisioningAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, error) { diff --git a/pkg/registry/apis/provisioning/repository/github.go b/pkg/registry/apis/provisioning/repository/github.go index 7c489eacac0..ef448fbc23c 100644 --- a/pkg/registry/apis/provisioning/repository/github.go +++ b/pkg/registry/apis/provisioning/repository/github.go @@ -566,7 +566,7 @@ func (r *githubRepository) parsePullRequestEvent(event *github.PullRequestEvent) } // Process is a backend job -func (r *githubRepository) Process(ctx context.Context, logger *slog.Logger, wrap provisioning.Job, replicator FileReplicator) (*provisioning.RepositoryStatus, error) { +func (r *githubRepository) Process(ctx context.Context, logger *slog.Logger, wrap provisioning.Job, replicator FileReplicator) (*provisioning.SyncStatus, error) { job := wrap.Spec if job.PR > 0 { @@ -580,7 +580,7 @@ func (r *githubRepository) Process(ctx context.Context, logger *slog.Logger, wra } latest := branch.Sha - lastSyncCommit := r.config.Status.CurrentGitCommit + lastSyncCommit := r.config.Status.Sync.Hash if lastSyncCommit == "" { logger.Info("initial sync") @@ -680,8 +680,8 @@ func (r *githubRepository) Process(ctx context.Context, logger *slog.Logger, wra } logger.InfoContext(ctx, "repository status updated", "commit", latest) - return &provisioning.RepositoryStatus{ - CurrentGitCommit: latest, + return &provisioning.SyncStatus{ + Hash: latest, }, nil } diff --git a/pkg/registry/apis/provisioning/repository/repository.go b/pkg/registry/apis/provisioning/repository/repository.go index 453730d89b2..f9a4fb1d70f 100644 --- a/pkg/registry/apis/provisioning/repository/repository.go +++ b/pkg/registry/apis/provisioning/repository/repository.go @@ -106,7 +106,7 @@ type Repository interface { type JobProcessor interface { // Temporary... likely want this as its own thing... eg GithubWorker or similar - Process(ctx context.Context, logger *slog.Logger, job provisioning.Job, replicator FileReplicator) (*provisioning.RepositoryStatus, error) + Process(ctx context.Context, logger *slog.Logger, job provisioning.Job, replicator FileReplicator) (*provisioning.SyncStatus, error) } // FileReplicator is an interface for replicating files diff --git a/pkg/registry/apis/provisioning/repository_controller.go b/pkg/registry/apis/provisioning/repository_controller.go new file mode 100644 index 00000000000..afe3e7ebdc9 --- /dev/null +++ b/pkg/registry/apis/provisioning/repository_controller.go @@ -0,0 +1,239 @@ +package provisioning + +import ( + "context" + "fmt" + "log/slog" + "time" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" + + "github.com/grafana/grafana/pkg/apimachinery/identity" + provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + client "github.com/grafana/grafana/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1" + informer "github.com/grafana/grafana/pkg/generated/informers/externalversions/provisioning/v0alpha1" + listers "github.com/grafana/grafana/pkg/generated/listers/provisioning/v0alpha1" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/auth" +) + +// RepositoryController controls how and when CRD is established. +type RepositoryController struct { + client client.ProvisioningV0alpha1Interface + repoLister listers.RepositoryLister + repoSynced cache.InformerSynced + + // Converts config to instance + repoGetter RepoGetter + identities auth.BackgroundIdentityService + + // To allow injection for testing. + syncFn func(key string) error + enqueueRepository func(obj any) + keyFunc func(obj any) (string, error) + + queue workqueue.TypedRateLimitingInterface[string] + logger *slog.Logger +} + +// NewRepositoryController creates new RepositoryController. +func NewRepositoryController( + provisioningClient client.ProvisioningV0alpha1Interface, + repoInformer informer.RepositoryInformer, + repoGetter RepoGetter, + identities auth.BackgroundIdentityService, +) (*RepositoryController, error) { + rc := &RepositoryController{ + client: provisioningClient, + repoLister: repoInformer.Lister(), + repoSynced: repoInformer.Informer().HasSynced, + queue: workqueue.NewTypedRateLimitingQueueWithConfig( + workqueue.DefaultTypedControllerRateLimiter[string](), + workqueue.TypedRateLimitingQueueConfig[string]{ + Name: "provisioningRepositoryController", + }, + ), + repoGetter: repoGetter, + identities: identities, + logger: slog.Default().With("logger", "provisioning-repository-controller"), + } + + _, err := repoInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: rc.addRepository, + UpdateFunc: rc.updateRepository, + DeleteFunc: rc.deleteRepository, + }) + if err != nil { + return nil, err + } + + rc.syncFn = rc.sync + rc.enqueueRepository = rc.enqueue + rc.keyFunc = repoKeyFunc + + return rc, nil +} + +func repoKeyFunc(obj any) (string, error) { + repo, ok := obj.(*provisioning.Repository) + if !ok { + return "", fmt.Errorf("expected a Repository but got %T", obj) + } + return cache.DeletionHandlingMetaNamespaceKeyFunc(repo) +} + +// Run starts the RepositoryController. +func (rc *RepositoryController) Run(ctx context.Context, workerCount int) { + defer utilruntime.HandleCrash() + defer rc.queue.ShutDown() + + rc.logger.Info("Starting RepositoryController") + defer rc.logger.Info("Shutting down RepositoryController") + + if !cache.WaitForCacheSync(ctx.Done(), rc.repoSynced) { + return + } + + rc.logger.Info("Starting workers", "count", workerCount) + for i := 0; i < workerCount; i++ { + go wait.UntilWithContext(ctx, rc.runWorker, time.Second) + } + + rc.logger.Info("Started workers") + <-ctx.Done() + rc.logger.Info("Shutting down workers") +} + +func (rc *RepositoryController) runWorker(ctx context.Context) { + for rc.processNextWorkItem(ctx) { + } +} + +func (rc *RepositoryController) enqueue(obj interface{}) { + key, err := rc.keyFunc(obj) + if err != nil { + utilruntime.HandleError(fmt.Errorf("couldn't get key for object: %v", err)) + return + } + rc.queue.Add(key) +} + +func (rc *RepositoryController) addRepository(obj interface{}) { + rc.enqueueRepository(obj) +} + +func (rc *RepositoryController) updateRepository(oldObj, newObj interface{}) { + rc.enqueueRepository(newObj) +} + +func (rc *RepositoryController) deleteRepository(obj interface{}) { + repo, ok := obj.(*provisioning.Repository) + if !ok { + rc.logger.Error("expected a Repository but got %T", obj) + return + } + // TODO: Add job that will remove everything owned by that repository + rc.logger.Info("TODO, remove everything from repository", "name", repo.Name) + // rc.enqueueRepository(repo) +} + +// processNextWorkItem deals with one key off the queue. +// It returns false when it's time to quit. +func (rc *RepositoryController) processNextWorkItem(ctx context.Context) bool { + key, quit := rc.queue.Get() + if quit { + return false + } + defer rc.queue.Done(key) + + rc.logger.Info("RepositoryController processing key", "key", key) + + err := rc.syncFn(key) + if err == nil { + rc.queue.Forget(key) + return true + } + + utilruntime.HandleError(fmt.Errorf("%v failed with: %v", key, err)) + rc.queue.AddRateLimited(key) + + return true +} + +// sync is the business logic of the controller. +func (rc *RepositoryController) sync(key string) error { + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + return err + } + + cachedRepo, err := rc.repoLister.Repositories(namespace).Get(name) + if apierrors.IsNotFound(err) { + return nil + } + if err != nil { + return err + } + + now := time.Now().UnixMilli() + elapsed := now - cachedRepo.Status.Health.Checked + if time.Duration(elapsed)*time.Millisecond < time.Second*30 { + // We checked status recently! + // avoids inf loop!!! + // This logic is not totally right -- we want to force this if anything in spec changed :thinkign: + return nil + } + + // This is used for the health check client + id, err := rc.identities.WorkerIdentity(context.Background(), namespace) + if err != nil { + return err + } + ctx := identity.WithRequester(context.Background(), id) + + // Make a copy we can mutate + cfg := cachedRepo.DeepCopy() + repo, err := rc.repoGetter.AsRepository(ctx, cfg) + if err != nil { + cfg.Status.Health = provisioning.HealthStatus{ + Checked: now, + Healthy: false, + Message: []string{ + "Unable to create repository from configuration", + err.Error(), + }, + } + } else { + res, err := TestRepository(ctx, repo, rc.logger) + if err != nil { + res = &provisioning.TestResults{ + Success: false, + Errors: []string{ + "error running test repository", + err.Error(), + }, + } + } + cfg.Status.Health = provisioning.HealthStatus{ + Checked: now, + Healthy: res.Success, + Message: res.Errors, + } + } + + _, err = rc.client.Repositories(cfg.GetNamespace()). + UpdateStatus(ctx, cfg, metav1.UpdateOptions{}) + + if apierrors.IsNotFound(err) || apierrors.IsConflict(err) { + // deleted or changed in the meantime, we'll get called again + return nil + } + if err != nil { + return err + } + return nil +} diff --git a/pkg/registry/apis/provisioning/worker.go b/pkg/registry/apis/provisioning/worker.go index 2c4d5b7fb79..936dcb201cc 100644 --- a/pkg/registry/apis/provisioning/worker.go +++ b/pkg/registry/apis/provisioning/worker.go @@ -77,18 +77,16 @@ func (g *JobWorker) Process(ctx context.Context, job provisioning.Job) (*provisi } // TODO: Can we use typed client for this? + cfg := repo.Config() + cfg.Status.Sync = *status + client := dynamicClient.Resource(provisioning.RepositoryResourceInfo.GroupVersionResource()) unstructuredResource := &unstructured.Unstructured{} - jj, _ := json.Marshal(repo.Config()) + jj, _ := json.Marshal(cfg) err = json.Unmarshal(jj, &unstructuredResource.Object) if err != nil { return nil, fmt.Errorf("error loading config json: %w", err) } - - if err := unstructured.SetNestedField(unstructuredResource.Object, status.CurrentGitCommit, "status", "currentGitCommit"); err != nil { - return nil, fmt.Errorf("set currentGitCommit: %w", err) - } - if _, err := client.UpdateStatus(ctx, unstructuredResource, metav1.UpdateOptions{}); err != nil { return nil, fmt.Errorf("update repository status: %w", err) } diff --git a/pkg/tests/apis/dashboard/dashboards_test.go b/pkg/tests/apis/dashboard/dashboards_test.go index 6df09d87578..e9ca8082f9e 100644 --- a/pkg/tests/apis/dashboard/dashboards_test.go +++ b/pkg/tests/apis/dashboard/dashboards_test.go @@ -45,6 +45,8 @@ func runDashboardTest(t *testing.T, helper *apis.K8sTestHelper) { }, } obj.SetGenerateName("aa") + obj.SetAPIVersion("dashboard.grafana.app/v0alpha1") + obj.SetKind("Dashboard") obj, err = client.Resource.Create(ctx, obj, metav1.CreateOptions{}) require.NoError(t, err) created := obj.GetName() diff --git a/pkg/tests/apis/provisioning/provisioning_test.go b/pkg/tests/apis/provisioning/provisioning_test.go index 7740cf21529..70af99776e2 100644 --- a/pkg/tests/apis/provisioning/provisioning_test.go +++ b/pkg/tests/apis/provisioning/provisioning_test.go @@ -44,6 +44,7 @@ func TestIntegrationProvisioning(t *testing.T) { }) helper.GetEnv().GitHubMockFactory.Constructor = func(ttc github.TestingTWithCleanup) github.Client { client := github.NewMockClient(ttc) + client.On("IsAuthenticated", mock.Anything).Maybe().Return(true) client.On("ListWebhooks", mock.Anything, mock.Anything, mock.Anything).Maybe().Return(nil, nil) client.On("CreateWebhook", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Maybe().Return(nil) // Don't need DeleteWebhook or EditWebhook, because they require that ListWebhooks returns a slice with elements. @@ -295,16 +296,6 @@ func TestIntegrationProvisioning(t *testing.T) { }`, string(js)) }) - t.Run("validation hooks", func(t *testing.T) { - // Add it if this is the only test that ran - obj, err := client.Resource.Create(ctx, - helper.LoadYAMLOrJSONFile("testdata/invalid.yaml"), - metav1.CreateOptions{}, - ) - require.Nil(t, obj) - require.Error(t, err) - }) - t.Run("creating repository creates folder", func(t *testing.T) { // Just make sure the folder doesn't exist in advance. err := folderClient.Resource.Delete(ctx, "thisisafolderref", metav1.DeleteOptions{}) diff --git a/pkg/tests/apis/provisioning/testdata/invalid.yaml b/pkg/tests/apis/provisioning/testdata/invalid.yaml deleted file mode 100644 index 835d22e20a1..00000000000 --- a/pkg/tests/apis/provisioning/testdata/invalid.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: provisioning.grafana.app/v0alpha1 -kind: Repository -metadata: - name: invalid-local-devenv -spec: - title: Should not allow saving this - type: local - local: - path: /etc/passwords