Provisioning: Extract to apps submodule (#109074)

This commit is contained in:
Stephanie Hingtgen
2025-08-01 14:35:18 -05:00
committed by GitHub
parent 172a69da75
commit 9f4773c9a5
192 changed files with 4774 additions and 766 deletions
-22
View File
@@ -1,22 +0,0 @@
package v0alpha1
// File types used from classic provisioning
// +enum
type ClassicFileType string
const (
// Dashboard JSON
ClassicDashboard ClassicFileType = "dashboard"
// Datasource definitions
// eg: https://github.com/grafana/grafana/blob/v11.3.1/conf/provisioning/datasources/sample.yaml
ClassicDatasources ClassicFileType = "datasources"
// Alert configuration
// https://github.com/grafana/grafana/blob/v11.3.1/conf/provisioning/alerting/sample.yaml
ClassicAlerting ClassicFileType = "alerting"
// Access control
// https://github.com/grafana/grafana/blob/v11.3.1/conf/provisioning/access-control/sample.yaml
ClassicAccessControl ClassicFileType = "access-control"
)
-6
View File
@@ -1,6 +0,0 @@
// +k8s:deepcopy-gen=package
// +k8s:openapi-gen=true
// +k8s:defaulter-gen=TypeMeta
// +groupName=provisioning.grafana.app
package v0alpha1 // import "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
-249
View File
@@ -1,249 +0,0 @@
package v0alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// The repository name and type are stored as labels
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type Job struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec JobSpec `json:"spec,omitempty"`
Status JobStatus `json:"status,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type JobList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Job `json:"items"`
}
// +enum
type JobAction string
const (
// JobActionPull replicates the remote branch in the local copy of the repository.
JobActionPull JobAction = "pull"
// JobActionPush replicates the local copy of the repository in the remote branch.
JobActionPush JobAction = "push"
// JobActionPullRequest adds additional useful information to a PR, such as comments with preview links and rendered images.
JobActionPullRequest JobAction = "pr"
// JobActionMigrate acts like JobActionExport, then JobActionPull. It also tries to preserve the history.
JobActionMigrate JobAction = "migrate"
// JobActionDelete deletes files in the remote repository
JobActionDelete JobAction = "delete"
// JobActionMove moves files in the remote repository
JobActionMove JobAction = "move"
)
// +enum
type JobState string
const (
// Job has been submitted, but not processed yet
JobStatePending JobState = "pending"
// The job is running
JobStateWorking JobState = "working"
// Finished with success
JobStateSuccess JobState = "success"
// Finished with errors
JobStateError JobState = "error"
// Finished with some non-critical errors
JobStateWarning JobState = "warning"
)
func (j JobState) Finished() bool {
return j == JobStateSuccess || j == JobStateError || j == JobStateWarning
}
type JobSpec struct {
Action JobAction `json:"action,omitempty"`
// The the repository reference (for now also in labels)
// This value is required, but will be popuplated from the job making the request
Repository string `json:"repository,omitempty"`
// Pull request options
PullRequest *PullRequestJobOptions `json:"pr,omitempty"`
// Required when the action is `push`
Push *ExportJobOptions `json:"push,omitempty"`
// Required when the action is `pull`
Pull *SyncJobOptions `json:"pull,omitempty"`
// Required when the action is `migrate`
Migrate *MigrateJobOptions `json:"migrate,omitempty"`
// Delete when the action is `delete`
Delete *DeleteJobOptions `json:"delete,omitempty"`
// Move when the action is `move`
Move *MoveJobOptions `json:"move,omitempty"`
}
type PullRequestJobOptions struct {
// The branch of commit hash
Ref string `json:"ref,omitempty"`
// Pull request number (when appropriate)
PR int `json:"pr,omitempty"`
// The specific commit hash that triggered this notice
Hash string `json:"hash,omitempty"`
// URL to the originator (eg, PR URL)
URL string `json:"url,omitempty"`
}
type SyncJobOptions struct {
// Incremental synchronization for versioned repositories
Incremental bool `json:"incremental"`
}
type ExportJobOptions struct {
// Message to use when committing the changes in a single commit
Message string `json:"message,omitempty"`
// The source folder (or empty) to export
Folder string `json:"folder,omitempty"`
// FIXME: we should validate this in admission hooks
// Target branch for export (only git)
Branch string `json:"branch,omitempty"`
// FIXME: we should validate this in admission hooks
// Prefix in target file system
Path string `json:"path,omitempty"`
}
type MigrateJobOptions struct {
// Preserve history (if possible)
History bool `json:"history,omitempty"`
// Message to use when committing the changes in a single commit
Message string `json:"message,omitempty"`
}
type DeleteJobOptions struct {
// Ref to the branch or commit hash to delete from
Ref string `json:"ref,omitempty"`
// Paths to be deleted. Examples:
// - dashboard.json (for a file)
// - a/b/c/other-dashboard.json (for a file)
// - nested/deep/ (for a directory)
// FIXME: we should validate this in admission hooks
Paths []string `json:"paths,omitempty"`
// Resources to delete
// This option has been created because currently the frontend does not use
// standarized app platform APIs. For performance and API consistency reasons, the preferred option
// is it to use the paths.
Resources []ResourceRef `json:"resources,omitempty"`
}
type ResourceRef struct {
// Name is the name of the resource, such as a dashboard UID.
Name string `json:"name,omitempty"`
// Kind is the type of resource, for example, "Dashboard".
Kind string `json:"kind,omitempty"`
// Group is the group of the resource, such as "dashboard.grafana.app".
Group string `json:"group,omitempty"`
}
type MoveJobOptions struct {
// Ref to the branch or commit hash that should move
Ref string `json:"ref,omitempty"`
// Paths to be deleted. Examples:
// - dashboard.json (for a file)
// - a/b/c/other-dashboard.json (for a file)
// - nested/deep/ (for a directory)
// FIXME: we should validate this in admission hooks
Paths []string `json:"paths,omitempty"`
// Destination path for the move (e.g. "new-location/")
TargetPath string `json:"targetPath,omitempty"`
// Resources to move
// This option has been created because currently the frontend does not use
// standarized app platform APIs. For performance and API consistency reasons, the preferred option
// is it to use the paths.
Resources []ResourceRef `json:"resources,omitempty"`
}
// The job status
type JobStatus struct {
State JobState `json:"state,omitempty"`
Started int64 `json:"started,omitempty"`
Finished int64 `json:"finished,omitempty"`
Message string `json:"message,omitempty"`
Errors []string `json:"errors,omitempty"`
// Optional value 0-100 that can be set while running
Progress float64 `json:"progress,omitempty"`
// Summary of processed actions
Summary []*JobResourceSummary `json:"summary,omitempty"`
}
// Convert a JOB to a
func (in JobStatus) ToSyncStatus(jobId string) SyncStatus {
return SyncStatus{
JobID: jobId,
State: in.State,
Started: in.Started,
Finished: in.Finished,
Message: in.Errors,
}
}
type JobResourceSummary struct {
Group string `json:"group,omitempty"`
Resource string `json:"resource,omitempty"`
Total int64 `json:"total,omitempty"` // the count (if known)
Create int64 `json:"create,omitempty"`
Update int64 `json:"update,omitempty"`
Delete int64 `json:"delete,omitempty"`
Write int64 `json:"write,omitempty"` // Create or update (export)
Error int64 `json:"error,omitempty"` // The error count
// No action required (useful for sync)
Noop int64 `json:"noop,omitempty"`
// Report errors for this resource type
// This may not be an exhaustive list and recommend looking at the logs for more info
Errors []string `json:"errors,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type WebhookResponse struct {
metav1.TypeMeta `json:",inline"`
// HTTP Status code
// 200 implies that the payload was understood but nothing is required
// 202 implies that an async job has been scheduled to handle the request
Code int `json:"code,omitempty"`
// Optional message
Message string `json:"added,omitempty"`
// Jobs to be processed
// When the response is 202 (Accepted) the queued jobs will be returned
Job *JobSpec `json:"job,omitempty"`
}
-134
View File
@@ -1,134 +0,0 @@
package v0alpha1
import (
"errors"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/grafana/grafana/pkg/apimachinery/utils"
)
const (
GROUP = "provisioning.grafana.app"
VERSION = "v0alpha1"
APIVERSION = GROUP + "/" + VERSION
)
var RepositoryResourceInfo = utils.NewResourceInfo(GROUP, VERSION,
"repositories", "repository", "Repositories",
func() runtime.Object { return &Repository{} }, // newObj
func() runtime.Object { return &RepositoryList{} }, // newList
utils.TableColumns{ // Returned by `kubectl get`. Doesn't affect disk storage.
Definition: []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name"},
{Name: "Created At", Type: "date"},
{Name: "Title", Type: "string"},
{Name: "Type", Type: "string"},
{Name: "Target", Type: "string"},
},
Reader: func(obj any) ([]interface{}, error) {
m, ok := obj.(*Repository)
if !ok {
return nil, errors.New("expected Repository")
}
var target string
switch m.Spec.Type {
case LocalRepositoryType:
target = m.Spec.Local.Path
case GitHubRepositoryType:
target = m.Spec.GitHub.URL
case GitRepositoryType:
target = m.Spec.Git.URL
case BitbucketRepositoryType:
target = m.Spec.Bitbucket.URL
case GitLabRepositoryType:
target = m.Spec.GitLab.URL
}
return []interface{}{
m.Name, // may our may not be nice to read
m.CreationTimestamp.UTC().Format(time.RFC3339),
m.Spec.Title, // explicitly configured title that can change
m.Spec.Type,
target,
}, nil
},
})
var JobResourceInfo = utils.NewResourceInfo(GROUP, VERSION,
"jobs", "job", "Job",
func() runtime.Object { return &Job{} }, // newObj
func() runtime.Object { return &JobList{} }, // newList
utils.TableColumns{ // Returned by `kubectl get`. Doesn't affect disk storage.
Definition: []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name"},
{Name: "Created At", Type: "date"},
{Name: "Action", Type: "string"},
{Name: "State", Type: "string"},
{Name: "Message", Type: "string"},
},
Reader: func(obj any) ([]interface{}, error) {
m, ok := obj.(*Job)
if !ok {
return nil, errors.New("expected Job")
}
return []interface{}{
m.Name, // may our may not be nice to read
m.CreationTimestamp.UTC().Format(time.RFC3339),
m.Spec.Action,
m.Status.State,
m.Status.Message,
}, nil
},
})
var (
// SchemeGroupVersion is group version used to register these objects
SchemeGroupVersion = schema.GroupVersion{Group: GROUP, Version: VERSION}
InternalGroupVersion = schema.GroupVersion{Group: GROUP, Version: runtime.APIVersionInternal}
// SchemaBuilder is used by standard codegen
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
localSchemeBuilder.Register(func(s *runtime.Scheme) error {
err := AddKnownTypes(SchemeGroupVersion, s)
if err != nil {
return err
}
metav1.AddToGroupVersion(s, SchemeGroupVersion)
return nil
})
}
// Adds the list of known types to the given scheme.
func AddKnownTypes(gv schema.GroupVersion, scheme *runtime.Scheme) error {
scheme.AddKnownTypes(gv,
&Repository{},
&RepositoryList{},
&WebhookResponse{},
&ResourceWrapper{},
&FileList{},
&HistoryList{},
&TestResults{},
&ResourceList{},
&ResourceStats{},
&Job{},
&JobList{},
&RefList{},
)
return nil
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
@@ -1,42 +0,0 @@
package v0alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Summary shows a view of the configuration that is sanitized and is OK for logged in users to see
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type RepositoryViewList struct {
metav1.TypeMeta `json:",inline"`
// The backend is using legacy storage
// FIXME: Not sure where this should be exposed... but we need it somewhere
// The UI should force the onboarding workflow when this is true
LegacyStorage bool `json:"legacyStorage,omitempty"`
// AvailableRepositoryTypes is the list of repository types supported in this instance (e.g. git, bitbucket, github, etc)
AvailableRepositoryTypes []RepositoryType `json:"availableRepositoryTypes,omitempty"`
// +mapType=atomic
Items []RepositoryView `json:"items"`
}
type RepositoryView struct {
// The k8s name for this repository
Name string `json:"name"`
// Repository display
Title string `json:"title"`
// The repository type
Type RepositoryType `json:"type"`
// When syncing, where values are saved
Target SyncTargetType `json:"target"`
// For git, this is the target branch
Branch string `json:"branch,omitempty"`
// The supported workflows
Workflows []Workflow `json:"workflows"`
}
-525
View File
@@ -1,525 +0,0 @@
package v0alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
"github.com/grafana/grafana/pkg/apimachinery/utils"
)
// 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"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec RepositorySpec `json:"spec,omitempty"`
Status RepositoryStatus `json:"status,omitempty"`
}
type LocalRepositoryConfig struct {
Path string `json:"path,omitempty"`
}
// Workflow used for changes in the repository.
// +enum
type Workflow string
const (
// WriteWorkflow allows a user to write directly to the repository
WriteWorkflow Workflow = "write"
// BranchWorkflow creates a branch for changes
BranchWorkflow Workflow = "branch"
)
type GitHubRepositoryConfig struct {
// The repository URL (e.g. `https://github.com/example/test`).
URL string `json:"url,omitempty"`
// The branch to use in the repository.
Branch string `json:"branch"`
// Token for accessing the repository. If set, it will be encrypted into encryptedToken, then set to an empty string again.
Token string `json:"token,omitempty"`
// Token for accessing the repository, but encrypted. This is not possible to read back to a user decrypted.
// +listType=atomic
EncryptedToken []byte `json:"encryptedToken,omitempty"`
// Whether we should show dashboard previews for pull requests.
// By default, this is false (i.e. we will not create previews).
GenerateDashboardPreviews bool `json:"generateDashboardPreviews,omitempty"`
// Path is the subdirectory for the Grafana data. If specified, Grafana will ignore anything that is outside this directory in the repository.
// This is usually something like `grafana/`. Trailing and leading slash are not required. They are always added when needed.
// The path is relative to the root of the repository, regardless of the leading slash.
//
// When specifying something like `grafana-`, we will not look for `grafana-*`; we will only look for files under the directory `/grafana-/`. That means `/grafana-example.json` would not be found.
Path string `json:"path,omitempty"`
}
type GitRepositoryConfig struct {
// The repository URL (e.g. `https://github.com/example/test.git`).
URL string `json:"url,omitempty"`
// The branch to use in the repository.
Branch string `json:"branch"`
// TokenUser is the user that will be used to access the repository if it's a personal access token.
TokenUser string `json:"tokenUser,omitempty"`
// Token for accessing the repository. If set, it will be encrypted into encryptedToken, then set to an empty string again.
Token string `json:"token,omitempty"`
// Token for accessing the repository, but encrypted. This is not possible to read back to a user decrypted.
// +listType=atomic
EncryptedToken []byte `json:"encryptedToken,omitempty"`
// Path is the subdirectory for the Grafana data. If specified, Grafana will ignore anything that is outside this directory in the repository.
// This is usually something like `grafana/`. Trailing and leading slash are not required. They are always added when needed.
// The path is relative to the root of the repository, regardless of the leading slash.
//
// When specifying something like `grafana-`, we will not look for `grafana-*`; we will only look for files under the directory `/grafana-/`. That means `/grafana-example.json` would not be found.
Path string `json:"path,omitempty"`
}
type BitbucketRepositoryConfig struct {
// The repository URL (e.g. `https://bitbucket.org/example/test`).
URL string `json:"url,omitempty"`
// The branch to use in the repository.
Branch string `json:"branch"`
// TokenUser is the user that will be used to access the repository if it's a personal access token.
TokenUser string `json:"tokenUser,omitempty"`
// Token for accessing the repository. If set, it will be encrypted into encryptedToken, then set to an empty string again.
Token string `json:"token,omitempty"`
// Token for accessing the repository, but encrypted. This is not possible to read back to a user decrypted.
// +listType=atomic
EncryptedToken []byte `json:"encryptedToken,omitempty"`
// Path is the subdirectory for the Grafana data. If specified, Grafana will ignore anything that is outside this directory in the repository.
// This is usually something like `grafana/`. Trailing and leading slash are not required. They are always added when needed.
// The path is relative to the root of the repository, regardless of the leading slash.
//
// When specifying something like `grafana-`, we will not look for `grafana-*`; we will only look for files under the directory `/grafana-/`. That means `/grafana-example.json` would not be found.
Path string `json:"path,omitempty"`
}
type GitLabRepositoryConfig struct {
// The repository URL (e.g. `https://gitlab.com/example/test`).
URL string `json:"url,omitempty"`
// The branch to use in the repository.
Branch string `json:"branch"`
// Token for accessing the repository. If set, it will be encrypted into encryptedToken, then set to an empty string again.
Token string `json:"token,omitempty"`
// Token for accessing the repository, but encrypted. This is not possible to read back to a user decrypted.
// +listType=atomic
EncryptedToken []byte `json:"encryptedToken,omitempty"`
// Path is the subdirectory for the Grafana data. If specified, Grafana will ignore anything that is outside this directory in the repository.
// This is usually something like `grafana/`. Trailing and leading slash are not required. They are always added when needed.
// The path is relative to the root of the repository, regardless of the leading slash.
//
// When specifying something like `grafana-`, we will not look for `grafana-*`; we will only look for files under the directory `/grafana-/`. That means `/grafana-example.json` would not be found.
Path string `json:"path,omitempty"`
}
// RepositoryType defines the types of Repository
// +enum
type RepositoryType string
// RepositoryType values
const (
LocalRepositoryType RepositoryType = "local"
GitHubRepositoryType RepositoryType = "github"
GitRepositoryType RepositoryType = "git"
BitbucketRepositoryType RepositoryType = "bitbucket"
GitLabRepositoryType RepositoryType = "gitlab"
)
// IsGit returns true if the repository type is git or github
func (r RepositoryType) IsGit() bool {
return r == GitRepositoryType || r == GitHubRepositoryType || r == BitbucketRepositoryType || r == GitLabRepositoryType
}
type RepositorySpec struct {
// The repository display name (shown in the UI)
Title string `json:"title"`
// Repository description
Description string `json:"description,omitempty"`
// UI driven Workflow that allow changes to the contends of the repository.
// The order is relevant for defining the precedence of the workflows.
// When empty, the repository does not support any edits (eg, readonly)
Workflows []Workflow `json:"workflows"`
// Sync settings -- how values are pulled from the repository into grafana
Sync SyncOptions `json:"sync"`
// The repository type. When selected oneOf the values below should be non-nil
Type RepositoryType `json:"type"`
// The repository on the local file system.
// Mutually exclusive with local | github.
Local *LocalRepositoryConfig `json:"local,omitempty"`
// The repository on GitHub.
// Mutually exclusive with local | github | git.
GitHub *GitHubRepositoryConfig `json:"github,omitempty"`
// The repository on Git.
// Mutually exclusive with local | github | git.
Git *GitRepositoryConfig `json:"git,omitempty"`
// The repository on Bitbucket.
// Mutually exclusive with local | github | git.
Bitbucket *BitbucketRepositoryConfig `json:"bitbucket,omitempty"`
// The repository on GitLab.
// Mutually exclusive with local | github | git.
GitLab *GitLabRepositoryConfig `json:"gitlab,omitempty"`
}
// SyncTargetType defines where we want all values to resolve
// +enum
type SyncTargetType string
// RepositoryType values
const (
// Resources are saved in the global context
// Only one repository may specify the `instance` target
// When this exists, the UI will promote writing to the instance repo
// rather than the grafana database (where possible)
SyncTargetTypeInstance SyncTargetType = "instance"
// Resources will be saved into a folder managed by this repository
// It will contain a copy of everything from the remote
// The folder k8s name will be the same as the repository k8s name
SyncTargetTypeFolder SyncTargetType = "folder"
)
type SyncOptions struct {
// Enabled must be saved as true before any sync job will run
Enabled bool `json:"enabled"`
// Where values should be saved
Target SyncTargetType `json:"target"`
// Shared folder target
// The value is a reference to the Kubernetes metadata name of the folder in the same namespace
// Folder string `json:"folder,omitempty"`
// When non-zero, the sync will run periodically
IntervalSeconds int64 `json:"intervalSeconds,omitempty"`
}
// 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 RepositoryStatus struct {
// The generation of the spec last time reconciliation ran
ObservedGeneration int64 `json:"observedGeneration"`
// This will get updated with the current health status (and updated periodically)
Health HealthStatus `json:"health"`
// Sync information with the last sync information
Sync SyncStatus `json:"sync"`
// The object count when sync last ran
// +listType=atomic
Stats []ResourceCount `json:"stats,omitempty"`
// Webhook Information (if applicable)
Webhook *WebhookStatus `json:"webhook"`
}
type HealthStatus struct {
// When not healthy, requests will not be executed
Healthy bool `json:"healthy"`
// When the health was checked last time
Checked int64 `json:"checked,omitempty"`
// Summary messages (can be shown to users)
// Will only be populated when not healthy
// +listType=atomic
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)
// +listType=atomic
Message []string `json:"message"`
// The repository ref when the last successful sync ran
LastRef string `json:"lastRef,omitempty"`
// Incremental synchronization for versioned repositories
Incremental bool `json:"incremental,omitempty"`
}
type WebhookStatus struct {
ID int64 `json:"id,omitempty"`
URL string `json:"url,omitempty"`
Secret string `json:"secret,omitempty"`
EncryptedSecret []byte `json:"encryptedSecret,omitempty"`
SubscribedEvents []string `json:"subscribedEvents,omitempty"`
LastEvent int64 `json:"lastEvent,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type RepositoryList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
// +listType=atomic
Items []Repository `json:"items"`
}
// The kubernetes action required when loading a given resource
// +enum
type ResourceAction string
// ResourceAction values
const (
ResourceActionCreate ResourceAction = "create"
ResourceActionUpdate ResourceAction = "update"
ResourceActionDelete ResourceAction = "delete"
ResourceActionMove ResourceAction = "move"
)
// This is a container type for any resource type
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type ResourceWrapper struct {
metav1.TypeMeta `json:",inline"`
// Path to the remote file
Path string `json:"path,omitempty"`
// The request ref (or branch if exists)
Ref string `json:"ref,omitempty"`
// The repo hash value
Hash string `json:"hash,omitempty"`
// Basic repository info
Repository ResourceRepositoryInfo `json:"repository"`
// Typed links for this file (only supported by external systems, github etc)
URLs *ResourceURLs `json:"urls,omitempty"`
// The modified time in the remote file system
Timestamp *metav1.Time `json:"timestamp,omitempty"`
// Different flavors of the same object
Resource ResourceObjects `json:"resource"`
// If errors exist, show them here
// +listType=atomic
Errors []string `json:"errors,omitempty"`
}
type ResourceType struct {
Group string `json:"group,omitempty"`
Version string `json:"version,omitempty"`
Kind string `json:"kind,omitempty"`
Resource string `json:"resource,omitempty"`
// For non-k8s native formats, what did this start as
Classic ClassicFileType `json:"classic,omitempty"`
}
type ResourceObjects struct {
// The identified type for this object
Type ResourceType `json:"type"`
// The resource from the repository with all modifications applied
// eg, the name, folder etc will all be applied to this object
File common.Unstructured `json:"file,omitempty"`
// The same value, currently saved in the grafana database
Existing common.Unstructured `json:"existing,omitempty"`
// The action required/used for dryRun
Action ResourceAction `json:"action,omitempty"`
// The value returned from a dryRun request
DryRun common.Unstructured `json:"dryRun,omitempty"`
// For write events, this will return the value that was added or updated
Upsert common.Unstructured `json:"upsert,omitempty"`
}
type ResourceRepositoryInfo struct {
// The repository type
Type RepositoryType `json:"type"`
// The display name for this repository
Title string `json:"title"`
// The namespace this belongs to
Namespace string `json:"namespace"`
// The name (identifier)
Name string `json:"name"`
}
type ResourceURLs struct {
// A URL pointing to the this file in the repository
SourceURL string `json:"sourceURL,omitempty"`
// A URL pointing to the repository this lives in
RepositoryURL string `json:"repositoryURL,omitempty"`
// A URL that will create a new pull requeset for this branch
NewPullRequestURL string `json:"newPullRequestURL,omitempty"`
// Compare this version to the target branch
CompareURL string `json:"compareURL,omitempty"`
}
// Information we can get just from the file listing
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type FileList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
// +listType=atomic
Items []FileItem `json:"items"`
}
type FileItem struct {
Path string `json:"path"`
Size int64 `json:"size,omitempty"`
Hash string `json:"hash,omitempty"`
Modified int64 `json:"modified,omitempty"`
Author string `json:"author,omitempty"`
}
// Information we can get just from the file listing
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type ResourceList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
// +listType=atomic
Items []ResourceListItem `json:"items"`
}
type ResourceListItem struct {
Path string `json:"path"`
Group string `json:"group"`
Resource string `json:"resource"`
Name string `json:"name"` // the k8s identifier
Hash string `json:"hash"`
Time int64 `json:"time,omitempty"`
Title string `json:"title,omitempty"`
Folder string `json:"folder,omitempty"`
}
// Information we can get just from the file listing
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type ResourceStats struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
// Stats across all unified storage
// When legacy storage is still used, this will offer a shim
// +listType=atomic
Instance []ResourceCount `json:"instance,omitempty"`
// Stats for each manager
// +listType=atomic
Managed []ManagerStats `json:"managed,omitempty"`
}
type ManagerStats struct {
// Manager kind
Kind utils.ManagerKind `json:"kind,omitempty"`
// Manager identity
Identity string `json:"id,omitempty"`
// stats
Stats []ResourceCount `json:"stats"`
}
type ResourceCount struct {
Group string `json:"group"`
Resource string `json:"resource"`
Count int64 `json:"count"`
}
// HistoryList is a list of versions of a resource
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type TestResults struct {
metav1.TypeMeta `json:",inline"`
// HTTP status code
Code int `json:"code"`
// Is the connection healthy
Success bool `json:"success"`
// Field related errors
Errors []ErrorDetails `json:"errors,omitempty"`
}
type ErrorDetails struct {
Type metav1.CauseType `json:"type"`
Field string `json:"field,omitempty"`
Detail string `json:"detail,omitempty"`
}
// HistoryList is a list of versions of a resource
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type HistoryList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
// +listType=atomic
Items []HistoryItem `json:"items"`
}
type Author struct {
Name string `json:"name"`
Username string `json:"username"`
AvatarURL string `json:"avatarURL,omitempty"`
}
type HistoryItem struct {
Ref string `json:"ref"`
Message string `json:"message"`
// +listType=atomic
Authors []Author `json:"authors"`
CreatedAt int64 `json:"createdAt"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type RefList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
// +listType=atomic
Items []RefItem `json:"items"`
}
type RefItem struct {
// The name of the reference (branch or tag)
Name string `json:"name"`
// The SHA hash of the commit this ref points to
Hash string `json:"hash,omitempty"`
// The URL to the reference (branch or tag)
RefURL string `json:"refURL,omitempty"`
}
@@ -1,50 +0,0 @@
package v0alpha1_test
import (
"testing"
"github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
)
func TestRepositoryType_IsGit(t *testing.T) {
tests := []struct {
name string
repoType v0alpha1.RepositoryType
want bool
}{
{
name: "git",
repoType: v0alpha1.GitRepositoryType,
want: true,
},
{
name: "github",
repoType: v0alpha1.GitHubRepositoryType,
want: true,
},
{
name: "bitbucket",
repoType: v0alpha1.BitbucketRepositoryType,
want: true,
},
{
name: "gitlab",
repoType: v0alpha1.GitLabRepositoryType,
want: true,
},
{
name: "local",
repoType: v0alpha1.LocalRepositoryType,
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.repoType.IsGit()
if got != tt.want {
t.Errorf("IsGit() = %v, want %v", got, tt.want)
}
})
}
}
File diff suppressed because it is too large Load Diff
@@ -1,19 +0,0 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by defaulter-gen. DO NOT EDIT.
package v0alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}
File diff suppressed because it is too large Load Diff
@@ -1,26 +0,0 @@
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,DeleteJobOptions,Paths
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,DeleteJobOptions,Resources
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,FileList,Items
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,HistoryList,Items
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,JobResourceSummary,Errors
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,JobStatus,Summary
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,ManagerStats,Stats
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,MoveJobOptions,Paths
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,MoveJobOptions,Resources
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,RefList,Items
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,RepositoryList,Items
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,RepositorySpec,Workflows
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,RepositoryView,Workflows
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,RepositoryViewList,AvailableRepositoryTypes
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,RepositoryViewList,Items
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,ResourceList,Items
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,TestResults,Errors
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,WebhookStatus,SubscribedEvents
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,JobSpec,PullRequest
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,ManagerStats,Identity
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,GitLab
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,ResourceWrapper,URLs
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