mirror of https://github.com/grafana/grafana
Alerting: Time Intervals API (#88201)
* expose ngalert API to public * add delete action to time-intervals * introduce time-interval model generated by app-platform-sdk from CUE model the fields of the model are chosen to be compatible with the current model * implement api server * add feature flag alertingApiServer ---- Test Infra * update helper to support creating custom users with enterprise permissions * add generator for Interval modelpull/89522/head
parent
3228b64fe6
commit
b075926202
@ -0,0 +1 @@ |
|||||||
|
module:"notifications" |
@ -0,0 +1,37 @@ |
|||||||
|
package core |
||||||
|
|
||||||
|
timeInterval: { |
||||||
|
kind: "TimeInterval" |
||||||
|
group: "notifications" |
||||||
|
apiResource: { |
||||||
|
groupOverride: "notifications.alerting.grafana.app" |
||||||
|
} |
||||||
|
codegen: { |
||||||
|
frontend: false |
||||||
|
backend: true |
||||||
|
} |
||||||
|
pluralName: "TimeIntervals" |
||||||
|
current: "v0alpha1" |
||||||
|
versions: { |
||||||
|
"v0alpha1": { |
||||||
|
schema: { |
||||||
|
#TimeRange: { |
||||||
|
start_time: string |
||||||
|
end_time: string |
||||||
|
} |
||||||
|
#Interval: { |
||||||
|
times?: [...#TimeRange] |
||||||
|
weekdays?: [...string] |
||||||
|
days_of_month?: [...string] |
||||||
|
months?: [...string] |
||||||
|
years?: [...string] |
||||||
|
location?: string |
||||||
|
} |
||||||
|
spec: { |
||||||
|
name: string |
||||||
|
time_intervals: [...#Interval] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:openapi-gen=true
|
||||||
|
// +k8s:defaulter-gen=TypeMeta
|
||||||
|
// +groupName=notifications.alerting.grafana.app
|
||||||
|
|
||||||
|
package v0alpha1 // import "github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1"
|
@ -0,0 +1,53 @@ |
|||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
import ( |
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||||
|
"k8s.io/apimachinery/pkg/runtime" |
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema" |
||||||
|
|
||||||
|
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" |
||||||
|
) |
||||||
|
|
||||||
|
func init() { |
||||||
|
localSchemeBuilder.Register(AddKnownTypes) |
||||||
|
} |
||||||
|
|
||||||
|
const ( |
||||||
|
GROUP = "notifications.alerting.grafana.app" |
||||||
|
VERSION = "v0alpha1" |
||||||
|
APIVERSION = GROUP + "/" + VERSION |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
TimeIntervalResourceInfo = common.NewResourceInfo(GROUP, VERSION, |
||||||
|
"timeintervals", "timeinterval", "TimeIntervals", |
||||||
|
func() runtime.Object { return &TimeInterval{} }, |
||||||
|
func() runtime.Object { return &TimeIntervalList{} }, |
||||||
|
) |
||||||
|
// SchemeGroupVersion is group version used to register these objects
|
||||||
|
SchemeGroupVersion = schema.GroupVersion{Group: GROUP, Version: VERSION} |
||||||
|
// SchemaBuilder is used by standard codegen
|
||||||
|
SchemeBuilder runtime.SchemeBuilder |
||||||
|
localSchemeBuilder = &SchemeBuilder |
||||||
|
AddToScheme = localSchemeBuilder.AddToScheme |
||||||
|
) |
||||||
|
|
||||||
|
// Adds the list of known types to the given scheme.
|
||||||
|
func AddKnownTypes(scheme *runtime.Scheme) error { |
||||||
|
return AddKnownTypesGroup(scheme, SchemeGroupVersion) |
||||||
|
} |
||||||
|
|
||||||
|
// Adds the list of known types to the given scheme and group version.
|
||||||
|
func AddKnownTypesGroup(scheme *runtime.Scheme, g schema.GroupVersion) error { |
||||||
|
scheme.AddKnownTypes(g, |
||||||
|
&TimeInterval{}, |
||||||
|
&TimeIntervalList{}, |
||||||
|
) |
||||||
|
metav1.AddToGroupVersion(scheme, g) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||||
|
func Resource(resource string) schema.GroupResource { |
||||||
|
return SchemeGroupVersion.WithResource(resource).GroupResource() |
||||||
|
} |
@ -0,0 +1,115 @@ |
|||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"math/rand" |
||||||
|
"slices" |
||||||
|
"strings" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/util" |
||||||
|
) |
||||||
|
|
||||||
|
// +k8s:openapi-gen=false
|
||||||
|
// +k8s:deepcopy-gen=false
|
||||||
|
type IntervalMutator func(spec *Interval) |
||||||
|
|
||||||
|
// +k8s:openapi-gen=false
|
||||||
|
// +k8s:deepcopy-gen=false
|
||||||
|
type IntervalGenerator struct { |
||||||
|
mutators []IntervalMutator |
||||||
|
} |
||||||
|
|
||||||
|
func (t IntervalGenerator) With(mutators ...IntervalMutator) IntervalGenerator { |
||||||
|
return IntervalGenerator{ |
||||||
|
mutators: append(t.mutators, mutators...), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (t IntervalGenerator) generateDaysOfMonth() string { |
||||||
|
isRange := rand.Int()%2 == 0 |
||||||
|
if !isRange { |
||||||
|
return fmt.Sprintf("%d", rand.Intn(30)+1) |
||||||
|
} |
||||||
|
from := rand.Intn(15) + 1 |
||||||
|
to := rand.Intn(31-from) + from + 1 |
||||||
|
return fmt.Sprintf("%d:%d", from, to) |
||||||
|
} |
||||||
|
|
||||||
|
func (t IntervalGenerator) generateTimeRange() TimeRange { |
||||||
|
from := rand.Int63n(1440 / 2) // [0, 719]
|
||||||
|
to := from + rand.Int63n(1440/2) + 1 // from < ([0,719] + [1,720]) < 1440
|
||||||
|
return TimeRange{ |
||||||
|
StartTime: time.Unix(from*60, 0).UTC().Format("15:04"), |
||||||
|
EndTime: time.Unix(to*60, 0).UTC().Format("15:04"), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (t IntervalGenerator) generateWeekday() string { |
||||||
|
day := rand.Intn(7) |
||||||
|
return strings.ToLower(time.Weekday(day).String()) |
||||||
|
} |
||||||
|
|
||||||
|
func (t IntervalGenerator) generateYear() string { |
||||||
|
from := 1970 + rand.Intn(100) |
||||||
|
if rand.Int()%3 == 0 { |
||||||
|
to := 1970 + from + rand.Intn(10) + 1 |
||||||
|
return fmt.Sprintf("%d:%d", from, to) |
||||||
|
} |
||||||
|
return fmt.Sprintf("%d", from) |
||||||
|
} |
||||||
|
|
||||||
|
func (t IntervalGenerator) generateLocation() *string { |
||||||
|
if rand.Int()%3 == 0 { |
||||||
|
return nil |
||||||
|
} |
||||||
|
return util.Pointer("UTC") |
||||||
|
} |
||||||
|
|
||||||
|
func (t IntervalGenerator) generateMonth() string { |
||||||
|
return fmt.Sprintf("%d", rand.Intn(12)+1) |
||||||
|
} |
||||||
|
|
||||||
|
func (t IntervalGenerator) GenerateMany(count int) []Interval { |
||||||
|
result := make([]Interval, 0, count) |
||||||
|
for i := 0; i < count; i++ { |
||||||
|
result = append(result, t.Generate()) |
||||||
|
} |
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
func (t IntervalGenerator) Generate() Interval { |
||||||
|
i := Interval{ |
||||||
|
DaysOfMonth: generateMany(rand.Intn(6), true, t.generateDaysOfMonth), |
||||||
|
Location: t.generateLocation(), |
||||||
|
Months: generateMany(rand.Intn(3), true, t.generateMonth), |
||||||
|
Times: generateMany(rand.Intn(6), true, t.generateTimeRange), |
||||||
|
Weekdays: generateMany(rand.Intn(3), true, t.generateWeekday), |
||||||
|
Years: generateMany(rand.Intn(3), true, t.generateYear), |
||||||
|
} |
||||||
|
for _, mutator := range t.mutators { |
||||||
|
mutator(&i) |
||||||
|
} |
||||||
|
return i |
||||||
|
} |
||||||
|
|
||||||
|
func generateMany[T comparable](repeatTimes int, unique bool, f func() T) []T { |
||||||
|
qty := repeatTimes + 1 |
||||||
|
result := make([]T, 0, qty) |
||||||
|
for i := 0; i < qty; i++ { |
||||||
|
r := f() |
||||||
|
if unique && slices.Contains(result, r) { |
||||||
|
continue |
||||||
|
} |
||||||
|
result = append(result, f()) |
||||||
|
} |
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
func CopyWith(in Interval, mutators ...IntervalMutator) Interval { |
||||||
|
r := *in.DeepCopy() |
||||||
|
for _, mut := range mutators { |
||||||
|
mut(&r) |
||||||
|
} |
||||||
|
return r |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
// Interval defines model for Interval.
|
||||||
|
// +k8s:openapi-gen=true
|
||||||
|
type Interval struct { |
||||||
|
// +listType=atomic
|
||||||
|
DaysOfMonth []string `json:"days_of_month,omitempty"` |
||||||
|
|
||||||
|
// +listType=atomic
|
||||||
|
Location *string `json:"location,omitempty"` |
||||||
|
|
||||||
|
// +listType=atomic
|
||||||
|
Months []string `json:"months,omitempty"` |
||||||
|
|
||||||
|
// +listType=atomic
|
||||||
|
Times []TimeRange `json:"times,omitempty"` |
||||||
|
|
||||||
|
// +listType=atomic
|
||||||
|
Weekdays []string `json:"weekdays,omitempty"` |
||||||
|
|
||||||
|
// +listType=atomic
|
||||||
|
Years []string `json:"years,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
// Spec defines model for Spec.
|
||||||
|
// +k8s:openapi-gen=true
|
||||||
|
type TimeIntervalSpec struct { |
||||||
|
Name string `json:"name"` |
||||||
|
// +listType=atomic
|
||||||
|
TimeIntervals []Interval `json:"time_intervals"` |
||||||
|
} |
||||||
|
|
||||||
|
// TimeRange defines model for TimeRange.
|
||||||
|
// +k8s:openapi-gen=true
|
||||||
|
type TimeRange struct { |
||||||
|
EndTime string `json:"end_time"` |
||||||
|
StartTime string `json:"start_time"` |
||||||
|
} |
@ -0,0 +1,87 @@ |
|||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"time" |
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||||
|
) |
||||||
|
|
||||||
|
// +genclient
|
||||||
|
// +k8s:openapi-gen=true
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
type TimeInterval struct { |
||||||
|
metav1.TypeMeta `json:",inline"` |
||||||
|
metav1.ObjectMeta `json:"metadata"` |
||||||
|
Spec TimeIntervalSpec `json:"spec"` |
||||||
|
} |
||||||
|
|
||||||
|
func (o *TimeInterval) GetSpec() any { |
||||||
|
return o.Spec |
||||||
|
} |
||||||
|
|
||||||
|
func (o *TimeInterval) SetSpec(spec any) error { |
||||||
|
cast, ok := spec.(TimeIntervalSpec) |
||||||
|
if !ok { |
||||||
|
return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec) |
||||||
|
} |
||||||
|
o.Spec = cast |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (o *TimeInterval) GetCreatedBy() string { |
||||||
|
if o.ObjectMeta.Annotations == nil { |
||||||
|
o.ObjectMeta.Annotations = make(map[string]string) |
||||||
|
} |
||||||
|
|
||||||
|
return o.ObjectMeta.Annotations["grafana.com/createdBy"] |
||||||
|
} |
||||||
|
|
||||||
|
func (o *TimeInterval) SetCreatedBy(createdBy string) { |
||||||
|
if o.ObjectMeta.Annotations == nil { |
||||||
|
o.ObjectMeta.Annotations = make(map[string]string) |
||||||
|
} |
||||||
|
|
||||||
|
o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy |
||||||
|
} |
||||||
|
|
||||||
|
func (o *TimeInterval) GetUpdateTimestamp() time.Time { |
||||||
|
if o.ObjectMeta.Annotations == nil { |
||||||
|
o.ObjectMeta.Annotations = make(map[string]string) |
||||||
|
} |
||||||
|
|
||||||
|
parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"]) |
||||||
|
return parsed |
||||||
|
} |
||||||
|
|
||||||
|
func (o *TimeInterval) SetUpdateTimestamp(updateTimestamp time.Time) { |
||||||
|
if o.ObjectMeta.Annotations == nil { |
||||||
|
o.ObjectMeta.Annotations = make(map[string]string) |
||||||
|
} |
||||||
|
|
||||||
|
o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339) |
||||||
|
} |
||||||
|
|
||||||
|
func (o *TimeInterval) GetUpdatedBy() string { |
||||||
|
if o.ObjectMeta.Annotations == nil { |
||||||
|
o.ObjectMeta.Annotations = make(map[string]string) |
||||||
|
} |
||||||
|
|
||||||
|
return o.ObjectMeta.Annotations["grafana.com/updatedBy"] |
||||||
|
} |
||||||
|
|
||||||
|
func (o *TimeInterval) SetUpdatedBy(updatedBy string) { |
||||||
|
if o.ObjectMeta.Annotations == nil { |
||||||
|
o.ObjectMeta.Annotations = make(map[string]string) |
||||||
|
} |
||||||
|
|
||||||
|
o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy |
||||||
|
} |
||||||
|
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
// +k8s:openapi-gen=true
|
||||||
|
type TimeIntervalList struct { |
||||||
|
metav1.TypeMeta `json:",inline"` |
||||||
|
metav1.ListMeta `json:"metadata"` |
||||||
|
Items []TimeInterval `json:"items"` |
||||||
|
} |
@ -0,0 +1,157 @@ |
|||||||
|
//go:build !ignore_autogenerated
|
||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
import ( |
||||||
|
runtime "k8s.io/apimachinery/pkg/runtime" |
||||||
|
) |
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Interval) DeepCopyInto(out *Interval) { |
||||||
|
*out = *in |
||||||
|
if in.DaysOfMonth != nil { |
||||||
|
in, out := &in.DaysOfMonth, &out.DaysOfMonth |
||||||
|
*out = make([]string, len(*in)) |
||||||
|
copy(*out, *in) |
||||||
|
} |
||||||
|
if in.Location != nil { |
||||||
|
in, out := &in.Location, &out.Location |
||||||
|
*out = new(string) |
||||||
|
**out = **in |
||||||
|
} |
||||||
|
if in.Months != nil { |
||||||
|
in, out := &in.Months, &out.Months |
||||||
|
*out = make([]string, len(*in)) |
||||||
|
copy(*out, *in) |
||||||
|
} |
||||||
|
if in.Times != nil { |
||||||
|
in, out := &in.Times, &out.Times |
||||||
|
*out = make([]TimeRange, len(*in)) |
||||||
|
copy(*out, *in) |
||||||
|
} |
||||||
|
if in.Weekdays != nil { |
||||||
|
in, out := &in.Weekdays, &out.Weekdays |
||||||
|
*out = make([]string, len(*in)) |
||||||
|
copy(*out, *in) |
||||||
|
} |
||||||
|
if in.Years != nil { |
||||||
|
in, out := &in.Years, &out.Years |
||||||
|
*out = make([]string, len(*in)) |
||||||
|
copy(*out, *in) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Interval.
|
||||||
|
func (in *Interval) DeepCopy() *Interval { |
||||||
|
if in == nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
out := new(Interval) |
||||||
|
in.DeepCopyInto(out) |
||||||
|
return out |
||||||
|
} |
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *TimeInterval) DeepCopyInto(out *TimeInterval) { |
||||||
|
*out = *in |
||||||
|
out.TypeMeta = in.TypeMeta |
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) |
||||||
|
in.Spec.DeepCopyInto(&out.Spec) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TimeInterval.
|
||||||
|
func (in *TimeInterval) DeepCopy() *TimeInterval { |
||||||
|
if in == nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
out := new(TimeInterval) |
||||||
|
in.DeepCopyInto(out) |
||||||
|
return out |
||||||
|
} |
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *TimeInterval) DeepCopyObject() runtime.Object { |
||||||
|
if c := in.DeepCopy(); c != nil { |
||||||
|
return c |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *TimeIntervalList) DeepCopyInto(out *TimeIntervalList) { |
||||||
|
*out = *in |
||||||
|
out.TypeMeta = in.TypeMeta |
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta) |
||||||
|
if in.Items != nil { |
||||||
|
in, out := &in.Items, &out.Items |
||||||
|
*out = make([]TimeInterval, len(*in)) |
||||||
|
for i := range *in { |
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i]) |
||||||
|
} |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TimeIntervalList.
|
||||||
|
func (in *TimeIntervalList) DeepCopy() *TimeIntervalList { |
||||||
|
if in == nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
out := new(TimeIntervalList) |
||||||
|
in.DeepCopyInto(out) |
||||||
|
return out |
||||||
|
} |
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *TimeIntervalList) DeepCopyObject() runtime.Object { |
||||||
|
if c := in.DeepCopy(); c != nil { |
||||||
|
return c |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *TimeIntervalSpec) DeepCopyInto(out *TimeIntervalSpec) { |
||||||
|
*out = *in |
||||||
|
if in.TimeIntervals != nil { |
||||||
|
in, out := &in.TimeIntervals, &out.TimeIntervals |
||||||
|
*out = make([]Interval, len(*in)) |
||||||
|
for i := range *in { |
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i]) |
||||||
|
} |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TimeIntervalSpec.
|
||||||
|
func (in *TimeIntervalSpec) DeepCopy() *TimeIntervalSpec { |
||||||
|
if in == nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
out := new(TimeIntervalSpec) |
||||||
|
in.DeepCopyInto(out) |
||||||
|
return out |
||||||
|
} |
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *TimeRange) DeepCopyInto(out *TimeRange) { |
||||||
|
*out = *in |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TimeRange.
|
||||||
|
func (in *TimeRange) DeepCopy() *TimeRange { |
||||||
|
if in == nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
out := new(TimeRange) |
||||||
|
in.DeepCopyInto(out) |
||||||
|
return out |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
//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 |
||||||
|
} |
@ -0,0 +1,303 @@ |
|||||||
|
//go:build !ignore_autogenerated
|
||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
// Code generated by openapi-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file was autogenerated by openapi-gen. Do not edit it manually!
|
||||||
|
|
||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
import ( |
||||||
|
common "k8s.io/kube-openapi/pkg/common" |
||||||
|
spec "k8s.io/kube-openapi/pkg/validation/spec" |
||||||
|
) |
||||||
|
|
||||||
|
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { |
||||||
|
return map[string]common.OpenAPIDefinition{ |
||||||
|
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.Interval": schema_pkg_apis_alerting_notifications_v0alpha1_Interval(ref), |
||||||
|
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.TimeInterval": schema_pkg_apis_alerting_notifications_v0alpha1_TimeInterval(ref), |
||||||
|
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.TimeIntervalList": schema_pkg_apis_alerting_notifications_v0alpha1_TimeIntervalList(ref), |
||||||
|
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.TimeIntervalSpec": schema_pkg_apis_alerting_notifications_v0alpha1_TimeIntervalSpec(ref), |
||||||
|
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.TimeRange": schema_pkg_apis_alerting_notifications_v0alpha1_TimeRange(ref), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func schema_pkg_apis_alerting_notifications_v0alpha1_Interval(ref common.ReferenceCallback) common.OpenAPIDefinition { |
||||||
|
return common.OpenAPIDefinition{ |
||||||
|
Schema: spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Description: "Interval defines model for Interval.", |
||||||
|
Type: []string{"object"}, |
||||||
|
Properties: map[string]spec.Schema{ |
||||||
|
"days_of_month": { |
||||||
|
VendorExtensible: spec.VendorExtensible{ |
||||||
|
Extensions: spec.Extensions{ |
||||||
|
"x-kubernetes-list-type": "atomic", |
||||||
|
}, |
||||||
|
}, |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Type: []string{"array"}, |
||||||
|
Items: &spec.SchemaOrArray{ |
||||||
|
Schema: &spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: "", |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
"location": { |
||||||
|
VendorExtensible: spec.VendorExtensible{ |
||||||
|
Extensions: spec.Extensions{ |
||||||
|
"x-kubernetes-list-type": "atomic", |
||||||
|
}, |
||||||
|
}, |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"months": { |
||||||
|
VendorExtensible: spec.VendorExtensible{ |
||||||
|
Extensions: spec.Extensions{ |
||||||
|
"x-kubernetes-list-type": "atomic", |
||||||
|
}, |
||||||
|
}, |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Type: []string{"array"}, |
||||||
|
Items: &spec.SchemaOrArray{ |
||||||
|
Schema: &spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: "", |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
"times": { |
||||||
|
VendorExtensible: spec.VendorExtensible{ |
||||||
|
Extensions: spec.Extensions{ |
||||||
|
"x-kubernetes-list-type": "atomic", |
||||||
|
}, |
||||||
|
}, |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Type: []string{"array"}, |
||||||
|
Items: &spec.SchemaOrArray{ |
||||||
|
Schema: &spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: map[string]interface{}{}, |
||||||
|
Ref: ref("github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.TimeRange"), |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
"weekdays": { |
||||||
|
VendorExtensible: spec.VendorExtensible{ |
||||||
|
Extensions: spec.Extensions{ |
||||||
|
"x-kubernetes-list-type": "atomic", |
||||||
|
}, |
||||||
|
}, |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Type: []string{"array"}, |
||||||
|
Items: &spec.SchemaOrArray{ |
||||||
|
Schema: &spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: "", |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
"years": { |
||||||
|
VendorExtensible: spec.VendorExtensible{ |
||||||
|
Extensions: spec.Extensions{ |
||||||
|
"x-kubernetes-list-type": "atomic", |
||||||
|
}, |
||||||
|
}, |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Type: []string{"array"}, |
||||||
|
Items: &spec.SchemaOrArray{ |
||||||
|
Schema: &spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: "", |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
Dependencies: []string{ |
||||||
|
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.TimeRange"}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func schema_pkg_apis_alerting_notifications_v0alpha1_TimeInterval(ref common.ReferenceCallback) common.OpenAPIDefinition { |
||||||
|
return common.OpenAPIDefinition{ |
||||||
|
Schema: spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Type: []string{"object"}, |
||||||
|
Properties: map[string]spec.Schema{ |
||||||
|
"kind": { |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"apiVersion": { |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"metadata": { |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: map[string]interface{}{}, |
||||||
|
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), |
||||||
|
}, |
||||||
|
}, |
||||||
|
"spec": { |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: map[string]interface{}{}, |
||||||
|
Ref: ref("github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.TimeIntervalSpec"), |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
Required: []string{"metadata", "spec"}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
Dependencies: []string{ |
||||||
|
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.TimeIntervalSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func schema_pkg_apis_alerting_notifications_v0alpha1_TimeIntervalList(ref common.ReferenceCallback) common.OpenAPIDefinition { |
||||||
|
return common.OpenAPIDefinition{ |
||||||
|
Schema: spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Type: []string{"object"}, |
||||||
|
Properties: map[string]spec.Schema{ |
||||||
|
"kind": { |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"apiVersion": { |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"metadata": { |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: map[string]interface{}{}, |
||||||
|
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), |
||||||
|
}, |
||||||
|
}, |
||||||
|
"items": { |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Type: []string{"array"}, |
||||||
|
Items: &spec.SchemaOrArray{ |
||||||
|
Schema: &spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: map[string]interface{}{}, |
||||||
|
Ref: ref("github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.TimeInterval"), |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
Required: []string{"metadata", "items"}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
Dependencies: []string{ |
||||||
|
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.TimeInterval", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func schema_pkg_apis_alerting_notifications_v0alpha1_TimeIntervalSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { |
||||||
|
return common.OpenAPIDefinition{ |
||||||
|
Schema: spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Description: "Spec defines model for Spec.", |
||||||
|
Type: []string{"object"}, |
||||||
|
Properties: map[string]spec.Schema{ |
||||||
|
"name": { |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: "", |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"time_intervals": { |
||||||
|
VendorExtensible: spec.VendorExtensible{ |
||||||
|
Extensions: spec.Extensions{ |
||||||
|
"x-kubernetes-list-type": "atomic", |
||||||
|
}, |
||||||
|
}, |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Type: []string{"array"}, |
||||||
|
Items: &spec.SchemaOrArray{ |
||||||
|
Schema: &spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: map[string]interface{}{}, |
||||||
|
Ref: ref("github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.Interval"), |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
Required: []string{"name", "time_intervals"}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
Dependencies: []string{ |
||||||
|
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1.Interval"}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func schema_pkg_apis_alerting_notifications_v0alpha1_TimeRange(ref common.ReferenceCallback) common.OpenAPIDefinition { |
||||||
|
return common.OpenAPIDefinition{ |
||||||
|
Schema: spec.Schema{ |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Description: "TimeRange defines model for TimeRange.", |
||||||
|
Type: []string{"object"}, |
||||||
|
Properties: map[string]spec.Schema{ |
||||||
|
"end_time": { |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: "", |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"start_time": { |
||||||
|
SchemaProps: spec.SchemaProps{ |
||||||
|
Default: "", |
||||||
|
Type: []string{"string"}, |
||||||
|
Format: "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
Required: []string{"end_time", "start_time"}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1,Interval,DaysOfMonth |
||||||
|
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1,TimeIntervalSpec,TimeIntervals |
||||||
|
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1,TimeRange,EndTime |
||||||
|
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1,TimeRange,StartTime |
@ -0,0 +1,83 @@ |
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
// IntervalApplyConfiguration represents an declarative configuration of the Interval type for use
|
||||||
|
// with apply.
|
||||||
|
type IntervalApplyConfiguration struct { |
||||||
|
DaysOfMonth []string `json:"days_of_month,omitempty"` |
||||||
|
Location *string `json:"location,omitempty"` |
||||||
|
Months []string `json:"months,omitempty"` |
||||||
|
Times []TimeRangeApplyConfiguration `json:"times,omitempty"` |
||||||
|
Weekdays []string `json:"weekdays,omitempty"` |
||||||
|
Years []string `json:"years,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
// IntervalApplyConfiguration constructs an declarative configuration of the Interval type for use with
|
||||||
|
// apply.
|
||||||
|
func Interval() *IntervalApplyConfiguration { |
||||||
|
return &IntervalApplyConfiguration{} |
||||||
|
} |
||||||
|
|
||||||
|
// WithDaysOfMonth adds the given value to the DaysOfMonth 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 DaysOfMonth field.
|
||||||
|
func (b *IntervalApplyConfiguration) WithDaysOfMonth(values ...string) *IntervalApplyConfiguration { |
||||||
|
for i := range values { |
||||||
|
b.DaysOfMonth = append(b.DaysOfMonth, values[i]) |
||||||
|
} |
||||||
|
return b |
||||||
|
} |
||||||
|
|
||||||
|
// WithLocation sets the Location 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 Location field is set to the value of the last call.
|
||||||
|
func (b *IntervalApplyConfiguration) WithLocation(value string) *IntervalApplyConfiguration { |
||||||
|
b.Location = &value |
||||||
|
return b |
||||||
|
} |
||||||
|
|
||||||
|
// WithMonths adds the given value to the Months 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 Months field.
|
||||||
|
func (b *IntervalApplyConfiguration) WithMonths(values ...string) *IntervalApplyConfiguration { |
||||||
|
for i := range values { |
||||||
|
b.Months = append(b.Months, values[i]) |
||||||
|
} |
||||||
|
return b |
||||||
|
} |
||||||
|
|
||||||
|
// WithTimes adds the given value to the Times 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 Times field.
|
||||||
|
func (b *IntervalApplyConfiguration) WithTimes(values ...*TimeRangeApplyConfiguration) *IntervalApplyConfiguration { |
||||||
|
for i := range values { |
||||||
|
if values[i] == nil { |
||||||
|
panic("nil value passed to WithTimes") |
||||||
|
} |
||||||
|
b.Times = append(b.Times, *values[i]) |
||||||
|
} |
||||||
|
return b |
||||||
|
} |
||||||
|
|
||||||
|
// WithWeekdays adds the given value to the Weekdays 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 Weekdays field.
|
||||||
|
func (b *IntervalApplyConfiguration) WithWeekdays(values ...string) *IntervalApplyConfiguration { |
||||||
|
for i := range values { |
||||||
|
b.Weekdays = append(b.Weekdays, values[i]) |
||||||
|
} |
||||||
|
return b |
||||||
|
} |
||||||
|
|
||||||
|
// WithYears adds the given value to the Years 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 Years field.
|
||||||
|
func (b *IntervalApplyConfiguration) WithYears(values ...string) *IntervalApplyConfiguration { |
||||||
|
for i := range values { |
||||||
|
b.Years = append(b.Years, values[i]) |
||||||
|
} |
||||||
|
return b |
||||||
|
} |
@ -0,0 +1,196 @@ |
|||||||
|
// 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" |
||||||
|
) |
||||||
|
|
||||||
|
// TimeIntervalApplyConfiguration represents an declarative configuration of the TimeInterval type for use
|
||||||
|
// with apply.
|
||||||
|
type TimeIntervalApplyConfiguration struct { |
||||||
|
v1.TypeMetaApplyConfiguration `json:",inline"` |
||||||
|
*v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` |
||||||
|
Spec *TimeIntervalSpecApplyConfiguration `json:"spec,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
// TimeInterval constructs an declarative configuration of the TimeInterval type for use with
|
||||||
|
// apply.
|
||||||
|
func TimeInterval(name, namespace string) *TimeIntervalApplyConfiguration { |
||||||
|
b := &TimeIntervalApplyConfiguration{} |
||||||
|
b.WithName(name) |
||||||
|
b.WithNamespace(namespace) |
||||||
|
b.WithKind("TimeInterval") |
||||||
|
b.WithAPIVersion("notifications.alerting.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 *TimeIntervalApplyConfiguration) WithKind(value string) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithAPIVersion(value string) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithName(value string) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithGenerateName(value string) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithNamespace(value string) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithUID(value types.UID) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithResourceVersion(value string) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithGeneration(value int64) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithCreationTimestamp(value metav1.Time) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithLabels(entries map[string]string) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithAnnotations(entries map[string]string) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *TimeIntervalApplyConfiguration { |
||||||
|
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 *TimeIntervalApplyConfiguration) WithFinalizers(values ...string) *TimeIntervalApplyConfiguration { |
||||||
|
b.ensureObjectMetaApplyConfigurationExists() |
||||||
|
for i := range values { |
||||||
|
b.Finalizers = append(b.Finalizers, values[i]) |
||||||
|
} |
||||||
|
return b |
||||||
|
} |
||||||
|
|
||||||
|
func (b *TimeIntervalApplyConfiguration) 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 *TimeIntervalApplyConfiguration) WithSpec(value *TimeIntervalSpecApplyConfiguration) *TimeIntervalApplyConfiguration { |
||||||
|
b.Spec = value |
||||||
|
return b |
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
// TimeIntervalSpecApplyConfiguration represents an declarative configuration of the TimeIntervalSpec type for use
|
||||||
|
// with apply.
|
||||||
|
type TimeIntervalSpecApplyConfiguration struct { |
||||||
|
Name *string `json:"name,omitempty"` |
||||||
|
TimeIntervals []IntervalApplyConfiguration `json:"time_intervals,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
// TimeIntervalSpecApplyConfiguration constructs an declarative configuration of the TimeIntervalSpec type for use with
|
||||||
|
// apply.
|
||||||
|
func TimeIntervalSpec() *TimeIntervalSpecApplyConfiguration { |
||||||
|
return &TimeIntervalSpecApplyConfiguration{} |
||||||
|
} |
||||||
|
|
||||||
|
// 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 *TimeIntervalSpecApplyConfiguration) WithName(value string) *TimeIntervalSpecApplyConfiguration { |
||||||
|
b.Name = &value |
||||||
|
return b |
||||||
|
} |
||||||
|
|
||||||
|
// WithTimeIntervals adds the given value to the TimeIntervals 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 TimeIntervals field.
|
||||||
|
func (b *TimeIntervalSpecApplyConfiguration) WithTimeIntervals(values ...*IntervalApplyConfiguration) *TimeIntervalSpecApplyConfiguration { |
||||||
|
for i := range values { |
||||||
|
if values[i] == nil { |
||||||
|
panic("nil value passed to WithTimeIntervals") |
||||||
|
} |
||||||
|
b.TimeIntervals = append(b.TimeIntervals, *values[i]) |
||||||
|
} |
||||||
|
return b |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
// TimeRangeApplyConfiguration represents an declarative configuration of the TimeRange type for use
|
||||||
|
// with apply.
|
||||||
|
type TimeRangeApplyConfiguration struct { |
||||||
|
EndTime *string `json:"end_time,omitempty"` |
||||||
|
StartTime *string `json:"start_time,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
// TimeRangeApplyConfiguration constructs an declarative configuration of the TimeRange type for use with
|
||||||
|
// apply.
|
||||||
|
func TimeRange() *TimeRangeApplyConfiguration { |
||||||
|
return &TimeRangeApplyConfiguration{} |
||||||
|
} |
||||||
|
|
||||||
|
// WithEndTime sets the EndTime 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 EndTime field is set to the value of the last call.
|
||||||
|
func (b *TimeRangeApplyConfiguration) WithEndTime(value string) *TimeRangeApplyConfiguration { |
||||||
|
b.EndTime = &value |
||||||
|
return b |
||||||
|
} |
||||||
|
|
||||||
|
// WithStartTime sets the StartTime 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 StartTime field is set to the value of the last call.
|
||||||
|
func (b *TimeRangeApplyConfiguration) WithStartTime(value string) *TimeRangeApplyConfiguration { |
||||||
|
b.StartTime = &value |
||||||
|
return b |
||||||
|
} |
@ -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/alerting_notifications/v0alpha1" |
||||||
|
"github.com/grafana/grafana/pkg/generated/clientset/versioned/scheme" |
||||||
|
rest "k8s.io/client-go/rest" |
||||||
|
) |
||||||
|
|
||||||
|
type NotificationsV0alpha1Interface interface { |
||||||
|
RESTClient() rest.Interface |
||||||
|
TimeIntervalsGetter |
||||||
|
} |
||||||
|
|
||||||
|
// NotificationsV0alpha1Client is used to interact with features provided by the notifications.alerting.grafana.app group.
|
||||||
|
type NotificationsV0alpha1Client struct { |
||||||
|
restClient rest.Interface |
||||||
|
} |
||||||
|
|
||||||
|
func (c *NotificationsV0alpha1Client) TimeIntervals(namespace string) TimeIntervalInterface { |
||||||
|
return newTimeIntervals(c, namespace) |
||||||
|
} |
||||||
|
|
||||||
|
// NewForConfig creates a new NotificationsV0alpha1Client for the given config.
|
||||||
|
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
|
||||||
|
// where httpClient was generated with rest.HTTPClientFor(c).
|
||||||
|
func NewForConfig(c *rest.Config) (*NotificationsV0alpha1Client, 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 NotificationsV0alpha1Client 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) (*NotificationsV0alpha1Client, 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 &NotificationsV0alpha1Client{client}, nil |
||||||
|
} |
||||||
|
|
||||||
|
// NewForConfigOrDie creates a new NotificationsV0alpha1Client for the given config and
|
||||||
|
// panics if there is an error in the config.
|
||||||
|
func NewForConfigOrDie(c *rest.Config) *NotificationsV0alpha1Client { |
||||||
|
client, err := NewForConfig(c) |
||||||
|
if err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
return client |
||||||
|
} |
||||||
|
|
||||||
|
// New creates a new NotificationsV0alpha1Client for the given RESTClient.
|
||||||
|
func New(c rest.Interface) *NotificationsV0alpha1Client { |
||||||
|
return &NotificationsV0alpha1Client{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 *NotificationsV0alpha1Client) RESTClient() rest.Interface { |
||||||
|
if c == nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
return c.restClient |
||||||
|
} |
@ -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 |
@ -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 |
@ -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/alerting_notifications/v0alpha1" |
||||||
|
rest "k8s.io/client-go/rest" |
||||||
|
testing "k8s.io/client-go/testing" |
||||||
|
) |
||||||
|
|
||||||
|
type FakeNotificationsV0alpha1 struct { |
||||||
|
*testing.Fake |
||||||
|
} |
||||||
|
|
||||||
|
func (c *FakeNotificationsV0alpha1) TimeIntervals(namespace string) v0alpha1.TimeIntervalInterface { |
||||||
|
return &FakeTimeIntervals{c, namespace} |
||||||
|
} |
||||||
|
|
||||||
|
// RESTClient returns a RESTClient that is used to communicate
|
||||||
|
// with API server by this client implementation.
|
||||||
|
func (c *FakeNotificationsV0alpha1) RESTClient() rest.Interface { |
||||||
|
var ret *rest.RESTClient |
||||||
|
return ret |
||||||
|
} |
@ -0,0 +1,140 @@ |
|||||||
|
// 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/alerting_notifications/v0alpha1" |
||||||
|
alertingnotificationsv0alpha1 "github.com/grafana/grafana/pkg/generated/applyconfiguration/alerting_notifications/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" |
||||||
|
) |
||||||
|
|
||||||
|
// FakeTimeIntervals implements TimeIntervalInterface
|
||||||
|
type FakeTimeIntervals struct { |
||||||
|
Fake *FakeNotificationsV0alpha1 |
||||||
|
ns string |
||||||
|
} |
||||||
|
|
||||||
|
var timeintervalsResource = v0alpha1.SchemeGroupVersion.WithResource("timeintervals") |
||||||
|
|
||||||
|
var timeintervalsKind = v0alpha1.SchemeGroupVersion.WithKind("TimeInterval") |
||||||
|
|
||||||
|
// Get takes name of the timeInterval, and returns the corresponding timeInterval object, and an error if there is any.
|
||||||
|
func (c *FakeTimeIntervals) Get(ctx context.Context, name string, options v1.GetOptions) (result *v0alpha1.TimeInterval, err error) { |
||||||
|
obj, err := c.Fake. |
||||||
|
Invokes(testing.NewGetAction(timeintervalsResource, c.ns, name), &v0alpha1.TimeInterval{}) |
||||||
|
|
||||||
|
if obj == nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return obj.(*v0alpha1.TimeInterval), err |
||||||
|
} |
||||||
|
|
||||||
|
// List takes label and field selectors, and returns the list of TimeIntervals that match those selectors.
|
||||||
|
func (c *FakeTimeIntervals) List(ctx context.Context, opts v1.ListOptions) (result *v0alpha1.TimeIntervalList, err error) { |
||||||
|
obj, err := c.Fake. |
||||||
|
Invokes(testing.NewListAction(timeintervalsResource, timeintervalsKind, c.ns, opts), &v0alpha1.TimeIntervalList{}) |
||||||
|
|
||||||
|
if obj == nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
label, _, _ := testing.ExtractFromListOptions(opts) |
||||||
|
if label == nil { |
||||||
|
label = labels.Everything() |
||||||
|
} |
||||||
|
list := &v0alpha1.TimeIntervalList{ListMeta: obj.(*v0alpha1.TimeIntervalList).ListMeta} |
||||||
|
for _, item := range obj.(*v0alpha1.TimeIntervalList).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 timeIntervals.
|
||||||
|
func (c *FakeTimeIntervals) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { |
||||||
|
return c.Fake. |
||||||
|
InvokesWatch(testing.NewWatchAction(timeintervalsResource, c.ns, opts)) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// Create takes the representation of a timeInterval and creates it. Returns the server's representation of the timeInterval, and an error, if there is any.
|
||||||
|
func (c *FakeTimeIntervals) Create(ctx context.Context, timeInterval *v0alpha1.TimeInterval, opts v1.CreateOptions) (result *v0alpha1.TimeInterval, err error) { |
||||||
|
obj, err := c.Fake. |
||||||
|
Invokes(testing.NewCreateAction(timeintervalsResource, c.ns, timeInterval), &v0alpha1.TimeInterval{}) |
||||||
|
|
||||||
|
if obj == nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return obj.(*v0alpha1.TimeInterval), err |
||||||
|
} |
||||||
|
|
||||||
|
// Update takes the representation of a timeInterval and updates it. Returns the server's representation of the timeInterval, and an error, if there is any.
|
||||||
|
func (c *FakeTimeIntervals) Update(ctx context.Context, timeInterval *v0alpha1.TimeInterval, opts v1.UpdateOptions) (result *v0alpha1.TimeInterval, err error) { |
||||||
|
obj, err := c.Fake. |
||||||
|
Invokes(testing.NewUpdateAction(timeintervalsResource, c.ns, timeInterval), &v0alpha1.TimeInterval{}) |
||||||
|
|
||||||
|
if obj == nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return obj.(*v0alpha1.TimeInterval), err |
||||||
|
} |
||||||
|
|
||||||
|
// Delete takes name of the timeInterval and deletes it. Returns an error if one occurs.
|
||||||
|
func (c *FakeTimeIntervals) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { |
||||||
|
_, err := c.Fake. |
||||||
|
Invokes(testing.NewDeleteActionWithOptions(timeintervalsResource, c.ns, name, opts), &v0alpha1.TimeInterval{}) |
||||||
|
|
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
// DeleteCollection deletes a collection of objects.
|
||||||
|
func (c *FakeTimeIntervals) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { |
||||||
|
action := testing.NewDeleteCollectionAction(timeintervalsResource, c.ns, listOpts) |
||||||
|
|
||||||
|
_, err := c.Fake.Invokes(action, &v0alpha1.TimeIntervalList{}) |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
// Patch applies the patch and returns the patched timeInterval.
|
||||||
|
func (c *FakeTimeIntervals) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v0alpha1.TimeInterval, err error) { |
||||||
|
obj, err := c.Fake. |
||||||
|
Invokes(testing.NewPatchSubresourceAction(timeintervalsResource, c.ns, name, pt, data, subresources...), &v0alpha1.TimeInterval{}) |
||||||
|
|
||||||
|
if obj == nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return obj.(*v0alpha1.TimeInterval), err |
||||||
|
} |
||||||
|
|
||||||
|
// Apply takes the given apply declarative configuration, applies it and returns the applied timeInterval.
|
||||||
|
func (c *FakeTimeIntervals) Apply(ctx context.Context, timeInterval *alertingnotificationsv0alpha1.TimeIntervalApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.TimeInterval, err error) { |
||||||
|
if timeInterval == nil { |
||||||
|
return nil, fmt.Errorf("timeInterval provided to Apply must not be nil") |
||||||
|
} |
||||||
|
data, err := json.Marshal(timeInterval) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
name := timeInterval.Name |
||||||
|
if name == nil { |
||||||
|
return nil, fmt.Errorf("timeInterval.Name must be provided to Apply") |
||||||
|
} |
||||||
|
obj, err := c.Fake. |
||||||
|
Invokes(testing.NewPatchSubresourceAction(timeintervalsResource, c.ns, *name, types.ApplyPatchType, data), &v0alpha1.TimeInterval{}) |
||||||
|
|
||||||
|
if obj == nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return obj.(*v0alpha1.TimeInterval), err |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
// Code generated by client-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
type TimeIntervalExpansion interface{} |
@ -0,0 +1,194 @@ |
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
// Code generated by client-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
json "encoding/json" |
||||||
|
"fmt" |
||||||
|
"time" |
||||||
|
|
||||||
|
v0alpha1 "github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1" |
||||||
|
alertingnotificationsv0alpha1 "github.com/grafana/grafana/pkg/generated/applyconfiguration/alerting_notifications/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" |
||||||
|
rest "k8s.io/client-go/rest" |
||||||
|
) |
||||||
|
|
||||||
|
// TimeIntervalsGetter has a method to return a TimeIntervalInterface.
|
||||||
|
// A group's client should implement this interface.
|
||||||
|
type TimeIntervalsGetter interface { |
||||||
|
TimeIntervals(namespace string) TimeIntervalInterface |
||||||
|
} |
||||||
|
|
||||||
|
// TimeIntervalInterface has methods to work with TimeInterval resources.
|
||||||
|
type TimeIntervalInterface interface { |
||||||
|
Create(ctx context.Context, timeInterval *v0alpha1.TimeInterval, opts v1.CreateOptions) (*v0alpha1.TimeInterval, error) |
||||||
|
Update(ctx context.Context, timeInterval *v0alpha1.TimeInterval, opts v1.UpdateOptions) (*v0alpha1.TimeInterval, 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.TimeInterval, error) |
||||||
|
List(ctx context.Context, opts v1.ListOptions) (*v0alpha1.TimeIntervalList, 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.TimeInterval, err error) |
||||||
|
Apply(ctx context.Context, timeInterval *alertingnotificationsv0alpha1.TimeIntervalApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.TimeInterval, err error) |
||||||
|
TimeIntervalExpansion |
||||||
|
} |
||||||
|
|
||||||
|
// timeIntervals implements TimeIntervalInterface
|
||||||
|
type timeIntervals struct { |
||||||
|
client rest.Interface |
||||||
|
ns string |
||||||
|
} |
||||||
|
|
||||||
|
// newTimeIntervals returns a TimeIntervals
|
||||||
|
func newTimeIntervals(c *NotificationsV0alpha1Client, namespace string) *timeIntervals { |
||||||
|
return &timeIntervals{ |
||||||
|
client: c.RESTClient(), |
||||||
|
ns: namespace, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Get takes name of the timeInterval, and returns the corresponding timeInterval object, and an error if there is any.
|
||||||
|
func (c *timeIntervals) Get(ctx context.Context, name string, options v1.GetOptions) (result *v0alpha1.TimeInterval, err error) { |
||||||
|
result = &v0alpha1.TimeInterval{} |
||||||
|
err = c.client.Get(). |
||||||
|
Namespace(c.ns). |
||||||
|
Resource("timeintervals"). |
||||||
|
Name(name). |
||||||
|
VersionedParams(&options, scheme.ParameterCodec). |
||||||
|
Do(ctx). |
||||||
|
Into(result) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// List takes label and field selectors, and returns the list of TimeIntervals that match those selectors.
|
||||||
|
func (c *timeIntervals) List(ctx context.Context, opts v1.ListOptions) (result *v0alpha1.TimeIntervalList, err error) { |
||||||
|
var timeout time.Duration |
||||||
|
if opts.TimeoutSeconds != nil { |
||||||
|
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second |
||||||
|
} |
||||||
|
result = &v0alpha1.TimeIntervalList{} |
||||||
|
err = c.client.Get(). |
||||||
|
Namespace(c.ns). |
||||||
|
Resource("timeintervals"). |
||||||
|
VersionedParams(&opts, scheme.ParameterCodec). |
||||||
|
Timeout(timeout). |
||||||
|
Do(ctx). |
||||||
|
Into(result) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Watch returns a watch.Interface that watches the requested timeIntervals.
|
||||||
|
func (c *timeIntervals) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { |
||||||
|
var timeout time.Duration |
||||||
|
if opts.TimeoutSeconds != nil { |
||||||
|
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second |
||||||
|
} |
||||||
|
opts.Watch = true |
||||||
|
return c.client.Get(). |
||||||
|
Namespace(c.ns). |
||||||
|
Resource("timeintervals"). |
||||||
|
VersionedParams(&opts, scheme.ParameterCodec). |
||||||
|
Timeout(timeout). |
||||||
|
Watch(ctx) |
||||||
|
} |
||||||
|
|
||||||
|
// Create takes the representation of a timeInterval and creates it. Returns the server's representation of the timeInterval, and an error, if there is any.
|
||||||
|
func (c *timeIntervals) Create(ctx context.Context, timeInterval *v0alpha1.TimeInterval, opts v1.CreateOptions) (result *v0alpha1.TimeInterval, err error) { |
||||||
|
result = &v0alpha1.TimeInterval{} |
||||||
|
err = c.client.Post(). |
||||||
|
Namespace(c.ns). |
||||||
|
Resource("timeintervals"). |
||||||
|
VersionedParams(&opts, scheme.ParameterCodec). |
||||||
|
Body(timeInterval). |
||||||
|
Do(ctx). |
||||||
|
Into(result) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Update takes the representation of a timeInterval and updates it. Returns the server's representation of the timeInterval, and an error, if there is any.
|
||||||
|
func (c *timeIntervals) Update(ctx context.Context, timeInterval *v0alpha1.TimeInterval, opts v1.UpdateOptions) (result *v0alpha1.TimeInterval, err error) { |
||||||
|
result = &v0alpha1.TimeInterval{} |
||||||
|
err = c.client.Put(). |
||||||
|
Namespace(c.ns). |
||||||
|
Resource("timeintervals"). |
||||||
|
Name(timeInterval.Name). |
||||||
|
VersionedParams(&opts, scheme.ParameterCodec). |
||||||
|
Body(timeInterval). |
||||||
|
Do(ctx). |
||||||
|
Into(result) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Delete takes name of the timeInterval and deletes it. Returns an error if one occurs.
|
||||||
|
func (c *timeIntervals) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { |
||||||
|
return c.client.Delete(). |
||||||
|
Namespace(c.ns). |
||||||
|
Resource("timeintervals"). |
||||||
|
Name(name). |
||||||
|
Body(&opts). |
||||||
|
Do(ctx). |
||||||
|
Error() |
||||||
|
} |
||||||
|
|
||||||
|
// DeleteCollection deletes a collection of objects.
|
||||||
|
func (c *timeIntervals) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { |
||||||
|
var timeout time.Duration |
||||||
|
if listOpts.TimeoutSeconds != nil { |
||||||
|
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second |
||||||
|
} |
||||||
|
return c.client.Delete(). |
||||||
|
Namespace(c.ns). |
||||||
|
Resource("timeintervals"). |
||||||
|
VersionedParams(&listOpts, scheme.ParameterCodec). |
||||||
|
Timeout(timeout). |
||||||
|
Body(&opts). |
||||||
|
Do(ctx). |
||||||
|
Error() |
||||||
|
} |
||||||
|
|
||||||
|
// Patch applies the patch and returns the patched timeInterval.
|
||||||
|
func (c *timeIntervals) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v0alpha1.TimeInterval, err error) { |
||||||
|
result = &v0alpha1.TimeInterval{} |
||||||
|
err = c.client.Patch(pt). |
||||||
|
Namespace(c.ns). |
||||||
|
Resource("timeintervals"). |
||||||
|
Name(name). |
||||||
|
SubResource(subresources...). |
||||||
|
VersionedParams(&opts, scheme.ParameterCodec). |
||||||
|
Body(data). |
||||||
|
Do(ctx). |
||||||
|
Into(result) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Apply takes the given apply declarative configuration, applies it and returns the applied timeInterval.
|
||||||
|
func (c *timeIntervals) Apply(ctx context.Context, timeInterval *alertingnotificationsv0alpha1.TimeIntervalApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.TimeInterval, err error) { |
||||||
|
if timeInterval == nil { |
||||||
|
return nil, fmt.Errorf("timeInterval provided to Apply must not be nil") |
||||||
|
} |
||||||
|
patchOpts := opts.ToPatchOptions() |
||||||
|
data, err := json.Marshal(timeInterval) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
name := timeInterval.Name |
||||||
|
if name == nil { |
||||||
|
return nil, fmt.Errorf("timeInterval.Name must be provided to Apply") |
||||||
|
} |
||||||
|
result = &v0alpha1.TimeInterval{} |
||||||
|
err = c.client.Patch(types.ApplyPatchType). |
||||||
|
Namespace(c.ns). |
||||||
|
Resource("timeintervals"). |
||||||
|
Name(*name). |
||||||
|
VersionedParams(&patchOpts, scheme.ParameterCodec). |
||||||
|
Body(data). |
||||||
|
Do(ctx). |
||||||
|
Into(result) |
||||||
|
return |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
// Code generated by informer-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package alerting_notifications |
||||||
|
|
||||||
|
import ( |
||||||
|
v0alpha1 "github.com/grafana/grafana/pkg/generated/informers/externalversions/alerting_notifications/v0alpha1" |
||||||
|
internalinterfaces "github.com/grafana/grafana/pkg/generated/informers/externalversions/internalinterfaces" |
||||||
|
) |
||||||
|
|
||||||
|
// 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) |
||||||
|
} |
@ -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 { |
||||||
|
// TimeIntervals returns a TimeIntervalInformer.
|
||||||
|
TimeIntervals() TimeIntervalInformer |
||||||
|
} |
||||||
|
|
||||||
|
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} |
||||||
|
} |
||||||
|
|
||||||
|
// TimeIntervals returns a TimeIntervalInformer.
|
||||||
|
func (v *version) TimeIntervals() TimeIntervalInformer { |
||||||
|
return &timeIntervalInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} |
||||||
|
} |
@ -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" |
||||||
|
|
||||||
|
alertingnotificationsv0alpha1 "github.com/grafana/grafana/pkg/apis/alerting_notifications/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/alerting_notifications/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" |
||||||
|
) |
||||||
|
|
||||||
|
// TimeIntervalInformer provides access to a shared informer and lister for
|
||||||
|
// TimeIntervals.
|
||||||
|
type TimeIntervalInformer interface { |
||||||
|
Informer() cache.SharedIndexInformer |
||||||
|
Lister() v0alpha1.TimeIntervalLister |
||||||
|
} |
||||||
|
|
||||||
|
type timeIntervalInformer struct { |
||||||
|
factory internalinterfaces.SharedInformerFactory |
||||||
|
tweakListOptions internalinterfaces.TweakListOptionsFunc |
||||||
|
namespace string |
||||||
|
} |
||||||
|
|
||||||
|
// NewTimeIntervalInformer constructs a new informer for TimeInterval 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 NewTimeIntervalInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { |
||||||
|
return NewFilteredTimeIntervalInformer(client, namespace, resyncPeriod, indexers, nil) |
||||||
|
} |
||||||
|
|
||||||
|
// NewFilteredTimeIntervalInformer constructs a new informer for TimeInterval 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 NewFilteredTimeIntervalInformer(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.NotificationsV0alpha1().TimeIntervals(namespace).List(context.TODO(), options) |
||||||
|
}, |
||||||
|
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { |
||||||
|
if tweakListOptions != nil { |
||||||
|
tweakListOptions(&options) |
||||||
|
} |
||||||
|
return client.NotificationsV0alpha1().TimeIntervals(namespace).Watch(context.TODO(), options) |
||||||
|
}, |
||||||
|
}, |
||||||
|
&alertingnotificationsv0alpha1.TimeInterval{}, |
||||||
|
resyncPeriod, |
||||||
|
indexers, |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
func (f *timeIntervalInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { |
||||||
|
return NewFilteredTimeIntervalInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) |
||||||
|
} |
||||||
|
|
||||||
|
func (f *timeIntervalInformer) Informer() cache.SharedIndexInformer { |
||||||
|
return f.factory.InformerFor(&alertingnotificationsv0alpha1.TimeInterval{}, f.defaultInformer) |
||||||
|
} |
||||||
|
|
||||||
|
func (f *timeIntervalInformer) Lister() v0alpha1.TimeIntervalLister { |
||||||
|
return v0alpha1.NewTimeIntervalLister(f.Informer().GetIndexer()) |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
// Code generated by lister-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v0alpha1 |
||||||
|
|
||||||
|
// TimeIntervalListerExpansion allows custom methods to be added to
|
||||||
|
// TimeIntervalLister.
|
||||||
|
type TimeIntervalListerExpansion interface{} |
||||||
|
|
||||||
|
// TimeIntervalNamespaceListerExpansion allows custom methods to be added to
|
||||||
|
// TimeIntervalNamespaceLister.
|
||||||
|
type TimeIntervalNamespaceListerExpansion interface{} |
@ -0,0 +1,85 @@ |
|||||||
|
// 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/alerting_notifications/v0alpha1" |
||||||
|
"k8s.io/apimachinery/pkg/api/errors" |
||||||
|
"k8s.io/apimachinery/pkg/labels" |
||||||
|
"k8s.io/client-go/tools/cache" |
||||||
|
) |
||||||
|
|
||||||
|
// TimeIntervalLister helps list TimeIntervals.
|
||||||
|
// All objects returned here must be treated as read-only.
|
||||||
|
type TimeIntervalLister interface { |
||||||
|
// List lists all TimeIntervals in the indexer.
|
||||||
|
// Objects returned here must be treated as read-only.
|
||||||
|
List(selector labels.Selector) (ret []*v0alpha1.TimeInterval, err error) |
||||||
|
// TimeIntervals returns an object that can list and get TimeIntervals.
|
||||||
|
TimeIntervals(namespace string) TimeIntervalNamespaceLister |
||||||
|
TimeIntervalListerExpansion |
||||||
|
} |
||||||
|
|
||||||
|
// timeIntervalLister implements the TimeIntervalLister interface.
|
||||||
|
type timeIntervalLister struct { |
||||||
|
indexer cache.Indexer |
||||||
|
} |
||||||
|
|
||||||
|
// NewTimeIntervalLister returns a new TimeIntervalLister.
|
||||||
|
func NewTimeIntervalLister(indexer cache.Indexer) TimeIntervalLister { |
||||||
|
return &timeIntervalLister{indexer: indexer} |
||||||
|
} |
||||||
|
|
||||||
|
// List lists all TimeIntervals in the indexer.
|
||||||
|
func (s *timeIntervalLister) List(selector labels.Selector) (ret []*v0alpha1.TimeInterval, err error) { |
||||||
|
err = cache.ListAll(s.indexer, selector, func(m interface{}) { |
||||||
|
ret = append(ret, m.(*v0alpha1.TimeInterval)) |
||||||
|
}) |
||||||
|
return ret, err |
||||||
|
} |
||||||
|
|
||||||
|
// TimeIntervals returns an object that can list and get TimeIntervals.
|
||||||
|
func (s *timeIntervalLister) TimeIntervals(namespace string) TimeIntervalNamespaceLister { |
||||||
|
return timeIntervalNamespaceLister{indexer: s.indexer, namespace: namespace} |
||||||
|
} |
||||||
|
|
||||||
|
// TimeIntervalNamespaceLister helps list and get TimeIntervals.
|
||||||
|
// All objects returned here must be treated as read-only.
|
||||||
|
type TimeIntervalNamespaceLister interface { |
||||||
|
// List lists all TimeIntervals in the indexer for a given namespace.
|
||||||
|
// Objects returned here must be treated as read-only.
|
||||||
|
List(selector labels.Selector) (ret []*v0alpha1.TimeInterval, err error) |
||||||
|
// Get retrieves the TimeInterval from the indexer for a given namespace and name.
|
||||||
|
// Objects returned here must be treated as read-only.
|
||||||
|
Get(name string) (*v0alpha1.TimeInterval, error) |
||||||
|
TimeIntervalNamespaceListerExpansion |
||||||
|
} |
||||||
|
|
||||||
|
// timeIntervalNamespaceLister implements the TimeIntervalNamespaceLister
|
||||||
|
// interface.
|
||||||
|
type timeIntervalNamespaceLister struct { |
||||||
|
indexer cache.Indexer |
||||||
|
namespace string |
||||||
|
} |
||||||
|
|
||||||
|
// List lists all TimeIntervals in the indexer for a given namespace.
|
||||||
|
func (s timeIntervalNamespaceLister) List(selector labels.Selector) (ret []*v0alpha1.TimeInterval, err error) { |
||||||
|
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { |
||||||
|
ret = append(ret, m.(*v0alpha1.TimeInterval)) |
||||||
|
}) |
||||||
|
return ret, err |
||||||
|
} |
||||||
|
|
||||||
|
// Get retrieves the TimeInterval from the indexer for a given namespace and name.
|
||||||
|
func (s timeIntervalNamespaceLister) Get(name string) (*v0alpha1.TimeInterval, error) { |
||||||
|
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
if !exists { |
||||||
|
return nil, errors.NewNotFound(v0alpha1.Resource("timeinterval"), name) |
||||||
|
} |
||||||
|
return obj.(*v0alpha1.TimeInterval), nil |
||||||
|
} |
@ -0,0 +1,112 @@ |
|||||||
|
package notifications |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"fmt" |
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus" |
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||||
|
"k8s.io/apimachinery/pkg/runtime" |
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema" |
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer" |
||||||
|
"k8s.io/apiserver/pkg/authorization/authorizer" |
||||||
|
"k8s.io/apiserver/pkg/registry/generic" |
||||||
|
"k8s.io/apiserver/pkg/registry/rest" |
||||||
|
genericapiserver "k8s.io/apiserver/pkg/server" |
||||||
|
"k8s.io/kube-openapi/pkg/common" |
||||||
|
|
||||||
|
notificationsModels "github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1" |
||||||
|
"github.com/grafana/grafana/pkg/apiserver/builder" |
||||||
|
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" |
||||||
|
timeInterval "github.com/grafana/grafana/pkg/registry/apis/alerting/notifications/timeinterval" |
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol" |
||||||
|
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" |
||||||
|
"github.com/grafana/grafana/pkg/services/featuremgmt" |
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert" |
||||||
|
"github.com/grafana/grafana/pkg/setting" |
||||||
|
) |
||||||
|
|
||||||
|
var _ builder.APIGroupBuilder = (*NotificationsAPIBuilder)(nil) |
||||||
|
|
||||||
|
// This is used just so wire has something unique to return
|
||||||
|
type NotificationsAPIBuilder struct { |
||||||
|
authz accesscontrol.AccessControl |
||||||
|
ng *ngalert.AlertNG |
||||||
|
namespacer request.NamespaceMapper |
||||||
|
gv schema.GroupVersion |
||||||
|
} |
||||||
|
|
||||||
|
func (t NotificationsAPIBuilder) GetDesiredDualWriterMode(dualWrite bool, toMode map[string]grafanarest.DualWriterMode) grafanarest.DualWriterMode { |
||||||
|
// Add required configuration support in order to enable other modes. For an example, see pkg/registry/apis/playlist/register.go
|
||||||
|
return grafanarest.Mode0 |
||||||
|
} |
||||||
|
|
||||||
|
func RegisterAPIService( |
||||||
|
features featuremgmt.FeatureToggles, |
||||||
|
apiregistration builder.APIRegistrar, |
||||||
|
cfg *setting.Cfg, |
||||||
|
ng *ngalert.AlertNG, |
||||||
|
) *NotificationsAPIBuilder { |
||||||
|
if ng.IsDisabled() || !features.IsEnabledGlobally(featuremgmt.FlagAlertingApiServer) { |
||||||
|
return nil |
||||||
|
} |
||||||
|
builder := &NotificationsAPIBuilder{ |
||||||
|
ng: ng, |
||||||
|
namespacer: request.GetNamespaceMapper(cfg), |
||||||
|
gv: notificationsModels.SchemeGroupVersion, |
||||||
|
authz: ng.Api.AccessControl, |
||||||
|
} |
||||||
|
apiregistration.RegisterAPI(builder) |
||||||
|
return builder |
||||||
|
} |
||||||
|
|
||||||
|
func (t NotificationsAPIBuilder) GetGroupVersion() schema.GroupVersion { |
||||||
|
return t.gv |
||||||
|
} |
||||||
|
|
||||||
|
func (t NotificationsAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { |
||||||
|
err := notificationsModels.AddToScheme(scheme) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
return scheme.SetVersionPriority(notificationsModels.SchemeGroupVersion) |
||||||
|
} |
||||||
|
|
||||||
|
func (t NotificationsAPIBuilder) GetAPIGroupInfo( |
||||||
|
scheme *runtime.Scheme, |
||||||
|
codecs serializer.CodecFactory, |
||||||
|
optsGetter generic.RESTOptionsGetter, |
||||||
|
desiredMode grafanarest.DualWriterMode, |
||||||
|
reg prometheus.Registerer, |
||||||
|
) (*genericapiserver.APIGroupInfo, error) { |
||||||
|
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(notificationsModels.GROUP, scheme, metav1.ParameterCodec, codecs) |
||||||
|
|
||||||
|
intervals, err := timeInterval.NewStorage(t.ng.Api.MuteTimings, t.namespacer, scheme, desiredMode, optsGetter, reg) |
||||||
|
if err != nil { |
||||||
|
return nil, fmt.Errorf("failed to initialize time-interval storage: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
apiGroupInfo.VersionedResourcesStorageMap[notificationsModels.VERSION] = map[string]rest.Storage{ |
||||||
|
notificationsModels.TimeIntervalResourceInfo.StoragePath(): intervals, |
||||||
|
} |
||||||
|
return &apiGroupInfo, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (t NotificationsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { |
||||||
|
return notificationsModels.GetOpenAPIDefinitions |
||||||
|
} |
||||||
|
|
||||||
|
func (t NotificationsAPIBuilder) GetAPIRoutes() *builder.APIRoutes { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (t NotificationsAPIBuilder) GetAuthorizer() authorizer.Authorizer { |
||||||
|
return authorizer.AuthorizerFunc( |
||||||
|
func(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) { |
||||||
|
switch a.GetResource() { |
||||||
|
case notificationsModels.TimeIntervalResourceInfo.GroupResource().Resource: |
||||||
|
return timeInterval.Authorize(ctx, t.authz, a) |
||||||
|
} |
||||||
|
return authorizer.DecisionNoOpinion, "", nil |
||||||
|
}) |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
package timeinterval |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
|
||||||
|
"k8s.io/apiserver/pkg/authorization/authorizer" |
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/appcontext" |
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol" |
||||||
|
) |
||||||
|
|
||||||
|
func Authorize(ctx context.Context, ac accesscontrol.AccessControl, attr authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { |
||||||
|
if attr.GetResource() != resourceInfo.GroupResource().Resource { |
||||||
|
return authorizer.DecisionNoOpinion, "", nil |
||||||
|
} |
||||||
|
user, err := appcontext.User(ctx) |
||||||
|
if err != nil { |
||||||
|
return authorizer.DecisionDeny, "valid user is required", err |
||||||
|
} |
||||||
|
|
||||||
|
var action accesscontrol.Evaluator |
||||||
|
switch attr.GetVerb() { |
||||||
|
case "patch": |
||||||
|
fallthrough |
||||||
|
case "create": |
||||||
|
fallthrough |
||||||
|
case "update": |
||||||
|
action = accesscontrol.EvalAny( |
||||||
|
accesscontrol.EvalPermission(accesscontrol.ActionAlertingNotificationsTimeIntervalsWrite), |
||||||
|
accesscontrol.EvalPermission(accesscontrol.ActionAlertingNotificationsWrite), |
||||||
|
) |
||||||
|
case "deletecollection": |
||||||
|
fallthrough |
||||||
|
case "delete": |
||||||
|
action = accesscontrol.EvalAny( |
||||||
|
accesscontrol.EvalPermission(accesscontrol.ActionAlertingNotificationsTimeIntervalsDelete), |
||||||
|
accesscontrol.EvalPermission(accesscontrol.ActionAlertingNotificationsWrite), |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
eval := accesscontrol.EvalAny( |
||||||
|
accesscontrol.EvalPermission(accesscontrol.ActionAlertingNotificationsTimeIntervalsRead), |
||||||
|
accesscontrol.EvalPermission(accesscontrol.ActionAlertingNotificationsRead), |
||||||
|
) |
||||||
|
if action != nil { |
||||||
|
eval = accesscontrol.EvalAll(eval, action) |
||||||
|
} |
||||||
|
|
||||||
|
ok, err := ac.Evaluate(ctx, user, eval) |
||||||
|
if ok { |
||||||
|
return authorizer.DecisionAllow, "", nil |
||||||
|
} |
||||||
|
return authorizer.DecisionDeny, "", err |
||||||
|
} |
@ -0,0 +1,97 @@ |
|||||||
|
package timeinterval |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"fmt" |
||||||
|
"hash/fnv" |
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||||
|
"k8s.io/apimachinery/pkg/types" |
||||||
|
|
||||||
|
model "github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1" |
||||||
|
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" |
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" |
||||||
|
) |
||||||
|
|
||||||
|
func getIntervalUID(t definitions.MuteTimeInterval) string { |
||||||
|
sum := fnv.New64() |
||||||
|
_, _ = sum.Write([]byte(t.Name)) |
||||||
|
return fmt.Sprintf("%016x", sum.Sum64()) |
||||||
|
} |
||||||
|
|
||||||
|
func convertToK8sResources(orgID int64, intervals []definitions.MuteTimeInterval, namespacer request.NamespaceMapper) (*model.TimeIntervalList, error) { |
||||||
|
data, err := json.Marshal(intervals) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
var specs []model.TimeIntervalSpec |
||||||
|
err = json.Unmarshal(data, &specs) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
result := &model.TimeIntervalList{} |
||||||
|
for idx := range specs { |
||||||
|
interval := intervals[idx] |
||||||
|
spec := specs[idx] |
||||||
|
uid := getIntervalUID(interval) // TODO replace to stable UID when we switch to normal storage
|
||||||
|
result.Items = append(result.Items, model.TimeInterval{ |
||||||
|
TypeMeta: resourceInfo.TypeMeta(), |
||||||
|
ObjectMeta: metav1.ObjectMeta{ |
||||||
|
UID: types.UID(uid), // TODO This is needed to make PATCH work
|
||||||
|
Name: uid, // TODO replace to stable UID when we switch to normal storage
|
||||||
|
Namespace: namespacer(orgID), |
||||||
|
Annotations: map[string]string{ // TODO find a better place for provenance?
|
||||||
|
"grafana.com/provenance": string(interval.Provenance), |
||||||
|
}, |
||||||
|
ResourceVersion: interval.Version, |
||||||
|
}, |
||||||
|
Spec: spec, |
||||||
|
}) |
||||||
|
} |
||||||
|
return result, nil |
||||||
|
} |
||||||
|
|
||||||
|
func convertToK8sResource(orgID int64, interval definitions.MuteTimeInterval, namespacer request.NamespaceMapper) (*model.TimeInterval, error) { |
||||||
|
data, err := json.Marshal(interval) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
spec := model.TimeIntervalSpec{} |
||||||
|
err = json.Unmarshal(data, &spec) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
uid := getIntervalUID(interval) // TODO replace to stable UID when we switch to normal storage
|
||||||
|
return &model.TimeInterval{ |
||||||
|
TypeMeta: resourceInfo.TypeMeta(), |
||||||
|
ObjectMeta: metav1.ObjectMeta{ |
||||||
|
UID: types.UID(uid), // TODO This is needed to make PATCH work
|
||||||
|
Name: uid, // TODO replace to stable UID when we switch to normal storage
|
||||||
|
Namespace: namespacer(orgID), |
||||||
|
Annotations: map[string]string{ // TODO find a better place for provenance?
|
||||||
|
"grafana.com/provenance": string(interval.Provenance), |
||||||
|
}, |
||||||
|
ResourceVersion: interval.Version, |
||||||
|
}, |
||||||
|
Spec: spec, |
||||||
|
}, nil |
||||||
|
} |
||||||
|
|
||||||
|
func convertToDomainModel(interval *model.TimeInterval) (definitions.MuteTimeInterval, error) { |
||||||
|
b, err := json.Marshal(interval.Spec) |
||||||
|
if err != nil { |
||||||
|
return definitions.MuteTimeInterval{}, err |
||||||
|
} |
||||||
|
result := definitions.MuteTimeInterval{} |
||||||
|
err = json.Unmarshal(b, &result) |
||||||
|
if err != nil { |
||||||
|
return definitions.MuteTimeInterval{}, err |
||||||
|
} |
||||||
|
result.Version = interval.ResourceVersion |
||||||
|
err = result.Validate() |
||||||
|
if err != nil { |
||||||
|
return definitions.MuteTimeInterval{}, err |
||||||
|
} |
||||||
|
return result, nil |
||||||
|
} |
@ -0,0 +1,205 @@ |
|||||||
|
package timeinterval |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"fmt" |
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors" |
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/internalversion" |
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||||
|
"k8s.io/apimachinery/pkg/runtime" |
||||||
|
"k8s.io/apiserver/pkg/registry/rest" |
||||||
|
|
||||||
|
notifications "github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1" |
||||||
|
grafanaRest "github.com/grafana/grafana/pkg/apiserver/rest" |
||||||
|
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" |
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" |
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/models" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
_ grafanaRest.LegacyStorage = (*legacyStorage)(nil) |
||||||
|
) |
||||||
|
|
||||||
|
var resourceInfo = notifications.TimeIntervalResourceInfo |
||||||
|
|
||||||
|
type TimeIntervalService interface { |
||||||
|
GetMuteTimings(ctx context.Context, orgID int64) ([]definitions.MuteTimeInterval, error) |
||||||
|
GetMuteTiming(ctx context.Context, name string, orgID int64) (definitions.MuteTimeInterval, error) |
||||||
|
CreateMuteTiming(ctx context.Context, mt definitions.MuteTimeInterval, orgID int64) (definitions.MuteTimeInterval, error) |
||||||
|
UpdateMuteTiming(ctx context.Context, mt definitions.MuteTimeInterval, orgID int64) (definitions.MuteTimeInterval, error) |
||||||
|
DeleteMuteTiming(ctx context.Context, name string, orgID int64, provenance definitions.Provenance, version string) error |
||||||
|
} |
||||||
|
|
||||||
|
type legacyStorage struct { |
||||||
|
service TimeIntervalService |
||||||
|
namespacer request.NamespaceMapper |
||||||
|
tableConverter rest.TableConvertor |
||||||
|
} |
||||||
|
|
||||||
|
func (s *legacyStorage) New() runtime.Object { |
||||||
|
return resourceInfo.NewFunc() |
||||||
|
} |
||||||
|
|
||||||
|
func (s *legacyStorage) Destroy() {} |
||||||
|
|
||||||
|
func (s *legacyStorage) NamespaceScoped() bool { |
||||||
|
return true // namespace == org
|
||||||
|
} |
||||||
|
|
||||||
|
func (s *legacyStorage) GetSingularName() string { |
||||||
|
return resourceInfo.GetSingularName() |
||||||
|
} |
||||||
|
|
||||||
|
func (s *legacyStorage) NewList() runtime.Object { |
||||||
|
return resourceInfo.NewListFunc() |
||||||
|
} |
||||||
|
|
||||||
|
func (s *legacyStorage) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { |
||||||
|
return s.tableConverter.ConvertToTable(ctx, object, tableOptions) |
||||||
|
} |
||||||
|
|
||||||
|
func (s *legacyStorage) List(ctx context.Context, _ *internalversion.ListOptions) (runtime.Object, error) { |
||||||
|
orgId, err := request.OrgIDForList(ctx) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
res, err := s.service.GetMuteTimings(ctx, orgId) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return convertToK8sResources(orgId, res, s.namespacer) |
||||||
|
} |
||||||
|
|
||||||
|
func (s *legacyStorage) Get(ctx context.Context, uid string, _ *metav1.GetOptions) (runtime.Object, error) { |
||||||
|
info, err := request.NamespaceInfoFrom(ctx, true) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
timings, err := s.service.GetMuteTimings(ctx, info.OrgID) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
for _, mt := range timings { |
||||||
|
if getIntervalUID(mt) == uid { |
||||||
|
return convertToK8sResource(info.OrgID, mt, s.namespacer) |
||||||
|
} |
||||||
|
} |
||||||
|
return nil, errors.NewNotFound(resourceInfo.GroupResource(), uid) |
||||||
|
} |
||||||
|
|
||||||
|
func (s *legacyStorage) Create(ctx context.Context, |
||||||
|
obj runtime.Object, |
||||||
|
createValidation rest.ValidateObjectFunc, |
||||||
|
_ *metav1.CreateOptions, |
||||||
|
) (runtime.Object, error) { |
||||||
|
info, err := request.NamespaceInfoFrom(ctx, true) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
if createValidation != nil { |
||||||
|
if err := createValidation(ctx, obj.DeepCopyObject()); err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
} |
||||||
|
p, ok := obj.(*notifications.TimeInterval) |
||||||
|
if !ok { |
||||||
|
return nil, fmt.Errorf("expected time-interval but got %s", obj.GetObjectKind().GroupVersionKind()) |
||||||
|
} |
||||||
|
if p.ObjectMeta.Name != "" { // TODO remove when metadata.name can be defined by user
|
||||||
|
return nil, errors.NewBadRequest("object's metadata.name should be empty") |
||||||
|
} |
||||||
|
model, err := convertToDomainModel(p) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
out, err := s.service.CreateMuteTiming(ctx, model, info.OrgID) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return convertToK8sResource(info.OrgID, out, s.namespacer) |
||||||
|
} |
||||||
|
|
||||||
|
func (s *legacyStorage) Update(ctx context.Context, |
||||||
|
uid string, |
||||||
|
objInfo rest.UpdatedObjectInfo, |
||||||
|
createValidation rest.ValidateObjectFunc, |
||||||
|
updateValidation rest.ValidateObjectUpdateFunc, |
||||||
|
_ bool, |
||||||
|
_ *metav1.UpdateOptions, |
||||||
|
) (runtime.Object, bool, error) { |
||||||
|
info, err := request.NamespaceInfoFrom(ctx, true) |
||||||
|
if err != nil { |
||||||
|
return nil, false, err |
||||||
|
} |
||||||
|
|
||||||
|
old, err := s.Get(ctx, uid, nil) |
||||||
|
if err != nil { |
||||||
|
return old, false, err |
||||||
|
} |
||||||
|
obj, err := objInfo.UpdatedObject(ctx, old) |
||||||
|
if err != nil { |
||||||
|
return old, false, err |
||||||
|
} |
||||||
|
if updateValidation != nil { |
||||||
|
if err := updateValidation(ctx, obj, old); err != nil { |
||||||
|
return nil, false, err |
||||||
|
} |
||||||
|
} |
||||||
|
p, ok := obj.(*notifications.TimeInterval) |
||||||
|
if !ok { |
||||||
|
return nil, false, fmt.Errorf("expected time-interval but got %s", obj.GetObjectKind().GroupVersionKind()) |
||||||
|
} |
||||||
|
interval, err := convertToDomainModel(p) |
||||||
|
if err != nil { |
||||||
|
return old, false, err |
||||||
|
} |
||||||
|
|
||||||
|
if p.ObjectMeta.Name != getIntervalUID(interval) { |
||||||
|
return nil, false, errors.NewBadRequest("title of cannot be changed. Consider creating a new resource.") |
||||||
|
} |
||||||
|
|
||||||
|
updated, err := s.service.UpdateMuteTiming(ctx, interval, info.OrgID) |
||||||
|
if err != nil { |
||||||
|
return nil, false, err |
||||||
|
} |
||||||
|
|
||||||
|
r, err := convertToK8sResource(info.OrgID, updated, s.namespacer) |
||||||
|
return r, false, err |
||||||
|
} |
||||||
|
|
||||||
|
// GracefulDeleter
|
||||||
|
func (s *legacyStorage) Delete(ctx context.Context, uid string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { |
||||||
|
info, err := request.NamespaceInfoFrom(ctx, true) |
||||||
|
if err != nil { |
||||||
|
return nil, false, err |
||||||
|
} |
||||||
|
old, err := s.Get(ctx, uid, nil) |
||||||
|
if err != nil { |
||||||
|
return old, false, err |
||||||
|
} |
||||||
|
if deleteValidation != nil { |
||||||
|
if err = deleteValidation(ctx, old); err != nil { |
||||||
|
return nil, false, err |
||||||
|
} |
||||||
|
} |
||||||
|
version := "" |
||||||
|
if options.Preconditions != nil && options.Preconditions.ResourceVersion != nil { |
||||||
|
version = *options.Preconditions.ResourceVersion |
||||||
|
} |
||||||
|
p, ok := old.(*notifications.TimeInterval) |
||||||
|
if !ok { |
||||||
|
return nil, false, fmt.Errorf("expected time-interval but got %s", old.GetObjectKind().GroupVersionKind()) |
||||||
|
} |
||||||
|
|
||||||
|
err = s.service.DeleteMuteTiming(ctx, p.Spec.Name, info.OrgID, definitions.Provenance(models.ProvenanceNone), version) // TODO add support for dry-run option
|
||||||
|
return old, false, err // false - will be deleted async
|
||||||
|
} |
||||||
|
|
||||||
|
func (s *legacyStorage) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *internalversion.ListOptions) (runtime.Object, error) { |
||||||
|
return nil, errors.NewMethodNotSupported(resourceInfo.GroupResource(), "deleteCollection") |
||||||
|
} |
@ -0,0 +1,79 @@ |
|||||||
|
package timeinterval |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||||
|
"k8s.io/apimachinery/pkg/runtime" |
||||||
|
"k8s.io/apiserver/pkg/registry/generic" |
||||||
|
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" |
||||||
|
"k8s.io/apiserver/pkg/registry/rest" |
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus" |
||||||
|
|
||||||
|
model "github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1" |
||||||
|
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" |
||||||
|
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" |
||||||
|
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" |
||||||
|
"github.com/grafana/grafana/pkg/services/apiserver/utils" |
||||||
|
) |
||||||
|
|
||||||
|
var _ grafanarest.Storage = (*storage)(nil) |
||||||
|
|
||||||
|
type storage struct { |
||||||
|
*genericregistry.Store |
||||||
|
} |
||||||
|
|
||||||
|
func (s storage) Compare(storageObj, legacyObj runtime.Object) bool { |
||||||
|
// TODO implement when supported dual write mode is not Mode0
|
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
func NewStorage( |
||||||
|
legacySvc TimeIntervalService, |
||||||
|
namespacer request.NamespaceMapper, |
||||||
|
scheme *runtime.Scheme, |
||||||
|
desiredMode grafanarest.DualWriterMode, |
||||||
|
optsGetter generic.RESTOptionsGetter, |
||||||
|
reg prometheus.Registerer) (rest.Storage, error) { |
||||||
|
legacyStore := &legacyStorage{ |
||||||
|
service: legacySvc, |
||||||
|
namespacer: namespacer, |
||||||
|
tableConverter: utils.NewTableConverter( |
||||||
|
resourceInfo.GroupResource(), |
||||||
|
[]metav1.TableColumnDefinition{ |
||||||
|
{Name: "Name", Type: "string", Format: "name"}, |
||||||
|
// {Name: "Intervals", Type: "string", Format: "string", Description: "The display name"},
|
||||||
|
}, |
||||||
|
func(obj any) ([]interface{}, error) { |
||||||
|
r, ok := obj.(*model.TimeInterval) |
||||||
|
if ok { |
||||||
|
return []interface{}{ |
||||||
|
r.Name, |
||||||
|
// r.Spec, //TODO implement formatting for Spec, same as UI?
|
||||||
|
}, nil |
||||||
|
} |
||||||
|
return nil, fmt.Errorf("expected resource or info") |
||||||
|
}), |
||||||
|
} |
||||||
|
if optsGetter != nil && desiredMode != grafanarest.Mode0 { |
||||||
|
strategy := grafanaregistry.NewStrategy(scheme) |
||||||
|
s := &genericregistry.Store{ |
||||||
|
NewFunc: resourceInfo.NewFunc, |
||||||
|
NewListFunc: resourceInfo.NewListFunc, |
||||||
|
PredicateFunc: grafanaregistry.Matcher, |
||||||
|
DefaultQualifiedResource: resourceInfo.GroupResource(), |
||||||
|
SingularQualifiedResource: resourceInfo.SingularGroupResource(), |
||||||
|
TableConvertor: legacyStore.tableConverter, |
||||||
|
CreateStrategy: strategy, |
||||||
|
UpdateStrategy: strategy, |
||||||
|
DeleteStrategy: strategy, |
||||||
|
} |
||||||
|
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: grafanaregistry.GetAttrs} |
||||||
|
if err := s.CompleteWithOptions(options); err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return grafanarest.NewDualWriter(desiredMode, legacyStore, storage{Store: s}, reg), nil |
||||||
|
} |
||||||
|
return legacyStore, nil |
||||||
|
} |
|
@ -0,0 +1,541 @@ |
|||||||
|
package timeinterval |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"encoding/json" |
||||||
|
"fmt" |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/prometheus/alertmanager/config" |
||||||
|
"github.com/stretchr/testify/require" |
||||||
|
"k8s.io/apimachinery/pkg/api/errors" |
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||||
|
"k8s.io/apimachinery/pkg/types" |
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1" |
||||||
|
"github.com/grafana/grafana/pkg/generated/clientset/versioned" |
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol" |
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" |
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions" |
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards" |
||||||
|
"github.com/grafana/grafana/pkg/services/featuremgmt" |
||||||
|
"github.com/grafana/grafana/pkg/services/folder/foldertest" |
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" |
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/store" |
||||||
|
"github.com/grafana/grafana/pkg/services/org" |
||||||
|
"github.com/grafana/grafana/pkg/tests/apis" |
||||||
|
"github.com/grafana/grafana/pkg/tests/testinfra" |
||||||
|
"github.com/grafana/grafana/pkg/tests/testsuite" |
||||||
|
"github.com/grafana/grafana/pkg/util" |
||||||
|
) |
||||||
|
|
||||||
|
func TestMain(m *testing.M) { |
||||||
|
testsuite.Run(m) |
||||||
|
} |
||||||
|
|
||||||
|
func getTestHelper(t *testing.T) *apis.K8sTestHelper { |
||||||
|
return apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ |
||||||
|
EnableFeatureToggles: []string{ |
||||||
|
featuremgmt.FlagAlertingApiServer, |
||||||
|
}, |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
func TestIntegrationResourceIdentifier(t *testing.T) { |
||||||
|
if testing.Short() { |
||||||
|
t.Skip("skipping integration test") |
||||||
|
} |
||||||
|
|
||||||
|
ctx := context.Background() |
||||||
|
helper := getTestHelper(t) |
||||||
|
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig()) |
||||||
|
require.NoError(t, err) |
||||||
|
client := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default") |
||||||
|
|
||||||
|
newInterval := &v0alpha1.TimeInterval{ |
||||||
|
ObjectMeta: v1.ObjectMeta{ |
||||||
|
Namespace: "default", |
||||||
|
}, |
||||||
|
Spec: v0alpha1.TimeIntervalSpec{ |
||||||
|
Name: "time-newInterval", |
||||||
|
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2), |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
t.Run("create should fail if object name is specified", func(t *testing.T) { |
||||||
|
interval := newInterval.DeepCopy() |
||||||
|
interval.Name = "time-newInterval" |
||||||
|
_, err := client.Create(ctx, interval, v1.CreateOptions{}) |
||||||
|
require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest but got %s", err) |
||||||
|
}) |
||||||
|
|
||||||
|
var resourceID string |
||||||
|
t.Run("create should succeed and provide resource name", func(t *testing.T) { |
||||||
|
actual, err := client.Create(ctx, newInterval, v1.CreateOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.NotEmptyf(t, actual.Name, "Resource name should not be empty") |
||||||
|
require.NotEmptyf(t, actual.UID, "Resource UID should not be empty") |
||||||
|
resourceID = actual.Name |
||||||
|
}) |
||||||
|
|
||||||
|
var existingInterval *v0alpha1.TimeInterval |
||||||
|
t.Run("resource should be available by the identifier", func(t *testing.T) { |
||||||
|
actual, err := client.Get(ctx, resourceID, v1.GetOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.NotEmptyf(t, actual.Name, "Resource name should not be empty") |
||||||
|
require.Equal(t, newInterval.Spec, actual.Spec) |
||||||
|
existingInterval = actual |
||||||
|
}) |
||||||
|
|
||||||
|
t.Run("update should fail if name in the specification changes", func(t *testing.T) { |
||||||
|
if existingInterval == nil { |
||||||
|
t.Skip() |
||||||
|
} |
||||||
|
updated := existingInterval.DeepCopy() |
||||||
|
updated.Spec.Name = "another-newInterval" |
||||||
|
_, err := client.Update(ctx, updated, v1.UpdateOptions{}) |
||||||
|
require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest but got %s", err) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
func TestIntegrationTimeIntervalAccessControl(t *testing.T) { |
||||||
|
if testing.Short() { |
||||||
|
t.Skip("skipping integration test") |
||||||
|
} |
||||||
|
|
||||||
|
ctx := context.Background() |
||||||
|
helper := getTestHelper(t) |
||||||
|
|
||||||
|
org1 := helper.Org1 |
||||||
|
|
||||||
|
type testCase struct { |
||||||
|
user apis.User |
||||||
|
canRead bool |
||||||
|
canUpdate bool |
||||||
|
canCreate bool |
||||||
|
canDelete bool |
||||||
|
} |
||||||
|
|
||||||
|
reader := helper.CreateUser("IntervalsReader", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{ |
||||||
|
{ |
||||||
|
Actions: []string{ |
||||||
|
accesscontrol.ActionAlertingNotificationsTimeIntervalsRead, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}) |
||||||
|
writer := helper.CreateUser("IntervalsWriter", "Org1", org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{ |
||||||
|
{ |
||||||
|
Actions: []string{ |
||||||
|
accesscontrol.ActionAlertingNotificationsTimeIntervalsRead, |
||||||
|
accesscontrol.ActionAlertingNotificationsTimeIntervalsWrite, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}) |
||||||
|
|
||||||
|
deleter := helper.CreateUser("IntervalsDeleter", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{ |
||||||
|
{ |
||||||
|
Actions: []string{ |
||||||
|
accesscontrol.ActionAlertingNotificationsTimeIntervalsRead, |
||||||
|
accesscontrol.ActionAlertingNotificationsTimeIntervalsDelete, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}) |
||||||
|
|
||||||
|
testCases := []testCase{ |
||||||
|
{ |
||||||
|
user: org1.Admin, |
||||||
|
canRead: true, |
||||||
|
canUpdate: true, |
||||||
|
canCreate: true, |
||||||
|
canDelete: true, |
||||||
|
}, |
||||||
|
{ |
||||||
|
user: org1.Editor, |
||||||
|
canRead: true, |
||||||
|
canUpdate: true, |
||||||
|
canCreate: true, |
||||||
|
canDelete: true, |
||||||
|
}, |
||||||
|
{ |
||||||
|
user: org1.Viewer, |
||||||
|
canRead: true, |
||||||
|
}, |
||||||
|
{ |
||||||
|
user: reader, |
||||||
|
canRead: true, |
||||||
|
}, |
||||||
|
{ |
||||||
|
user: writer, |
||||||
|
canRead: true, |
||||||
|
canCreate: true, |
||||||
|
canUpdate: true, |
||||||
|
}, |
||||||
|
{ |
||||||
|
user: deleter, |
||||||
|
canRead: true, |
||||||
|
canDelete: true, |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
admin := org1.Admin |
||||||
|
adminK8sClient, err := versioned.NewForConfig(admin.NewRestConfig()) |
||||||
|
require.NoError(t, err) |
||||||
|
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default") |
||||||
|
|
||||||
|
for _, tc := range testCases { |
||||||
|
t.Run(fmt.Sprintf("user '%s'", tc.user.Identity.GetLogin()), func(t *testing.T) { |
||||||
|
k8sClient, err := versioned.NewForConfig(tc.user.NewRestConfig()) |
||||||
|
require.NoError(t, err) |
||||||
|
client := k8sClient.NotificationsV0alpha1().TimeIntervals("default") |
||||||
|
|
||||||
|
var expected = &v0alpha1.TimeInterval{ |
||||||
|
ObjectMeta: v1.ObjectMeta{ |
||||||
|
Namespace: "default", |
||||||
|
Annotations: map[string]string{ |
||||||
|
"grafana.com/provenance": "", |
||||||
|
}, |
||||||
|
}, |
||||||
|
Spec: v0alpha1.TimeIntervalSpec{ |
||||||
|
Name: fmt.Sprintf("time-interval-1-%s", tc.user.Identity.GetLogin()), |
||||||
|
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2), |
||||||
|
}, |
||||||
|
} |
||||||
|
d, err := json.Marshal(expected) |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
if tc.canCreate { |
||||||
|
t.Run("should be able to create time interval", func(t *testing.T) { |
||||||
|
actual, err := client.Create(ctx, expected, v1.CreateOptions{}) |
||||||
|
require.NoErrorf(t, err, "Payload %s", string(d)) |
||||||
|
require.Equal(t, expected.Spec, actual.Spec) |
||||||
|
|
||||||
|
t.Run("should fail if already exists", func(t *testing.T) { |
||||||
|
_, err := client.Create(ctx, actual, v1.CreateOptions{}) |
||||||
|
require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err) |
||||||
|
}) |
||||||
|
|
||||||
|
expected = actual |
||||||
|
}) |
||||||
|
} else { |
||||||
|
t.Run("should be forbidden to create", func(t *testing.T) { |
||||||
|
_, err := client.Create(ctx, expected, v1.CreateOptions{}) |
||||||
|
require.Truef(t, errors.IsForbidden(err), "Payload %s", string(d)) |
||||||
|
}) |
||||||
|
|
||||||
|
// create resource to proceed with other tests
|
||||||
|
expected, err = adminClient.Create(ctx, expected, v1.CreateOptions{}) |
||||||
|
require.NoErrorf(t, err, "Payload %s", string(d)) |
||||||
|
require.NotNil(t, expected) |
||||||
|
} |
||||||
|
|
||||||
|
if tc.canRead { |
||||||
|
t.Run("should be able to list time intervals", func(t *testing.T) { |
||||||
|
list, err := client.List(ctx, v1.ListOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.Len(t, list.Items, 1) |
||||||
|
}) |
||||||
|
|
||||||
|
t.Run("should be able to read time interval by resource identifier", func(t *testing.T) { |
||||||
|
got, err := client.Get(ctx, expected.Name, v1.GetOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.Equal(t, expected, got) |
||||||
|
|
||||||
|
t.Run("should get NotFound if resource does not exist", func(t *testing.T) { |
||||||
|
_, err := client.Get(ctx, "Notfound", v1.GetOptions{}) |
||||||
|
require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} else { |
||||||
|
t.Run("should be forbidden to list time intervals", func(t *testing.T) { |
||||||
|
_, err := client.List(ctx, v1.ListOptions{}) |
||||||
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) |
||||||
|
}) |
||||||
|
|
||||||
|
t.Run("should be forbidden to read time interval by name", func(t *testing.T) { |
||||||
|
_, err := client.Get(ctx, expected.Name, v1.GetOptions{}) |
||||||
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) |
||||||
|
|
||||||
|
t.Run("should get forbidden even if name does not exist", func(t *testing.T) { |
||||||
|
_, err := client.Get(ctx, "Notfound", v1.GetOptions{}) |
||||||
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
updatedExpected := expected.DeepCopy() |
||||||
|
updatedExpected.Spec.TimeIntervals = v0alpha1.IntervalGenerator{}.GenerateMany(2) |
||||||
|
|
||||||
|
d, err = json.Marshal(updatedExpected) |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
if tc.canUpdate { |
||||||
|
t.Run("should be able to update time interval", func(t *testing.T) { |
||||||
|
updated, err := client.Update(ctx, updatedExpected, v1.UpdateOptions{}) |
||||||
|
require.NoErrorf(t, err, "Payload %s", string(d)) |
||||||
|
|
||||||
|
expected = updated |
||||||
|
|
||||||
|
t.Run("should get NotFound if name does not exist", func(t *testing.T) { |
||||||
|
up := updatedExpected.DeepCopy() |
||||||
|
up.Name = "notFound" |
||||||
|
_, err := client.Update(ctx, up, v1.UpdateOptions{}) |
||||||
|
require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} else { |
||||||
|
t.Run("should be forbidden to update time interval", func(t *testing.T) { |
||||||
|
_, err := client.Update(ctx, updatedExpected, v1.UpdateOptions{}) |
||||||
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) |
||||||
|
|
||||||
|
t.Run("should get forbidden even if resource does not exist", func(t *testing.T) { |
||||||
|
up := updatedExpected.DeepCopy() |
||||||
|
up.Name = "notFound" |
||||||
|
_, err := client.Update(ctx, up, v1.UpdateOptions{}) |
||||||
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
deleteOptions := v1.DeleteOptions{Preconditions: &v1.Preconditions{ResourceVersion: util.Pointer(expected.ResourceVersion)}} |
||||||
|
|
||||||
|
if tc.canDelete { |
||||||
|
t.Run("should be able to delete time interval", func(t *testing.T) { |
||||||
|
err := client.Delete(ctx, expected.Name, deleteOptions) |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
t.Run("should get NotFound if name does not exist", func(t *testing.T) { |
||||||
|
err := client.Delete(ctx, "notfound", v1.DeleteOptions{}) |
||||||
|
require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) |
||||||
|
}) |
||||||
|
}) |
||||||
|
} else { |
||||||
|
t.Run("should be forbidden to delete time interval", func(t *testing.T) { |
||||||
|
err := client.Delete(ctx, expected.Name, deleteOptions) |
||||||
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) |
||||||
|
|
||||||
|
t.Run("should be forbidden even if resource does not exist", func(t *testing.T) { |
||||||
|
err := client.Delete(ctx, "notfound", v1.DeleteOptions{}) |
||||||
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) |
||||||
|
}) |
||||||
|
}) |
||||||
|
require.NoError(t, adminClient.Delete(ctx, expected.Name, v1.DeleteOptions{})) |
||||||
|
} |
||||||
|
|
||||||
|
if tc.canRead { |
||||||
|
t.Run("should get empty list if no mute timings", func(t *testing.T) { |
||||||
|
list, err := client.List(ctx, v1.ListOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.Len(t, list.Items, 0) |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestIntegrationTimeIntervalProvisioning(t *testing.T) { |
||||||
|
if testing.Short() { |
||||||
|
t.Skip("skipping integration test") |
||||||
|
} |
||||||
|
|
||||||
|
ctx := context.Background() |
||||||
|
helper := getTestHelper(t) |
||||||
|
|
||||||
|
org := helper.Org1 |
||||||
|
|
||||||
|
admin := org.Admin |
||||||
|
adminK8sClient, err := versioned.NewForConfig(admin.NewRestConfig()) |
||||||
|
require.NoError(t, err) |
||||||
|
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default") |
||||||
|
|
||||||
|
env := helper.GetEnv() |
||||||
|
ac := acimpl.ProvideAccessControl(env.FeatureToggles) |
||||||
|
db, err := store.ProvideDBStore(env.Cfg, env.FeatureToggles, env.SQLStore, &foldertest.FakeService{}, &dashboards.FakeDashboardService{}, ac) |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
created, err := adminClient.Create(ctx, &v0alpha1.TimeInterval{ |
||||||
|
ObjectMeta: v1.ObjectMeta{ |
||||||
|
Namespace: "default", |
||||||
|
}, |
||||||
|
Spec: v0alpha1.TimeIntervalSpec{ |
||||||
|
Name: "time-interval-1", |
||||||
|
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2), |
||||||
|
}, |
||||||
|
}, v1.CreateOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.Equal(t, "", created.Annotations["grafana.com/provenance"]) |
||||||
|
|
||||||
|
t.Run("should provide provenance status", func(t *testing.T) { |
||||||
|
require.NoError(t, db.SetProvenance(ctx, &definitions.MuteTimeInterval{ |
||||||
|
MuteTimeInterval: config.MuteTimeInterval{ |
||||||
|
Name: created.Spec.Name, |
||||||
|
}, |
||||||
|
}, admin.Identity.GetOrgID(), "API")) |
||||||
|
|
||||||
|
got, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.Equal(t, "API", got.Annotations["grafana.com/provenance"]) |
||||||
|
}) |
||||||
|
t.Run("should not let update if provisioned", func(t *testing.T) { |
||||||
|
updated := created.DeepCopy() |
||||||
|
updated.Spec.TimeIntervals = v0alpha1.IntervalGenerator{}.GenerateMany(2) |
||||||
|
|
||||||
|
_, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) |
||||||
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) |
||||||
|
}) |
||||||
|
|
||||||
|
t.Run("should not let delete if provisioned", func(t *testing.T) { |
||||||
|
err := adminClient.Delete(ctx, created.Name, v1.DeleteOptions{}) |
||||||
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
func TestIntegrationTimeIntervalOptimisticConcurrency(t *testing.T) { |
||||||
|
if testing.Short() { |
||||||
|
t.Skip("skipping integration test") |
||||||
|
} |
||||||
|
|
||||||
|
ctx := context.Background() |
||||||
|
helper := getTestHelper(t) |
||||||
|
|
||||||
|
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig()) |
||||||
|
require.NoError(t, err) |
||||||
|
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default") |
||||||
|
|
||||||
|
interval := v0alpha1.TimeInterval{ |
||||||
|
ObjectMeta: v1.ObjectMeta{ |
||||||
|
Namespace: "default", |
||||||
|
}, |
||||||
|
Spec: v0alpha1.TimeIntervalSpec{ |
||||||
|
Name: "time-interval", |
||||||
|
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2), |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
created, err := adminClient.Create(ctx, &interval, v1.CreateOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.NotNil(t, created) |
||||||
|
require.NotEmpty(t, created.ResourceVersion) |
||||||
|
|
||||||
|
t.Run("should forbid if version does not match", func(t *testing.T) { |
||||||
|
updated := created.DeepCopy() |
||||||
|
updated.ResourceVersion = "test" |
||||||
|
_, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) |
||||||
|
require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err) |
||||||
|
}) |
||||||
|
t.Run("should update if version matches", func(t *testing.T) { |
||||||
|
updated := created.DeepCopy() |
||||||
|
updated.Spec.TimeIntervals = v0alpha1.IntervalGenerator{}.GenerateMany(2) |
||||||
|
actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.EqualValues(t, updated.Spec, actualUpdated.Spec) |
||||||
|
require.NotEqual(t, updated.ResourceVersion, actualUpdated.ResourceVersion) |
||||||
|
}) |
||||||
|
t.Run("should update if version is empty", func(t *testing.T) { |
||||||
|
updated := created.DeepCopy() |
||||||
|
updated.ResourceVersion = "" |
||||||
|
updated.Spec.TimeIntervals = v0alpha1.IntervalGenerator{}.GenerateMany(2) |
||||||
|
|
||||||
|
actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.EqualValues(t, updated.Spec, actualUpdated.Spec) |
||||||
|
require.NotEqual(t, created.ResourceVersion, actualUpdated.ResourceVersion) |
||||||
|
}) |
||||||
|
t.Run("should fail to delete if version does not match", func(t *testing.T) { |
||||||
|
actual, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ |
||||||
|
Preconditions: &v1.Preconditions{ |
||||||
|
ResourceVersion: util.Pointer("something"), |
||||||
|
}, |
||||||
|
}) |
||||||
|
require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err) |
||||||
|
}) |
||||||
|
t.Run("should succeed if version matches", func(t *testing.T) { |
||||||
|
actual, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ |
||||||
|
Preconditions: &v1.Preconditions{ |
||||||
|
ResourceVersion: util.Pointer(actual.ResourceVersion), |
||||||
|
}, |
||||||
|
}) |
||||||
|
require.NoError(t, err) |
||||||
|
}) |
||||||
|
t.Run("should succeed if version is empty", func(t *testing.T) { |
||||||
|
actual, err := adminClient.Create(ctx, &interval, v1.CreateOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ |
||||||
|
Preconditions: &v1.Preconditions{ |
||||||
|
ResourceVersion: util.Pointer(actual.ResourceVersion), |
||||||
|
}, |
||||||
|
}) |
||||||
|
require.NoError(t, err) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
func TestIntegrationTimeIntervalPatch(t *testing.T) { |
||||||
|
if testing.Short() { |
||||||
|
t.Skip("skipping integration test") |
||||||
|
} |
||||||
|
|
||||||
|
ctx := context.Background() |
||||||
|
helper := getTestHelper(t) |
||||||
|
|
||||||
|
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig()) |
||||||
|
require.NoError(t, err) |
||||||
|
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default") |
||||||
|
|
||||||
|
interval := v0alpha1.TimeInterval{ |
||||||
|
ObjectMeta: v1.ObjectMeta{ |
||||||
|
Namespace: "default", |
||||||
|
}, |
||||||
|
Spec: v0alpha1.TimeIntervalSpec{ |
||||||
|
Name: "time-interval", |
||||||
|
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2), |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
current, err := adminClient.Create(ctx, &interval, v1.CreateOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.NotNil(t, current) |
||||||
|
require.NotEmpty(t, current.ResourceVersion) |
||||||
|
|
||||||
|
t.Run("should patch with merge patch", func(t *testing.T) { |
||||||
|
patch := `{ |
||||||
|
"spec": { |
||||||
|
"time_intervals" : [] |
||||||
|
} |
||||||
|
}` |
||||||
|
|
||||||
|
result, err := adminClient.Patch(ctx, current.Name, types.MergePatchType, []byte(patch), v1.PatchOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
require.Empty(t, result.Spec.TimeIntervals) |
||||||
|
current = result |
||||||
|
}) |
||||||
|
|
||||||
|
t.Run("should patch with json patch", func(t *testing.T) { |
||||||
|
expected := v0alpha1.IntervalGenerator{}.Generate() |
||||||
|
|
||||||
|
patch := []map[string]interface{}{ |
||||||
|
{ |
||||||
|
"op": "add", |
||||||
|
"path": "/spec/time_intervals/-", |
||||||
|
"value": expected, |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
patchData, err := json.Marshal(patch) |
||||||
|
require.NoError(t, err) |
||||||
|
|
||||||
|
result, err := adminClient.Patch(ctx, current.Name, types.JSONPatchType, patchData, v1.PatchOptions{}) |
||||||
|
require.NoError(t, err) |
||||||
|
expectedSpec := *current.Spec.DeepCopy() |
||||||
|
expectedSpec.TimeIntervals = []v0alpha1.Interval{ |
||||||
|
expected, |
||||||
|
} |
||||||
|
require.EqualValues(t, expectedSpec, result.Spec) |
||||||
|
current = result |
||||||
|
}) |
||||||
|
} |
Loading…
Reference in new issue